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 +4 -4
- data/README.md +11 -12
- data/VERSION +1 -1
- data/bin/gladiator_runner.rb +2 -1
- data/lib/glimmer-cs-gladiator.rb +1 -1
- data/lib/models/glimmer/gladiator/command.rb +4 -4
- data/lib/models/glimmer/gladiator/dir.rb +51 -43
- data/lib/models/glimmer/gladiator/file.rb +109 -70
- data/lib/views/glimmer/gladiator.rb +390 -288
- data/lib/views/glimmer/gladiator/text_editor.rb +33 -23
- 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: c9b90cb14c65857fcd2aae74b253de63975e07979598fff9859016fa49eab9c2
|
|
4
|
+
data.tar.gz: 780b56d9e8e71e1d25d0399eec1c634fa1283af07059f4ec7042a4ff42c7c31d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
[](http://badge.fury.io/rb/glimmer-cs-gladiator)
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
(
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
1
|
+
0.5.3
|
data/bin/gladiator_runner.rb
CHANGED
data/lib/glimmer-cs-gladiator.rb
CHANGED
|
@@ -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
|
|
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', '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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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}"
|
|
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
|
-
|
|
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.
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
222
|
-
|
|
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
|
-
|
|
252
|
-
|
|
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
|