glimmer-cs-gladiator 0.3.1 → 0.5.2
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 +13 -9
- 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 +8 -4
- data/lib/models/glimmer/gladiator/dir.rb +51 -43
- data/lib/models/glimmer/gladiator/file.rb +122 -72
- data/lib/views/glimmer/gladiator.rb +436 -283
- data/lib/views/glimmer/gladiator/text_editor.rb +40 -21
- 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: 5de57f9122b239134e9567e99976ed7c5e859edf89a91f72f15f257597ee0815
|
4
|
+
data.tar.gz: 99414159618bea5a0a99fd37772424b452f26471ca6e5dd791ff0ce26135646c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e7d7c9cca67e351dbf169d785c6ef927bcd911f03a5b4505fdd2973c9b9291b1a72f8475dceeae592bb3d56de85a65f96b9f1cb96575dc91768d13b46f52749
|
7
|
+
data.tar.gz: 35c3dc09a4f5d0e29d8e52dd0cbae1ffc879f6d7cd3d5ec0cc2cbabde3475f3898a959c34d7adf60789c9a8c8fa6e2e5ebcfefe9e5e1db8ba0e7281b268ef572
|
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.2 - [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.2'
|
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:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.2
|
data/bin/gladiator_runner.rb
CHANGED
data/lib/glimmer-cs-gladiator.rb
CHANGED
@@ -2,13 +2,15 @@ module Glimmer
|
|
2
2
|
class Gladiator
|
3
3
|
class Command
|
4
4
|
class << self
|
5
|
+
include Glimmer
|
6
|
+
|
5
7
|
def command_history
|
6
8
|
@command_history ||= {}
|
7
9
|
end
|
8
10
|
|
9
11
|
def command_history_for(file)
|
10
12
|
# keeping a first command to make redo support work by remembering next command after undoing all
|
11
|
-
command_history[file] ||= [Command.new(file)]
|
13
|
+
command_history[file] ||= [Command.new(file)]
|
12
14
|
end
|
13
15
|
|
14
16
|
def do(file, method = nil, command: nil)
|
@@ -19,12 +21,14 @@ module Glimmer
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def undo(file)
|
22
|
-
return if command_history_for(file).size <= 1
|
23
|
-
command_history_for(file).pop
|
24
|
+
return if command_history_for(file).size <= 1
|
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', '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
|
-
|
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.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
|
-
|
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,41 @@ 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
|
-
|
92
|
+
|
93
|
+
def selection_count
|
94
|
+
selection.y - selection.x
|
95
|
+
end
|
96
|
+
|
97
|
+
def selection_count=(value)
|
98
|
+
self.selection = Point.new(caret_position, caret_position + value.to_i)
|
99
|
+
end
|
100
|
+
|
76
101
|
def name=(the_name)
|
77
|
-
new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name)
|
102
|
+
new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name) unless scratchpad?
|
78
103
|
@name = the_name
|
79
|
-
if ::File.
|
104
|
+
if !scratchpad? && ::File.exist?(path)
|
80
105
|
FileUtils.mv(path, new_path)
|
81
106
|
self.path = new_path
|
82
107
|
end
|
83
108
|
end
|
84
109
|
|
85
110
|
def dirty_content=(the_content)
|
86
|
-
@dirty_content = the_content
|
111
|
+
@dirty_content = the_content
|
87
112
|
notify_observers(:content)
|
88
113
|
end
|
89
|
-
|
114
|
+
|
90
115
|
def start_filewatcher
|
116
|
+
return if scratchpad?
|
91
117
|
@filewatcher = Filewatcher.new(@path)
|
92
|
-
@thread = Thread.new(@filewatcher) do |fw|
|
118
|
+
@thread = Thread.new(@filewatcher) do |fw|
|
93
119
|
fw.watch do |filename, event|
|
94
120
|
begin
|
95
121
|
read_dirty_content = ::File.read(path)
|
@@ -104,27 +130,28 @@ module Glimmer
|
|
104
130
|
end
|
105
131
|
end
|
106
132
|
end
|
107
|
-
|
133
|
+
|
108
134
|
def stop_filewatcher
|
109
135
|
@filewatcher&.stop
|
110
136
|
end
|
111
137
|
|
112
138
|
def format_dirty_content_for_writing!
|
113
|
-
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"
|
114
141
|
self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
|
115
142
|
end
|
116
|
-
|
143
|
+
|
117
144
|
def write_dirty_content
|
118
|
-
return
|
145
|
+
return if scratchpad? || !::File.exist?(path)
|
119
146
|
format_dirty_content_for_writing!
|
120
147
|
::File.write(path, dirty_content) if ::File.exists?(path)
|
121
148
|
rescue => e
|
122
149
|
puts "Error in writing dirty content for #{path}"
|
123
150
|
puts e.full_message
|
124
151
|
end
|
125
|
-
|
152
|
+
|
126
153
|
def write_raw_dirty_content
|
127
|
-
return
|
154
|
+
return if scratchpad? || !::File.exist?(path)
|
128
155
|
::File.write(path, dirty_content) if ::File.exists?(path)
|
129
156
|
rescue => e
|
130
157
|
puts "Error in writing raw dirty content for #{path}"
|
@@ -138,16 +165,17 @@ module Glimmer
|
|
138
165
|
def current_line
|
139
166
|
lines[line_number - 1]
|
140
167
|
end
|
141
|
-
|
168
|
+
|
142
169
|
def delete!
|
143
|
-
FileUtils.rm(path)
|
170
|
+
FileUtils.rm(path) unless scratchpad?
|
144
171
|
end
|
145
|
-
|
172
|
+
|
146
173
|
def prefix_new_line!
|
147
174
|
the_lines = lines
|
148
175
|
the_lines[line_number-1...line_number-1] = [current_line_indentation]
|
149
176
|
self.dirty_content = the_lines.join("\n")
|
150
177
|
self.caret_position = caret_position_for_line_index(line_number-1) + current_line_indentation.size
|
178
|
+
self.selection_count = 0
|
151
179
|
end
|
152
180
|
|
153
181
|
def insert_new_line!
|
@@ -155,6 +183,7 @@ module Glimmer
|
|
155
183
|
the_lines[line_number...line_number] = [current_line_indentation]
|
156
184
|
self.dirty_content = the_lines.join("\n")
|
157
185
|
self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
|
186
|
+
self.selection_count = 0
|
158
187
|
end
|
159
188
|
|
160
189
|
def comment_line!
|
@@ -182,7 +211,7 @@ module Glimmer
|
|
182
211
|
delta += 2
|
183
212
|
end
|
184
213
|
end
|
185
|
-
self.dirty_content = new_lines.join("\n")
|
214
|
+
self.dirty_content = new_lines.join("\n")
|
186
215
|
if old_selection_count.to_i > 0
|
187
216
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
188
217
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
@@ -192,7 +221,7 @@ module Glimmer
|
|
192
221
|
self.caret_position = new_caret_position
|
193
222
|
end
|
194
223
|
end
|
195
|
-
|
224
|
+
|
196
225
|
def indent!
|
197
226
|
new_lines = lines
|
198
227
|
old_lines = lines
|
@@ -208,7 +237,7 @@ module Glimmer
|
|
208
237
|
new_lines[the_line_index] = " #{the_line}"
|
209
238
|
end
|
210
239
|
old_caret_position = self.caret_position
|
211
|
-
self.dirty_content = new_lines.join("\n")
|
240
|
+
self.dirty_content = new_lines.join("\n")
|
212
241
|
if old_selection_count.to_i > 0
|
213
242
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
214
243
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
@@ -216,7 +245,7 @@ module Glimmer
|
|
216
245
|
self.caret_position = old_caret_position + delta
|
217
246
|
end
|
218
247
|
end
|
219
|
-
|
248
|
+
|
220
249
|
def outdent!
|
221
250
|
new_lines = lines
|
222
251
|
old_lines = lines
|
@@ -237,7 +266,7 @@ module Glimmer
|
|
237
266
|
delta = -1
|
238
267
|
end
|
239
268
|
end
|
240
|
-
self.dirty_content = new_lines.join("\n")
|
269
|
+
self.dirty_content = new_lines.join("\n")
|
241
270
|
if old_selection_count.to_i > 0
|
242
271
|
self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
|
243
272
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
@@ -247,7 +276,7 @@ module Glimmer
|
|
247
276
|
self.caret_position = new_caret_position
|
248
277
|
end
|
249
278
|
end
|
250
|
-
|
279
|
+
|
251
280
|
def kill_line!
|
252
281
|
new_lines = lines
|
253
282
|
return if new_lines.size < 1
|
@@ -260,7 +289,7 @@ module Glimmer
|
|
260
289
|
self.caret_position = caret_position_for_line_index(old_line_index) + [line_position, lines[old_line_index].to_s.size].min
|
261
290
|
self.selection_count = 0
|
262
291
|
end
|
263
|
-
|
292
|
+
|
264
293
|
def duplicate_line!
|
265
294
|
new_lines = lines
|
266
295
|
old_lines = lines
|
@@ -284,13 +313,13 @@ module Glimmer
|
|
284
313
|
self.caret_position = old_caret_position + delta
|
285
314
|
end
|
286
315
|
end
|
287
|
-
|
316
|
+
|
288
317
|
def find_next
|
289
|
-
return if find_text.to_s.empty?
|
318
|
+
return if find_text.to_s.empty?
|
290
319
|
all_lines = lines
|
291
320
|
the_line_index = line_index_for_caret_position(caret_position)
|
292
321
|
line_position = line_position_for_caret_position(caret_position)
|
293
|
-
found =
|
322
|
+
found = found_text?(caret_position)
|
294
323
|
2.times do |i|
|
295
324
|
rotation = the_line_index
|
296
325
|
all_lines.rotate(rotation).each_with_index do |the_line, the_index|
|
@@ -307,7 +336,7 @@ module Glimmer
|
|
307
336
|
end
|
308
337
|
end
|
309
338
|
end
|
310
|
-
|
339
|
+
|
311
340
|
def find_previous
|
312
341
|
return if find_text.to_s.empty?
|
313
342
|
all_lines = lines
|
@@ -332,7 +361,7 @@ module Glimmer
|
|
332
361
|
end
|
333
362
|
end
|
334
363
|
end
|
335
|
-
|
364
|
+
|
336
365
|
def ensure_find_next
|
337
366
|
return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
|
338
367
|
find_next unless found_text?(self.caret_position)
|
@@ -341,37 +370,45 @@ module Glimmer
|
|
341
370
|
def found_text?(caret_position)
|
342
371
|
dirty_content[caret_position.to_i, find_text.to_s.size].to_s.downcase == find_text.to_s.downcase
|
343
372
|
end
|
344
|
-
|
373
|
+
|
345
374
|
def replace_next!
|
346
375
|
return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
|
347
376
|
ensure_find_next
|
348
377
|
new_dirty_content = dirty_content
|
349
378
|
new_dirty_content[caret_position, find_text.size] = replace_text.to_s
|
350
379
|
self.dirty_content = new_dirty_content
|
351
|
-
find_next
|
380
|
+
find_next
|
352
381
|
find_next if replace_text.to_s.include?(find_text) && !replace_text.to_s.start_with?(find_text)
|
353
382
|
end
|
354
|
-
|
383
|
+
|
355
384
|
def page_up
|
356
385
|
self.selection_count = 0
|
357
386
|
self.line_number = [(self.line_number - 15), 1].max
|
358
387
|
end
|
359
|
-
|
388
|
+
|
360
389
|
def page_down
|
361
390
|
self.selection_count = 0
|
362
391
|
self.line_number = [(self.line_number + 15), lines.size].min
|
363
392
|
end
|
364
|
-
|
393
|
+
|
365
394
|
def home
|
366
395
|
self.selection_count = 0
|
367
396
|
self.line_number = 1
|
368
397
|
end
|
369
|
-
|
398
|
+
|
370
399
|
def end
|
371
400
|
self.selection_count = 0
|
372
401
|
self.line_number = lines.size
|
373
402
|
end
|
374
|
-
|
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
|
+
|
375
412
|
def move_up!
|
376
413
|
old_lines = lines
|
377
414
|
return if old_lines.size < 2
|
@@ -390,7 +427,7 @@ module Glimmer
|
|
390
427
|
self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
|
391
428
|
self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
|
392
429
|
end
|
393
|
-
|
430
|
+
|
394
431
|
def move_down!
|
395
432
|
old_lines = lines
|
396
433
|
return if old_lines.size < 2
|
@@ -409,25 +446,38 @@ module Glimmer
|
|
409
446
|
self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
|
410
447
|
self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
|
411
448
|
end
|
412
|
-
|
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
|
+
|
413
463
|
def lines
|
414
464
|
dirty_content.split("\n")
|
415
465
|
end
|
416
|
-
|
466
|
+
|
417
467
|
def line_for_caret_position(caret_position)
|
418
468
|
lines[line_index_for_caret_position(caret_position.to_i)]
|
419
469
|
end
|
420
|
-
|
470
|
+
|
421
471
|
def line_index_for_caret_position(caret_position)
|
422
472
|
dirty_content[0...caret_position.to_i].count("\n")
|
423
473
|
end
|
424
|
-
|
474
|
+
|
425
475
|
def caret_position_for_line_index(line_index)
|
426
476
|
cp = lines[0...line_index].join("\n").size
|
427
477
|
cp += 1 if line_index > 0
|
428
478
|
cp
|
429
479
|
end
|
430
|
-
|
480
|
+
|
431
481
|
def caret_position_for_caret_position_start_of_line(caret_position)
|
432
482
|
caret_position_for_line_index(line_index_for_caret_position(caret_position))
|
433
483
|
end
|
@@ -438,23 +488,23 @@ module Glimmer
|
|
438
488
|
caret_position = caret_position.to_i
|
439
489
|
caret_position - caret_position_for_caret_position_start_of_line(caret_position)
|
440
490
|
end
|
441
|
-
|
491
|
+
|
442
492
|
def line_caret_positions_for_selection(caret_position, selection_count)
|
443
493
|
line_indices = line_indices_for_selection(caret_position, selection_count)
|
444
494
|
line_caret_positions = line_indices.map { |line_index| caret_position_for_line_index(line_index) }.to_a
|
445
495
|
end
|
446
|
-
|
496
|
+
|
447
497
|
def end_caret_position_line_index(caret_position, selection_count)
|
448
498
|
end_caret_position = caret_position + selection_count.to_i
|
449
499
|
end_caret_position -= 1 if dirty_content[end_caret_position - 1] == "\n"
|
450
500
|
end_line_index = line_index_for_caret_position(end_caret_position)
|
451
501
|
end
|
452
|
-
|
502
|
+
|
453
503
|
def lines_for_selection(caret_position, selection_count)
|
454
504
|
line_indices = line_indices_for_selection(caret_position, selection_count)
|
455
505
|
lines[line_indices.first..line_indices.last]
|
456
506
|
end
|
457
|
-
|
507
|
+
|
458
508
|
def line_indices_for_selection(caret_position, selection_count)
|
459
509
|
start_line_index = line_index_for_caret_position(caret_position)
|
460
510
|
if selection_count.to_i > 0
|
@@ -464,22 +514,22 @@ module Glimmer
|
|
464
514
|
end
|
465
515
|
(start_line_index..end_line_index).to_a
|
466
516
|
end
|
467
|
-
|
517
|
+
|
468
518
|
def children
|
469
519
|
[]
|
470
520
|
end
|
471
|
-
|
521
|
+
|
472
522
|
def to_s
|
473
523
|
path
|
474
524
|
end
|
475
|
-
|
525
|
+
|
476
526
|
def eql?(other)
|
477
527
|
self.path.eql?(other&.path)
|
478
528
|
end
|
479
|
-
|
529
|
+
|
480
530
|
def hash
|
481
531
|
self.path.hash
|
482
532
|
end
|
483
|
-
end
|
533
|
+
end
|
484
534
|
end
|
485
535
|
end
|