glimmer-cs-gladiator 0.3.0 → 0.5.1
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 +4 -4
- data/README.md +15 -9
- data/VERSION +1 -1
- data/bin/gladiator_runner.rb +2 -1
- data/lib/models/glimmer/gladiator/command.rb +8 -4
- data/lib/models/glimmer/gladiator/dir.rb +51 -51
- data/lib/models/glimmer/gladiator/file.rb +119 -77
- data/lib/views/glimmer/gladiator.rb +404 -273
- data/lib/views/glimmer/gladiator/text_editor.rb +37 -19
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b1fe5cc493fe6df44d316fe7e4fc9e19eb6e0f463724e5bbf1254fb35379463
|
4
|
+
data.tar.gz: eb399a865ec9e5ab6f4f269cf8c318f8931eda1e014ea557516cc30a979bb249
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c20d228ba4421dc54f55206a9c75418c0fe6f1369f27984864c3b22620b42880670d9da3416d5db65e0d3a8028521bddd4f07747fd6cf9fb3a61aec23f617e1
|
7
|
+
data.tar.gz: 30bec26afe87951052c68b1bf2d6a1e4475d715d9de37664bdb3ecc36584ae363bb941152da4f268db8a119360c165e202ba36b998c6c6feb3df9bbf487ddcac
|
data/README.md
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
# <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.
|
1
|
+
# <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.5.1 - [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
|
[](http://badge.fury.io/rb/glimmer-cs-gladiator)
|
4
4
|
|
5
5
|

|
6
6
|
|
7
|
-
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 [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).
|
8
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).
|
9
|
-
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.
|
10
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.
|
11
11
|
|
12
12
|
## Features
|
13
13
|
|
14
14
|
Gladiator currently supports the following text editing features (including keyboard shortcuts with Mac CMD=CTRL on Windows/Linux):
|
15
|
+
- Ruby Syntax Highlighting with colors
|
15
16
|
- File explorer navigation with context menu to open file, rename, delete, add new file, add new directory, or refresh tree (CMD+T)
|
16
17
|
- File lookup by name ignoring slashes, underscores, and dots to ease lookup (CMD+R)
|
17
18
|
- Watch open file for external changes to automatically refresh in editor
|
@@ -21,7 +22,7 @@ Gladiator currently supports the following text editing features (including keyb
|
|
21
22
|
- Jump to Line (CMD+L)
|
22
23
|
- Multiple tab support (CMD+SHIFT+[ & CMD+SHIFT+] for tab navigation. CMD+1-9 to jump to a specific tab)
|
23
24
|
- Remember opened tabs, caret position, top line, window size, and window location
|
24
|
-
- Autosave on focus out/quit/open new file
|
25
|
+
- Autosave on focus out/quit/open new file
|
25
26
|
- Duplicate Line(s)/selection (CMD+D)
|
26
27
|
- Kill Line(s)/selection (CMD+K)
|
27
28
|
- Move line/selection up (CMD+UP)
|
@@ -30,12 +31,15 @@ Gladiator currently supports the following text editing features (including keyb
|
|
30
31
|
- Indent/Unindent line/selection (CMD+] & CMD+[)
|
31
32
|
- Insert/Prefix New Line (CMD+ENTER & CMD+SHIFT+ENTER)
|
32
33
|
- Drag and Drop Text Editor Split Screen (drag a file from File Tree or File Lookup List, and it splits the screen)
|
34
|
+
- Run Ruby code (CMD+SHIFT+R)
|
35
|
+
- Scratchpad for running arbitrary Ruby/Glimmer code without saving to disk (CMD+SHIFT+S)
|
36
|
+
- Change Split Orientation to Horizontal/Vertical via View Menu (CMD+SHIFT+O)
|
33
37
|
|
34
38
|
## Platforms
|
35
39
|
|
36
40
|
- Mac: Gladiator works best on the Mac. This is the platform it is most used on and receives the most maintenance for.
|
37
|
-
- Windows: Gladiator works OK on Windows, but has some annoying bugs.
|
38
|
-
- Linux: Gladiator works with
|
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.
|
39
43
|
|
40
44
|
## Pre-requisites
|
41
45
|
|
@@ -95,11 +99,11 @@ bin/gladiator relative-or-absolute-path/to/project
|
|
95
99
|
|
96
100
|
### Glimmer Custom Shell Reuse
|
97
101
|
|
98
|
-
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
|
99
103
|
following to the application's `Gemfile`:
|
100
104
|
|
101
105
|
```
|
102
|
-
gem 'glimmer-cs-gladiator', '~> 0.
|
106
|
+
gem 'glimmer-cs-gladiator', '~> 0.5.1'
|
103
107
|
```
|
104
108
|
|
105
109
|
Run:
|
@@ -112,7 +116,7 @@ And, then instantiate the Gladiator [custom shell](https://github.com/AndyObtiva
|
|
112
116
|
|
113
117
|
## Env Var Options
|
114
118
|
|
115
|
-
Gladiator opens with the current directory as the root by default.
|
119
|
+
Gladiator opens with the current directory as the root by default.
|
116
120
|
If you would like to open another directory, set `LOCAL_DIR` environment variable.
|
117
121
|
|
118
122
|
Example:
|
@@ -131,7 +135,9 @@ It currently remembers:
|
|
131
135
|
- Last opened file
|
132
136
|
- Caret position
|
133
137
|
- Top line position
|
138
|
+
- Window size
|
134
139
|
- Opened tabs
|
140
|
+
- Split tabs
|
135
141
|
- Ignore Paths
|
136
142
|
|
137
143
|
## Gotcha
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.1
|
data/bin/gladiator_runner.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module Glimmer
|
2
2
|
class Gladiator
|
3
|
-
class Command
|
3
|
+
class Command
|
4
4
|
class << self
|
5
|
+
include Glimmer
|
6
|
+
|
5
7
|
def command_history
|
6
8
|
@command_history ||= {}
|
7
9
|
end
|
@@ -11,7 +13,7 @@ module Glimmer
|
|
11
13
|
command_history[file] ||= [Command.new(file)]
|
12
14
|
end
|
13
15
|
|
14
|
-
def do(file, method = nil, command: nil)
|
16
|
+
def do(file, method = nil, command: nil)
|
15
17
|
command ||= Command.new(file, method)
|
16
18
|
command_history_for(file)&.last&.next_command = command
|
17
19
|
command.do
|
@@ -20,11 +22,13 @@ module Glimmer
|
|
20
22
|
|
21
23
|
def undo(file)
|
22
24
|
return if command_history_for(file).size <= 1
|
23
|
-
command_history_for(file).pop
|
25
|
+
command = command_history_for(file).pop
|
26
|
+
command&.undo
|
24
27
|
end
|
25
28
|
|
26
29
|
def redo(file)
|
27
|
-
command_history_for(file).last
|
30
|
+
command = command_history_for(file).last
|
31
|
+
command&.redo
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
@@ -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
|
12
|
+
attr_reader :name, :parent, :path
|
31
13
|
attr_writer :all_children
|
32
14
|
|
33
|
-
def initialize(path,
|
34
|
-
@
|
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']
|
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,32 +45,24 @@ module Glimmer
|
|
44
45
|
end
|
45
46
|
|
46
47
|
def generate_display_path
|
47
|
-
is_local_dir ? path : @display_path = @path.sub(
|
48
|
+
is_local_dir ? path : @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
|
48
49
|
end
|
49
50
|
|
50
|
-
def name=(the_name)
|
51
|
-
self.display_path = display_path.sub(/#{Regexp.escape(@name)}$/, the_name)
|
52
|
-
@name = the_name
|
53
|
-
new_path = ::File.expand_path(display_path)
|
54
|
-
FileUtils.mv(path, new_path)
|
55
|
-
self.path = display_path
|
56
|
-
end
|
57
|
-
|
58
51
|
def children
|
59
52
|
@children ||= retrieve_children
|
60
53
|
end
|
61
54
|
|
62
55
|
def retrieve_children
|
63
56
|
@children = ::Dir.glob(::File.join(@path, '*')).reject do |p|
|
64
|
-
# TODO make sure to configure ignore_paths in a preferences dialog
|
65
|
-
|
57
|
+
# TODO make sure to configure ignore_paths in a preferences dialog
|
58
|
+
project_dir.ignore_paths.reduce(false) do |result, ignore_path|
|
66
59
|
result || p.include?(ignore_path)
|
67
60
|
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|
|
61
|
+
end.map do |p|
|
62
|
+
::File.file?(p) ? Gladiator::File.new(p, project_dir) : Gladiator::Dir.new(p, project_dir)
|
63
|
+
end.sort_by do |c|
|
64
|
+
c.path.to_s.downcase
|
65
|
+
end.sort_by do |c|
|
73
66
|
c.class.name
|
74
67
|
end.each do |child|
|
75
68
|
child.retrieve_children if child.is_a?(Dir)
|
@@ -105,7 +98,7 @@ module Glimmer
|
|
105
98
|
|
106
99
|
def filter=(value)
|
107
100
|
if value.to_s.empty?
|
108
|
-
@filter = nil
|
101
|
+
@filter = nil
|
109
102
|
else
|
110
103
|
@filter = value
|
111
104
|
end
|
@@ -117,8 +110,8 @@ module Glimmer
|
|
117
110
|
def filtered
|
118
111
|
return if filter.nil?
|
119
112
|
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(
|
113
|
+
children_files.select do |child|
|
114
|
+
child_path = child.path.to_s.sub(project_dir.path, '')
|
122
115
|
child_path.downcase.include?(filter.downcase) ||
|
123
116
|
child_path.downcase.gsub(/[_\/.-]/, '').include?(filter.downcase.gsub(/[_\/.-]/, ''))
|
124
117
|
end.sort_by {|c| c.path.to_s.downcase}
|
@@ -141,14 +134,19 @@ module Glimmer
|
|
141
134
|
end
|
142
135
|
|
143
136
|
def selected_child_path=(selected_path)
|
144
|
-
|
145
|
-
|
146
|
-
|
137
|
+
return (project_dir.selected_child = nil) if selected_path.nil?
|
138
|
+
# scratchpad scenario
|
139
|
+
if selected_path.empty? #scratchpad
|
140
|
+
@selected_child&.write_dirty_content
|
141
|
+
return (self.selected_child = File.new)
|
142
|
+
end
|
143
|
+
full_selected_path = selected_path.include?(project_dir.path) ? selected_path : ::File.join(project_dir.path, selected_path)
|
144
|
+
return if ::Dir.exist?(full_selected_path) ||
|
147
145
|
(selected_child && selected_child.path == full_selected_path)
|
148
146
|
selected_path = full_selected_path
|
149
147
|
if ::File.file?(selected_path)
|
150
148
|
@selected_child&.write_dirty_content
|
151
|
-
new_child = Gladiator::File.new(selected_path)
|
149
|
+
new_child = Gladiator::File.new(selected_path, project_dir)
|
152
150
|
begin
|
153
151
|
unless new_child.dirty_content.nil?
|
154
152
|
self.selected_child&.stop_filewatcher
|
@@ -168,6 +166,12 @@ module Glimmer
|
|
168
166
|
@selected_child&.path
|
169
167
|
end
|
170
168
|
|
169
|
+
def selected_child=(new_child)
|
170
|
+
file_properties = @selected_child&.backup_properties if @selected_child == new_child
|
171
|
+
@selected_child = new_child
|
172
|
+
@selected_child.restore_properties(file_properties) if file_properties
|
173
|
+
end
|
174
|
+
|
171
175
|
def delete!
|
172
176
|
FileUtils.rm_rf(path)
|
173
177
|
end
|
@@ -183,11 +187,7 @@ module Glimmer
|
|
183
187
|
def hash
|
184
188
|
self.path.hash
|
185
189
|
end
|
186
|
-
end
|
190
|
+
end
|
187
191
|
end
|
188
192
|
end
|
189
|
-
|
190
|
-
at_exit do
|
191
|
-
Glimmer::Gladiator::Dir.local_dir.selected_child&.write_raw_dirty_content
|
192
|
-
end
|
193
193
|
|
@@ -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
|
-
|
8
|
-
attr_accessor :dirty_content, :line_numbers_content, :selection, :
|
9
|
-
attr_reader :name, :path
|
10
|
-
|
11
|
-
def initialize(path)
|
12
|
-
raise "Not a file path: #{path}"
|
5
|
+
|
6
|
+
attr_accessor :dirty_content, :line_numbers_content, :selection, :line_number, :find_text, :replace_text, :top_pixel, :display_path, :case_sensitive
|
7
|
+
attr_reader :name, :path, :project_dir
|
8
|
+
|
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)
|
16
|
-
@
|
13
|
+
@name = path.empty? ? 'Scratchpad' : ::File.basename(path)
|
14
|
+
self.path = ::File.expand_path(path) unless path.empty?
|
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,20 +39,41 @@ 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
|
-
|
49
|
+
return if @path.empty?
|
50
|
+
@display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
|
51
51
|
end
|
52
52
|
|
53
|
+
def scratchpad?
|
54
|
+
path.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
|
-
|
56
|
-
|
72
|
+
value = value.gsub("\t", ' ')
|
73
|
+
if dirty_content != value
|
74
|
+
Command.do(self) # record a native (OS-widget) operation
|
75
|
+
self.dirty_content = value
|
76
|
+
end
|
57
77
|
end
|
58
78
|
|
59
79
|
def content
|
@@ -61,35 +81,32 @@ module Glimmer
|
|
61
81
|
end
|
62
82
|
|
63
83
|
def caret_position=(value)
|
84
|
+
old_top_pixel = top_pixel
|
64
85
|
self.selection = Point.new(value, value + selection_count.to_i)
|
65
|
-
|
66
|
-
async_exec do
|
67
|
-
self.top_index = line_index_for_caret_position(value)
|
68
|
-
end
|
69
|
-
end
|
86
|
+
self.top_pixel = old_top_pixel
|
70
87
|
end
|
71
|
-
|
88
|
+
|
72
89
|
def caret_position
|
73
90
|
selection.x
|
74
91
|
end
|
75
|
-
|
76
|
-
def
|
77
|
-
|
78
|
-
@name = the_name
|
79
|
-
if ::File.exists?(path)
|
80
|
-
FileUtils.mv(path, new_path)
|
81
|
-
self.path = new_path
|
82
|
-
end
|
92
|
+
|
93
|
+
def selection_count
|
94
|
+
selection.y - selection.x
|
83
95
|
end
|
84
|
-
|
96
|
+
|
97
|
+
def selection_count=(value)
|
98
|
+
self.selection = Point.new(caret_position, caret_position + value.to_i)
|
99
|
+
end
|
100
|
+
|
85
101
|
def dirty_content=(the_content)
|
86
|
-
@dirty_content = the_content
|
102
|
+
@dirty_content = the_content
|
87
103
|
notify_observers(:content)
|
88
104
|
end
|
89
|
-
|
105
|
+
|
90
106
|
def start_filewatcher
|
107
|
+
return if scratchpad?
|
91
108
|
@filewatcher = Filewatcher.new(@path)
|
92
|
-
@thread = Thread.new(@filewatcher) do |fw|
|
109
|
+
@thread = Thread.new(@filewatcher) do |fw|
|
93
110
|
fw.watch do |filename, event|
|
94
111
|
begin
|
95
112
|
read_dirty_content = ::File.read(path)
|
@@ -104,27 +121,28 @@ module Glimmer
|
|
104
121
|
end
|
105
122
|
end
|
106
123
|
end
|
107
|
-
|
124
|
+
|
108
125
|
def stop_filewatcher
|
109
126
|
@filewatcher&.stop
|
110
127
|
end
|
111
128
|
|
112
129
|
def format_dirty_content_for_writing!
|
113
|
-
new_dirty_content =
|
130
|
+
new_dirty_content = dirty_content.split("\n").map {|line| line.strip.empty? ? line : line.rstrip }.join("\n")
|
131
|
+
new_dirty_content = "#{new_dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
|
114
132
|
self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
|
115
133
|
end
|
116
|
-
|
134
|
+
|
117
135
|
def write_dirty_content
|
118
|
-
return
|
136
|
+
return if scratchpad? || !::File.exist?(path)
|
119
137
|
format_dirty_content_for_writing!
|
120
138
|
::File.write(path, dirty_content) if ::File.exists?(path)
|
121
139
|
rescue => e
|
122
140
|
puts "Error in writing dirty content for #{path}"
|
123
141
|
puts e.full_message
|
124
142
|
end
|
125
|
-
|
143
|
+
|
126
144
|
def write_raw_dirty_content
|
127
|
-
return
|
145
|
+
return if scratchpad? || !::File.exist?(path)
|
128
146
|
::File.write(path, dirty_content) if ::File.exists?(path)
|
129
147
|
rescue => e
|
130
148
|
puts "Error in writing raw dirty content for #{path}"
|
@@ -138,16 +156,17 @@ module Glimmer
|
|
138
156
|
def current_line
|
139
157
|
lines[line_number - 1]
|
140
158
|
end
|
141
|
-
|
159
|
+
|
142
160
|
def delete!
|
143
|
-
FileUtils.rm(path)
|
161
|
+
FileUtils.rm(path) unless scratchpad?
|
144
162
|
end
|
145
|
-
|
163
|
+
|
146
164
|
def prefix_new_line!
|
147
165
|
the_lines = lines
|
148
166
|
the_lines[line_number-1...line_number-1] = [current_line_indentation]
|
149
167
|
self.dirty_content = the_lines.join("\n")
|
150
168
|
self.caret_position = caret_position_for_line_index(line_number-1) + current_line_indentation.size
|
169
|
+
self.selection_count = 0
|
151
170
|
end
|
152
171
|
|
153
172
|
def insert_new_line!
|
@@ -155,6 +174,7 @@ module Glimmer
|
|
155
174
|
the_lines[line_number...line_number] = [current_line_indentation]
|
156
175
|
self.dirty_content = the_lines.join("\n")
|
157
176
|
self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
|
177
|
+
self.selection_count = 0
|
158
178
|
end
|
159
179
|
|
160
180
|
def comment_line!
|
@@ -182,7 +202,7 @@ module Glimmer
|
|
182
202
|
delta += 2
|
183
203
|
end
|
184
204
|
end
|
185
|
-
self.dirty_content = new_lines.join("\n")
|
205
|
+
self.dirty_content = new_lines.join("\n")
|
186
206
|
if old_selection_count.to_i > 0
|
187
207
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
188
208
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
@@ -192,7 +212,7 @@ module Glimmer
|
|
192
212
|
self.caret_position = new_caret_position
|
193
213
|
end
|
194
214
|
end
|
195
|
-
|
215
|
+
|
196
216
|
def indent!
|
197
217
|
new_lines = lines
|
198
218
|
old_lines = lines
|
@@ -208,7 +228,7 @@ module Glimmer
|
|
208
228
|
new_lines[the_line_index] = " #{the_line}"
|
209
229
|
end
|
210
230
|
old_caret_position = self.caret_position
|
211
|
-
self.dirty_content = new_lines.join("\n")
|
231
|
+
self.dirty_content = new_lines.join("\n")
|
212
232
|
if old_selection_count.to_i > 0
|
213
233
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
214
234
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
@@ -216,7 +236,7 @@ module Glimmer
|
|
216
236
|
self.caret_position = old_caret_position + delta
|
217
237
|
end
|
218
238
|
end
|
219
|
-
|
239
|
+
|
220
240
|
def outdent!
|
221
241
|
new_lines = lines
|
222
242
|
old_lines = lines
|
@@ -237,7 +257,7 @@ module Glimmer
|
|
237
257
|
delta = -1
|
238
258
|
end
|
239
259
|
end
|
240
|
-
self.dirty_content = new_lines.join("\n")
|
260
|
+
self.dirty_content = new_lines.join("\n")
|
241
261
|
if old_selection_count.to_i > 0
|
242
262
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
243
263
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
@@ -247,7 +267,7 @@ module Glimmer
|
|
247
267
|
self.caret_position = new_caret_position
|
248
268
|
end
|
249
269
|
end
|
250
|
-
|
270
|
+
|
251
271
|
def kill_line!
|
252
272
|
new_lines = lines
|
253
273
|
return if new_lines.size < 1
|
@@ -260,7 +280,7 @@ module Glimmer
|
|
260
280
|
self.caret_position = caret_position_for_line_index(old_line_index) + [line_position, lines[old_line_index].to_s.size].min
|
261
281
|
self.selection_count = 0
|
262
282
|
end
|
263
|
-
|
283
|
+
|
264
284
|
def duplicate_line!
|
265
285
|
new_lines = lines
|
266
286
|
old_lines = lines
|
@@ -284,13 +304,13 @@ module Glimmer
|
|
284
304
|
self.caret_position = old_caret_position + delta
|
285
305
|
end
|
286
306
|
end
|
287
|
-
|
307
|
+
|
288
308
|
def find_next
|
289
|
-
return if find_text.to_s.empty?
|
309
|
+
return if find_text.to_s.empty?
|
290
310
|
all_lines = lines
|
291
311
|
the_line_index = line_index_for_caret_position(caret_position)
|
292
312
|
line_position = line_position_for_caret_position(caret_position)
|
293
|
-
found =
|
313
|
+
found = found_text?(caret_position)
|
294
314
|
2.times do |i|
|
295
315
|
rotation = the_line_index
|
296
316
|
all_lines.rotate(rotation).each_with_index do |the_line, the_index|
|
@@ -307,7 +327,7 @@ module Glimmer
|
|
307
327
|
end
|
308
328
|
end
|
309
329
|
end
|
310
|
-
|
330
|
+
|
311
331
|
def find_previous
|
312
332
|
return if find_text.to_s.empty?
|
313
333
|
all_lines = lines
|
@@ -332,7 +352,7 @@ module Glimmer
|
|
332
352
|
end
|
333
353
|
end
|
334
354
|
end
|
335
|
-
|
355
|
+
|
336
356
|
def ensure_find_next
|
337
357
|
return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
|
338
358
|
find_next unless found_text?(self.caret_position)
|
@@ -341,7 +361,7 @@ module Glimmer
|
|
341
361
|
def found_text?(caret_position)
|
342
362
|
dirty_content[caret_position.to_i, find_text.to_s.size].to_s.downcase == find_text.to_s.downcase
|
343
363
|
end
|
344
|
-
|
364
|
+
|
345
365
|
def replace_next!
|
346
366
|
return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
|
347
367
|
ensure_find_next
|
@@ -349,28 +369,37 @@ module Glimmer
|
|
349
369
|
new_dirty_content[caret_position, find_text.size] = replace_text.to_s
|
350
370
|
self.dirty_content = new_dirty_content
|
351
371
|
find_next
|
372
|
+
find_next if replace_text.to_s.include?(find_text) && !replace_text.to_s.start_with?(find_text)
|
352
373
|
end
|
353
|
-
|
374
|
+
|
354
375
|
def page_up
|
355
376
|
self.selection_count = 0
|
356
377
|
self.line_number = [(self.line_number - 15), 1].max
|
357
378
|
end
|
358
|
-
|
379
|
+
|
359
380
|
def page_down
|
360
381
|
self.selection_count = 0
|
361
382
|
self.line_number = [(self.line_number + 15), lines.size].min
|
362
383
|
end
|
363
|
-
|
384
|
+
|
364
385
|
def home
|
365
386
|
self.selection_count = 0
|
366
387
|
self.line_number = 1
|
367
388
|
end
|
368
|
-
|
389
|
+
|
369
390
|
def end
|
370
391
|
self.selection_count = 0
|
371
392
|
self.line_number = lines.size
|
372
393
|
end
|
373
|
-
|
394
|
+
|
395
|
+
def start_of_line
|
396
|
+
self.caret_position = caret_position_for_line_index(self.line_number - 1)
|
397
|
+
end
|
398
|
+
|
399
|
+
def end_of_line
|
400
|
+
self.caret_position = caret_position_for_line_index(self.line_number) - 1
|
401
|
+
end
|
402
|
+
|
374
403
|
def move_up!
|
375
404
|
old_lines = lines
|
376
405
|
return if old_lines.size < 2
|
@@ -389,7 +418,7 @@ module Glimmer
|
|
389
418
|
self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
|
390
419
|
self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
|
391
420
|
end
|
392
|
-
|
421
|
+
|
393
422
|
def move_down!
|
394
423
|
old_lines = lines
|
395
424
|
return if old_lines.size < 2
|
@@ -408,25 +437,38 @@ module Glimmer
|
|
408
437
|
self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
|
409
438
|
self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
|
410
439
|
end
|
411
|
-
|
440
|
+
|
441
|
+
def run
|
442
|
+
begin
|
443
|
+
if scratchpad?
|
444
|
+
eval content
|
445
|
+
else
|
446
|
+
write_dirty_content
|
447
|
+
load path
|
448
|
+
end
|
449
|
+
rescue SyntaxError, StandardError => e
|
450
|
+
puts e.full_message
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
412
454
|
def lines
|
413
455
|
dirty_content.split("\n")
|
414
456
|
end
|
415
|
-
|
457
|
+
|
416
458
|
def line_for_caret_position(caret_position)
|
417
459
|
lines[line_index_for_caret_position(caret_position.to_i)]
|
418
460
|
end
|
419
|
-
|
461
|
+
|
420
462
|
def line_index_for_caret_position(caret_position)
|
421
463
|
dirty_content[0...caret_position.to_i].count("\n")
|
422
464
|
end
|
423
|
-
|
465
|
+
|
424
466
|
def caret_position_for_line_index(line_index)
|
425
467
|
cp = lines[0...line_index].join("\n").size
|
426
468
|
cp += 1 if line_index > 0
|
427
469
|
cp
|
428
470
|
end
|
429
|
-
|
471
|
+
|
430
472
|
def caret_position_for_caret_position_start_of_line(caret_position)
|
431
473
|
caret_position_for_line_index(line_index_for_caret_position(caret_position))
|
432
474
|
end
|
@@ -437,23 +479,23 @@ module Glimmer
|
|
437
479
|
caret_position = caret_position.to_i
|
438
480
|
caret_position - caret_position_for_caret_position_start_of_line(caret_position)
|
439
481
|
end
|
440
|
-
|
482
|
+
|
441
483
|
def line_caret_positions_for_selection(caret_position, selection_count)
|
442
484
|
line_indices = line_indices_for_selection(caret_position, selection_count)
|
443
485
|
line_caret_positions = line_indices.map { |line_index| caret_position_for_line_index(line_index) }.to_a
|
444
486
|
end
|
445
|
-
|
487
|
+
|
446
488
|
def end_caret_position_line_index(caret_position, selection_count)
|
447
489
|
end_caret_position = caret_position + selection_count.to_i
|
448
490
|
end_caret_position -= 1 if dirty_content[end_caret_position - 1] == "\n"
|
449
491
|
end_line_index = line_index_for_caret_position(end_caret_position)
|
450
492
|
end
|
451
|
-
|
493
|
+
|
452
494
|
def lines_for_selection(caret_position, selection_count)
|
453
495
|
line_indices = line_indices_for_selection(caret_position, selection_count)
|
454
496
|
lines[line_indices.first..line_indices.last]
|
455
497
|
end
|
456
|
-
|
498
|
+
|
457
499
|
def line_indices_for_selection(caret_position, selection_count)
|
458
500
|
start_line_index = line_index_for_caret_position(caret_position)
|
459
501
|
if selection_count.to_i > 0
|
@@ -463,22 +505,22 @@ module Glimmer
|
|
463
505
|
end
|
464
506
|
(start_line_index..end_line_index).to_a
|
465
507
|
end
|
466
|
-
|
508
|
+
|
467
509
|
def children
|
468
510
|
[]
|
469
511
|
end
|
470
|
-
|
512
|
+
|
471
513
|
def to_s
|
472
514
|
path
|
473
515
|
end
|
474
|
-
|
516
|
+
|
475
517
|
def eql?(other)
|
476
518
|
self.path.eql?(other&.path)
|
477
519
|
end
|
478
|
-
|
520
|
+
|
479
521
|
def hash
|
480
522
|
self.path.hash
|
481
523
|
end
|
482
|
-
end
|
524
|
+
end
|
483
525
|
end
|
484
526
|
end
|