glimmer-cs-gladiator 0.4.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b17d21c81f04c1f1fc1ad516013d9e62a6abeb0900096b1bd13c95c6cf10ccd
4
- data.tar.gz: 78d41ab949f3f40c71f2abfa26310a32f3720eecb64dcf5b90d2f155c2b35345
3
+ metadata.gz: c9b90cb14c65857fcd2aae74b253de63975e07979598fff9859016fa49eab9c2
4
+ data.tar.gz: 780b56d9e8e71e1d25d0399eec1c634fa1283af07059f4ec7042a4ff42c7c31d
5
5
  SHA512:
6
- metadata.gz: bff6362c1eb4cc711c507ac90aa34e5a5b11653fe7b48f475bd829b37fdb1a87ca6b2317b35ff11f14f287aebfe2e35dee5e47ea2e9575f74c7b9971a1231b77
7
- data.tar.gz: dc19f782cfb448e32f8054fee66797001af383cdcbedf26aeed3a3beaddef4309edefa4ca59c9be4192cd534d8a670bed35bd691ee458e3c5d22a43938e9d5e2
6
+ metadata.gz: 381596e40835072897b07ed25faa61f3edd72fba81a4637303b4e2dbb5698a0564f7737b01e7e9ff40f038673d25b5ad20fc8e8875d40a1082df8e1169cf3b09
7
+ data.tar.gz: d5fd3e26fe95a495eb4ce84eea62ceb3a0080eeae41a15ea45dbfd53275615daa2f90dfa2a0c07de67893387febed5021fb5e46af81be0e5a17afb8aa000453c
data/README.md CHANGED
@@ -1,14 +1,12 @@
1
- # <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.4.0 - [Ugliest Text Editor Ever](https://www.reddit.com/r/ruby/comments/hgve8k/gladiator_glimmer_editor_ugliest_text_editor_ever/)
1
+ # <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.5.3 - [Ugliest Text Editor Ever](https://www.reddit.com/r/ruby/comments/hgve8k/gladiator_glimmer_editor_ugliest_text_editor_ever/)
2
2
  ## [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 /> Glimmer Custom Shell](https://github.com/AndyObtiva/glimmer-dsl-swt#custom-shell-gem)
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-cs-gladiator.svg)](http://badge.fury.io/rb/glimmer-cs-gladiator)
4
4
 
5
5
  ![Gladiator](images/glimmer-gladiator.png)
6
6
 
7
- (Now, slightly less ugly with Ruby syntax highlighting colors)
8
-
9
- Gladiator (short for Glimmer Editor) is a [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) sample project under on-going development that demonstrates how to build a text editor in Ruby using [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) (JRuby Desktop Development GUI Library).
7
+ Gladiator (short for Glimmer Editor) is a [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) sample beta project under on-going development that demonstrates how to build a text editor in Ruby using [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) (JRuby Desktop Development GUI Library).
10
8
  It is not intended to be a full-fledged editor by any means, yet mostly a fun educational exercise in using [Glimmer](https://github.com/AndyObtiva/glimmer).
11
- Gladiator is also a personal tool for shaping an editor exactly the way I like, with all the keyboard shortcuts I prefer.
9
+ Gladiator is also a personal tool for shaping an editor exactly the way I like, with all the keyboard shortcuts I prefer.
12
10
  I leave building truly professional text editors to software tooling experts who would hopefully use [Glimmer](https://github.com/AndyObtiva/glimmer) one day. Otherwise, I have been happily using Gladiator to develop all my [open-source projects](https://github.com/AndyObtiva) since May of 2020.
13
11
 
14
12
  ## Features
@@ -24,7 +22,7 @@ Gladiator currently supports the following text editing features (including keyb
24
22
  - Jump to Line (CMD+L)
25
23
  - Multiple tab support (CMD+SHIFT+[ & CMD+SHIFT+] for tab navigation. CMD+1-9 to jump to a specific tab)
26
24
  - Remember opened tabs, caret position, top line, window size, and window location
27
- - Autosave on focus out/quit/open new file
25
+ - Autosave on focus out/quit/open new file
28
26
  - Duplicate Line(s)/selection (CMD+D)
29
27
  - Kill Line(s)/selection (CMD+K)
30
28
  - Move line/selection up (CMD+UP)
@@ -33,14 +31,15 @@ Gladiator currently supports the following text editing features (including keyb
33
31
  - Indent/Unindent line/selection (CMD+] & CMD+[)
34
32
  - Insert/Prefix New Line (CMD+ENTER & CMD+SHIFT+ENTER)
35
33
  - Drag and Drop Text Editor Split Screen (drag a file from File Tree or File Lookup List, and it splits the screen)
36
- - Run current Ruby file via Run Menu (CMD+SHIFT+R)
34
+ - Run Ruby code (CMD+SHIFT+R)
35
+ - Scratchpad for running arbitrary Ruby/Glimmer code without saving to disk (CMD+SHIFT+S)
37
36
  - Change Split Orientation to Horizontal/Vertical via View Menu (CMD+SHIFT+O)
38
37
 
39
38
  ## Platforms
40
39
 
41
40
  - Mac: Gladiator works best on the Mac. This is the platform it is most used on and receives the most maintenance for.
42
- - Windows: Gladiator works OK on Windows, but has some annoying bugs.
43
- - Linux: Gladiator works with very bad handicaps on Linux (performing text editing operations causes scroll jitter)
41
+ - Windows: Gladiator works OK on Windows, but has some annoying bugs. Contributers could help fix.
42
+ - Linux: Gladiator works with handicaps on Linux (performing some text editing operations causes scroll jitter). Contributers could help fix.
44
43
 
45
44
  ## Pre-requisites
46
45
 
@@ -100,11 +99,11 @@ bin/gladiator relative-or-absolute-path/to/project
100
99
 
101
100
  ### Glimmer Custom Shell Reuse
102
101
 
103
- To reuse Gladiator as a Glimmer Custom Shell inside another Glimmer application, add the
102
+ To reuse Gladiator as a Glimmer Custom Shell inside another Glimmer application, add the
104
103
  following to the application's `Gemfile`:
105
104
 
106
105
  ```
107
- gem 'glimmer-cs-gladiator', '~> 0.4.0'
106
+ gem 'glimmer-cs-gladiator', '~> 0.5.3'
108
107
  ```
109
108
 
110
109
  Run:
@@ -117,7 +116,7 @@ And, then instantiate the Gladiator [custom shell](https://github.com/AndyObtiva
117
116
 
118
117
  ## Env Var Options
119
118
 
120
- Gladiator opens with the current directory as the root by default.
119
+ Gladiator opens with the current directory as the root by default.
121
120
  If you would like to open another directory, set `LOCAL_DIR` environment variable.
122
121
 
123
122
  Example:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.3
@@ -2,4 +2,5 @@ require_relative '../lib/glimmer-cs-gladiator'
2
2
 
3
3
  include Glimmer
4
4
 
5
- gladiator.open
5
+ local_dir = ENV['LOCAL_DIR'] || '.'
6
+ gladiator(project_dir_path: local_dir).open
@@ -23,7 +23,7 @@ module Glimmer
23
23
  args = SWTProxy.constantify_args(args)
24
24
  @swt_layout = self.class.swt_layout_class_for(underscored_layout_name).new(*args)
25
25
  @widget_proxy.swt_widget.setLayout(@swt_layout)
26
- end
26
+ end
27
27
  end
28
28
  end
29
29
  end
@@ -1,6 +1,6 @@
1
1
  module Glimmer
2
2
  class Gladiator
3
- class Command
3
+ class Command
4
4
  class << self
5
5
  include Glimmer
6
6
 
@@ -10,10 +10,10 @@ module Glimmer
10
10
 
11
11
  def command_history_for(file)
12
12
  # keeping a first command to make redo support work by remembering next command after undoing all
13
- command_history[file] ||= [Command.new(file)]
13
+ command_history[file] ||= [Command.new(file)]
14
14
  end
15
15
 
16
- def do(file, method = nil, command: nil)
16
+ def do(file, method = nil, command: nil)
17
17
  command ||= Command.new(file, method)
18
18
  command_history_for(file)&.last&.next_command = command
19
19
  command.do
@@ -21,7 +21,7 @@ module Glimmer
21
21
  end
22
22
 
23
23
  def undo(file)
24
- return if command_history_for(file).size <= 1
24
+ return if command_history_for(file).size <= 1
25
25
  command = command_history_for(file).pop
26
26
  command&.undo
27
27
  end
@@ -4,39 +4,40 @@ module Glimmer
4
4
  class Gladiator
5
5
  class Dir
6
6
  include Glimmer
7
+ include Glimmer::DataBinding::ObservableModel
7
8
 
8
9
  REFRESH_DELAY = 7
9
10
 
10
- class << self
11
- def local_dir
12
- unless @local_dir
13
- @local_dir = new(ENV['LOCAL_DIR'] || '.', true)
14
- # @local_dir.refresh
15
- @filewatcher = Filewatcher.new(@local_dir.path)
16
- @thread = Thread.new(@filewatcher) do |fw|
17
- fw.watch do |filename, event|
18
- if @last_update.nil? || (Time.now.to_f - @last_update) > REFRESH_DELAY
19
- @local_dir.refresh if !filename.include?('new_file') && !@local_dir.selected_child_path_history.include?(filename) && filename != @local_dir.selected_child_path
20
- end
21
- @last_update = Time.now.to_f
22
- end
23
- end
24
- end
25
- @local_dir
26
- end
27
- end
28
-
29
11
  attr_accessor :selected_child, :filter, :children, :filtered_path_options, :filtered_path, :display_path, :ignore_paths
30
- attr_reader :name, :parent, :path, :is_local_dir
12
+ attr_reader :name, :parent, :path
31
13
  attr_writer :all_children
32
14
 
33
- def initialize(path, is_local_dir = false)
34
- @is_local_dir = is_local_dir
15
+ def initialize(path, project_dir = nil)
16
+ @project_dir = project_dir
17
+ if is_local_dir
18
+ @filewatcher = Filewatcher.new(path)
19
+ @thread = Thread.new(@filewatcher) do |fw|
20
+ fw.watch do |filename, event|
21
+ if @last_update.nil? || (Time.now.to_f - @last_update) > REFRESH_DELAY
22
+ refresh if !filename.include?('new_file') && !selected_child_path_history.include?(filename) && filename != selected_child_path
23
+ end
24
+ @last_update = Time.now.to_f
25
+ end
26
+ end
27
+ end
35
28
  self.path = ::File.expand_path(path)
36
29
  @name = ::File.basename(::File.expand_path(path))
37
- @ignore_paths = ['packages', 'tmp', 'vendor']
30
+ @ignore_paths = ['.gladiator', '.git', 'coverage', 'packages', 'tmp', 'vendor']
38
31
  self.filtered_path_options = []
39
32
  end
33
+
34
+ def is_local_dir
35
+ @project_dir.nil?
36
+ end
37
+
38
+ def project_dir
39
+ @project_dir || self
40
+ end
40
41
 
41
42
  def path=(the_path)
42
43
  @path = the_path
@@ -44,7 +45,7 @@ module Glimmer
44
45
  end
45
46
 
46
47
  def generate_display_path
47
- is_local_dir ? path : @display_path = @path.sub(Dir.local_dir.path, '').sub(/^\//, '')
48
+ is_local_dir ? path : @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
48
49
  end
49
50
 
50
51
  def name=(the_name)
@@ -61,15 +62,15 @@ module Glimmer
61
62
 
62
63
  def retrieve_children
63
64
  @children = ::Dir.glob(::File.join(@path, '*')).reject do |p|
64
- # TODO make sure to configure ignore_paths in a preferences dialog
65
- Dir.local_dir.ignore_paths.reduce(false) do |result, ignore_path|
65
+ # TODO make sure to configure ignore_paths in a preferences dialog
66
+ project_dir.ignore_paths.reduce(false) do |result, ignore_path|
66
67
  result || p.include?(ignore_path)
67
68
  end
68
- end.map do |p|
69
- ::File.file?(p) ? Gladiator::File.new(p) : Gladiator::Dir.new(p)
70
- end.sort_by do |c|
71
- c.path.to_s.downcase
72
- end.sort_by do |c|
69
+ end.map do |p|
70
+ ::File.file?(p) ? Gladiator::File.new(p, project_dir) : Gladiator::Dir.new(p, project_dir)
71
+ end.sort_by do |c|
72
+ c.path.to_s.downcase
73
+ end.sort_by do |c|
73
74
  c.class.name
74
75
  end.each do |child|
75
76
  child.retrieve_children if child.is_a?(Dir)
@@ -105,7 +106,7 @@ module Glimmer
105
106
 
106
107
  def filter=(value)
107
108
  if value.to_s.empty?
108
- @filter = nil
109
+ @filter = nil
109
110
  else
110
111
  @filter = value
111
112
  end
@@ -117,8 +118,8 @@ module Glimmer
117
118
  def filtered
118
119
  return if filter.nil?
119
120
  children_files = !@last_filter.to_s.empty? && filter.downcase.start_with?(@last_filter.downcase) ? @last_filtered : all_children_files
120
- children_files.select do |child|
121
- child_path = child.path.to_s.sub(Dir.local_dir.path, '')
121
+ children_files.select do |child|
122
+ child_path = child.path.to_s.sub(project_dir.path, '')
122
123
  child_path.downcase.include?(filter.downcase) ||
123
124
  child_path.downcase.gsub(/[_\/.-]/, '').include?(filter.downcase.gsub(/[_\/.-]/, ''))
124
125
  end.sort_by {|c| c.path.to_s.downcase}
@@ -141,14 +142,19 @@ module Glimmer
141
142
  end
142
143
 
143
144
  def selected_child_path=(selected_path)
144
- full_selected_path = selected_path.include?(Dir.local_dir.path) ? selected_path : ::File.join(Dir.local_dir.path, selected_path)
145
- return if selected_path.nil? ||
146
- ::Dir.exist?(full_selected_path) ||
145
+ return (project_dir.selected_child = nil) if selected_path.nil?
146
+ # scratchpad scenario
147
+ if selected_path.empty? #scratchpad
148
+ @selected_child&.write_dirty_content
149
+ return (self.selected_child = File.new)
150
+ end
151
+ full_selected_path = selected_path.include?(project_dir.path) ? selected_path : ::File.join(project_dir.path, selected_path)
152
+ return if ::Dir.exist?(full_selected_path) ||
147
153
  (selected_child && selected_child.path == full_selected_path)
148
154
  selected_path = full_selected_path
149
155
  if ::File.file?(selected_path)
150
156
  @selected_child&.write_dirty_content
151
- new_child = Gladiator::File.new(selected_path)
157
+ new_child = Gladiator::File.new(selected_path, project_dir)
152
158
  begin
153
159
  unless new_child.dirty_content.nil?
154
160
  self.selected_child&.stop_filewatcher
@@ -168,6 +174,12 @@ module Glimmer
168
174
  @selected_child&.path
169
175
  end
170
176
 
177
+ def selected_child=(new_child)
178
+ file_properties = @selected_child&.backup_properties if @selected_child == new_child
179
+ @selected_child = new_child
180
+ @selected_child.restore_properties(file_properties) if file_properties
181
+ end
182
+
171
183
  def delete!
172
184
  FileUtils.rm_rf(path)
173
185
  end
@@ -183,11 +195,7 @@ module Glimmer
183
195
  def hash
184
196
  self.path.hash
185
197
  end
186
- end
198
+ end
187
199
  end
188
200
  end
189
-
190
- at_exit do
191
- Glimmer::Gladiator::Dir.local_dir.selected_child&.write_raw_dirty_content
192
- end
193
201
 
@@ -1,22 +1,21 @@
1
- require 'models/glimmer/gladiator/dir'
2
-
3
1
  module Glimmer
4
2
  class Gladiator
5
3
  class File
6
4
  include Glimmer
7
-
5
+
8
6
  attr_accessor :dirty_content, :line_numbers_content, :selection, :line_number, :find_text, :replace_text, :top_pixel, :display_path, :case_sensitive
9
- attr_reader :name, :path
7
+ attr_reader :name, :path, :project_dir
10
8
 
11
- def initialize(path)
12
- raise "Not a file path: #{path}" unless ::File.file?(path)
9
+ def initialize(path='', project_dir=nil)
10
+ raise "Not a file path: #{path}" if path.nil? || (!path.empty? && !::File.file?(path))
11
+ @project_dir = project_dir
13
12
  @command_history = []
14
- @name = ::File.basename(path)
15
- self.path = ::File.expand_path(path)
13
+ @name = path.empty? ? 'Scratchpad' : ::File.basename(path)
14
+ self.path = ::File.expand_path(path) unless path.empty?
16
15
  @top_pixel = 0
17
16
  @selection_count = 0
18
17
  @selection = Point.new(0, 0 + @selection_count)
19
- read_dirty_content = ::File.read(path)
18
+ read_dirty_content = path.empty? ? '' : ::File.read(path)
20
19
  begin
21
20
  # test read dirty content
22
21
  read_dirty_content.split("\n")
@@ -40,16 +39,34 @@ module Glimmer
40
39
  # no op in case of a binary file
41
40
  end
42
41
  end
43
-
42
+
44
43
  def path=(the_path)
45
44
  @path = the_path
46
45
  generate_display_path
47
46
  end
48
-
47
+
49
48
  def generate_display_path
50
- @display_path = @path.sub(Dir.local_dir.path, '').sub(/^\//, '')
49
+ return if @path.empty?
50
+ @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
51
51
  end
52
52
 
53
+ def scratchpad?
54
+ path.to_s.empty?
55
+ end
56
+
57
+ def backup_properties
58
+ [:find_text, :replace_text, :case_sensitive, :top_pixel, :caret_position, :selection_count].reduce({}) do |hash, property|
59
+ hash.merge(property => send(property))
60
+ end
61
+ end
62
+
63
+ def restore_properties(properties_hash)
64
+ return if properties_hash[:caret_position] == 0 && properties_hash[:selection_count] == 0 && properties_hash[:find_text].nil? && properties_hash[:replace_text].nil? && properties_hash[:top_pixel] == 0 && properties_hash[:case_sensitive].nil?
65
+ properties_hash.each do |property, value|
66
+ send("#{property}=", value)
67
+ end
68
+ end
69
+
53
70
  # to use for widget data-binding
54
71
  def content=(value)
55
72
  value = value.gsub("\t", ' ')
@@ -68,7 +85,7 @@ module Glimmer
68
85
  self.selection = Point.new(value, value + selection_count.to_i)
69
86
  self.top_pixel = old_top_pixel
70
87
  end
71
-
88
+
72
89
  def caret_position
73
90
  selection.x
74
91
  end
@@ -76,28 +93,29 @@ module Glimmer
76
93
  def selection_count
77
94
  selection.y - selection.x
78
95
  end
79
-
96
+
80
97
  def selection_count=(value)
81
98
  self.selection = Point.new(caret_position, caret_position + value.to_i)
82
- end
83
-
99
+ end
100
+
84
101
  def name=(the_name)
85
- new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name)
102
+ new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name) unless scratchpad?
86
103
  @name = the_name
87
- if ::File.exists?(path)
104
+ if !scratchpad? && ::File.exist?(path)
88
105
  FileUtils.mv(path, new_path)
89
106
  self.path = new_path
90
107
  end
91
108
  end
92
109
 
93
110
  def dirty_content=(the_content)
94
- @dirty_content = the_content if ::File.exist?(path)
111
+ @dirty_content = the_content
95
112
  notify_observers(:content)
96
113
  end
97
-
114
+
98
115
  def start_filewatcher
116
+ return if scratchpad?
99
117
  @filewatcher = Filewatcher.new(@path)
100
- @thread = Thread.new(@filewatcher) do |fw|
118
+ @thread = Thread.new(@filewatcher) do |fw|
101
119
  fw.watch do |filename, event|
102
120
  begin
103
121
  read_dirty_content = ::File.read(path)
@@ -112,27 +130,28 @@ module Glimmer
112
130
  end
113
131
  end
114
132
  end
115
-
133
+
116
134
  def stop_filewatcher
117
135
  @filewatcher&.stop
118
136
  end
119
137
 
120
138
  def format_dirty_content_for_writing!
121
- new_dirty_content = "#{dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
139
+ new_dirty_content = dirty_content.split("\n").map {|line| line.strip.empty? ? line : line.rstrip }.join("\n")
140
+ new_dirty_content = "#{new_dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
122
141
  self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
123
142
  end
124
-
143
+
125
144
  def write_dirty_content
126
- return unless ::File.exist?(path)
145
+ return if scratchpad? || !::File.exist?(path)
127
146
  format_dirty_content_for_writing!
128
147
  ::File.write(path, dirty_content) if ::File.exists?(path)
129
148
  rescue => e
130
149
  puts "Error in writing dirty content for #{path}"
131
150
  puts e.full_message
132
151
  end
133
-
152
+
134
153
  def write_raw_dirty_content
135
- return unless ::File.exist?(path)
154
+ return if scratchpad? || !::File.exist?(path)
136
155
  ::File.write(path, dirty_content) if ::File.exists?(path)
137
156
  rescue => e
138
157
  puts "Error in writing raw dirty content for #{path}"
@@ -143,19 +162,20 @@ module Glimmer
143
162
  current_line.to_s.match(/^(\s+)/).to_a[1].to_s
144
163
  end
145
164
 
146
- def current_line
165
+ def current_line
147
166
  lines[line_number - 1]
148
167
  end
149
168
 
150
169
  def delete!
151
- FileUtils.rm(path)
170
+ FileUtils.rm(path) unless scratchpad?
152
171
  end
153
-
172
+
154
173
  def prefix_new_line!
155
174
  the_lines = lines
156
175
  the_lines[line_number-1...line_number-1] = [current_line_indentation]
157
176
  self.dirty_content = the_lines.join("\n")
158
177
  self.caret_position = caret_position_for_line_index(line_number-1) + current_line_indentation.size
178
+ self.selection_count = 0
159
179
  end
160
180
 
161
181
  def insert_new_line!
@@ -163,6 +183,7 @@ module Glimmer
163
183
  the_lines[line_number...line_number] = [current_line_indentation]
164
184
  self.dirty_content = the_lines.join("\n")
165
185
  self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
186
+ self.selection_count = 0
166
187
  end
167
188
 
168
189
  def comment_line!
@@ -190,7 +211,7 @@ module Glimmer
190
211
  delta += 2
191
212
  end
192
213
  end
193
- self.dirty_content = new_lines.join("\n")
214
+ self.dirty_content = new_lines.join("\n")
194
215
  if old_selection_count.to_i > 0
195
216
  self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
196
217
  self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
@@ -200,7 +221,7 @@ module Glimmer
200
221
  self.caret_position = new_caret_position
201
222
  end
202
223
  end
203
-
224
+
204
225
  def indent!
205
226
  new_lines = lines
206
227
  old_lines = lines
@@ -216,16 +237,15 @@ module Glimmer
216
237
  new_lines[the_line_index] = " #{the_line}"
217
238
  end
218
239
  old_caret_position = self.caret_position
219
- self.dirty_content = new_lines.join("\n")
240
+ self.dirty_content = new_lines.join("\n")
220
241
  if old_selection_count.to_i > 0
221
- caret_position_value = caret_position_for_line_index(old_caret_position_line_index)
222
- selection_count_value = (caret_position_for_line_index(old_end_caret_line_index + 1) - caret_position_value)
223
- self.selection = Point.new(caret_position_value, caret_position_value + selection_count_value)
242
+ self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
243
+ self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
224
244
  else
225
245
  self.caret_position = old_caret_position + delta
226
246
  end
227
247
  end
228
-
248
+
229
249
  def outdent!
230
250
  new_lines = lines
231
251
  old_lines = lines
@@ -246,18 +266,17 @@ module Glimmer
246
266
  delta = -1
247
267
  end
248
268
  end
249
- self.dirty_content = new_lines.join("\n")
269
+ self.dirty_content = new_lines.join("\n")
250
270
  if old_selection_count.to_i > 0
251
- caret_position_value = caret_position_for_line_index(old_caret_position_line_index)
252
- selection_count_value = (caret_position_for_line_index(old_end_caret_line_index + 1) - caret_position_value)
253
- self.selection = Point.new(caret_position_value, caret_position_value + selection_count_value)
271
+ self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
272
+ self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
254
273
  else
255
274
  new_caret_position = old_caret_position + delta
256
275
  new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
257
276
  self.caret_position = new_caret_position
258
277
  end
259
278
  end
260
-
279
+
261
280
  def kill_line!
262
281
  new_lines = lines
263
282
  return if new_lines.size < 1
@@ -270,7 +289,7 @@ module Glimmer
270
289
  self.caret_position = caret_position_for_line_index(old_line_index) + [line_position, lines[old_line_index].to_s.size].min
271
290
  self.selection_count = 0
272
291
  end
273
-
292
+
274
293
  def duplicate_line!
275
294
  new_lines = lines
276
295
  old_lines = lines
@@ -294,9 +313,9 @@ module Glimmer
294
313
  self.caret_position = old_caret_position + delta
295
314
  end
296
315
  end
297
-
316
+
298
317
  def find_next
299
- return if find_text.to_s.empty?
318
+ return if find_text.to_s.empty?
300
319
  all_lines = lines
301
320
  the_line_index = line_index_for_caret_position(caret_position)
302
321
  line_position = line_position_for_caret_position(caret_position)
@@ -312,13 +331,12 @@ module Glimmer
312
331
  if occurrence_index
313
332
  self.caret_position = caret_position_for_line_index(the_index) + start_position + occurrence_index
314
333
  self.selection_count = find_text.to_s.size
315
- self.selection = Point.new(self.caret_position, self.caret_position + self.selection_count)
316
334
  return
317
335
  end
318
336
  end
319
337
  end
320
338
  end
321
-
339
+
322
340
  def find_previous
323
341
  return if find_text.to_s.empty?
324
342
  all_lines = lines
@@ -343,7 +361,7 @@ module Glimmer
343
361
  end
344
362
  end
345
363
  end
346
-
364
+
347
365
  def ensure_find_next
348
366
  return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
349
367
  find_next unless found_text?(self.caret_position)
@@ -352,37 +370,45 @@ module Glimmer
352
370
  def found_text?(caret_position)
353
371
  dirty_content[caret_position.to_i, find_text.to_s.size].to_s.downcase == find_text.to_s.downcase
354
372
  end
355
-
373
+
356
374
  def replace_next!
357
375
  return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
358
376
  ensure_find_next
359
377
  new_dirty_content = dirty_content
360
378
  new_dirty_content[caret_position, find_text.size] = replace_text.to_s
361
379
  self.dirty_content = new_dirty_content
362
- find_next
380
+ find_next
363
381
  find_next if replace_text.to_s.include?(find_text) && !replace_text.to_s.start_with?(find_text)
364
382
  end
365
-
383
+
366
384
  def page_up
367
385
  self.selection_count = 0
368
386
  self.line_number = [(self.line_number - 15), 1].max
369
387
  end
370
-
388
+
371
389
  def page_down
372
390
  self.selection_count = 0
373
391
  self.line_number = [(self.line_number + 15), lines.size].min
374
392
  end
375
-
393
+
376
394
  def home
377
395
  self.selection_count = 0
378
396
  self.line_number = 1
379
397
  end
380
-
398
+
381
399
  def end
382
400
  self.selection_count = 0
383
401
  self.line_number = lines.size
384
402
  end
385
-
403
+
404
+ def start_of_line
405
+ self.caret_position = caret_position_for_line_index(self.line_number - 1)
406
+ end
407
+
408
+ def end_of_line
409
+ self.caret_position = caret_position_for_line_index(self.line_number) - 1
410
+ end
411
+
386
412
  def move_up!
387
413
  old_lines = lines
388
414
  return if old_lines.size < 2
@@ -401,7 +427,7 @@ module Glimmer
401
427
  self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
402
428
  self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
403
429
  end
404
-
430
+
405
431
  def move_down!
406
432
  old_lines = lines
407
433
  return if old_lines.size < 2
@@ -420,25 +446,38 @@ module Glimmer
420
446
  self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
421
447
  self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
422
448
  end
423
-
449
+
450
+ def run
451
+ begin
452
+ if scratchpad?
453
+ eval content
454
+ else
455
+ write_dirty_content
456
+ load path
457
+ end
458
+ rescue SyntaxError, StandardError => e
459
+ puts e.full_message
460
+ end
461
+ end
462
+
424
463
  def lines
425
464
  dirty_content.split("\n")
426
465
  end
427
-
466
+
428
467
  def line_for_caret_position(caret_position)
429
468
  lines[line_index_for_caret_position(caret_position.to_i)]
430
469
  end
431
-
470
+
432
471
  def line_index_for_caret_position(caret_position)
433
472
  dirty_content[0...caret_position.to_i].count("\n")
434
473
  end
435
-
474
+
436
475
  def caret_position_for_line_index(line_index)
437
476
  cp = lines[0...line_index].join("\n").size
438
477
  cp += 1 if line_index > 0
439
478
  cp
440
479
  end
441
-
480
+
442
481
  def caret_position_for_caret_position_start_of_line(caret_position)
443
482
  caret_position_for_line_index(line_index_for_caret_position(caret_position))
444
483
  end
@@ -449,23 +488,23 @@ module Glimmer
449
488
  caret_position = caret_position.to_i
450
489
  caret_position - caret_position_for_caret_position_start_of_line(caret_position)
451
490
  end
452
-
491
+
453
492
  def line_caret_positions_for_selection(caret_position, selection_count)
454
493
  line_indices = line_indices_for_selection(caret_position, selection_count)
455
494
  line_caret_positions = line_indices.map { |line_index| caret_position_for_line_index(line_index) }.to_a
456
495
  end
457
-
496
+
458
497
  def end_caret_position_line_index(caret_position, selection_count)
459
498
  end_caret_position = caret_position + selection_count.to_i
460
499
  end_caret_position -= 1 if dirty_content[end_caret_position - 1] == "\n"
461
500
  end_line_index = line_index_for_caret_position(end_caret_position)
462
501
  end
463
-
502
+
464
503
  def lines_for_selection(caret_position, selection_count)
465
504
  line_indices = line_indices_for_selection(caret_position, selection_count)
466
505
  lines[line_indices.first..line_indices.last]
467
506
  end
468
-
507
+
469
508
  def line_indices_for_selection(caret_position, selection_count)
470
509
  start_line_index = line_index_for_caret_position(caret_position)
471
510
  if selection_count.to_i > 0
@@ -475,22 +514,22 @@ module Glimmer
475
514
  end
476
515
  (start_line_index..end_line_index).to_a
477
516
  end
478
-
517
+
479
518
  def children
480
519
  []
481
520
  end
482
-
521
+
483
522
  def to_s
484
523
  path
485
524
  end
486
-
525
+
487
526
  def eql?(other)
488
527
  self.path.eql?(other&.path)
489
528
  end
490
-
529
+
491
530
  def hash
492
531
  self.path.hash
493
532
  end
494
- end
533
+ end
495
534
  end
496
535
  end