glimmer-cs-gladiator 0.5.2 → 0.6.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 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