glimmer-cs-gladiator 0.5.0 → 0.6.0
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 +56 -27
- data/VERSION +1 -1
- data/lib/glimmer-cs-gladiator.rb +1 -1
- data/lib/models/glimmer/gladiator/command.rb +44 -11
- data/lib/models/glimmer/gladiator/dir.rb +54 -18
- data/lib/models/glimmer/gladiator/file.rb +126 -61
- data/lib/views/glimmer/gladiator.rb +534 -242
- data/lib/views/glimmer/gladiator/text_editor.rb +22 -14
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 686df61b4e15ac85a1cc5d08cb3e83f088bce3a40b2a6e155101f657189075f3
|
4
|
+
data.tar.gz: 12874887ef0d8a846ef43d5eb89ad2d1ec184fe3d0171a4cf692a1f9348efe61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8816804e0a23b860d98b6f583dba265cafac70ce3960b297f5c99dfa6de27d55441c5f959378d4851901e7cf059ec565bdbfc5911c114e8f41e250191f4b27fb
|
7
|
+
data.tar.gz: 288eccb3f7edbd055d54c0f05d9878a1630c057ca1f7464f7ecb586e5a632d33466197511f0e564900816dbb0b76b3a86ddc743d0fb0d60763a776ef592eb9d2
|
data/README.md
CHANGED
@@ -1,28 +1,24 @@
|
|
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.6.0 - [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 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).
|
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
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
|
-
Gladiator currently supports the following text editing features (including keyboard shortcuts with Mac CMD=CTRL on Windows/Linux)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
-
|
19
|
-
- Watch project subdirectories for changes to automatically refresh in file explorer/file lookup
|
20
|
-
- Find & Replace (CMD+F)
|
14
|
+
Gladiator currently supports the following text editing features (including keyboard shortcuts with Mac CMD=CTRL on Windows/Linux)
|
15
|
+
|
16
|
+
### Text Editor
|
17
|
+
|
18
|
+
- Text Editor with Colored Ruby Syntax Highlighting
|
21
19
|
- Show Line Numbers
|
22
|
-
-
|
23
|
-
-
|
24
|
-
- Remember opened tabs, caret position, top line, window size, and window location
|
25
|
-
- Autosave on focus out/quit/open new file
|
20
|
+
- Multi-tab support (CMD+SHIFT+[ & CMD+SHIFT+] for tab navigation. CMD+1-9 to jump to a specific tab)
|
21
|
+
- Drag and drop split pane (drag a file from File Tree or File Lookup List, and it splits the pane)
|
26
22
|
- Duplicate Line(s)/selection (CMD+D)
|
27
23
|
- Kill Line(s)/selection (CMD+K)
|
28
24
|
- Move line/selection up (CMD+UP)
|
@@ -30,10 +26,41 @@ Gladiator currently supports the following text editing features (including keyb
|
|
30
26
|
- Comment/Uncomment line/selection (CMD+/)
|
31
27
|
- Indent/Unindent line/selection (CMD+] & CMD+[)
|
32
28
|
- Insert/Prefix New Line (CMD+ENTER & CMD+SHIFT+ENTER)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
-
|
29
|
+
|
30
|
+
### File Explorer Tree
|
31
|
+
|
32
|
+
- Collapsable file explorer tree listing files and directories for open project
|
33
|
+
- Context menu to open file, rename, delete, add new file, add new directory, and refresh tree
|
34
|
+
- Jump to open file in tree (CMD+T)
|
35
|
+
|
36
|
+
### File Lookup List Filter
|
37
|
+
|
38
|
+
- Collapsable file lookup list filter (CMD+R)
|
39
|
+
- Semi-fuzzy filtering by ignoring slashes, underscores, and dots to ease lookup
|
40
|
+
|
41
|
+
### Navigation Area
|
42
|
+
|
43
|
+
- Show current text editor file name
|
44
|
+
- Show file navigation stats (Caret Position / Line Position / Selection Count / Top Pixel)
|
45
|
+
- Jump to Line (CMD+L)
|
46
|
+
- Find & Replace (CMD+F)
|
47
|
+
|
48
|
+
### Menus
|
49
|
+
|
50
|
+
- File Menu to Open Project (CMD+SHIFT+P) and open Scratchpad for running arbitrary Ruby/Glimmer code without saving to disk (CMD+SHIFT+S)
|
51
|
+
- View Menu to Split Pane & Change Split Orientation to Horizontal/Vertical (CMD+SHIFT+O)
|
52
|
+
- Run Menu to run Ruby code (CMD+SHIFT+R)
|
53
|
+
|
54
|
+
### Watch External Changes
|
55
|
+
|
56
|
+
- Watch open file for external changes to automatically refresh in editor
|
57
|
+
- Watch project subdirectories for changes to automatically refresh in file explorer/file lookup
|
58
|
+
|
59
|
+
### Automatic Data Management
|
60
|
+
|
61
|
+
- Autosave on focus out/quit/open new file
|
62
|
+
- Remember opened tabs, caret position, top pixel, window size, and window location
|
63
|
+
- [Default](#configuration) "ignore paths" to avoid bogging down editor with irrelevant directory files
|
37
64
|
|
38
65
|
## Platforms
|
39
66
|
|
@@ -77,6 +104,12 @@ You may run the `gladiator` command to bring up the text editor in the project d
|
|
77
104
|
gladiator
|
78
105
|
```
|
79
106
|
|
107
|
+
On Linux, you may need to run with extra memory via this command instead:
|
108
|
+
|
109
|
+
```
|
110
|
+
gladiator -J-Xmx1200M
|
111
|
+
```
|
112
|
+
|
80
113
|
On Windows, you may need to run with extra memory via this command instead:
|
81
114
|
|
82
115
|
```
|
@@ -103,7 +136,7 @@ To reuse Gladiator as a Glimmer Custom Shell inside another Glimmer application,
|
|
103
136
|
following to the application's `Gemfile`:
|
104
137
|
|
105
138
|
```
|
106
|
-
gem 'glimmer-cs-gladiator', '~> 0.
|
139
|
+
gem 'glimmer-cs-gladiator', '~> 0.6.0'
|
107
140
|
```
|
108
141
|
|
109
142
|
Run:
|
@@ -129,16 +162,12 @@ Opens Gladiator with "/Users/User/code" as the root directory.
|
|
129
162
|
|
130
163
|
## Configuration
|
131
164
|
|
132
|
-
Gladiator automatically saves configuration data in a `.gladiator` file at the directory it is run from.
|
165
|
+
Gladiator automatically saves configuration data in a `.gladiator` file at the directory it is run from. It may be edited to add extra ignore paths.
|
133
166
|
|
134
167
|
It currently remembers:
|
135
|
-
- Last opened
|
136
|
-
-
|
137
|
-
-
|
138
|
-
- Window size
|
139
|
-
- Opened tabs
|
140
|
-
- Split tabs
|
141
|
-
- Ignore Paths
|
168
|
+
- Last opened files (in both split panes if split)
|
169
|
+
- Window size and position
|
170
|
+
- Ignore Paths (default: '.gladiator', '.git', 'coverage', 'packages', 'node_modules', 'tmp', 'vendor')
|
142
171
|
|
143
172
|
## Gotcha
|
144
173
|
|
@@ -173,4 +202,4 @@ Copyright (c) 2020 Andy Maleh. See [LICENSE.txt](LICENSE.txt) for further detail
|
|
173
202
|
|
174
203
|
[<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 />](https://github.com/AndyObtiva/glimmer) Built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) (JRuby Desktop Development GUI Library)
|
175
204
|
|
176
|
-
Gladiator icon made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
|
205
|
+
Gladiator icon made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/lib/glimmer-cs-gladiator.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Glimmer
|
2
2
|
class Gladiator
|
3
|
-
class Command
|
3
|
+
class Command
|
4
|
+
include Glimmer
|
5
|
+
|
4
6
|
class << self
|
5
7
|
include Glimmer
|
6
8
|
|
@@ -10,18 +12,25 @@ module Glimmer
|
|
10
12
|
|
11
13
|
def command_history_for(file)
|
12
14
|
# keeping a first command to make redo support work by remembering next command after undoing all
|
13
|
-
command_history[file] ||= [Command.new(file)]
|
15
|
+
command_history[file] ||= [Command.new(file)]
|
14
16
|
end
|
15
17
|
|
16
|
-
def do(file, method = nil, command: nil)
|
17
|
-
command
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def do(file, method = nil, *args, command: nil)
|
19
|
+
if command.nil?
|
20
|
+
command ||= Command.new(file, method, *args)
|
21
|
+
command.previous_command = command_history_for(file).last
|
22
|
+
unless command_history_for(file).last.method == :change_content! && method == :change_content!
|
23
|
+
command_history_for(file).last.next_command = command
|
24
|
+
end
|
25
|
+
command.do
|
26
|
+
command_history_for(file) << command unless command_history_for(file).last.method == :change_content! && method == :change_content!
|
27
|
+
else
|
28
|
+
command_history_for(file) << command
|
29
|
+
end
|
21
30
|
end
|
22
31
|
|
23
32
|
def undo(file)
|
24
|
-
return if command_history_for(file).size <= 1
|
33
|
+
return if command_history_for(file).size <= 1
|
25
34
|
command = command_history_for(file).pop
|
26
35
|
command&.undo
|
27
36
|
end
|
@@ -30,15 +39,22 @@ module Glimmer
|
|
30
39
|
command = command_history_for(file).last
|
31
40
|
command&.redo
|
32
41
|
end
|
42
|
+
|
43
|
+
def clear(file)
|
44
|
+
command_history[file] = [Command.new(file)]
|
45
|
+
end
|
33
46
|
end
|
34
47
|
|
35
|
-
attr_accessor :file, :method, :
|
48
|
+
attr_accessor :file, :method, :args, :previous_command, :next_command,
|
49
|
+
:file_dirty_content, :file_caret_position, :file_selection_count, :previous_file_dirty_content, :previous_file_caret_position, :previous_file_selection_count
|
36
50
|
|
37
|
-
def initialize(file, method = nil)
|
51
|
+
def initialize(file, method = nil, *args)
|
38
52
|
@file = file
|
39
53
|
@method = method
|
54
|
+
@args = args
|
40
55
|
end
|
41
56
|
|
57
|
+
|
42
58
|
def native?
|
43
59
|
@method.nil?
|
44
60
|
end
|
@@ -56,6 +72,9 @@ module Glimmer
|
|
56
72
|
|
57
73
|
def redo
|
58
74
|
return if next_command.nil?# || next_command.native?
|
75
|
+
@file.dirty_content = next_command.file_dirty_content.clone
|
76
|
+
@file.caret_position = next_command.file_caret_position
|
77
|
+
@file.selection_count = next_command.file_selection_count
|
59
78
|
Command.do(next_command.file, command: next_command)
|
60
79
|
end
|
61
80
|
|
@@ -63,6 +82,10 @@ module Glimmer
|
|
63
82
|
@previous_file_dirty_content = @file.dirty_content.clone
|
64
83
|
@previous_file_caret_position = @file.caret_position
|
65
84
|
@previous_file_selection_count = @file.selection_count
|
85
|
+
if @method == :change_content!
|
86
|
+
@previous_file_caret_position = @file.last_caret_position
|
87
|
+
@previous_file_selection_count = @file.last_selection_count
|
88
|
+
end
|
66
89
|
end
|
67
90
|
|
68
91
|
def restore
|
@@ -72,7 +95,17 @@ module Glimmer
|
|
72
95
|
end
|
73
96
|
|
74
97
|
def execute
|
75
|
-
@file.
|
98
|
+
@file.start_command
|
99
|
+
@file.send(@method, *@args)
|
100
|
+
@file.end_command
|
101
|
+
@file_dirty_content = @file.dirty_content.clone
|
102
|
+
@file_caret_position = @file.caret_position
|
103
|
+
@file_selection_count = @file.selection_count
|
104
|
+
if previous_command.method == :change_content! && @method == :change_content!
|
105
|
+
previous_command.file_dirty_content = @file_dirty_content
|
106
|
+
previous_command.file_caret_position = @file_caret_position
|
107
|
+
previous_command.file_selection_count = @file_selection_count
|
108
|
+
end
|
76
109
|
end
|
77
110
|
end
|
78
111
|
end
|
@@ -6,8 +6,6 @@ module Glimmer
|
|
6
6
|
include Glimmer
|
7
7
|
include Glimmer::DataBinding::ObservableModel
|
8
8
|
|
9
|
-
REFRESH_DELAY = 7
|
10
|
-
|
11
9
|
attr_accessor :selected_child, :filter, :children, :filtered_path_options, :filtered_path, :display_path, :ignore_paths
|
12
10
|
attr_reader :name, :parent, :path
|
13
11
|
attr_writer :all_children
|
@@ -15,19 +13,30 @@ module Glimmer
|
|
15
13
|
def initialize(path, project_dir = nil)
|
16
14
|
@project_dir = project_dir
|
17
15
|
if is_local_dir
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
@filewatcher = Filewatcher.new(path)
|
17
|
+
Thread.new(@filewatcher) do |fw|
|
18
|
+
begin
|
19
|
+
fw.watch do |filename, event|
|
20
|
+
# TODO do fine grained processing of events for enhanced performance (e.g. dir refresh vs file change)
|
21
|
+
# TODO do fine grained file change only without a refresh delay for enhanced performance
|
22
|
+
begin
|
23
|
+
if !@refresh_in_progress && !filename.include?('new_file') && (event != :updated || find_child_file(filename).nil?)
|
24
|
+
Thread.new {
|
25
|
+
refresh
|
26
|
+
}
|
27
|
+
end
|
28
|
+
rescue => e
|
29
|
+
puts e.full_message
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue => e
|
33
|
+
puts e.full_message
|
34
|
+
end
|
35
|
+
end
|
27
36
|
end
|
28
37
|
self.path = ::File.expand_path(path)
|
29
38
|
@name = ::File.basename(::File.expand_path(path))
|
30
|
-
@ignore_paths = ['.gladiator', '.git', 'coverage', 'packages', 'tmp', 'vendor']
|
39
|
+
@ignore_paths = ['.gladiator', '.git', 'coverage', 'packages', 'node_modules', 'tmp', 'vendor']
|
31
40
|
self.filtered_path_options = []
|
32
41
|
end
|
33
42
|
|
@@ -48,6 +57,14 @@ module Glimmer
|
|
48
57
|
is_local_dir ? path : @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
|
49
58
|
end
|
50
59
|
|
60
|
+
def name=(the_name)
|
61
|
+
self.display_path = display_path.sub(/#{Regexp.escape(@name)}$/, the_name)
|
62
|
+
@name = the_name
|
63
|
+
new_path = ::File.expand_path(display_path)
|
64
|
+
FileUtils.mv(path, new_path)
|
65
|
+
self.path = display_path
|
66
|
+
end
|
67
|
+
|
51
68
|
def children
|
52
69
|
@children ||= retrieve_children
|
53
70
|
end
|
@@ -59,7 +76,7 @@ module Glimmer
|
|
59
76
|
result || p.include?(ignore_path)
|
60
77
|
end
|
61
78
|
end.map do |p|
|
62
|
-
::File.file?(p) ?
|
79
|
+
::File.file?(p) ? File.new(p, project_dir) : Dir.new(p, project_dir)
|
63
80
|
end.sort_by do |c|
|
64
81
|
c.path.to_s.downcase
|
65
82
|
end.sort_by do |c|
|
@@ -68,6 +85,22 @@ module Glimmer
|
|
68
85
|
child.retrieve_children if child.is_a?(Dir)
|
69
86
|
end
|
70
87
|
end
|
88
|
+
|
89
|
+
def find_child_file(child_path)
|
90
|
+
depth_first_search_file(self, child_path)
|
91
|
+
end
|
92
|
+
|
93
|
+
def depth_first_search_file(dir, file_path)
|
94
|
+
dir.children.each do |child|
|
95
|
+
if child.is_a?(File)
|
96
|
+
return child if child.path.include?(file_path)
|
97
|
+
else
|
98
|
+
result = depth_first_search_file(child, file_path)
|
99
|
+
return result unless result.nil?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
nil
|
103
|
+
end
|
71
104
|
|
72
105
|
def selected_child_path_history
|
73
106
|
@selected_child_path_history ||= []
|
@@ -83,6 +116,7 @@ module Glimmer
|
|
83
116
|
|
84
117
|
def refresh(async: true, force: false)
|
85
118
|
return if @refresh_paused && !force
|
119
|
+
@refresh_in_progress = true
|
86
120
|
retrieve_children
|
87
121
|
collect_all_children
|
88
122
|
refresh_operation = lambda do
|
@@ -94,6 +128,7 @@ module Glimmer
|
|
94
128
|
else
|
95
129
|
sync_exec(&refresh_operation)
|
96
130
|
end
|
131
|
+
@refresh_in_progress = false
|
97
132
|
end
|
98
133
|
|
99
134
|
def filter=(value)
|
@@ -134,19 +169,19 @@ module Glimmer
|
|
134
169
|
end
|
135
170
|
|
136
171
|
def selected_child_path=(selected_path)
|
172
|
+
return (project_dir.selected_child = nil) if selected_path.nil?
|
137
173
|
# scratchpad scenario
|
138
|
-
if selected_path
|
174
|
+
if selected_path.empty? # Scratchpad
|
139
175
|
@selected_child&.write_dirty_content
|
140
176
|
return (self.selected_child = File.new)
|
141
177
|
end
|
142
178
|
full_selected_path = selected_path.include?(project_dir.path) ? selected_path : ::File.join(project_dir.path, selected_path)
|
143
|
-
return if
|
144
|
-
::Dir.exist?(full_selected_path) ||
|
179
|
+
return if ::Dir.exist?(full_selected_path) ||
|
145
180
|
(selected_child && selected_child.path == full_selected_path)
|
146
181
|
selected_path = full_selected_path
|
147
182
|
if ::File.file?(selected_path)
|
148
183
|
@selected_child&.write_dirty_content
|
149
|
-
new_child =
|
184
|
+
new_child = find_child_file(selected_path)
|
150
185
|
begin
|
151
186
|
unless new_child.dirty_content.nil?
|
152
187
|
self.selected_child&.stop_filewatcher
|
@@ -167,6 +202,7 @@ module Glimmer
|
|
167
202
|
end
|
168
203
|
|
169
204
|
def selected_child=(new_child)
|
205
|
+
return if selected_child == new_child
|
170
206
|
file_properties = @selected_child&.backup_properties if @selected_child == new_child
|
171
207
|
@selected_child = new_child
|
172
208
|
@selected_child.restore_properties(file_properties) if file_properties
|
@@ -183,7 +219,7 @@ module Glimmer
|
|
183
219
|
def eql?(other)
|
184
220
|
self.path.eql?(other&.path)
|
185
221
|
end
|
186
|
-
|
222
|
+
|
187
223
|
def hash
|
188
224
|
self.path.hash
|
189
225
|
end
|
@@ -3,7 +3,7 @@ module Glimmer
|
|
3
3
|
class File
|
4
4
|
include Glimmer
|
5
5
|
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :line_numbers_content, :line_number, :find_text, :replace_text, :top_pixel, :display_path, :case_sensitive, :caret_position, :selection_count, :last_caret_position, :last_selection_count, :line_position
|
7
7
|
attr_reader :name, :path, :project_dir
|
8
8
|
|
9
9
|
def initialize(path='', project_dir=nil)
|
@@ -13,33 +13,48 @@ module Glimmer
|
|
13
13
|
@name = path.empty? ? 'Scratchpad' : ::File.basename(path)
|
14
14
|
self.path = ::File.expand_path(path) unless path.empty?
|
15
15
|
@top_pixel = 0
|
16
|
+
@caret_position = 0
|
16
17
|
@selection_count = 0
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
18
|
+
@last_selection_count = 0
|
19
|
+
@line_number = 1
|
20
|
+
@init = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def init_content
|
24
|
+
unless @init
|
25
|
+
@init = true
|
26
|
+
begin
|
27
|
+
# test read dirty content
|
28
|
+
observe(self, :dirty_content) do
|
29
|
+
line_count = lines.empty? ? 1 : lines.size
|
30
|
+
lines_text_size = [line_count.to_s.size, 4].max
|
31
|
+
old_top_pixel = top_pixel
|
32
|
+
self.line_numbers_content = line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
|
33
|
+
self.top_pixel = old_top_pixel
|
34
|
+
end
|
35
|
+
the_dirty_content = read_dirty_content
|
36
|
+
the_dirty_content.split("\n") # test that it is not a binary file (crashes to rescue block otherwise)
|
37
|
+
self.dirty_content = the_dirty_content
|
38
|
+
observe(self, :caret_position) do |new_caret_position|
|
39
|
+
new_line_number = line_index_for_caret_position(caret_position) + 1
|
40
|
+
current_line_number = line_number
|
41
|
+
self.line_number = new_line_number unless current_line_number && current_line_number == new_line_number
|
42
|
+
self.line_position = caret_position - caret_position_for_line_index(line_number - 1) + 1
|
43
|
+
end
|
44
|
+
observe(self, :line_number) do |new_line_number|
|
33
45
|
line_index = line_number - 1
|
34
46
|
new_caret_position = caret_position_for_line_index(line_index)
|
35
|
-
|
47
|
+
current_caret_position = caret_position
|
48
|
+
line_index_for_new_caret_position = line_index_for_caret_position(new_caret_position)
|
49
|
+
line_index_for_current_caret_position = line_index_for_caret_position(current_caret_position)
|
50
|
+
self.caret_position = new_caret_position unless (current_caret_position && line_index_for_new_caret_position == line_index_for_current_caret_position)
|
36
51
|
end
|
52
|
+
rescue # in case of a binary file
|
53
|
+
stop_filewatcher
|
37
54
|
end
|
38
|
-
rescue
|
39
|
-
# no op in case of a binary file
|
40
55
|
end
|
41
56
|
end
|
42
|
-
|
57
|
+
|
43
58
|
def path=(the_path)
|
44
59
|
@path = the_path
|
45
60
|
generate_display_path
|
@@ -49,9 +64,18 @@ module Glimmer
|
|
49
64
|
return if @path.empty?
|
50
65
|
@display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
|
51
66
|
end
|
67
|
+
|
68
|
+
def name=(the_name)
|
69
|
+
new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name) unless scratchpad?
|
70
|
+
@name = the_name
|
71
|
+
if !scratchpad? && ::File.exist?(path)
|
72
|
+
FileUtils.mv(path, new_path)
|
73
|
+
self.path = new_path
|
74
|
+
end
|
75
|
+
end
|
52
76
|
|
53
77
|
def scratchpad?
|
54
|
-
path.empty?
|
78
|
+
path.to_s.empty?
|
55
79
|
end
|
56
80
|
|
57
81
|
def backup_properties
|
@@ -66,41 +90,73 @@ module Glimmer
|
|
66
90
|
send("#{property}=", value)
|
67
91
|
end
|
68
92
|
end
|
93
|
+
|
94
|
+
def caret_position=(value)
|
95
|
+
@last_caret_position = @caret_position
|
96
|
+
@caret_position = value
|
97
|
+
end
|
98
|
+
|
99
|
+
def selection_count=(value)
|
100
|
+
#@last_selection_count = @selection_count
|
101
|
+
@selection_count = value
|
102
|
+
@last_selection_count = @selection_count
|
103
|
+
end
|
104
|
+
|
105
|
+
def dirty_content
|
106
|
+
init_content
|
107
|
+
@dirty_content
|
108
|
+
end
|
109
|
+
|
110
|
+
def dirty_content=(the_content)
|
111
|
+
# TODO set partial dirty content by line(s) for enhanced performance
|
112
|
+
@dirty_content = the_content
|
113
|
+
old_caret_position = caret_position
|
114
|
+
old_top_pixel = top_pixel
|
115
|
+
|
116
|
+
notify_observers(:content)
|
117
|
+
if @formatting_dirty_content_for_writing
|
118
|
+
self.caret_position = old_caret_position
|
119
|
+
self.top_pixel = old_top_pixel
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def content
|
124
|
+
dirty_content
|
125
|
+
end
|
69
126
|
|
70
127
|
# to use for widget data-binding
|
71
128
|
def content=(value)
|
72
129
|
value = value.gsub("\t", ' ')
|
73
130
|
if dirty_content != value
|
74
|
-
Command.do(self
|
75
|
-
self.dirty_content = value
|
131
|
+
Command.do(self, :change_content!, value)
|
76
132
|
end
|
77
133
|
end
|
78
|
-
|
79
|
-
def
|
80
|
-
dirty_content
|
134
|
+
|
135
|
+
def change_content!(value)
|
136
|
+
self.dirty_content = value
|
81
137
|
end
|
82
138
|
|
83
|
-
def
|
84
|
-
|
85
|
-
self.selection = Point.new(value, value + selection_count.to_i)
|
86
|
-
self.top_pixel = old_top_pixel
|
139
|
+
def start_command
|
140
|
+
@commmand_in_progress = true
|
87
141
|
end
|
88
|
-
|
89
|
-
def
|
90
|
-
|
142
|
+
|
143
|
+
def end_command
|
144
|
+
@commmand_in_progress = false
|
91
145
|
end
|
92
|
-
|
93
|
-
def
|
94
|
-
|
146
|
+
|
147
|
+
def command_in_progress?
|
148
|
+
@commmand_in_progress
|
95
149
|
end
|
96
|
-
|
97
|
-
def
|
98
|
-
|
150
|
+
|
151
|
+
def close
|
152
|
+
stop_filewatcher
|
153
|
+
remove_all_observers
|
154
|
+
initialize(path, project_dir)
|
155
|
+
Command.clear(self)
|
99
156
|
end
|
100
|
-
|
101
|
-
def
|
102
|
-
|
103
|
-
notify_observers(:content)
|
157
|
+
|
158
|
+
def read_dirty_content
|
159
|
+
path.empty? ? '' : ::File.read(path)
|
104
160
|
end
|
105
161
|
|
106
162
|
def start_filewatcher
|
@@ -108,15 +164,13 @@ module Glimmer
|
|
108
164
|
@filewatcher = Filewatcher.new(@path)
|
109
165
|
@thread = Thread.new(@filewatcher) do |fw|
|
110
166
|
fw.watch do |filename, event|
|
111
|
-
|
112
|
-
|
113
|
-
# test read dirty content
|
114
|
-
read_dirty_content.split("\n")
|
115
|
-
async_exec do
|
167
|
+
async_exec do
|
168
|
+
begin
|
116
169
|
self.dirty_content = read_dirty_content if read_dirty_content != dirty_content
|
170
|
+
rescue StandardError, Errno::ENOENT
|
171
|
+
# in case of a binary file
|
172
|
+
stop_filewatcher
|
117
173
|
end
|
118
|
-
rescue
|
119
|
-
# no op in case of a binary file
|
120
174
|
end
|
121
175
|
end
|
122
176
|
end
|
@@ -126,21 +180,28 @@ module Glimmer
|
|
126
180
|
@filewatcher&.stop
|
127
181
|
end
|
128
182
|
|
129
|
-
def format_dirty_content_for_writing!
|
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"
|
132
|
-
self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
|
133
|
-
end
|
134
|
-
|
135
183
|
def write_dirty_content
|
136
|
-
|
184
|
+
# TODO write partial dirty content by line(s) for enhanced performance
|
185
|
+
return if scratchpad? || !::File.exist?(path) || !::File.exists?(path) || read_dirty_content == dirty_content
|
137
186
|
format_dirty_content_for_writing!
|
138
|
-
::File.write(path, dirty_content)
|
139
|
-
rescue => e
|
187
|
+
::File.write(path, dirty_content)
|
188
|
+
rescue StandardError, ArgumentError => e
|
140
189
|
puts "Error in writing dirty content for #{path}"
|
141
190
|
puts e.full_message
|
142
191
|
end
|
143
192
|
|
193
|
+
def format_dirty_content_for_writing!
|
194
|
+
return if @commmand_in_progress
|
195
|
+
# TODO f ix c ar e t pos it ion after formatting dirty content (diff?)
|
196
|
+
new_dirty_content = dirty_content.to_s.split("\n").map {|line| line.strip.empty? ? line : line.rstrip }.join("\n")
|
197
|
+
new_dirty_content = "#{new_dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
|
198
|
+
if new_dirty_content != self.dirty_content
|
199
|
+
@formatting_dirty_content_for_writing = true
|
200
|
+
self.dirty_content = new_dirty_content
|
201
|
+
@formatting_dirty_content_for_writing = false
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
144
205
|
def write_raw_dirty_content
|
145
206
|
return if scratchpad? || !::File.exist?(path)
|
146
207
|
::File.write(path, dirty_content) if ::File.exists?(path)
|
@@ -176,7 +237,7 @@ module Glimmer
|
|
176
237
|
self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
|
177
238
|
self.selection_count = 0
|
178
239
|
end
|
179
|
-
|
240
|
+
|
180
241
|
def comment_line!
|
181
242
|
old_lines = lines
|
182
243
|
return if old_lines.size < 1
|
@@ -210,6 +271,7 @@ module Glimmer
|
|
210
271
|
new_caret_position = old_caret_position + delta
|
211
272
|
new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
|
212
273
|
self.caret_position = new_caret_position
|
274
|
+
self.selection_count = 0
|
213
275
|
end
|
214
276
|
end
|
215
277
|
|
@@ -234,6 +296,7 @@ module Glimmer
|
|
234
296
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
235
297
|
else
|
236
298
|
self.caret_position = old_caret_position + delta
|
299
|
+
self.selection_count = 0
|
237
300
|
end
|
238
301
|
end
|
239
302
|
|
@@ -265,6 +328,7 @@ module Glimmer
|
|
265
328
|
new_caret_position = old_caret_position + delta
|
266
329
|
new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
|
267
330
|
self.caret_position = new_caret_position
|
331
|
+
self.selection_count = 0
|
268
332
|
end
|
269
333
|
end
|
270
334
|
|
@@ -302,6 +366,7 @@ module Glimmer
|
|
302
366
|
self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
|
303
367
|
else
|
304
368
|
self.caret_position = old_caret_position + delta
|
369
|
+
self.selection_count = 0
|
305
370
|
end
|
306
371
|
end
|
307
372
|
|