glimmer-cs-gladiator 0.4.1 → 0.5.4
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 +23 -21
 - data/VERSION +1 -1
 - data/bin/gladiator_runner.rb +2 -1
 - data/lib/glimmer-cs-gladiator.rb +1 -1
 - data/lib/models/glimmer/gladiator/command.rb +4 -4
 - data/lib/models/glimmer/gladiator/dir.rb +78 -42
 - data/lib/models/glimmer/gladiator/file.rb +180 -102
 - data/lib/views/glimmer/gladiator.rb +465 -297
 - data/lib/views/glimmer/gladiator/text_editor.rb +34 -27
 - 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: d31e7dd5189317eaeb3a91a175a050ffaaeb4e82d6c8709167477d26dd7bf237
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 370a540665a9d7f3d08154f1e98530521f72e9a720f35fa83f982747e2e5bf5e
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 7af2ad9407c442ad6634a843ad3b5fc6cac47dadbd84ec0dc0b19f8d38b858950648a951383be811f040232ab426cbf0dffc1ad1d003a33a6a3cefd07d6c6832
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a9d30dc68de3f7de8fa25c9860c57885892e4ceeea734c63bc4fd2b257736afc0e1b0c7a062d03af93991d03d05907dbfbe058adcf6e13d695ce524167ce5aef
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,20 +1,21 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.4 
     | 
| 
      
 1 
     | 
    
         
            +
            # <img src='https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/master/images/glimmer-cs-gladiator-logo.svg' height=85 /> Gladiator 0.5.4 - [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 
     | 
    
         
            -
            ( 
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            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).
         
     | 
| 
       10 
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).
         
     | 
| 
       11 
     | 
    
         
            -
            Gladiator is also a personal tool for shaping an editor exactly the way I like, with all the keyboard shortcuts I prefer. 
     | 
| 
      
 9 
     | 
    
         
            +
            Gladiator is also a personal tool for shaping an editor exactly the way I like, with all the keyboard shortcuts I prefer.
         
     | 
| 
       12 
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.
         
     | 
| 
       13 
11 
     | 
    
         | 
| 
       14 
12 
     | 
    
         
             
            ## Features
         
     | 
| 
       15 
13 
     | 
    
         | 
| 
       16 
14 
     | 
    
         
             
            Gladiator currently supports the following text editing features (including keyboard shortcuts with Mac CMD=CTRL on Windows/Linux):
         
     | 
| 
       17 
15 
     | 
    
         
             
            - Ruby Syntax Highlighting with colors
         
     | 
| 
      
 16 
     | 
    
         
            +
            - Open Project from File Menu (CMD+SHIFT+P)
         
     | 
| 
      
 17 
     | 
    
         
            +
            - Scratchpad for running arbitrary Ruby/Glimmer code without saving to disk (CMD+SHIFT+S)
         
     | 
| 
      
 18 
     | 
    
         
            +
            - Run Ruby code (CMD+SHIFT+R)
         
     | 
| 
       18 
19 
     | 
    
         
             
            - File explorer navigation with context menu to open file, rename, delete, add new file, add new directory, or refresh tree (CMD+T)
         
     | 
| 
       19 
20 
     | 
    
         
             
            - File lookup by name ignoring slashes, underscores, and dots to ease lookup (CMD+R)
         
     | 
| 
       20 
21 
     | 
    
         
             
            - Watch open file for external changes to automatically refresh in editor
         
     | 
| 
         @@ -24,7 +25,7 @@ Gladiator currently supports the following text editing features (including keyb 
     | 
|
| 
       24 
25 
     | 
    
         
             
            - Jump to Line (CMD+L)
         
     | 
| 
       25 
26 
     | 
    
         
             
            - Multiple tab support (CMD+SHIFT+[ & CMD+SHIFT+] for tab navigation. CMD+1-9 to jump to a specific tab)
         
     | 
| 
       26 
27 
     | 
    
         
             
            - Remember opened tabs, caret position, top line, window size, and window location
         
     | 
| 
       27 
     | 
    
         
            -
            - Autosave on focus out/quit/open new file 
     | 
| 
      
 28 
     | 
    
         
            +
            - Autosave on focus out/quit/open new file
         
     | 
| 
       28 
29 
     | 
    
         
             
            - Duplicate Line(s)/selection (CMD+D)
         
     | 
| 
       29 
30 
     | 
    
         
             
            - Kill Line(s)/selection (CMD+K)
         
     | 
| 
       30 
31 
     | 
    
         
             
            - Move line/selection up (CMD+UP)
         
     | 
| 
         @@ -32,15 +33,14 @@ Gladiator currently supports the following text editing features (including keyb 
     | 
|
| 
       32 
33 
     | 
    
         
             
            - Comment/Uncomment line/selection (CMD+/)
         
     | 
| 
       33 
34 
     | 
    
         
             
            - Indent/Unindent line/selection (CMD+] & CMD+[)
         
     | 
| 
       34 
35 
     | 
    
         
             
            - Insert/Prefix New Line (CMD+ENTER & CMD+SHIFT+ENTER)
         
     | 
| 
       35 
     | 
    
         
            -
            -  
     | 
| 
       36 
     | 
    
         
            -
            -  
     | 
| 
       37 
     | 
    
         
            -
            - Change Split Orientation to Horizontal/Vertical via View Menu (CMD+SHIFT+O)
         
     | 
| 
      
 36 
     | 
    
         
            +
            - Split Pane & Change Split Orientation to Horizontal/Vertical via View Menu (CMD+SHIFT+O)
         
     | 
| 
      
 37 
     | 
    
         
            +
            - Drag and Drop Text Editor Split Screen (drag a file from File Tree or File Lookup List, and it splits the pane)
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
            ## Platforms
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
            - Mac: Gladiator works best on the Mac. This is the platform it is most used on and receives the most maintenance for.
         
     | 
| 
       42 
     | 
    
         
            -
            - Windows: Gladiator works OK on Windows, but has some annoying bugs.
         
     | 
| 
       43 
     | 
    
         
            -
            - Linux: Gladiator works with  
     | 
| 
      
 42 
     | 
    
         
            +
            - Windows: Gladiator works OK on Windows, but has some annoying bugs. Contributers could help fix.
         
     | 
| 
      
 43 
     | 
    
         
            +
            - Linux: Gladiator works with handicaps on Linux (performing some text editing operations causes scroll jitter). Contributers could help fix.
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
45 
     | 
    
         
             
            ## Pre-requisites
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
         @@ -78,6 +78,12 @@ You may run the `gladiator` command to bring up the text editor in the project d 
     | 
|
| 
       78 
78 
     | 
    
         
             
            gladiator
         
     | 
| 
       79 
79 
     | 
    
         
             
            ```
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
      
 81 
     | 
    
         
            +
            On Linux, you may need to run with extra memory via this command instead:
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            ```
         
     | 
| 
      
 84 
     | 
    
         
            +
            gladiator -J-Xmx1200M
         
     | 
| 
      
 85 
     | 
    
         
            +
            ```
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
       81 
87 
     | 
    
         
             
            On Windows, you may need to run with extra memory via this command instead:
         
     | 
| 
       82 
88 
     | 
    
         | 
| 
       83 
89 
     | 
    
         
             
            ```
         
     | 
| 
         @@ -100,11 +106,11 @@ bin/gladiator relative-or-absolute-path/to/project 
     | 
|
| 
       100 
106 
     | 
    
         | 
| 
       101 
107 
     | 
    
         
             
            ### Glimmer Custom Shell Reuse
         
     | 
| 
       102 
108 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
            To reuse Gladiator as a Glimmer Custom Shell inside another Glimmer application, add the 
     | 
| 
      
 109 
     | 
    
         
            +
            To reuse Gladiator as a Glimmer Custom Shell inside another Glimmer application, add the
         
     | 
| 
       104 
110 
     | 
    
         
             
            following to the application's `Gemfile`:
         
     | 
| 
       105 
111 
     | 
    
         | 
| 
       106 
112 
     | 
    
         
             
            ```
         
     | 
| 
       107 
     | 
    
         
            -
            gem 'glimmer-cs-gladiator', '~> 0.4 
     | 
| 
      
 113 
     | 
    
         
            +
            gem 'glimmer-cs-gladiator', '~> 0.5.4'
         
     | 
| 
       108 
114 
     | 
    
         
             
            ```
         
     | 
| 
       109 
115 
     | 
    
         | 
| 
       110 
116 
     | 
    
         
             
            Run:
         
     | 
| 
         @@ -117,7 +123,7 @@ And, then instantiate the Gladiator [custom shell](https://github.com/AndyObtiva 
     | 
|
| 
       117 
123 
     | 
    
         | 
| 
       118 
124 
     | 
    
         
             
            ## Env Var Options
         
     | 
| 
       119 
125 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
            Gladiator opens with the current directory as the root by default. 
     | 
| 
      
 126 
     | 
    
         
            +
            Gladiator opens with the current directory as the root by default.
         
     | 
| 
       121 
127 
     | 
    
         
             
            If you would like to open another directory, set `LOCAL_DIR` environment variable.
         
     | 
| 
       122 
128 
     | 
    
         | 
| 
       123 
129 
     | 
    
         
             
            Example:
         
     | 
| 
         @@ -133,13 +139,9 @@ Opens Gladiator with "/Users/User/code" as the root directory. 
     | 
|
| 
       133 
139 
     | 
    
         
             
            Gladiator automatically saves configuration data in a `.gladiator` file at the directory it is run from.
         
     | 
| 
       134 
140 
     | 
    
         | 
| 
       135 
141 
     | 
    
         
             
            It currently remembers:
         
     | 
| 
       136 
     | 
    
         
            -
            - Last opened  
     | 
| 
       137 
     | 
    
         
            -
            -  
     | 
| 
       138 
     | 
    
         
            -
            -  
     | 
| 
       139 
     | 
    
         
            -
            - Window size
         
     | 
| 
       140 
     | 
    
         
            -
            - Opened tabs
         
     | 
| 
       141 
     | 
    
         
            -
            - Split tabs
         
     | 
| 
       142 
     | 
    
         
            -
            - Ignore Paths
         
     | 
| 
      
 142 
     | 
    
         
            +
            - Last opened files (in both split panes if split)
         
     | 
| 
      
 143 
     | 
    
         
            +
            - Window size and position
         
     | 
| 
      
 144 
     | 
    
         
            +
            - Ignore Paths (default: '.gladiator', '.git', 'coverage', 'packages', 'node_modules', 'tmp', 'vendor')
         
     | 
| 
       143 
145 
     | 
    
         | 
| 
       144 
146 
     | 
    
         
             
            ## Gotcha
         
     | 
| 
       145 
147 
     | 
    
         | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            0.4 
     | 
| 
      
 1 
     | 
    
         
            +
            0.5.4
         
     | 
    
        data/bin/gladiator_runner.rb
    CHANGED
    
    
    
        data/lib/glimmer-cs-gladiator.rb
    CHANGED
    
    
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Glimmer
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Gladiator
         
     | 
| 
       3 
     | 
    
         
            -
                class Command 
     | 
| 
      
 3 
     | 
    
         
            +
                class Command
         
     | 
| 
       4 
4 
     | 
    
         
             
                  class << self
         
     | 
| 
       5 
5 
     | 
    
         
             
                    include Glimmer
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -10,10 +10,10 @@ module Glimmer 
     | 
|
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                    def command_history_for(file)
         
     | 
| 
       12 
12 
     | 
    
         
             
                      # keeping a first command to make redo support work by remembering next command after undoing all
         
     | 
| 
       13 
     | 
    
         
            -
                      command_history[file] ||= [Command.new(file)] 
     | 
| 
      
 13 
     | 
    
         
            +
                      command_history[file] ||= [Command.new(file)]
         
     | 
| 
       14 
14 
     | 
    
         
             
                    end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                    def do(file, method = nil, command: nil) 
     | 
| 
      
 16 
     | 
    
         
            +
                    def do(file, method = nil, command: nil)
         
     | 
| 
       17 
17 
     | 
    
         
             
                      command ||= Command.new(file, method)
         
     | 
| 
       18 
18 
     | 
    
         
             
                      command_history_for(file)&.last&.next_command = command
         
     | 
| 
       19 
19 
     | 
    
         
             
                      command.do
         
     | 
| 
         @@ -21,7 +21,7 @@ module Glimmer 
     | 
|
| 
       21 
21 
     | 
    
         
             
                    end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    def undo(file)
         
     | 
| 
       24 
     | 
    
         
            -
                      return if command_history_for(file).size <= 1 
     | 
| 
      
 24 
     | 
    
         
            +
                      return if command_history_for(file).size <= 1
         
     | 
| 
       25 
25 
     | 
    
         
             
                      command = command_history_for(file).pop
         
     | 
| 
       26 
26 
     | 
    
         
             
                      command&.undo
         
     | 
| 
       27 
27 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -4,39 +4,49 @@ module Glimmer 
     | 
|
| 
       4 
4 
     | 
    
         
             
              class Gladiator
         
     | 
| 
       5 
5 
     | 
    
         
             
                class Dir
         
     | 
| 
       6 
6 
     | 
    
         
             
                  include Glimmer
         
     | 
| 
      
 7 
     | 
    
         
            +
                  include Glimmer::DataBinding::ObservableModel
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                   
     | 
| 
      
 9 
     | 
    
         
            +
                  attr_accessor :selected_child, :filter, :children, :filtered_path_options, :filtered_path, :display_path, :ignore_paths
         
     | 
| 
      
 10 
     | 
    
         
            +
                  attr_reader :name, :parent, :path
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_writer :all_children
         
     | 
| 
       9 
12 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                   
     | 
| 
       11 
     | 
    
         
            -
                     
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                         
     | 
| 
       16 
     | 
    
         
            -
                        @thread = Thread.new(@filewatcher) do |fw| 
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def initialize(path, project_dir = nil)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @project_dir = project_dir
         
     | 
| 
      
 15 
     | 
    
         
            +
                    if is_local_dir
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @filewatcher = Filewatcher.new(path)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      Thread.new(@filewatcher) do |fw|
         
     | 
| 
      
 18 
     | 
    
         
            +
                        begin
         
     | 
| 
       17 
19 
     | 
    
         
             
                          fw.watch do |filename, event|
         
     | 
| 
       18 
     | 
    
         
            -
                             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 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
         
     | 
| 
       20 
30 
     | 
    
         
             
                            end
         
     | 
| 
       21 
     | 
    
         
            -
                            @last_update = Time.now.to_f
         
     | 
| 
       22 
31 
     | 
    
         
             
                          end
         
     | 
| 
      
 32 
     | 
    
         
            +
                        rescue => e
         
     | 
| 
      
 33 
     | 
    
         
            +
                          puts e.full_message
         
     | 
| 
       23 
34 
     | 
    
         
             
                        end
         
     | 
| 
       24 
35 
     | 
    
         
             
                      end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                    end        
         
     | 
| 
       27 
     | 
    
         
            -
                  end
         
     | 
| 
       28 
     | 
    
         
            -
              
         
     | 
| 
       29 
     | 
    
         
            -
                  attr_accessor :selected_child, :filter, :children, :filtered_path_options, :filtered_path, :display_path, :ignore_paths
         
     | 
| 
       30 
     | 
    
         
            -
                  attr_reader :name, :parent, :path, :is_local_dir
         
     | 
| 
       31 
     | 
    
         
            -
                  attr_writer :all_children
         
     | 
| 
       32 
     | 
    
         
            -
              
         
     | 
| 
       33 
     | 
    
         
            -
                  def initialize(path, is_local_dir = false)
         
     | 
| 
       34 
     | 
    
         
            -
                    @is_local_dir = is_local_dir
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
       35 
37 
     | 
    
         
             
                    self.path = ::File.expand_path(path)
         
     | 
| 
       36 
38 
     | 
    
         
             
                    @name = ::File.basename(::File.expand_path(path))
         
     | 
| 
       37 
     | 
    
         
            -
                    @ignore_paths = ['packages', 'tmp', 'vendor']
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @ignore_paths = ['.gladiator', '.git', 'coverage', 'packages', 'node_modules', 'tmp', 'vendor']
         
     | 
| 
       38 
40 
     | 
    
         
             
                    self.filtered_path_options = []
         
     | 
| 
       39 
41 
     | 
    
         
             
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  
         
     | 
| 
      
 43 
     | 
    
         
            +
                  def is_local_dir
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @project_dir.nil?
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def project_dir
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @project_dir || self
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
       40 
50 
     | 
    
         | 
| 
       41 
51 
     | 
    
         
             
                  def path=(the_path)
         
     | 
| 
       42 
52 
     | 
    
         
             
                    @path = the_path
         
     | 
| 
         @@ -44,7 +54,7 @@ module Glimmer 
     | 
|
| 
       44 
54 
     | 
    
         
             
                  end
         
     | 
| 
       45 
55 
     | 
    
         | 
| 
       46 
56 
     | 
    
         
             
                  def generate_display_path
         
     | 
| 
       47 
     | 
    
         
            -
                    is_local_dir ? path : @display_path = @path.sub( 
     | 
| 
      
 57 
     | 
    
         
            +
                    is_local_dir ? path : @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
         
     | 
| 
       48 
58 
     | 
    
         
             
                  end
         
     | 
| 
       49 
59 
     | 
    
         | 
| 
       50 
60 
     | 
    
         
             
                  def name=(the_name)
         
     | 
| 
         @@ -61,20 +71,36 @@ module Glimmer 
     | 
|
| 
       61 
71 
     | 
    
         | 
| 
       62 
72 
     | 
    
         
             
                  def retrieve_children
         
     | 
| 
       63 
73 
     | 
    
         
             
                    @children = ::Dir.glob(::File.join(@path, '*')).reject do |p|
         
     | 
| 
       64 
     | 
    
         
            -
                      # TODO make sure to configure ignore_paths in a preferences dialog 
     | 
| 
       65 
     | 
    
         
            -
                       
     | 
| 
      
 74 
     | 
    
         
            +
                      # TODO make sure to configure ignore_paths in a preferences dialog
         
     | 
| 
      
 75 
     | 
    
         
            +
                      project_dir.ignore_paths.reduce(false) do |result, ignore_path|
         
     | 
| 
       66 
76 
     | 
    
         
             
                        result || p.include?(ignore_path)
         
     | 
| 
       67 
77 
     | 
    
         
             
                      end
         
     | 
| 
       68 
     | 
    
         
            -
                    end.map do |p| 
     | 
| 
       69 
     | 
    
         
            -
                      ::File.file?(p) ?  
     | 
| 
       70 
     | 
    
         
            -
                    end.sort_by do |c| 
     | 
| 
       71 
     | 
    
         
            -
                      c.path.to_s.downcase 
     | 
| 
       72 
     | 
    
         
            -
                    end.sort_by do |c| 
     | 
| 
      
 78 
     | 
    
         
            +
                    end.map do |p|
         
     | 
| 
      
 79 
     | 
    
         
            +
                      ::File.file?(p) ? File.new(p, project_dir) : Dir.new(p, project_dir)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end.sort_by do |c|
         
     | 
| 
      
 81 
     | 
    
         
            +
                      c.path.to_s.downcase
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end.sort_by do |c|
         
     | 
| 
       73 
83 
     | 
    
         
             
                      c.class.name
         
     | 
| 
       74 
84 
     | 
    
         
             
                    end.each do |child|
         
     | 
| 
       75 
85 
     | 
    
         
             
                      child.retrieve_children if child.is_a?(Dir)
         
     | 
| 
       76 
86 
     | 
    
         
             
                    end
         
     | 
| 
       77 
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
         
     | 
| 
       78 
104 
     | 
    
         | 
| 
       79 
105 
     | 
    
         
             
                  def selected_child_path_history
         
     | 
| 
       80 
106 
     | 
    
         
             
                    @selected_child_path_history ||= []
         
     | 
| 
         @@ -90,6 +116,7 @@ module Glimmer 
     | 
|
| 
       90 
116 
     | 
    
         | 
| 
       91 
117 
     | 
    
         
             
                  def refresh(async: true, force: false)
         
     | 
| 
       92 
118 
     | 
    
         
             
                    return if @refresh_paused && !force
         
     | 
| 
      
 119 
     | 
    
         
            +
                    @refresh_in_progress = true
         
     | 
| 
       93 
120 
     | 
    
         
             
                    retrieve_children
         
     | 
| 
       94 
121 
     | 
    
         
             
                    collect_all_children
         
     | 
| 
       95 
122 
     | 
    
         
             
                    refresh_operation = lambda do
         
     | 
| 
         @@ -101,11 +128,12 @@ module Glimmer 
     | 
|
| 
       101 
128 
     | 
    
         
             
                    else
         
     | 
| 
       102 
129 
     | 
    
         
             
                      sync_exec(&refresh_operation)
         
     | 
| 
       103 
130 
     | 
    
         
             
                    end
         
     | 
| 
      
 131 
     | 
    
         
            +
                    @refresh_in_progress = false
         
     | 
| 
       104 
132 
     | 
    
         
             
                  end
         
     | 
| 
       105 
133 
     | 
    
         | 
| 
       106 
134 
     | 
    
         
             
                  def filter=(value)
         
     | 
| 
       107 
135 
     | 
    
         
             
                    if value.to_s.empty?
         
     | 
| 
       108 
     | 
    
         
            -
                      @filter = nil 
     | 
| 
      
 136 
     | 
    
         
            +
                      @filter = nil
         
     | 
| 
       109 
137 
     | 
    
         
             
                    else
         
     | 
| 
       110 
138 
     | 
    
         
             
                      @filter = value
         
     | 
| 
       111 
139 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -117,8 +145,8 @@ module Glimmer 
     | 
|
| 
       117 
145 
     | 
    
         
             
                  def filtered
         
     | 
| 
       118 
146 
     | 
    
         
             
                    return if filter.nil?
         
     | 
| 
       119 
147 
     | 
    
         
             
                    children_files = !@last_filter.to_s.empty? && filter.downcase.start_with?(@last_filter.downcase) ? @last_filtered : all_children_files
         
     | 
| 
       120 
     | 
    
         
            -
                    children_files.select do |child| 
     | 
| 
       121 
     | 
    
         
            -
                      child_path = child.path.to_s.sub( 
     | 
| 
      
 148 
     | 
    
         
            +
                    children_files.select do |child|
         
     | 
| 
      
 149 
     | 
    
         
            +
                      child_path = child.path.to_s.sub(project_dir.path, '')
         
     | 
| 
       122 
150 
     | 
    
         
             
                      child_path.downcase.include?(filter.downcase) ||
         
     | 
| 
       123 
151 
     | 
    
         
             
                        child_path.downcase.gsub(/[_\/.-]/, '').include?(filter.downcase.gsub(/[_\/.-]/, ''))
         
     | 
| 
       124 
152 
     | 
    
         
             
                    end.sort_by {|c| c.path.to_s.downcase}
         
     | 
| 
         @@ -141,14 +169,19 @@ module Glimmer 
     | 
|
| 
       141 
169 
     | 
    
         
             
                  end
         
     | 
| 
       142 
170 
     | 
    
         | 
| 
       143 
171 
     | 
    
         
             
                  def selected_child_path=(selected_path)
         
     | 
| 
       144 
     | 
    
         
            -
                     
     | 
| 
       145 
     | 
    
         
            -
                     
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
      
 172 
     | 
    
         
            +
                    return (project_dir.selected_child = nil) if selected_path.nil?
         
     | 
| 
      
 173 
     | 
    
         
            +
                    # scratchpad scenario
         
     | 
| 
      
 174 
     | 
    
         
            +
                    if selected_path.empty? # Scratchpad
         
     | 
| 
      
 175 
     | 
    
         
            +
                      @selected_child&.write_dirty_content
         
     | 
| 
      
 176 
     | 
    
         
            +
                      return (self.selected_child = File.new)
         
     | 
| 
      
 177 
     | 
    
         
            +
                    end
         
     | 
| 
      
 178 
     | 
    
         
            +
                    full_selected_path = selected_path.include?(project_dir.path) ? selected_path : ::File.join(project_dir.path, selected_path)
         
     | 
| 
      
 179 
     | 
    
         
            +
                    return if ::Dir.exist?(full_selected_path) ||
         
     | 
| 
       147 
180 
     | 
    
         
             
                              (selected_child && selected_child.path == full_selected_path)
         
     | 
| 
       148 
181 
     | 
    
         
             
                    selected_path = full_selected_path
         
     | 
| 
       149 
182 
     | 
    
         
             
                    if ::File.file?(selected_path)
         
     | 
| 
       150 
183 
     | 
    
         
             
                      @selected_child&.write_dirty_content
         
     | 
| 
       151 
     | 
    
         
            -
                      new_child =  
     | 
| 
      
 184 
     | 
    
         
            +
                      new_child = find_child_file(selected_path)
         
     | 
| 
       152 
185 
     | 
    
         
             
                      begin
         
     | 
| 
       153 
186 
     | 
    
         
             
                        unless new_child.dirty_content.nil?
         
     | 
| 
       154 
187 
     | 
    
         
             
                          self.selected_child&.stop_filewatcher
         
     | 
| 
         @@ -168,6 +201,13 @@ module Glimmer 
     | 
|
| 
       168 
201 
     | 
    
         
             
                    @selected_child&.path
         
     | 
| 
       169 
202 
     | 
    
         
             
                  end
         
     | 
| 
       170 
203 
     | 
    
         | 
| 
      
 204 
     | 
    
         
            +
                  def selected_child=(new_child)
         
     | 
| 
      
 205 
     | 
    
         
            +
                    return if selected_child == new_child
         
     | 
| 
      
 206 
     | 
    
         
            +
                    file_properties = @selected_child&.backup_properties if @selected_child == new_child
         
     | 
| 
      
 207 
     | 
    
         
            +
                    @selected_child = new_child
         
     | 
| 
      
 208 
     | 
    
         
            +
                    @selected_child.restore_properties(file_properties) if file_properties
         
     | 
| 
      
 209 
     | 
    
         
            +
                  end
         
     | 
| 
      
 210 
     | 
    
         
            +
                  
         
     | 
| 
       171 
211 
     | 
    
         
             
                  def delete!
         
     | 
| 
       172 
212 
     | 
    
         
             
                    FileUtils.rm_rf(path)
         
     | 
| 
       173 
213 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -183,11 +223,7 @@ module Glimmer 
     | 
|
| 
       183 
223 
     | 
    
         
             
                  def hash
         
     | 
| 
       184 
224 
     | 
    
         
             
                    self.path.hash
         
     | 
| 
       185 
225 
     | 
    
         
             
                  end
         
     | 
| 
       186 
     | 
    
         
            -
                end 
     | 
| 
      
 226 
     | 
    
         
            +
                end
         
     | 
| 
       187 
227 
     | 
    
         
             
              end
         
     | 
| 
       188 
228 
     | 
    
         
             
            end
         
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
       190 
     | 
    
         
            -
            at_exit do
         
     | 
| 
       191 
     | 
    
         
            -
              Glimmer::Gladiator::Dir.local_dir.selected_child&.write_raw_dirty_content
         
     | 
| 
       192 
     | 
    
         
            -
            end
         
     | 
| 
       193 
229 
     | 
    
         | 
| 
         @@ -1,43 +1,56 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'models/glimmer/gladiator/dir'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module Glimmer
         
     | 
| 
       4 
2 
     | 
    
         
             
              class Gladiator
         
     | 
| 
       5 
3 
     | 
    
         
             
                class File
         
     | 
| 
       6 
4 
     | 
    
         
             
                  include Glimmer
         
     | 
| 
       7 
     | 
    
         
            -
              
         
     | 
| 
       8 
     | 
    
         
            -
                  attr_accessor :dirty_content, :line_numbers_content, :selection, :line_number, :find_text, :replace_text, :top_pixel, :display_path, :case_sensitive
         
     | 
| 
       9 
     | 
    
         
            -
                  attr_reader :name, :path
         
     | 
| 
       10 
5 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                   
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_accessor :line_numbers_content, :selection, :line_number, :find_text, :replace_text, :top_pixel, :display_path, :case_sensitive
         
     | 
| 
      
 7 
     | 
    
         
            +
                  attr_reader :name, :path, :project_dir
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(path='', project_dir=nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    raise "Not a file path: #{path}" if path.nil? || (!path.empty? && !::File.file?(path))
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @project_dir = project_dir
         
     | 
| 
       13 
12 
     | 
    
         
             
                    @command_history = []
         
     | 
| 
       14 
     | 
    
         
            -
                    @name = ::File.basename(path)
         
     | 
| 
       15 
     | 
    
         
            -
                    self.path = ::File.expand_path(path)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @name = path.empty? ? 'Scratchpad' : ::File.basename(path)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    self.path = ::File.expand_path(path) unless path.empty?
         
     | 
| 
       16 
15 
     | 
    
         
             
                    @top_pixel = 0
         
     | 
| 
       17 
16 
     | 
    
         
             
                    @selection_count = 0
         
     | 
| 
       18 
17 
     | 
    
         
             
                    @selection = Point.new(0, 0 + @selection_count)
         
     | 
| 
       19 
     | 
    
         
            -
                     
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                      observe(self, :line_number) do
         
     | 
| 
       33 
     | 
    
         
            -
                        if line_number
         
     | 
| 
       34 
     | 
    
         
            -
                          line_index = line_number - 1
         
     | 
| 
       35 
     | 
    
         
            -
                          new_caret_position = caret_position_for_line_index(line_index)
         
     | 
| 
       36 
     | 
    
         
            -
                          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)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @line_number = 1
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def init_content
         
     | 
| 
      
 22 
     | 
    
         
            +
                    unless @init
         
     | 
| 
      
 23 
     | 
    
         
            +
                      @init = true
         
     | 
| 
      
 24 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 25 
     | 
    
         
            +
                        # test read dirty content
         
     | 
| 
      
 26 
     | 
    
         
            +
                        observe(self, :dirty_content) do
         
     | 
| 
      
 27 
     | 
    
         
            +
                          lines_text_size = lines.size.to_s.size
         
     | 
| 
      
 28 
     | 
    
         
            +
                          old_top_pixel = top_pixel
         
     | 
| 
      
 29 
     | 
    
         
            +
                          self.line_numbers_content = lines.size.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
         
     | 
| 
      
 30 
     | 
    
         
            +
                          self.top_pixel = old_top_pixel
         
     | 
| 
       37 
31 
     | 
    
         
             
                        end
         
     | 
| 
      
 32 
     | 
    
         
            +
                        the_dirty_content = read_dirty_content
         
     | 
| 
      
 33 
     | 
    
         
            +
                        the_dirty_content.split("\n") # test that it is not a binary file (crashes to rescue block otherwise)
         
     | 
| 
      
 34 
     | 
    
         
            +
                        self.dirty_content = the_dirty_content
         
     | 
| 
      
 35 
     | 
    
         
            +
                        observe(self, :selection) do
         
     | 
| 
      
 36 
     | 
    
         
            +
                          new_line_number = line_index_for_caret_position(caret_position) + 1
         
     | 
| 
      
 37 
     | 
    
         
            +
                          async_exec {
         
     | 
| 
      
 38 
     | 
    
         
            +
                            self.line_number = new_line_number
         
     | 
| 
      
 39 
     | 
    
         
            +
                          }
         
     | 
| 
      
 40 
     | 
    
         
            +
                        end
         
     | 
| 
      
 41 
     | 
    
         
            +
                        observe(self, :line_number) do
         
     | 
| 
      
 42 
     | 
    
         
            +
                          if line_number
         
     | 
| 
      
 43 
     | 
    
         
            +
                            line_index = line_number - 1
         
     | 
| 
      
 44 
     | 
    
         
            +
                            new_caret_position = caret_position_for_line_index(line_index)
         
     | 
| 
      
 45 
     | 
    
         
            +
                            current_caret_position = self.caret_position
         
     | 
| 
      
 46 
     | 
    
         
            +
                            async_exec {
         
     | 
| 
      
 47 
     | 
    
         
            +
                              self.caret_position = new_caret_position unless current_caret_position && line_index_for_caret_position(new_caret_position) == line_index_for_caret_position(current_caret_position)
         
     | 
| 
      
 48 
     | 
    
         
            +
                            }
         
     | 
| 
      
 49 
     | 
    
         
            +
                          end
         
     | 
| 
      
 50 
     | 
    
         
            +
                        end
         
     | 
| 
      
 51 
     | 
    
         
            +
                      rescue # in case of a binary file
         
     | 
| 
      
 52 
     | 
    
         
            +
                        stop_filewatcher
         
     | 
| 
       38 
53 
     | 
    
         
             
                      end
         
     | 
| 
       39 
     | 
    
         
            -
                    rescue
         
     | 
| 
       40 
     | 
    
         
            -
                      # no op in case of a binary file
         
     | 
| 
       41 
54 
     | 
    
         
             
                    end
         
     | 
| 
       42 
55 
     | 
    
         
             
                  end
         
     | 
| 
       43 
56 
     | 
    
         | 
| 
         @@ -45,15 +58,34 @@ module Glimmer 
     | 
|
| 
       45 
58 
     | 
    
         
             
                    @path = the_path
         
     | 
| 
       46 
59 
     | 
    
         
             
                    generate_display_path
         
     | 
| 
       47 
60 
     | 
    
         
             
                  end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
       49 
62 
     | 
    
         
             
                  def generate_display_path
         
     | 
| 
       50 
     | 
    
         
            -
                     
     | 
| 
      
 63 
     | 
    
         
            +
                    return if @path.empty?
         
     | 
| 
      
 64 
     | 
    
         
            +
                    @display_path = @path.sub(project_dir.path, '').sub(/^\//, '')
         
     | 
| 
       51 
65 
     | 
    
         
             
                  end
         
     | 
| 
       52 
66 
     | 
    
         | 
| 
      
 67 
     | 
    
         
            +
                  def scratchpad?
         
     | 
| 
      
 68 
     | 
    
         
            +
                    path.to_s.empty?
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  def backup_properties
         
     | 
| 
      
 72 
     | 
    
         
            +
                    [:find_text, :replace_text, :case_sensitive, :top_pixel, :caret_position, :selection_count].reduce({}) do |hash, property|
         
     | 
| 
      
 73 
     | 
    
         
            +
                      hash.merge(property => send(property))
         
     | 
| 
      
 74 
     | 
    
         
            +
                    end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  def restore_properties(properties_hash)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    return if properties_hash[:caret_position] == 0 && properties_hash[:selection_count] == 0 && properties_hash[:find_text].nil? && properties_hash[:replace_text].nil? && properties_hash[:top_pixel] == 0 && properties_hash[:case_sensitive].nil?
         
     | 
| 
      
 79 
     | 
    
         
            +
                    properties_hash.each do |property, value|
         
     | 
| 
      
 80 
     | 
    
         
            +
                      send("#{property}=", value)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
       53 
84 
     | 
    
         
             
                  # to use for widget data-binding
         
     | 
| 
       54 
85 
     | 
    
         
             
                  def content=(value)
         
     | 
| 
       55 
86 
     | 
    
         
             
                    value = value.gsub("\t", '  ')
         
     | 
| 
       56 
87 
     | 
    
         
             
                    if dirty_content != value
         
     | 
| 
      
 88 
     | 
    
         
            +
                      # TODO fix this command recording hack by truly recording every text change as a proper command (add process_key command, paste command, cut command, etc...)
         
     | 
| 
       57 
89 
     | 
    
         
             
                      Command.do(self) # record a native (OS-widget) operation
         
     | 
| 
       58 
90 
     | 
    
         
             
                      self.dirty_content = value
         
     | 
| 
       59 
91 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -68,7 +100,7 @@ module Glimmer 
     | 
|
| 
       68 
100 
     | 
    
         
             
                    self.selection = Point.new(value, value + selection_count.to_i)
         
     | 
| 
       69 
101 
     | 
    
         
             
                    self.top_pixel = old_top_pixel
         
     | 
| 
       70 
102 
     | 
    
         
             
                  end
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
       72 
104 
     | 
    
         
             
                  def caret_position
         
     | 
| 
       73 
105 
     | 
    
         
             
                    selection.x
         
     | 
| 
       74 
106 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -76,63 +108,85 @@ module Glimmer 
     | 
|
| 
       76 
108 
     | 
    
         
             
                  def selection_count
         
     | 
| 
       77 
109 
     | 
    
         
             
                    selection.y - selection.x
         
     | 
| 
       78 
110 
     | 
    
         
             
                  end
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
       80 
112 
     | 
    
         
             
                  def selection_count=(value)
         
     | 
| 
       81 
113 
     | 
    
         
             
                    self.selection = Point.new(caret_position, caret_position + value.to_i)
         
     | 
| 
       82 
     | 
    
         
            -
                  end 
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
       84 
116 
     | 
    
         
             
                  def name=(the_name)
         
     | 
| 
       85 
     | 
    
         
            -
                    new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    new_path = path.sub(/#{Regexp.escape(@name)}$/, the_name) unless scratchpad?
         
     | 
| 
       86 
118 
     | 
    
         
             
                    @name = the_name
         
     | 
| 
       87 
     | 
    
         
            -
                    if ::File. 
     | 
| 
      
 119 
     | 
    
         
            +
                    if !scratchpad? && ::File.exist?(path)
         
     | 
| 
       88 
120 
     | 
    
         
             
                      FileUtils.mv(path, new_path)
         
     | 
| 
       89 
121 
     | 
    
         
             
                      self.path = new_path
         
     | 
| 
       90 
122 
     | 
    
         
             
                    end
         
     | 
| 
       91 
123 
     | 
    
         
             
                  end
         
     | 
| 
       92 
124 
     | 
    
         | 
| 
      
 125 
     | 
    
         
            +
                  def dirty_content
         
     | 
| 
      
 126 
     | 
    
         
            +
                    init_content
         
     | 
| 
      
 127 
     | 
    
         
            +
                    @dirty_content
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
                  
         
     | 
| 
       93 
130 
     | 
    
         
             
                  def dirty_content=(the_content)
         
     | 
| 
       94 
     | 
    
         
            -
                     
     | 
| 
      
 131 
     | 
    
         
            +
                    # TODO set partial dirty content by line(s) for enhanced performance
         
     | 
| 
      
 132 
     | 
    
         
            +
                    @dirty_content = the_content
         
     | 
| 
      
 133 
     | 
    
         
            +
                    old_caret_position = caret_position
         
     | 
| 
      
 134 
     | 
    
         
            +
                    old_top_pixel = top_pixel
         
     | 
| 
       95 
135 
     | 
    
         
             
                    notify_observers(:content)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    if @formatting_dirty_content_for_writing
         
     | 
| 
      
 137 
     | 
    
         
            +
                      self.caret_position = old_caret_position
         
     | 
| 
      
 138 
     | 
    
         
            +
                      self.selection_count = 0
         
     | 
| 
      
 139 
     | 
    
         
            +
                      self.top_pixel = old_top_pixel
         
     | 
| 
      
 140 
     | 
    
         
            +
                    end
         
     | 
| 
      
 141 
     | 
    
         
            +
                  end
         
     | 
| 
      
 142 
     | 
    
         
            +
                  
         
     | 
| 
      
 143 
     | 
    
         
            +
                  def read_dirty_content
         
     | 
| 
      
 144 
     | 
    
         
            +
                    path.empty? ? '' : ::File.read(path)
         
     | 
| 
       96 
145 
     | 
    
         
             
                  end
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
       98 
147 
     | 
    
         
             
                  def start_filewatcher
         
     | 
| 
      
 148 
     | 
    
         
            +
                    return if scratchpad?
         
     | 
| 
       99 
149 
     | 
    
         
             
                    @filewatcher = Filewatcher.new(@path)
         
     | 
| 
       100 
     | 
    
         
            -
                    @thread = Thread.new(@filewatcher) do |fw| 
     | 
| 
      
 150 
     | 
    
         
            +
                    @thread = Thread.new(@filewatcher) do |fw|
         
     | 
| 
       101 
151 
     | 
    
         
             
                      fw.watch do |filename, event|
         
     | 
| 
       102 
     | 
    
         
            -
                         
     | 
| 
       103 
     | 
    
         
            -
                           
     | 
| 
       104 
     | 
    
         
            -
                          # test read dirty content
         
     | 
| 
       105 
     | 
    
         
            -
                          read_dirty_content.split("\n")
         
     | 
| 
       106 
     | 
    
         
            -
                          async_exec do
         
     | 
| 
      
 152 
     | 
    
         
            +
                        async_exec do
         
     | 
| 
      
 153 
     | 
    
         
            +
                          begin
         
     | 
| 
       107 
154 
     | 
    
         
             
                            self.dirty_content = read_dirty_content if read_dirty_content != dirty_content
         
     | 
| 
      
 155 
     | 
    
         
            +
                          rescue StandardError, Errno::ENOENT
         
     | 
| 
      
 156 
     | 
    
         
            +
                            # in case of a binary file
         
     | 
| 
      
 157 
     | 
    
         
            +
                            stop_filewatcher
         
     | 
| 
       108 
158 
     | 
    
         
             
                          end
         
     | 
| 
       109 
     | 
    
         
            -
                        rescue
         
     | 
| 
       110 
     | 
    
         
            -
                          # no op in case of a binary file
         
     | 
| 
       111 
159 
     | 
    
         
             
                        end
         
     | 
| 
       112 
160 
     | 
    
         
             
                      end
         
     | 
| 
       113 
161 
     | 
    
         
             
                    end
         
     | 
| 
       114 
162 
     | 
    
         
             
                  end
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
       116 
164 
     | 
    
         
             
                  def stop_filewatcher
         
     | 
| 
       117 
165 
     | 
    
         
             
                    @filewatcher&.stop
         
     | 
| 
       118 
166 
     | 
    
         
             
                  end
         
     | 
| 
       119 
167 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
                  def format_dirty_content_for_writing!
         
     | 
| 
       121 
     | 
    
         
            -
                    new_dirty_content = "#{dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"      
         
     | 
| 
       122 
     | 
    
         
            -
                    self.dirty_content = new_dirty_content if new_dirty_content != self.dirty_content
         
     | 
| 
       123 
     | 
    
         
            -
                  end
         
     | 
| 
       124 
     | 
    
         
            -
              
         
     | 
| 
       125 
168 
     | 
    
         
             
                  def write_dirty_content
         
     | 
| 
       126 
     | 
    
         
            -
                     
     | 
| 
      
 169 
     | 
    
         
            +
                    # TODO write partial dirty content by line(s) for enhanced performance
         
     | 
| 
      
 170 
     | 
    
         
            +
                    return if scratchpad? || !::File.exist?(path) || !::File.exists?(path) || read_dirty_content == dirty_content
         
     | 
| 
       127 
171 
     | 
    
         
             
                    format_dirty_content_for_writing!
         
     | 
| 
       128 
     | 
    
         
            -
                    ::File.write(path, dirty_content) 
     | 
| 
       129 
     | 
    
         
            -
                  rescue => e
         
     | 
| 
      
 172 
     | 
    
         
            +
                    ::File.write(path, dirty_content)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  rescue StandardError, ArgumentError => e
         
     | 
| 
       130 
174 
     | 
    
         
             
                    puts "Error in writing dirty content for #{path}"
         
     | 
| 
       131 
175 
     | 
    
         
             
                    puts e.full_message
         
     | 
| 
       132 
176 
     | 
    
         
             
                  end
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  def format_dirty_content_for_writing!
         
     | 
| 
      
 179 
     | 
    
         
            +
                    new_dirty_content = dirty_content.split("\n").map {|line| line.strip.empty? ? line : line.rstrip }.join("\n")
         
     | 
| 
      
 180 
     | 
    
         
            +
                    new_dirty_content = "#{new_dirty_content.gsub("\r\n", "\n").gsub("\r", "\n").sub(/\n+\z/, '')}\n"
         
     | 
| 
      
 181 
     | 
    
         
            +
                    if new_dirty_content != self.dirty_content
         
     | 
| 
      
 182 
     | 
    
         
            +
                      @formatting_dirty_content_for_writing = true
         
     | 
| 
      
 183 
     | 
    
         
            +
                      self.dirty_content = new_dirty_content
         
     | 
| 
      
 184 
     | 
    
         
            +
                      @formatting_dirty_content_for_writing = false
         
     | 
| 
      
 185 
     | 
    
         
            +
                    end
         
     | 
| 
      
 186 
     | 
    
         
            +
                  end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
       134 
188 
     | 
    
         
             
                  def write_raw_dirty_content
         
     | 
| 
       135 
     | 
    
         
            -
                    return  
     | 
| 
      
 189 
     | 
    
         
            +
                    return if scratchpad? || !::File.exist?(path)
         
     | 
| 
       136 
190 
     | 
    
         
             
                    ::File.write(path, dirty_content) if ::File.exists?(path)
         
     | 
| 
       137 
191 
     | 
    
         
             
                  rescue => e
         
     | 
| 
       138 
192 
     | 
    
         
             
                    puts "Error in writing raw dirty content for #{path}"
         
     | 
| 
         @@ -143,19 +197,20 @@ module Glimmer 
     | 
|
| 
       143 
197 
     | 
    
         
             
                    current_line.to_s.match(/^(\s+)/).to_a[1].to_s
         
     | 
| 
       144 
198 
     | 
    
         
             
                  end
         
     | 
| 
       145 
199 
     | 
    
         | 
| 
       146 
     | 
    
         
            -
                  def current_line 
     | 
| 
      
 200 
     | 
    
         
            +
                  def current_line
         
     | 
| 
       147 
201 
     | 
    
         
             
                    lines[line_number - 1]
         
     | 
| 
       148 
202 
     | 
    
         
             
                  end
         
     | 
| 
       149 
203 
     | 
    
         | 
| 
       150 
204 
     | 
    
         
             
                  def delete!
         
     | 
| 
       151 
     | 
    
         
            -
                    FileUtils.rm(path) 
     | 
| 
      
 205 
     | 
    
         
            +
                    FileUtils.rm(path) unless scratchpad?
         
     | 
| 
       152 
206 
     | 
    
         
             
                  end
         
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
       154 
208 
     | 
    
         
             
                  def prefix_new_line!
         
     | 
| 
       155 
209 
     | 
    
         
             
                    the_lines = lines
         
     | 
| 
       156 
210 
     | 
    
         
             
                    the_lines[line_number-1...line_number-1] = [current_line_indentation]
         
     | 
| 
       157 
211 
     | 
    
         
             
                    self.dirty_content = the_lines.join("\n")
         
     | 
| 
       158 
212 
     | 
    
         
             
                    self.caret_position = caret_position_for_line_index(line_number-1) + current_line_indentation.size
         
     | 
| 
      
 213 
     | 
    
         
            +
                    self.selection_count = 0
         
     | 
| 
       159 
214 
     | 
    
         
             
                  end
         
     | 
| 
       160 
215 
     | 
    
         | 
| 
       161 
216 
     | 
    
         
             
                  def insert_new_line!
         
     | 
| 
         @@ -163,8 +218,9 @@ module Glimmer 
     | 
|
| 
       163 
218 
     | 
    
         
             
                    the_lines[line_number...line_number] = [current_line_indentation]
         
     | 
| 
       164 
219 
     | 
    
         
             
                    self.dirty_content = the_lines.join("\n")
         
     | 
| 
       165 
220 
     | 
    
         
             
                    self.caret_position = caret_position_for_line_index(line_number) + current_line_indentation.size
         
     | 
| 
      
 221 
     | 
    
         
            +
                    self.selection_count = 0
         
     | 
| 
       166 
222 
     | 
    
         
             
                  end
         
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
      
 223 
     | 
    
         
            +
                  
         
     | 
| 
       168 
224 
     | 
    
         
             
                  def comment_line!
         
     | 
| 
       169 
225 
     | 
    
         
             
                    old_lines = lines
         
     | 
| 
       170 
226 
     | 
    
         
             
                    return if old_lines.size < 1
         
     | 
| 
         @@ -190,7 +246,7 @@ module Glimmer 
     | 
|
| 
       190 
246 
     | 
    
         
             
                        delta += 2
         
     | 
| 
       191 
247 
     | 
    
         
             
                      end
         
     | 
| 
       192 
248 
     | 
    
         
             
                    end
         
     | 
| 
       193 
     | 
    
         
            -
                    self.dirty_content = new_lines.join("\n") 
     | 
| 
      
 249 
     | 
    
         
            +
                    self.dirty_content = new_lines.join("\n")
         
     | 
| 
       194 
250 
     | 
    
         
             
                    if old_selection_count.to_i > 0
         
     | 
| 
       195 
251 
     | 
    
         
             
                      self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
         
     | 
| 
       196 
252 
     | 
    
         
             
                      self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
         
     | 
| 
         @@ -198,9 +254,10 @@ module Glimmer 
     | 
|
| 
       198 
254 
     | 
    
         
             
                      new_caret_position = old_caret_position + delta
         
     | 
| 
       199 
255 
     | 
    
         
             
                      new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
         
     | 
| 
       200 
256 
     | 
    
         
             
                      self.caret_position = new_caret_position
         
     | 
| 
      
 257 
     | 
    
         
            +
                      self.selection_count = 0
         
     | 
| 
       201 
258 
     | 
    
         
             
                    end
         
     | 
| 
       202 
259 
     | 
    
         
             
                  end
         
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
       204 
261 
     | 
    
         
             
                  def indent!
         
     | 
| 
       205 
262 
     | 
    
         
             
                    new_lines = lines
         
     | 
| 
       206 
263 
     | 
    
         
             
                    old_lines = lines
         
     | 
| 
         @@ -216,16 +273,16 @@ module Glimmer 
     | 
|
| 
       216 
273 
     | 
    
         
             
                      new_lines[the_line_index] = "  #{the_line}"
         
     | 
| 
       217 
274 
     | 
    
         
             
                    end
         
     | 
| 
       218 
275 
     | 
    
         
             
                    old_caret_position = self.caret_position
         
     | 
| 
       219 
     | 
    
         
            -
                    self.dirty_content = new_lines.join("\n") 
     | 
| 
      
 276 
     | 
    
         
            +
                    self.dirty_content = new_lines.join("\n")
         
     | 
| 
       220 
277 
     | 
    
         
             
                    if old_selection_count.to_i > 0
         
     | 
| 
       221 
     | 
    
         
            -
                       
     | 
| 
       222 
     | 
    
         
            -
                       
     | 
| 
       223 
     | 
    
         
            -
                      self.selection = Point.new(caret_position_value, caret_position_value + selection_count_value)
         
     | 
| 
      
 278 
     | 
    
         
            +
                      self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
         
     | 
| 
      
 279 
     | 
    
         
            +
                      self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
         
     | 
| 
       224 
280 
     | 
    
         
             
                    else
         
     | 
| 
       225 
281 
     | 
    
         
             
                      self.caret_position = old_caret_position + delta
         
     | 
| 
      
 282 
     | 
    
         
            +
                      self.selection_count = 0
         
     | 
| 
       226 
283 
     | 
    
         
             
                    end
         
     | 
| 
       227 
284 
     | 
    
         
             
                  end
         
     | 
| 
       228 
     | 
    
         
            -
             
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
       229 
286 
     | 
    
         
             
                  def outdent!
         
     | 
| 
       230 
287 
     | 
    
         
             
                    new_lines = lines
         
     | 
| 
       231 
288 
     | 
    
         
             
                    old_lines = lines
         
     | 
| 
         @@ -246,18 +303,18 @@ module Glimmer 
     | 
|
| 
       246 
303 
     | 
    
         
             
                        delta = -1
         
     | 
| 
       247 
304 
     | 
    
         
             
                      end
         
     | 
| 
       248 
305 
     | 
    
         
             
                    end
         
     | 
| 
       249 
     | 
    
         
            -
                    self.dirty_content = new_lines.join("\n") 
     | 
| 
      
 306 
     | 
    
         
            +
                    self.dirty_content = new_lines.join("\n")
         
     | 
| 
       250 
307 
     | 
    
         
             
                    if old_selection_count.to_i > 0
         
     | 
| 
       251 
     | 
    
         
            -
                       
     | 
| 
       252 
     | 
    
         
            -
                       
     | 
| 
       253 
     | 
    
         
            -
                      self.selection = Point.new(caret_position_value, caret_position_value + selection_count_value)
         
     | 
| 
      
 308 
     | 
    
         
            +
                      self.caret_position = caret_position_for_line_index(old_caret_position_line_index)
         
     | 
| 
      
 309 
     | 
    
         
            +
                      self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
         
     | 
| 
       254 
310 
     | 
    
         
             
                    else
         
     | 
| 
       255 
311 
     | 
    
         
             
                      new_caret_position = old_caret_position + delta
         
     | 
| 
       256 
312 
     | 
    
         
             
                      new_caret_position = [new_caret_position, old_caret_position_line_caret_position].max
         
     | 
| 
       257 
313 
     | 
    
         
             
                      self.caret_position = new_caret_position
         
     | 
| 
      
 314 
     | 
    
         
            +
                      self.selection_count = 0
         
     | 
| 
       258 
315 
     | 
    
         
             
                    end
         
     | 
| 
       259 
316 
     | 
    
         
             
                  end
         
     | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
       261 
318 
     | 
    
         
             
                  def kill_line!
         
     | 
| 
       262 
319 
     | 
    
         
             
                    new_lines = lines
         
     | 
| 
       263 
320 
     | 
    
         
             
                    return if new_lines.size < 1
         
     | 
| 
         @@ -270,7 +327,7 @@ module Glimmer 
     | 
|
| 
       270 
327 
     | 
    
         
             
                    self.caret_position = caret_position_for_line_index(old_line_index) + [line_position, lines[old_line_index].to_s.size].min
         
     | 
| 
       271 
328 
     | 
    
         
             
                    self.selection_count = 0
         
     | 
| 
       272 
329 
     | 
    
         
             
                  end
         
     | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
       274 
331 
     | 
    
         
             
                  def duplicate_line!
         
     | 
| 
       275 
332 
     | 
    
         
             
                    new_lines = lines
         
     | 
| 
       276 
333 
     | 
    
         
             
                    old_lines = lines
         
     | 
| 
         @@ -292,11 +349,12 @@ module Glimmer 
     | 
|
| 
       292 
349 
     | 
    
         
             
                      self.selection_count = (caret_position_for_line_index(old_end_caret_line_index + 1) - self.caret_position)
         
     | 
| 
       293 
350 
     | 
    
         
             
                    else
         
     | 
| 
       294 
351 
     | 
    
         
             
                      self.caret_position = old_caret_position + delta
         
     | 
| 
      
 352 
     | 
    
         
            +
                      self.selection_count = 0
         
     | 
| 
       295 
353 
     | 
    
         
             
                    end
         
     | 
| 
       296 
354 
     | 
    
         
             
                  end
         
     | 
| 
       297 
     | 
    
         
            -
             
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
       298 
356 
     | 
    
         
             
                  def find_next
         
     | 
| 
       299 
     | 
    
         
            -
                    return if find_text.to_s.empty? 
     | 
| 
      
 357 
     | 
    
         
            +
                    return if find_text.to_s.empty?
         
     | 
| 
       300 
358 
     | 
    
         
             
                    all_lines = lines
         
     | 
| 
       301 
359 
     | 
    
         
             
                    the_line_index = line_index_for_caret_position(caret_position)
         
     | 
| 
       302 
360 
     | 
    
         
             
                    line_position = line_position_for_caret_position(caret_position)
         
     | 
| 
         @@ -312,13 +370,12 @@ module Glimmer 
     | 
|
| 
       312 
370 
     | 
    
         
             
                        if occurrence_index
         
     | 
| 
       313 
371 
     | 
    
         
             
                          self.caret_position = caret_position_for_line_index(the_index) + start_position + occurrence_index
         
     | 
| 
       314 
372 
     | 
    
         
             
                          self.selection_count = find_text.to_s.size
         
     | 
| 
       315 
     | 
    
         
            -
                          self.selection = Point.new(self.caret_position, self.caret_position + self.selection_count)
         
     | 
| 
       316 
373 
     | 
    
         
             
                          return
         
     | 
| 
       317 
374 
     | 
    
         
             
                        end
         
     | 
| 
       318 
375 
     | 
    
         
             
                      end
         
     | 
| 
       319 
376 
     | 
    
         
             
                    end
         
     | 
| 
       320 
377 
     | 
    
         
             
                  end
         
     | 
| 
       321 
     | 
    
         
            -
             
     | 
| 
      
 378 
     | 
    
         
            +
             
     | 
| 
       322 
379 
     | 
    
         
             
                  def find_previous
         
     | 
| 
       323 
380 
     | 
    
         
             
                    return if find_text.to_s.empty?
         
     | 
| 
       324 
381 
     | 
    
         
             
                    all_lines = lines
         
     | 
| 
         @@ -343,7 +400,7 @@ module Glimmer 
     | 
|
| 
       343 
400 
     | 
    
         
             
                      end
         
     | 
| 
       344 
401 
     | 
    
         
             
                    end
         
     | 
| 
       345 
402 
     | 
    
         
             
                  end
         
     | 
| 
       346 
     | 
    
         
            -
             
     | 
| 
      
 403 
     | 
    
         
            +
             
     | 
| 
       347 
404 
     | 
    
         
             
                  def ensure_find_next
         
     | 
| 
       348 
405 
     | 
    
         
             
                    return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
         
     | 
| 
       349 
406 
     | 
    
         
             
                    find_next unless found_text?(self.caret_position)
         
     | 
| 
         @@ -352,37 +409,45 @@ module Glimmer 
     | 
|
| 
       352 
409 
     | 
    
         
             
                  def found_text?(caret_position)
         
     | 
| 
       353 
410 
     | 
    
         
             
                    dirty_content[caret_position.to_i, find_text.to_s.size].to_s.downcase == find_text.to_s.downcase
         
     | 
| 
       354 
411 
     | 
    
         
             
                  end
         
     | 
| 
       355 
     | 
    
         
            -
             
     | 
| 
      
 412 
     | 
    
         
            +
             
     | 
| 
       356 
413 
     | 
    
         
             
                  def replace_next!
         
     | 
| 
       357 
414 
     | 
    
         
             
                    return if find_text.to_s.empty? || dirty_content.to_s.strip.size < 1
         
     | 
| 
       358 
415 
     | 
    
         
             
                    ensure_find_next
         
     | 
| 
       359 
416 
     | 
    
         
             
                    new_dirty_content = dirty_content
         
     | 
| 
       360 
417 
     | 
    
         
             
                    new_dirty_content[caret_position, find_text.size] = replace_text.to_s
         
     | 
| 
       361 
418 
     | 
    
         
             
                    self.dirty_content = new_dirty_content
         
     | 
| 
       362 
     | 
    
         
            -
                    find_next 
     | 
| 
      
 419 
     | 
    
         
            +
                    find_next
         
     | 
| 
       363 
420 
     | 
    
         
             
                    find_next if replace_text.to_s.include?(find_text) && !replace_text.to_s.start_with?(find_text)
         
     | 
| 
       364 
421 
     | 
    
         
             
                  end
         
     | 
| 
       365 
     | 
    
         
            -
             
     | 
| 
      
 422 
     | 
    
         
            +
                  
         
     | 
| 
       366 
423 
     | 
    
         
             
                  def page_up
         
     | 
| 
       367 
424 
     | 
    
         
             
                    self.selection_count = 0
         
     | 
| 
       368 
425 
     | 
    
         
             
                    self.line_number = [(self.line_number - 15), 1].max
         
     | 
| 
       369 
426 
     | 
    
         
             
                  end
         
     | 
| 
       370 
     | 
    
         
            -
             
     | 
| 
      
 427 
     | 
    
         
            +
             
     | 
| 
       371 
428 
     | 
    
         
             
                  def page_down
         
     | 
| 
       372 
429 
     | 
    
         
             
                    self.selection_count = 0
         
     | 
| 
       373 
430 
     | 
    
         
             
                    self.line_number = [(self.line_number + 15), lines.size].min
         
     | 
| 
       374 
431 
     | 
    
         
             
                  end
         
     | 
| 
       375 
     | 
    
         
            -
             
     | 
| 
      
 432 
     | 
    
         
            +
             
     | 
| 
       376 
433 
     | 
    
         
             
                  def home
         
     | 
| 
       377 
434 
     | 
    
         
             
                    self.selection_count = 0
         
     | 
| 
       378 
435 
     | 
    
         
             
                    self.line_number = 1
         
     | 
| 
       379 
436 
     | 
    
         
             
                  end
         
     | 
| 
       380 
     | 
    
         
            -
             
     | 
| 
      
 437 
     | 
    
         
            +
             
     | 
| 
       381 
438 
     | 
    
         
             
                  def end
         
     | 
| 
       382 
439 
     | 
    
         
             
                    self.selection_count = 0
         
     | 
| 
       383 
440 
     | 
    
         
             
                    self.line_number = lines.size
         
     | 
| 
       384 
441 
     | 
    
         
             
                  end
         
     | 
| 
       385 
     | 
    
         
            -
             
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
                  def start_of_line
         
     | 
| 
      
 444 
     | 
    
         
            +
                    self.caret_position = caret_position_for_line_index(self.line_number - 1)
         
     | 
| 
      
 445 
     | 
    
         
            +
                  end
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
                  def end_of_line
         
     | 
| 
      
 448 
     | 
    
         
            +
                    self.caret_position = caret_position_for_line_index(self.line_number) - 1
         
     | 
| 
      
 449 
     | 
    
         
            +
                  end
         
     | 
| 
      
 450 
     | 
    
         
            +
             
     | 
| 
       386 
451 
     | 
    
         
             
                  def move_up!
         
     | 
| 
       387 
452 
     | 
    
         
             
                    old_lines = lines
         
     | 
| 
       388 
453 
     | 
    
         
             
                    return if old_lines.size < 2
         
     | 
| 
         @@ -401,7 +466,7 @@ module Glimmer 
     | 
|
| 
       401 
466 
     | 
    
         
             
                    self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
         
     | 
| 
       402 
467 
     | 
    
         
             
                    self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
         
     | 
| 
       403 
468 
     | 
    
         
             
                  end
         
     | 
| 
       404 
     | 
    
         
            -
             
     | 
| 
      
 469 
     | 
    
         
            +
             
     | 
| 
       405 
470 
     | 
    
         
             
                  def move_down!
         
     | 
| 
       406 
471 
     | 
    
         
             
                    old_lines = lines
         
     | 
| 
       407 
472 
     | 
    
         
             
                    return if old_lines.size < 2
         
     | 
| 
         @@ -420,25 +485,38 @@ module Glimmer 
     | 
|
| 
       420 
485 
     | 
    
         
             
                    self.caret_position = caret_position_for_line_index(new_line_index) + [old_caret_position_line_position, new_lines[new_line_index].size].min
         
     | 
| 
       421 
486 
     | 
    
         
             
                    self.selection_count = old_selection_count.to_i if old_selection_count.to_i > 0
         
     | 
| 
       422 
487 
     | 
    
         
             
                  end
         
     | 
| 
       423 
     | 
    
         
            -
             
     | 
| 
      
 488 
     | 
    
         
            +
                  
         
     | 
| 
      
 489 
     | 
    
         
            +
                  def run
         
     | 
| 
      
 490 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 491 
     | 
    
         
            +
                      if scratchpad?
         
     | 
| 
      
 492 
     | 
    
         
            +
                        eval content
         
     | 
| 
      
 493 
     | 
    
         
            +
                      else
         
     | 
| 
      
 494 
     | 
    
         
            +
                        write_dirty_content
         
     | 
| 
      
 495 
     | 
    
         
            +
                        load path
         
     | 
| 
      
 496 
     | 
    
         
            +
                      end
         
     | 
| 
      
 497 
     | 
    
         
            +
                    rescue SyntaxError, StandardError => e
         
     | 
| 
      
 498 
     | 
    
         
            +
                      puts e.full_message
         
     | 
| 
      
 499 
     | 
    
         
            +
                    end
         
     | 
| 
      
 500 
     | 
    
         
            +
                  end
         
     | 
| 
      
 501 
     | 
    
         
            +
             
     | 
| 
       424 
502 
     | 
    
         
             
                  def lines
         
     | 
| 
       425 
503 
     | 
    
         
             
                    dirty_content.split("\n")
         
     | 
| 
       426 
504 
     | 
    
         
             
                  end
         
     | 
| 
       427 
     | 
    
         
            -
             
     | 
| 
      
 505 
     | 
    
         
            +
             
     | 
| 
       428 
506 
     | 
    
         
             
                  def line_for_caret_position(caret_position)
         
     | 
| 
       429 
507 
     | 
    
         
             
                    lines[line_index_for_caret_position(caret_position.to_i)]
         
     | 
| 
       430 
508 
     | 
    
         
             
                  end
         
     | 
| 
       431 
     | 
    
         
            -
             
     | 
| 
      
 509 
     | 
    
         
            +
             
     | 
| 
       432 
510 
     | 
    
         
             
                  def line_index_for_caret_position(caret_position)
         
     | 
| 
       433 
511 
     | 
    
         
             
                    dirty_content[0...caret_position.to_i].count("\n")
         
     | 
| 
       434 
512 
     | 
    
         
             
                  end
         
     | 
| 
       435 
     | 
    
         
            -
             
     | 
| 
      
 513 
     | 
    
         
            +
             
     | 
| 
       436 
514 
     | 
    
         
             
                  def caret_position_for_line_index(line_index)
         
     | 
| 
       437 
515 
     | 
    
         
             
                    cp = lines[0...line_index].join("\n").size
         
     | 
| 
       438 
516 
     | 
    
         
             
                    cp += 1 if line_index > 0
         
     | 
| 
       439 
517 
     | 
    
         
             
                    cp
         
     | 
| 
       440 
518 
     | 
    
         
             
                  end
         
     | 
| 
       441 
     | 
    
         
            -
             
     | 
| 
      
 519 
     | 
    
         
            +
             
     | 
| 
       442 
520 
     | 
    
         
             
                  def caret_position_for_caret_position_start_of_line(caret_position)
         
     | 
| 
       443 
521 
     | 
    
         
             
                    caret_position_for_line_index(line_index_for_caret_position(caret_position))
         
     | 
| 
       444 
522 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -449,23 +527,23 @@ module Glimmer 
     | 
|
| 
       449 
527 
     | 
    
         
             
                    caret_position = caret_position.to_i
         
     | 
| 
       450 
528 
     | 
    
         
             
                    caret_position - caret_position_for_caret_position_start_of_line(caret_position)
         
     | 
| 
       451 
529 
     | 
    
         
             
                  end
         
     | 
| 
       452 
     | 
    
         
            -
             
     | 
| 
      
 530 
     | 
    
         
            +
             
     | 
| 
       453 
531 
     | 
    
         
             
                  def line_caret_positions_for_selection(caret_position, selection_count)
         
     | 
| 
       454 
532 
     | 
    
         
             
                    line_indices = line_indices_for_selection(caret_position, selection_count)
         
     | 
| 
       455 
533 
     | 
    
         
             
                    line_caret_positions = line_indices.map { |line_index| caret_position_for_line_index(line_index) }.to_a
         
     | 
| 
       456 
534 
     | 
    
         
             
                  end
         
     | 
| 
       457 
     | 
    
         
            -
             
     | 
| 
      
 535 
     | 
    
         
            +
             
     | 
| 
       458 
536 
     | 
    
         
             
                  def end_caret_position_line_index(caret_position, selection_count)
         
     | 
| 
       459 
537 
     | 
    
         
             
                    end_caret_position = caret_position + selection_count.to_i
         
     | 
| 
       460 
538 
     | 
    
         
             
                    end_caret_position -= 1 if dirty_content[end_caret_position - 1] == "\n"
         
     | 
| 
       461 
539 
     | 
    
         
             
                    end_line_index = line_index_for_caret_position(end_caret_position)
         
     | 
| 
       462 
540 
     | 
    
         
             
                  end
         
     | 
| 
       463 
     | 
    
         
            -
             
     | 
| 
      
 541 
     | 
    
         
            +
             
     | 
| 
       464 
542 
     | 
    
         
             
                  def lines_for_selection(caret_position, selection_count)
         
     | 
| 
       465 
543 
     | 
    
         
             
                    line_indices = line_indices_for_selection(caret_position, selection_count)
         
     | 
| 
       466 
544 
     | 
    
         
             
                    lines[line_indices.first..line_indices.last]
         
     | 
| 
       467 
545 
     | 
    
         
             
                  end
         
     | 
| 
       468 
     | 
    
         
            -
             
     | 
| 
      
 546 
     | 
    
         
            +
             
     | 
| 
       469 
547 
     | 
    
         
             
                  def line_indices_for_selection(caret_position, selection_count)
         
     | 
| 
       470 
548 
     | 
    
         
             
                    start_line_index = line_index_for_caret_position(caret_position)
         
     | 
| 
       471 
549 
     | 
    
         
             
                    if selection_count.to_i > 0
         
     | 
| 
         @@ -475,22 +553,22 @@ module Glimmer 
     | 
|
| 
       475 
553 
     | 
    
         
             
                    end
         
     | 
| 
       476 
554 
     | 
    
         
             
                    (start_line_index..end_line_index).to_a
         
     | 
| 
       477 
555 
     | 
    
         
             
                  end
         
     | 
| 
       478 
     | 
    
         
            -
             
     | 
| 
      
 556 
     | 
    
         
            +
             
     | 
| 
       479 
557 
     | 
    
         
             
                  def children
         
     | 
| 
       480 
558 
     | 
    
         
             
                    []
         
     | 
| 
       481 
559 
     | 
    
         
             
                  end
         
     | 
| 
       482 
     | 
    
         
            -
             
     | 
| 
      
 560 
     | 
    
         
            +
             
     | 
| 
       483 
561 
     | 
    
         
             
                  def to_s
         
     | 
| 
       484 
562 
     | 
    
         
             
                    path
         
     | 
| 
       485 
563 
     | 
    
         
             
                  end
         
     | 
| 
       486 
     | 
    
         
            -
             
     | 
| 
      
 564 
     | 
    
         
            +
             
     | 
| 
       487 
565 
     | 
    
         
             
                  def eql?(other)
         
     | 
| 
       488 
566 
     | 
    
         
             
                    self.path.eql?(other&.path)
         
     | 
| 
       489 
567 
     | 
    
         
             
                  end
         
     | 
| 
       490 
     | 
    
         
            -
             
     | 
| 
      
 568 
     | 
    
         
            +
             
     | 
| 
       491 
569 
     | 
    
         
             
                  def hash
         
     | 
| 
       492 
570 
     | 
    
         
             
                    self.path.hash
         
     | 
| 
       493 
571 
     | 
    
         
             
                  end
         
     | 
| 
       494 
     | 
    
         
            -
                end 
     | 
| 
      
 572 
     | 
    
         
            +
                end
         
     | 
| 
       495 
573 
     | 
    
         
             
              end
         
     | 
| 
       496 
574 
     | 
    
         
             
            end
         
     |