glimmer-cs-gladiator 0.4.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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