glimmer-cs-gladiator 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/glimmer-cs-gladiator.svg)](http://badge.fury.io/rb/glimmer-cs-gladiator)
|
4
4
|
|
5
5
|
![Gladiator](images/glimmer-gladiator.png)
|
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
|
|