glimmer-cs-gladiator 0.5.2 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5de57f9122b239134e9567e99976ed7c5e859edf89a91f72f15f257597ee0815
4
- data.tar.gz: 99414159618bea5a0a99fd37772424b452f26471ca6e5dd791ff0ce26135646c
3
+ metadata.gz: 3c07882b7fc3a12df1d64f02148ac6d018c1edd45fdea10c6d5285bdd55df137
4
+ data.tar.gz: fdacfe1e7f81879c96f0d746cc1e62ec66e6a202a934dae2f9bb7c1027f91a95
5
5
  SHA512:
6
- metadata.gz: 6e7d7c9cca67e351dbf169d785c6ef927bcd911f03a5b4505fdd2973c9b9291b1a72f8475dceeae592bb3d56de85a65f96b9f1cb96575dc91768d13b46f52749
7
- data.tar.gz: 35c3dc09a4f5d0e29d8e52dd0cbae1ffc879f6d7cd3d5ec0cc2cbabde3475f3898a959c34d7adf60789c9a8c8fa6e2e5ebcfefe9e5e1db8ba0e7281b268ef572
6
+ metadata.gz: 42e38a486000c47409ecefd8f120950e856abd9163a3131b8733e65f9bbb337437ed660374c363ccded21db8c4491c158922be6e5510b2af2a8ed2b3e5aa96f1
7
+ data.tar.gz: 36fcaddd1f4d6766f53fb19bd26aaeeaf5e2f86164e6244620f3d5cc5e9067bf48b2172005c850d408d1dc7a80c43dabbe5e9f59c6be53664de4f312d78de844
data/README.md CHANGED
@@ -1,4 +1,4 @@
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/)
1
+ # <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.6.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
  [![Gem Version](https://badge.fury.io/rb/glimmer-cs-gladiator.svg)](http://badge.fury.io/rb/glimmer-cs-gladiator)
4
4
 
@@ -11,18 +11,14 @@ I leave building truly professional text editors to software tooling experts who
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
- - Ruby Syntax Highlighting with colors
16
- - File explorer navigation with context menu to open file, rename, delete, add new file, add new directory, or refresh tree (CMD+T)
17
- - File lookup by name ignoring slashes, underscores, and dots to ease lookup (CMD+R)
18
- - Watch open file for external changes to automatically refresh in editor
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
- - Jump to Line (CMD+L)
23
- - Multiple tab support (CMD+SHIFT+[ & CMD+SHIFT+] for tab navigation. CMD+1-9 to jump to a specific tab)
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
- - 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)
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
 
@@ -43,7 +70,7 @@ Gladiator currently supports the following text editing features (including keyb
43
70
 
44
71
  ## Pre-requisites
45
72
 
46
- - [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) (JRuby Desktop Development GUI Library): '>= 4.17.2.0', '< 5.0.0.0' (dependency included in Ruby gem).
73
+ - [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) (JRuby Desktop Development GUI Framework): '>= 4.17.2.0', '< 5.0.0.0' (dependency included in Ruby gem).
47
74
  - [JRuby](https://www.jruby.org/download): Same version required by [Glimmer](https://github.com/AndyObtiva/glimmer-dsl-swt)
48
75
  - [JDK](https://www.oracle.com/java/technologies/javase-downloads.html): Same version required by [Glimmer](https://github.com/AndyObtiva/glimmer-dsl-swt)
49
76
 
@@ -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.5.2'
139
+ gem 'glimmer-cs-gladiator', '~> 0.6.2'
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 file
136
- - Caret position
137
- - Top line position
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
 
@@ -171,6 +200,6 @@ Copyright (c) 2020 Andy Maleh. See [LICENSE.txt](LICENSE.txt) for further detail
171
200
 
172
201
  --
173
202
 
174
- [<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)
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 Framework)
175
204
 
176
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.5.2
1
+ 0.6.2
@@ -1,6 +1,8 @@
1
1
  module Glimmer
2
2
  class Gladiator
3
3
  class Command
4
+ include Glimmer
5
+
4
6
  class << self
5
7
  include Glimmer
6
8
 
@@ -13,11 +15,18 @@ module Glimmer
13
15
  command_history[file] ||= [Command.new(file)]
14
16
  end
15
17
 
16
- def do(file, method = nil, command: nil)
17
- command ||= Command.new(file, method)
18
- command_history_for(file)&.last&.next_command = command
19
- command.do
20
- command_history_for(file) << command
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)
@@ -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, :next_command, :previous_file_content, :previous_file_caret_position, :previous_file_selection_count
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.send(@method)
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
- @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
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
 
@@ -67,7 +76,7 @@ module Glimmer
67
76
  result || p.include?(ignore_path)
68
77
  end
69
78
  end.map do |p|
70
- ::File.file?(p) ? Gladiator::File.new(p, project_dir) : Gladiator::Dir.new(p, project_dir)
79
+ ::File.file?(p) ? File.new(p, project_dir) : Dir.new(p, project_dir)
71
80
  end.sort_by do |c|
72
81
  c.path.to_s.downcase
73
82
  end.sort_by do |c|
@@ -76,6 +85,22 @@ module Glimmer
76
85
  child.retrieve_children if child.is_a?(Dir)
77
86
  end
78
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
79
104
 
80
105
  def selected_child_path_history
81
106
  @selected_child_path_history ||= []
@@ -91,6 +116,7 @@ module Glimmer
91
116
 
92
117
  def refresh(async: true, force: false)
93
118
  return if @refresh_paused && !force
119
+ @refresh_in_progress = true
94
120
  retrieve_children
95
121
  collect_all_children
96
122
  refresh_operation = lambda do
@@ -102,6 +128,7 @@ module Glimmer
102
128
  else
103
129
  sync_exec(&refresh_operation)
104
130
  end
131
+ @refresh_in_progress = false
105
132
  end
106
133
 
107
134
  def filter=(value)
@@ -144,7 +171,7 @@ module Glimmer
144
171
  def selected_child_path=(selected_path)
145
172
  return (project_dir.selected_child = nil) if selected_path.nil?
146
173
  # scratchpad scenario
147
- if selected_path.empty? #scratchpad
174
+ if selected_path.empty? # Scratchpad
148
175
  @selected_child&.write_dirty_content
149
176
  return (self.selected_child = File.new)
150
177
  end
@@ -154,7 +181,7 @@ module Glimmer
154
181
  selected_path = full_selected_path
155
182
  if ::File.file?(selected_path)
156
183
  @selected_child&.write_dirty_content
157
- new_child = Gladiator::File.new(selected_path, project_dir)
184
+ new_child = find_child_file(selected_path)
158
185
  begin
159
186
  unless new_child.dirty_content.nil?
160
187
  self.selected_child&.stop_filewatcher
@@ -175,6 +202,7 @@ module Glimmer
175
202
  end
176
203
 
177
204
  def selected_child=(new_child)
205
+ return if selected_child == new_child
178
206
  file_properties = @selected_child&.backup_properties if @selected_child == new_child
179
207
  @selected_child = new_child
180
208
  @selected_child.restore_properties(file_properties) if file_properties
@@ -191,7 +219,7 @@ module Glimmer
191
219
  def eql?(other)
192
220
  self.path.eql?(other&.path)
193
221
  end
194
-
222
+
195
223
  def hash
196
224
  self.path.hash
197
225
  end
@@ -3,7 +3,7 @@ module Glimmer
3
3
  class File
4
4
  include Glimmer
5
5
 
6
- attr_accessor :dirty_content, :line_numbers_content, :selection, :line_number, :find_text, :replace_text, :top_pixel, :display_path, :case_sensitive
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,55 @@ 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
- @selection = Point.new(0, 0 + @selection_count)
18
- read_dirty_content = path.empty? ? '' : ::File.read(path)
19
- begin
20
- # test read dirty content
21
- read_dirty_content.split("\n")
22
- observe(self, :dirty_content) do
23
- lines_text_size = lines.size.to_s.size
24
- self.line_numbers_content = lines.size.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
25
- end
26
- @line_number = 1
27
- self.dirty_content = read_dirty_content
28
- observe(self, :selection) do
29
- self.line_number = line_index_for_caret_position(caret_position) + 1
30
- end
31
- observe(self, :line_number) do
32
- if line_number
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
+ update_line_number_from_caret_position(new_caret_position)
40
+ end
41
+ observe(self, :line_number) do |new_line_number|
33
42
  line_index = line_number - 1
34
43
  new_caret_position = caret_position_for_line_index(line_index)
35
- self.caret_position = new_caret_position unless self.caret_position && line_index_for_caret_position(new_caret_position) == line_index_for_caret_position(caret_position)
44
+ current_caret_position = caret_position
45
+ line_index_for_new_caret_position = line_index_for_caret_position(new_caret_position)
46
+ line_index_for_current_caret_position = line_index_for_caret_position(current_caret_position)
47
+ self.caret_position = new_caret_position unless (current_caret_position && line_index_for_new_caret_position == line_index_for_current_caret_position)
36
48
  end
49
+ rescue # in case of a binary file
50
+ stop_filewatcher
37
51
  end
38
- rescue
39
- # no op in case of a binary file
40
52
  end
41
53
  end
42
-
54
+
55
+ def update_line_number_from_caret_position(new_caret_position)
56
+ new_line_number = line_index_for_caret_position(caret_position) + 1
57
+ current_line_number = line_number
58
+ unless (current_line_number && current_line_number == new_line_number)
59
+ self.line_number = new_line_number
60
+ # TODO check if the following line is needed
61
+ self.line_position = caret_position - caret_position_for_line_index(line_number - 1) + 1
62
+ end
63
+ end
64
+
43
65
  def path=(the_path)
44
66
  @path = the_path
45
67
  generate_display_path
@@ -49,6 +71,15 @@ module Glimmer
49
71
  return if @path.empty?
50
72
  @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
51
73
  end
74
+
75
+ def name=(the_name)
76
+ new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name) unless scratchpad?
77
+ @name = the_name
78
+ if !scratchpad? && ::File.exist?(path)
79
+ FileUtils.mv(path, new_path)
80
+ self.path = new_path
81
+ end
82
+ end
52
83
 
53
84
  def scratchpad?
54
85
  path.to_s.empty?
@@ -66,50 +97,74 @@ module Glimmer
66
97
  send("#{property}=", value)
67
98
  end
68
99
  end
100
+
101
+ def caret_position=(value)
102
+ @last_caret_position = @caret_position
103
+ @caret_position = value
104
+ end
69
105
 
70
- # to use for widget data-binding
71
- def content=(value)
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
106
+ def selection_count=(value)
107
+ #@last_selection_count = @selection_count
108
+ @selection_count = value
109
+ @last_selection_count = @selection_count
77
110
  end
78
111
 
112
+ def dirty_content
113
+ init_content
114
+ @dirty_content
115
+ end
116
+
117
+ def dirty_content=(the_content)
118
+ # TODO set partial dirty content by line(s) for enhanced performance
119
+ @dirty_content = the_content
120
+ old_caret_position = caret_position
121
+ old_top_pixel = top_pixel
122
+
123
+ notify_observers(:content)
124
+ if @formatting_dirty_content_for_writing
125
+ self.caret_position = old_caret_position
126
+ self.top_pixel = old_top_pixel
127
+ end
128
+ end
129
+
79
130
  def content
80
131
  dirty_content
81
132
  end
82
133
 
83
- def caret_position=(value)
84
- old_top_pixel = top_pixel
85
- self.selection = Point.new(value, value + selection_count.to_i)
86
- self.top_pixel = old_top_pixel
134
+ # to use for widget data-binding
135
+ def content=(value)
136
+ value = value.gsub("\t", ' ')
137
+ if dirty_content != value
138
+ Command.do(self, :change_content!, value)
139
+ end
87
140
  end
88
-
89
- def caret_position
90
- selection.x
141
+
142
+ def change_content!(value)
143
+ self.dirty_content = value
144
+ update_line_number_from_caret_position(caret_position)
91
145
  end
92
146
 
93
- def selection_count
94
- selection.y - selection.x
147
+ def start_command
148
+ @commmand_in_progress = true
95
149
  end
96
-
97
- def selection_count=(value)
98
- self.selection = Point.new(caret_position, caret_position + value.to_i)
150
+
151
+ def end_command
152
+ @commmand_in_progress = false
99
153
  end
100
-
101
- def name=(the_name)
102
- new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name) unless scratchpad?
103
- @name = the_name
104
- if !scratchpad? && ::File.exist?(path)
105
- FileUtils.mv(path, new_path)
106
- self.path = new_path
107
- end
154
+
155
+ def command_in_progress?
156
+ @commmand_in_progress
108
157
  end
109
158
 
110
- def dirty_content=(the_content)
111
- @dirty_content = the_content
112
- notify_observers(:content)
159
+ def close
160
+ stop_filewatcher
161
+ remove_all_observers
162
+ initialize(path, project_dir)
163
+ Command.clear(self)
164
+ end
165
+
166
+ def read_dirty_content
167
+ path.empty? ? '' : ::File.read(path)
113
168
  end
114
169
 
115
170
  def start_filewatcher
@@ -117,15 +172,13 @@ module Glimmer
117
172
  @filewatcher = Filewatcher.new(@path)
118
173
  @thread = Thread.new(@filewatcher) do |fw|
119
174
  fw.watch do |filename, event|
120
- begin
121
- read_dirty_content = ::File.read(path)
122
- # test read dirty content
123
- read_dirty_content.split("\n")
124
- async_exec do
175
+ async_exec do
176
+ begin
125
177
  self.dirty_content = read_dirty_content if read_dirty_content != dirty_content
178
+ rescue StandardError, Errno::ENOENT
179
+ # in case of a binary file
180
+ stop_filewatcher
126
181
  end
127
- rescue
128
- # no op in case of a binary file
129
182
  end
130
183
  end
131
184
  end
@@ -135,21 +188,28 @@ module Glimmer
135
188
  @filewatcher&.stop
136
189
  end
137
190
 
138
- def format_dirty_content_for_writing!
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"
141
- self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
142
- end
143
-
144
191
  def write_dirty_content
145
- return if scratchpad? || !::File.exist?(path)
192
+ # TODO write partial dirty content by line(s) for enhanced performance
193
+ return if scratchpad? || !::File.exist?(path) || !::File.exists?(path) || read_dirty_content == dirty_content
146
194
  format_dirty_content_for_writing!
147
- ::File.write(path, dirty_content) if ::File.exists?(path)
148
- rescue => e
195
+ ::File.write(path, dirty_content)
196
+ rescue StandardError, ArgumentError => e
149
197
  puts "Error in writing dirty content for #{path}"
150
198
  puts e.full_message
151
199
  end
152
200
 
201
+ def format_dirty_content_for_writing!
202
+ return if @commmand_in_progress
203
+ # TODO f ix c ar e t pos it ion after formatting dirty content (diff?)
204
+ new_dirty_content = dirty_content.to_s.split("\n").map {|line| line.strip.empty? ? line : line.rstrip }.join("\n")
205
+ new_dirty_content = "#{new_dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
206
+ if new_dirty_content != self.dirty_content
207
+ @formatting_dirty_content_for_writing = true
208
+ self.dirty_content = new_dirty_content
209
+ @formatting_dirty_content_for_writing = false
210
+ end
211
+ end
212
+
153
213
  def write_raw_dirty_content
154
214
  return if scratchpad? || !::File.exist?(path)
155
215
  ::File.write(path, dirty_content) if ::File.exists?(path)
@@ -185,7 +245,7 @@ module Glimmer
185
245
  self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
186
246
  self.selection_count = 0
187
247
  end
188
-
248
+
189
249
  def comment_line!
190
250
  old_lines = lines
191
251
  return if old_lines.size < 1
@@ -219,6 +279,7 @@ module Glimmer
219
279
  new_caret_position = old_caret_position + delta
220
280
  new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
221
281
  self.caret_position = new_caret_position
282
+ self.selection_count = 0
222
283
  end
223
284
  end
224
285
 
@@ -243,6 +304,7 @@ module Glimmer
243
304
  self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
244
305
  else
245
306
  self.caret_position = old_caret_position + delta
307
+ self.selection_count = 0
246
308
  end
247
309
  end
248
310
 
@@ -274,6 +336,7 @@ module Glimmer
274
336
  new_caret_position = old_caret_position + delta
275
337
  new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
276
338
  self.caret_position = new_caret_position
339
+ self.selection_count = 0
277
340
  end
278
341
  end
279
342
 
@@ -311,6 +374,7 @@ module Glimmer
311
374
  self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
312
375
  else
313
376
  self.caret_position = old_caret_position + delta
377
+ self.selection_count = 0
314
378
  end
315
379
  end
316
380
 
@@ -471,7 +535,7 @@ module Glimmer
471
535
  def line_index_for_caret_position(caret_position)
472
536
  dirty_content[0...caret_position.to_i].count("\n")
473
537
  end
474
-
538
+
475
539
  def caret_position_for_line_index(line_index)
476
540
  cp = lines[0...line_index].join("\n").size
477
541
  cp += 1 if line_index > 0