glimmer-cs-gladiator 0.1.1 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -13
- data/bin/gladiator +8 -1
- data/lib/models/glimmer/gladiator/dir.rb +62 -22
- data/lib/models/glimmer/gladiator/file.rb +149 -52
- data/lib/views/glimmer/gladiator.rb +327 -123
- data/lib/views/glimmer/gladiator/text_editor.rb +119 -0
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d758e5b444ef3d48c0214ffb763e3dab3f9ca9748961e879b9ebdb626e9c2ea
|
4
|
+
data.tar.gz: cb575fbe30017319190278483334256aeb04d277798a5e3351f944c3d3a61481
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4223591b0608f621432a7ee1a1f710ad4a1684aaafb6d1d9152f064b8d707216ba3dc5fece5836764db058a9a88d209d161ee8abc5062d4fb9a4a821cb986c61
|
7
|
+
data.tar.gz: 3296674924ae085c139919e9e22a32d1c5a322b163b7fc6954e89bc02af4cb2a7c80e9a49359d9d136f4113206c48ebfcedbbe917e3f97e35529575abed1832a
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Gladiator (Glimmer Editor) 0.1.
|
1
|
+
# Gladiator (Glimmer Editor) 0.1.6 - Glimmer Custom Shell
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/glimmer-cs-gladiator.svg)](http://badge.fury.io/rb/glimmer-cs-gladiator)
|
3
3
|
|
4
4
|
![Gladiator](images/glimmer-gladiator.png)
|
@@ -9,18 +9,29 @@ Gladiator is also a personal tool for shaping an editor exactly the way I like.
|
|
9
9
|
I leave building truly professional text editors to software tooling experts who would hopefully use Glimmer one day.
|
10
10
|
|
11
11
|
Gladiator currently supports the following text editing features:
|
12
|
-
- File explorer navigation to open file
|
13
|
-
- File lookup by name
|
14
|
-
-
|
12
|
+
- File explorer navigation to open file, rename, delete, add new file, add new directory, or refresh tree (CMD+T)
|
13
|
+
- File lookup by name ignoring slashes, underscores, and dots to ease lookup (CMD+R)
|
14
|
+
- Watch open file for external changes to automatically refresh in editor
|
15
|
+
- Watch project subdirectories for changes to automatically refresh in file explorer/file lookup
|
16
|
+
- Find & Replace (CMD+F)
|
15
17
|
- Show Line Numbers
|
16
|
-
- Jump to Line
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
20
|
-
- Duplicate Line(s)
|
21
|
-
- Kill Line(s)
|
22
|
-
- Move up
|
23
|
-
- Move down
|
18
|
+
- Jump to Line (CMD+L)
|
19
|
+
- Multiple tab support (CMD+SHIFT+[ & CMD+SHIFT+] for tab navigation. CMD+1-9 to jump to a specific tab)
|
20
|
+
- Remember opened tabs, caret position, top line, window size, and window location
|
21
|
+
- Autosave on focus out/quit/open new file
|
22
|
+
- Duplicate Line(s)/selection (CMD+D)
|
23
|
+
- Kill Line(s)/selection (CMD+K)
|
24
|
+
- Move line/selection up (CMD+UP)
|
25
|
+
- Move line/selection down (CMD+DOWN)
|
26
|
+
- Comment/Uncomment line/selection (CMD+/)
|
27
|
+
- Indent/Unindent line/selection (CMD+] & CMD+[)
|
28
|
+
- Insert/Prefix New Line (CMD+ENTER & CMD+SHIFT+ENTER)
|
29
|
+
|
30
|
+
## Platforms
|
31
|
+
|
32
|
+
- Mac: Gladiator works best on the Mac.
|
33
|
+
- Linux: Gladiator works with handicaps on Linux (performing text editing operations causes scroll jitter)
|
34
|
+
- Windows: Not tested on Windows yet, but should theoretically work there too.
|
24
35
|
|
25
36
|
## Pre-requisites
|
26
37
|
|
@@ -49,7 +60,7 @@ To reuse Gladiator as a Glimmer Custom Shell inside another Glimmer application,
|
|
49
60
|
following to the application's `Gemfile`:
|
50
61
|
|
51
62
|
```
|
52
|
-
gem 'glimmer-cs-gladiator', '0.1.
|
63
|
+
gem 'glimmer-cs-gladiator', '0.1.6'
|
53
64
|
```
|
54
65
|
|
55
66
|
Run:
|
data/bin/gladiator
CHANGED
@@ -3,4 +3,11 @@
|
|
3
3
|
require 'glimmer/launcher'
|
4
4
|
|
5
5
|
gladiator_runner = File.expand_path('../gladiator_runner.rb', __FILE__)
|
6
|
-
Glimmer::Launcher.new([gladiator_runner, '-J-Xrs'] + ARGV)
|
6
|
+
launcher = Glimmer::Launcher.new([gladiator_runner, '-J-Xrs'] + ARGV)
|
7
|
+
launcher.application_paths.to_a.each do |file|
|
8
|
+
if file != gladiator_runner
|
9
|
+
launcher.application_paths.delete(file)
|
10
|
+
ENV['LOCAL_DIR'] ||= file
|
11
|
+
end
|
12
|
+
end
|
13
|
+
launcher.launch
|
@@ -15,41 +15,66 @@ module Glimmer
|
|
15
15
|
@thread = Thread.new(@filewatcher) do |fw|
|
16
16
|
fw.watch do |filename, event|
|
17
17
|
if @last_update.nil? || (Time.now.to_f - @last_update) > REFRESH_DELAY
|
18
|
-
dir.refresh if filename != dir.selected_child_path
|
18
|
+
dir.refresh if !filename.include?('new_file') && !dir.selected_child_path_history.include?(filename) && filename != dir.selected_child_path
|
19
19
|
end
|
20
20
|
@last_update = Time.now.to_f
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
-
end
|
24
|
+
end
|
25
25
|
end
|
26
26
|
|
27
|
-
attr_accessor :selected_child, :filter, :children, :filtered_path_options
|
28
|
-
attr_reader :
|
27
|
+
attr_accessor :selected_child, :filter, :children, :filtered_path_options, :filtered_path, :path, :display_path
|
28
|
+
attr_reader :name, :parent
|
29
|
+
attr_writer :all_children, :children
|
29
30
|
|
30
31
|
def initialize(path)
|
31
|
-
@
|
32
|
+
@display_path = path
|
33
|
+
@path = ::File.expand_path(@display_path)
|
34
|
+
@name = ::File.basename(::File.expand_path(path))
|
32
35
|
self.filtered_path_options = []
|
33
36
|
end
|
37
|
+
|
38
|
+
def name=(the_name)
|
39
|
+
self.display_path = display_path.sub(/#{Regexp.escape(@name)}$/, the_name)
|
40
|
+
@name = the_name
|
41
|
+
new_path = ::File.expand_path(display_path)
|
42
|
+
FileUtils.mv(path, new_path)
|
43
|
+
self.path = display_path
|
44
|
+
end
|
34
45
|
|
35
46
|
def children
|
36
47
|
@children ||= retrieve_children
|
37
48
|
end
|
38
|
-
|
49
|
+
|
39
50
|
def retrieve_children
|
40
|
-
::Dir.glob(::File.join(@
|
51
|
+
::Dir.glob(::File.join(@display_path, '*')).map {|p| ::File.file?(p) ? Gladiator::File.new(p) : Gladiator::Dir.new(p)}.sort_by {|c| c.path.to_s.downcase }.sort_by {|c| c.class.name }
|
41
52
|
end
|
42
53
|
|
43
|
-
def
|
54
|
+
def selected_child_path_history
|
55
|
+
@selected_child_path_history ||= []
|
56
|
+
end
|
57
|
+
|
58
|
+
def pause_refresh
|
59
|
+
@refresh_paused = true
|
60
|
+
end
|
61
|
+
|
62
|
+
def resume_refresh
|
63
|
+
@refresh_paused = false
|
64
|
+
end
|
65
|
+
|
66
|
+
def refresh(async: true, force: false)
|
67
|
+
return if @refresh_paused && !force
|
44
68
|
new_all_children = retrieve_all_children
|
45
|
-
new_children = retrieve_children
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
69
|
+
new_children = retrieve_children
|
70
|
+
refresh_operation = lambda do
|
71
|
+
self.all_children = new_all_children
|
72
|
+
self.children = new_children
|
73
|
+
end
|
74
|
+
if async
|
75
|
+
async_exec(&refresh_operation)
|
76
|
+
else
|
77
|
+
sync_exec(&refresh_operation)
|
53
78
|
end
|
54
79
|
end
|
55
80
|
|
@@ -66,7 +91,7 @@ module Glimmer
|
|
66
91
|
return if filter.nil?
|
67
92
|
all_children_files.select do |child|
|
68
93
|
child.path.downcase.include?(filter.downcase) ||
|
69
|
-
child.path.downcase.gsub(/[_
|
94
|
+
child.path.downcase.gsub(/[_\/\.]/, '').include?(filter.downcase)
|
70
95
|
end.sort_by {|c| c.path.to_s.downcase}
|
71
96
|
end
|
72
97
|
|
@@ -75,7 +100,7 @@ module Glimmer
|
|
75
100
|
end
|
76
101
|
|
77
102
|
def retrieve_all_children
|
78
|
-
::Dir.glob(::File.join(@
|
103
|
+
::Dir.glob(::File.join(@display_path, '**', '*')).map {|p| ::File.file?(p) ? Gladiator::File.new(p) : Gladiator::Dir.new(p)}
|
79
104
|
end
|
80
105
|
|
81
106
|
def all_children_files
|
@@ -83,31 +108,46 @@ module Glimmer
|
|
83
108
|
end
|
84
109
|
|
85
110
|
def selected_child_path=(selected_path)
|
86
|
-
if selected_path
|
111
|
+
return if selected_path.nil? ||
|
112
|
+
::Dir.exist?(selected_path) ||
|
113
|
+
(selected_child && ::File.expand_path(selected_child.path) == ::File.expand_path(selected_path))
|
114
|
+
if ::File.file?(selected_path)
|
87
115
|
@selected_child&.write_dirty_content
|
88
116
|
new_child = Gladiator::File.new(selected_path)
|
89
117
|
begin
|
90
118
|
unless new_child.dirty_content.nil?
|
91
119
|
self.selected_child&.stop_filewatcher
|
120
|
+
selected_child_path_history << new_child.path if new_child && !selected_child_path_history.include?(new_child.path)
|
92
121
|
self.selected_child = new_child
|
93
122
|
self.selected_child.start_filewatcher
|
94
123
|
end
|
95
124
|
rescue
|
96
125
|
# no op
|
97
126
|
end
|
127
|
+
else
|
128
|
+
refresh
|
98
129
|
end
|
99
130
|
end
|
100
131
|
|
101
132
|
def selected_child_path
|
102
133
|
@selected_child&.path
|
103
134
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
135
|
+
|
136
|
+
def delete!
|
137
|
+
FileUtils.rm_rf(path)
|
138
|
+
end
|
107
139
|
|
108
140
|
def to_s
|
109
141
|
path
|
110
142
|
end
|
143
|
+
|
144
|
+
def eql?(other)
|
145
|
+
self.path.eql?(other&.path)
|
146
|
+
end
|
147
|
+
|
148
|
+
def hash
|
149
|
+
self.path.hash
|
150
|
+
end
|
111
151
|
end
|
112
152
|
end
|
113
153
|
end
|
@@ -5,13 +5,17 @@ module Glimmer
|
|
5
5
|
class File
|
6
6
|
include Glimmer
|
7
7
|
|
8
|
-
attr_accessor :
|
9
|
-
attr_reader :
|
8
|
+
attr_accessor :line_numbers_content, :selection, :selection_count, :line_number, :find_text, :replace_text, :top_index, :path, :display_path
|
9
|
+
attr_reader :name, :dirty_content
|
10
10
|
|
11
11
|
def initialize(path)
|
12
12
|
raise "Not a file path: #{path}" unless ::File.file?(path)
|
13
13
|
@display_path = path
|
14
|
+
@name = ::File.basename(path)
|
14
15
|
@path = ::File.expand_path(path)
|
16
|
+
@top_index = 0
|
17
|
+
@selection_count = 0
|
18
|
+
@selection = Point.new(0, 0 + @selection_count)
|
15
19
|
read_dirty_content = ::File.read(path)
|
16
20
|
begin
|
17
21
|
# test read dirty content
|
@@ -20,20 +24,47 @@ module Glimmer
|
|
20
24
|
lines_text_size = lines.size.to_s.size
|
21
25
|
self.line_numbers_content = lines.size.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
|
22
26
|
end
|
27
|
+
@line_number = 1
|
23
28
|
self.dirty_content = read_dirty_content
|
24
|
-
observe(self, :
|
29
|
+
observe(self, :selection) do
|
25
30
|
self.line_number = line_index_for_caret_position(caret_position) + 1
|
26
31
|
end
|
27
32
|
observe(self, :line_number) do
|
28
33
|
if line_number
|
29
|
-
|
30
|
-
|
34
|
+
line_index = line_number - 1
|
35
|
+
new_caret_position = caret_position_for_line_index(line_index)
|
36
|
+
self.caret_position = new_caret_position unless self.caret_position && line_index_for_caret_position(new_caret_position) == line_index_for_caret_position(caret_position)
|
31
37
|
end
|
32
38
|
end
|
33
39
|
rescue
|
34
40
|
# no op in case of a binary file
|
35
41
|
end
|
36
42
|
end
|
43
|
+
|
44
|
+
def caret_position=(value)
|
45
|
+
self.selection = Point.new(value, value + selection_count.to_i)
|
46
|
+
if OS.linux?
|
47
|
+
async_exec do
|
48
|
+
self.top_index = line_index_for_caret_position(value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def caret_position
|
54
|
+
selection.x
|
55
|
+
end
|
56
|
+
|
57
|
+
def name=(the_name)
|
58
|
+
self.display_path = display_path.sub(/#{Regexp.escape(@name)}$/, the_name)
|
59
|
+
@name = the_name
|
60
|
+
new_path = ::File.expand_path(display_path)
|
61
|
+
FileUtils.mv(path, new_path)
|
62
|
+
self.path = new_path
|
63
|
+
end
|
64
|
+
|
65
|
+
def dirty_content=(the_content)
|
66
|
+
@dirty_content = the_content if ::File.exist?(path)
|
67
|
+
end
|
37
68
|
|
38
69
|
def start_filewatcher
|
39
70
|
@filewatcher = Filewatcher.new(@path)
|
@@ -56,23 +87,55 @@ module Glimmer
|
|
56
87
|
def stop_filewatcher
|
57
88
|
@filewatcher&.stop
|
58
89
|
end
|
59
|
-
|
60
|
-
def
|
90
|
+
|
91
|
+
def format_dirty_content_for_writing!
|
61
92
|
new_dirty_content = "#{dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
|
62
93
|
self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
|
63
|
-
|
94
|
+
end
|
95
|
+
|
96
|
+
def write_dirty_content
|
97
|
+
return unless ::File.exist?(path)
|
98
|
+
format_dirty_content_for_writing!
|
99
|
+
::File.write(path, dirty_content) if ::File.exists?(path)
|
64
100
|
rescue => e
|
65
101
|
puts "Error in writing dirty content for #{path}"
|
66
102
|
puts e.full_message
|
67
103
|
end
|
68
104
|
|
69
105
|
def write_raw_dirty_content
|
70
|
-
|
106
|
+
return unless ::File.exist?(path)
|
107
|
+
::File.write(path, dirty_content) if ::File.exists?(path)
|
71
108
|
rescue => e
|
72
109
|
puts "Error in writing raw dirty content for #{path}"
|
73
110
|
puts e.full_message
|
74
111
|
end
|
75
|
-
|
112
|
+
|
113
|
+
def current_line_indentation
|
114
|
+
current_line.to_s.match(/^(\s+)/).to_a[1].to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
def current_line
|
118
|
+
lines[line_number - 1]
|
119
|
+
end
|
120
|
+
|
121
|
+
def delete!
|
122
|
+
FileUtils.rm(path)
|
123
|
+
end
|
124
|
+
|
125
|
+
def prefix_new_line!
|
126
|
+
the_lines = lines
|
127
|
+
the_lines[line_number-1...line_number-1] = [current_line_indentation]
|
128
|
+
self.dirty_content = the_lines.join("\n")
|
129
|
+
self.caret_position = caret_position_for_line_index(line_number-1) + current_line_indentation.size
|
130
|
+
end
|
131
|
+
|
132
|
+
def insert_new_line!
|
133
|
+
the_lines = lines
|
134
|
+
the_lines[line_number...line_number] = [current_line_indentation]
|
135
|
+
self.dirty_content = the_lines.join("\n")
|
136
|
+
self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
|
137
|
+
end
|
138
|
+
|
76
139
|
def comment_line!
|
77
140
|
old_lines = lines
|
78
141
|
return if old_lines.size < 1
|
@@ -98,7 +161,7 @@ module Glimmer
|
|
98
161
|
end
|
99
162
|
end
|
100
163
|
self.dirty_content = new_lines.join("\n")
|
101
|
-
if old_selection_count > 0
|
164
|
+
if old_selection_count.to_i > 0
|
102
165
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
103
166
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
104
167
|
else
|
@@ -124,7 +187,7 @@ module Glimmer
|
|
124
187
|
end
|
125
188
|
old_caret_position = self.caret_position
|
126
189
|
self.dirty_content = new_lines.join("\n")
|
127
|
-
if old_selection_count > 0
|
190
|
+
if old_selection_count.to_i > 0
|
128
191
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
129
192
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
130
193
|
else
|
@@ -144,7 +207,7 @@ module Glimmer
|
|
144
207
|
delta = 0
|
145
208
|
line_indices_for_selection(caret_position, selection_count).each do |the_line_index|
|
146
209
|
the_line = old_lines[the_line_index]
|
147
|
-
if the_line.start_with?(' ')
|
210
|
+
if the_line.to_s.start_with?(' ')
|
148
211
|
new_lines[the_line_index] = the_line.sub(/ /, '')
|
149
212
|
delta = -2
|
150
213
|
elsif the_line.start_with?(' ')
|
@@ -153,7 +216,7 @@ module Glimmer
|
|
153
216
|
end
|
154
217
|
end
|
155
218
|
self.dirty_content = new_lines.join("\n")
|
156
|
-
if old_selection_count > 0
|
219
|
+
if old_selection_count.to_i > 0
|
157
220
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
158
221
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
159
222
|
else
|
@@ -165,12 +228,15 @@ module Glimmer
|
|
165
228
|
|
166
229
|
def kill_line!
|
167
230
|
new_lines = lines
|
168
|
-
return if new_lines.size <
|
231
|
+
return if new_lines.size < 1
|
169
232
|
line_indices = line_indices_for_selection(caret_position, selection_count)
|
170
233
|
new_lines = new_lines[0...line_indices.first] + new_lines[(line_indices.last+1)...new_lines.size]
|
171
234
|
old_caret_position = self.caret_position
|
172
|
-
self.
|
173
|
-
|
235
|
+
old_line_index = self.line_number - 1
|
236
|
+
line_position = line_position_for_caret_position(old_caret_position)
|
237
|
+
self.dirty_content = "#{new_lines.join("\n")}\n"
|
238
|
+
self.caret_position = caret_position_for_line_index(old_line_index) + [line_position, lines[old_line_index].to_s.size].min
|
239
|
+
self.selection_count = 0
|
174
240
|
end
|
175
241
|
|
176
242
|
def duplicate_line!
|
@@ -189,7 +255,7 @@ module Glimmer
|
|
189
255
|
new_lines.insert(the_line_indices.first + i, the_line)
|
190
256
|
end
|
191
257
|
self.dirty_content = new_lines.join("\n")
|
192
|
-
if old_selection_count > 0
|
258
|
+
if old_selection_count.to_i > 0
|
193
259
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
194
260
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
195
261
|
else
|
@@ -201,12 +267,21 @@ module Glimmer
|
|
201
267
|
return if find_text.to_s.empty?
|
202
268
|
all_lines = lines
|
203
269
|
the_line_index = line_index_for_caret_position(caret_position)
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
270
|
+
line_position = line_position_for_caret_position(caret_position)
|
271
|
+
found =
|
272
|
+
2.times do |i|
|
273
|
+
rotation = the_line_index
|
274
|
+
all_lines.rotate(rotation).each_with_index do |the_line, the_index|
|
275
|
+
the_index = (the_index + rotation)%all_lines.size
|
276
|
+
start_position = 0
|
277
|
+
start_position = line_position + find_text.to_s.size if i == 0 && the_index == the_line_index && found_text?(caret_position)
|
278
|
+
text_to_find_in = the_line.downcase[start_position..-1]
|
279
|
+
occurrence_index = text_to_find_in&.index(find_text.to_s.downcase)
|
280
|
+
if occurrence_index
|
281
|
+
self.caret_position = caret_position_for_line_index(the_index) + start_position + occurrence_index
|
282
|
+
self.selection_count = find_text.to_s.size
|
283
|
+
return
|
284
|
+
end
|
210
285
|
end
|
211
286
|
end
|
212
287
|
end
|
@@ -215,21 +290,34 @@ module Glimmer
|
|
215
290
|
return if find_text.to_s.empty?
|
216
291
|
all_lines = lines
|
217
292
|
the_line_index = line_index_for_caret_position(caret_position)
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
293
|
+
line_position = line_position_for_caret_position(caret_position)
|
294
|
+
2.times do |i|
|
295
|
+
rotation = - the_line_index - 1 + all_lines.size
|
296
|
+
all_lines.reverse.rotate(rotation).each_with_index do |the_line, the_index|
|
297
|
+
the_index = all_lines.size - 1 - (the_index + rotation)%all_lines.size
|
298
|
+
if the_index == the_line_index
|
299
|
+
start_position = i > 0 ? 0 : (the_line.size - line_position)
|
300
|
+
else
|
301
|
+
start_position = 0
|
302
|
+
end
|
303
|
+
text_to_find_in = the_line.downcase.reverse[start_position...the_line.size].to_s
|
304
|
+
occurrence_index = text_to_find_in.index(find_text.to_s.downcase.reverse)
|
305
|
+
if occurrence_index
|
306
|
+
self.caret_position = caret_position_for_line_index(the_index) + (the_line.size - (start_position + occurrence_index + find_text.to_s.size))
|
307
|
+
self.selection_count = find_text.to_s.size
|
308
|
+
return
|
309
|
+
end
|
226
310
|
end
|
227
311
|
end
|
228
312
|
end
|
229
313
|
|
230
314
|
def ensure_find_next
|
231
315
|
return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
|
232
|
-
find_next unless
|
316
|
+
find_next unless found_text?(self.caret_position)
|
317
|
+
end
|
318
|
+
|
319
|
+
def found_text?(caret_position)
|
320
|
+
dirty_content[caret_position.to_i, find_text.to_s.size].to_s.downcase == find_text.to_s.downcase
|
233
321
|
end
|
234
322
|
|
235
323
|
def replace_next!
|
@@ -242,10 +330,12 @@ module Glimmer
|
|
242
330
|
end
|
243
331
|
|
244
332
|
def page_up
|
333
|
+
self.selection_count = 0
|
245
334
|
self.line_number = [(self.line_number - 15), 1].max
|
246
335
|
end
|
247
336
|
|
248
337
|
def page_down
|
338
|
+
self.selection_count = 0
|
249
339
|
self.line_number = [(self.line_number + 15), lines.size].min
|
250
340
|
end
|
251
341
|
|
@@ -262,23 +352,18 @@ module Glimmer
|
|
262
352
|
return if old_lines.size < 2
|
263
353
|
old_selection_count = self.selection_count
|
264
354
|
old_caret_position = self.caret_position
|
265
|
-
|
266
|
-
|
355
|
+
old_caret_position_line_caret_position = caret_position_for_caret_position_start_of_line(old_caret_position)
|
356
|
+
old_caret_position_line_position = old_caret_position - old_caret_position_line_caret_position
|
267
357
|
old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
|
268
358
|
new_lines = lines
|
269
359
|
the_line_indices = line_indices_for_selection(caret_position, selection_count)
|
270
360
|
the_lines = lines_for_selection(caret_position, selection_count)
|
271
361
|
new_line_index = [the_line_indices.first - 1, 0].max
|
272
|
-
delta = -1 * (new_lines[new_line_index].size + 1)
|
273
362
|
new_lines[the_line_indices.first..the_line_indices.last] = []
|
274
363
|
new_lines[new_line_index...new_line_index] = the_lines
|
275
364
|
self.dirty_content = new_lines.join("\n")
|
276
|
-
|
277
|
-
|
278
|
-
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position + delta)
|
279
|
-
else
|
280
|
-
self.caret_position = old_caret_position + delta
|
281
|
-
end
|
365
|
+
self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
|
366
|
+
self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
|
282
367
|
end
|
283
368
|
|
284
369
|
def move_down!
|
@@ -286,23 +371,18 @@ module Glimmer
|
|
286
371
|
return if old_lines.size < 2
|
287
372
|
old_selection_count = self.selection_count
|
288
373
|
old_caret_position = self.caret_position
|
289
|
-
|
290
|
-
|
374
|
+
old_caret_position_line_caret_position = caret_position_for_caret_position_start_of_line(old_caret_position)
|
375
|
+
old_caret_position_line_position = old_caret_position - old_caret_position_line_caret_position
|
291
376
|
old_end_caret_line_index = end_caret_position_line_index(caret_position, selection_count)
|
292
377
|
new_lines = lines
|
293
378
|
the_line_indices = line_indices_for_selection(caret_position, selection_count)
|
294
379
|
the_lines = lines_for_selection(caret_position, selection_count)
|
295
380
|
new_line_index = [the_line_indices.first + 1, new_lines.size - 1].min
|
296
|
-
delta = new_lines[new_line_index].size + 1
|
297
381
|
new_lines[the_line_indices.first..the_line_indices.last] = []
|
298
382
|
new_lines[new_line_index...new_line_index] = the_lines
|
299
383
|
self.dirty_content = new_lines.join("\n")
|
300
|
-
|
301
|
-
|
302
|
-
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position + delta)
|
303
|
-
else
|
304
|
-
self.caret_position = old_caret_position + delta
|
305
|
-
end
|
384
|
+
self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
|
385
|
+
self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
|
306
386
|
end
|
307
387
|
|
308
388
|
def lines
|
@@ -318,12 +398,21 @@ module Glimmer
|
|
318
398
|
end
|
319
399
|
|
320
400
|
def caret_position_for_line_index(line_index)
|
321
|
-
lines[0...line_index].join("\n").size
|
401
|
+
cp = lines[0...line_index].join("\n").size
|
402
|
+
cp += 1 if line_index > 0
|
403
|
+
cp
|
322
404
|
end
|
323
405
|
|
324
406
|
def caret_position_for_caret_position_start_of_line(caret_position)
|
325
407
|
caret_position_for_line_index(line_index_for_caret_position(caret_position))
|
326
408
|
end
|
409
|
+
|
410
|
+
# position within line containing "caret position" (e.g. for caret position 5 in 1st line, they match as 5, for 15 in line 2 with line 1 having 10 characters, line position is 4)
|
411
|
+
# TODO consider renaming to line_character_position_for_caret_position
|
412
|
+
def line_position_for_caret_position(caret_position)
|
413
|
+
caret_position = caret_position.to_i
|
414
|
+
caret_position - caret_position_for_caret_position_start_of_line(caret_position)
|
415
|
+
end
|
327
416
|
|
328
417
|
def line_caret_positions_for_selection(caret_position, selection_count)
|
329
418
|
line_indices = line_indices_for_selection(caret_position, selection_count)
|
@@ -358,6 +447,14 @@ module Glimmer
|
|
358
447
|
def to_s
|
359
448
|
path
|
360
449
|
end
|
450
|
+
|
451
|
+
def eql?(other)
|
452
|
+
self.path.eql?(other&.path)
|
453
|
+
end
|
454
|
+
|
455
|
+
def hash
|
456
|
+
self.path.hash
|
457
|
+
end
|
361
458
|
end
|
362
459
|
end
|
363
460
|
end
|