diakonos 0.8.11 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +433 -0
  3. data/LICENCE.md +675 -0
  4. data/bin/diakonos +6 -0
  5. data/diakonos-256-colour.conf +220 -0
  6. data/diakonos.conf +1802 -0
  7. data/help/about-help.dhf +31 -0
  8. data/help/clipboard.dhf +45 -0
  9. data/help/close-file.dhf +6 -0
  10. data/help/code-block-navigation.dhf +16 -0
  11. data/help/column-markers.dhf +15 -0
  12. data/help/config.dhf +69 -0
  13. data/help/cursor-stack.dhf +19 -0
  14. data/help/delete.dhf +41 -0
  15. data/help/extensions.dhf +125 -0
  16. data/help/file-type.dhf +24 -0
  17. data/help/key-mapping.dhf +127 -0
  18. data/help/line-numbers.dhf +22 -0
  19. data/help/macros.dhf +27 -0
  20. data/help/new-file.dhf +6 -0
  21. data/help/open-file.dhf +21 -0
  22. data/help/quit.dhf +7 -0
  23. data/help/resizing.dhf +19 -0
  24. data/help/ruby.dhf +17 -0
  25. data/help/save-file.dhf +10 -0
  26. data/help/scripting.dhf +92 -0
  27. data/help/search.dhf +103 -0
  28. data/help/shell.dhf +60 -0
  29. data/help/speed.dhf +23 -0
  30. data/help/support.dhf +15 -0
  31. data/help/switch-buffers.dhf +15 -0
  32. data/help/tabs.dhf +36 -0
  33. data/help/undo.dhf +9 -0
  34. data/help/uninstall.dhf +18 -0
  35. data/help/welcome.dhf +32 -0
  36. data/help/word-wrap.dhf +17 -0
  37. data/lib/diakonos/about.rb +69 -0
  38. data/lib/diakonos/bookmark.rb +46 -0
  39. data/lib/diakonos/buffer/bookmarking.rb +47 -0
  40. data/lib/diakonos/buffer/cursor.rb +335 -0
  41. data/lib/diakonos/buffer/delete.rb +170 -0
  42. data/lib/diakonos/buffer/display.rb +356 -0
  43. data/lib/diakonos/buffer/file.rb +157 -0
  44. data/lib/diakonos/buffer/indentation.rb +175 -0
  45. data/lib/diakonos/buffer/searching.rb +552 -0
  46. data/lib/diakonos/buffer/selection.rb +360 -0
  47. data/lib/diakonos/buffer/undo.rb +73 -0
  48. data/lib/diakonos/buffer-hash.rb +60 -0
  49. data/lib/diakonos/buffer-management.rb +59 -0
  50. data/lib/diakonos/buffer.rb +698 -0
  51. data/lib/diakonos/clipboard-klipper-dbus.rb +62 -0
  52. data/lib/diakonos/clipboard-klipper.rb +62 -0
  53. data/lib/diakonos/clipboard-osx.rb +59 -0
  54. data/lib/diakonos/clipboard-xclip.rb +60 -0
  55. data/lib/diakonos/clipboard.rb +47 -0
  56. data/lib/diakonos/config-file.rb +67 -0
  57. data/lib/diakonos/config.rb +381 -0
  58. data/lib/diakonos/core-ext/enumerable.rb +15 -0
  59. data/lib/diakonos/core-ext/hash.rb +60 -0
  60. data/lib/diakonos/core-ext/object.rb +6 -0
  61. data/lib/diakonos/core-ext/regexp.rb +6 -0
  62. data/lib/diakonos/core-ext/string.rb +122 -0
  63. data/lib/diakonos/ctag.rb +28 -0
  64. data/lib/diakonos/cursor.rb +27 -0
  65. data/lib/diakonos/display/format.rb +75 -0
  66. data/lib/diakonos/display.rb +336 -0
  67. data/lib/diakonos/extension-set.rb +49 -0
  68. data/lib/diakonos/extension.rb +34 -0
  69. data/lib/diakonos/finding.rb +40 -0
  70. data/lib/diakonos/functions/basics.rb +34 -0
  71. data/lib/diakonos/functions/bookmarking.rb +61 -0
  72. data/lib/diakonos/functions/buffers.rb +489 -0
  73. data/lib/diakonos/functions/clipboard.rb +70 -0
  74. data/lib/diakonos/functions/cursor.rb +264 -0
  75. data/lib/diakonos/functions/grepping.rb +83 -0
  76. data/lib/diakonos/functions/indentation.rb +71 -0
  77. data/lib/diakonos/functions/readline.rb +93 -0
  78. data/lib/diakonos/functions/search.rb +179 -0
  79. data/lib/diakonos/functions/selection.rb +98 -0
  80. data/lib/diakonos/functions/sessions.rb +78 -0
  81. data/lib/diakonos/functions/shell.rb +250 -0
  82. data/lib/diakonos/functions/tags.rb +65 -0
  83. data/lib/diakonos/functions/text-manipulation.rb +196 -0
  84. data/lib/diakonos/functions-deprecated.rb +77 -0
  85. data/lib/diakonos/functions.rb +292 -0
  86. data/lib/diakonos/grep.rb +98 -0
  87. data/lib/diakonos/help.rb +47 -0
  88. data/lib/diakonos/hooks.rb +13 -0
  89. data/lib/diakonos/installation.rb +19 -0
  90. data/lib/diakonos/interaction-handler.rb +216 -0
  91. data/lib/diakonos/interaction.rb +52 -0
  92. data/lib/diakonos/key-map.rb +62 -0
  93. data/lib/diakonos/keying.rb +442 -0
  94. data/lib/diakonos/line-mover.rb +42 -0
  95. data/lib/diakonos/list.rb +59 -0
  96. data/lib/diakonos/logging.rb +27 -0
  97. data/lib/diakonos/mode.rb +17 -0
  98. data/lib/diakonos/mouse.rb +18 -0
  99. data/lib/diakonos/number-fitter.rb +11 -0
  100. data/lib/diakonos/range.rb +31 -0
  101. data/lib/diakonos/readline/functions.rb +82 -0
  102. data/lib/diakonos/readline.rb +222 -0
  103. data/lib/diakonos/search.rb +58 -0
  104. data/lib/diakonos/sessions.rb +257 -0
  105. data/lib/diakonos/sized-array.rb +48 -0
  106. data/lib/diakonos/text-mark.rb +19 -0
  107. data/lib/diakonos/vendor/fuzzy_file_finder.rb +365 -0
  108. data/lib/diakonos/version.rb +25 -0
  109. data/lib/diakonos/window.rb +43 -0
  110. data/lib/diakonos.rb +592 -0
  111. metadata +160 -68
@@ -0,0 +1,82 @@
1
+ module Diakonos
2
+
3
+ class Readline
4
+
5
+ def abort
6
+ @input = nil
7
+ @done = true
8
+ end
9
+
10
+ def accept( item )
11
+ if item && @on_dirs == :go_into_dirs && File.directory?( item )
12
+ complete_input
13
+ else
14
+ @done = true
15
+ end
16
+ end
17
+
18
+ def backspace
19
+ if cursor_left
20
+ delete
21
+ end
22
+ end
23
+
24
+ def cursor_bol
25
+ @input_cursor = 0
26
+ sync
27
+ end
28
+
29
+ def cursor_eol
30
+ @input_cursor = @input.length
31
+ sync
32
+ end
33
+
34
+ def cursor_left
35
+ return false if @input_cursor < 1
36
+ @input_cursor -= 1
37
+ sync
38
+ true
39
+ end
40
+
41
+ def cursor_right
42
+ return if @input_cursor >= @input.length
43
+ @input_cursor += 1
44
+ sync
45
+ end
46
+
47
+ def delete
48
+ return if @input_cursor >= @input.length
49
+ @input = @input[ 0...@input_cursor ] + @input[ (@input_cursor + 1)..-1 ]
50
+ sync
51
+ end
52
+
53
+ def delete_line
54
+ @input = ""
55
+ sync
56
+ end
57
+
58
+ def delete_word
59
+ head = @input[ 0...@input_cursor ]
60
+ chopped = head.sub( /\w+\W*$/, '' )
61
+ @input = chopped + @input[ @input_cursor..-1 ]
62
+ @input_cursor -= head.length - chopped.length
63
+ sync
64
+ end
65
+
66
+ def history_up
67
+ return if @history_index < 1
68
+ @history[ @history_index ] = @input
69
+ @history_index -= 1
70
+ @input = @history[ @history_index ]
71
+ end
72
+
73
+ def history_down
74
+ return if @history_index > @history.length - 2
75
+ @history[ @history_index ] = @input
76
+ @history_index += 1
77
+ @input = @history[ @history_index ]
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,222 @@
1
+ module Diakonos
2
+
3
+ class Readline
4
+
5
+ attr_reader :input
6
+
7
+ # completion_array is the array of strings that tab completion can use
8
+ # The block returns true if a refresh is needed?
9
+ # @param options :initial_text, :completion_array, :history, :do_complete, :on_dirs
10
+ def initialize(
11
+ list_manager:,
12
+ keystroke_processor:,
13
+ testing: false,
14
+ window:,
15
+ start_pos:,
16
+ options: {},
17
+ &block
18
+ )
19
+ @list_manager = list_manager
20
+ @keystroke_processor = keystroke_processor
21
+ @testing = testing
22
+ @window = window
23
+ @start_pos = start_pos
24
+ @window.setpos( 0, start_pos )
25
+ @initial_text = options[ :initial_text ] || ''
26
+ @completion_array = options[ :completion_array ]
27
+ @list_filename = @list_manager.list_filename
28
+
29
+ @history = options[ :history ] || []
30
+ @history << @initial_text
31
+ @history_index = [ @history.length - 1, 0 ].max
32
+
33
+ @do_complete = options[ :do_complete ] || ::Diakonos::DONT_COMPLETE
34
+ @on_dirs = options[ :on_dirs ] || :go_into_dirs
35
+ @numbered_list = options[ :numbered_list ]
36
+
37
+ @block = block
38
+
39
+ # ---
40
+
41
+ @input = @initial_text.dup
42
+ if ! @input.empty?
43
+ call_block
44
+ end
45
+
46
+ @icurx = @window.curx
47
+ @icury = @window.cury
48
+ @view_y = 0
49
+ if ! @testing
50
+ @window.addstr @initial_text
51
+ end
52
+ @input_cursor = @initial_text.length
53
+ @opened_list_file = false
54
+
55
+ if @do_complete
56
+ complete_input
57
+ end
58
+ end
59
+
60
+ def get_input
61
+ while ! done?
62
+ @keystroke_processor.process_keystroke(Array.new, 'input')
63
+ end
64
+ input
65
+ end
66
+
67
+ def call_block
68
+ if @block
69
+ @block.call( @input )
70
+ @window.refresh
71
+ end
72
+ end
73
+
74
+ def set_input( input = '' )
75
+ if numbered_list? && input =~ /^\w /
76
+ input = input[ 3..-1 ]
77
+ end
78
+ @input = input
79
+ end
80
+
81
+ def done?
82
+ @done
83
+ end
84
+
85
+ def finish
86
+ @done = true
87
+ end
88
+
89
+ def list_sync( line )
90
+ return if line.nil?
91
+ set_input line
92
+ cursor_write_input
93
+ end
94
+
95
+ def numbered_list?
96
+ @numbered_list
97
+ end
98
+
99
+ def sync
100
+ if @input_cursor > @input.length
101
+ @input_cursor = @input.length
102
+ elsif @input_cursor < @view_y
103
+ @view_y = @input_cursor
104
+ end
105
+
106
+ diff = ( @input_cursor - @view_y ) + 1 - ( Curses::cols - @start_pos )
107
+ if diff > 0
108
+ @view_y += diff
109
+ end
110
+
111
+ @window.setpos( @window.cury, @start_pos + @input_cursor - @view_y )
112
+ redraw_input
113
+ call_block
114
+ end
115
+
116
+ def paste( s )
117
+ @input = @input[ 0...@input_cursor ] + s + @input[ @input_cursor..-1 ]
118
+ @input_cursor += s.length
119
+ sync
120
+ end
121
+
122
+ def redraw_input
123
+ input = @input[ @view_y...(@view_y + Curses::cols) ]
124
+
125
+ curx = @window.curx
126
+ cury = @window.cury
127
+ @window.setpos( @icury, @icurx )
128
+ @window.addstr "%-#{ Curses::cols - curx }s%s" % [
129
+ input,
130
+ " " * [ ( Curses::cols - input.length ), 0 ].max
131
+ ]
132
+ @window.setpos( cury, curx )
133
+ @window.refresh
134
+ end
135
+
136
+ # Redisplays the input text starting at the start of the user input area,
137
+ # positioning the cursor at the end of the text.
138
+ def cursor_write_input
139
+ if @input
140
+ @input_cursor = @input.length
141
+ @window.setpos( @window.cury, @icurx + @input.length )
142
+ redraw_input
143
+ end
144
+ end
145
+
146
+ def complete_input
147
+ if @completion_array && @input.length > 0
148
+ len = @input.length
149
+ matches = @completion_array.find_all { |el| el[ 0...len ] == @input && len <= el.length }
150
+ else
151
+ path = File.expand_path( @input || '.' )
152
+ if FileTest.directory? path
153
+ path << '/'
154
+ end
155
+ matches = Dir.glob( ( path + "*" ).gsub( /\*\*/, "*" ) )
156
+ if @on_dirs == :accept_dirs
157
+ matches = matches.select { |m| File.directory? m }
158
+ end
159
+ end
160
+ matches.sort!
161
+
162
+ if matches.length == 1
163
+ @input = matches[ 0 ]
164
+ cursor_write_input
165
+ File.open( @list_filename, "w" ) do |f|
166
+ if @completion_array.nil?
167
+ f.puts "(unique)"
168
+ else
169
+ f.puts @input
170
+ end
171
+ end
172
+ if @completion_array.nil? && FileTest.directory?( @input )
173
+ @input << "/"
174
+ cursor_write_input
175
+ if @on_dirs != :accept_dirs
176
+ complete_input
177
+ end
178
+ end
179
+ elsif matches.length > 1
180
+ common = matches[ 0 ]
181
+ File.open( @list_filename, "w" ) do |f|
182
+ i = nil
183
+ matches.each do |match|
184
+ f.print match
185
+ if FileTest.directory?( match )
186
+ f.print '/'
187
+ end
188
+ f.puts
189
+
190
+ if match[ 0 ] != common[ 0 ]
191
+ common = nil
192
+ break
193
+ end
194
+
195
+ up_to = [ common.length - 1, match.length - 1 ].min
196
+ i = 1
197
+ while ( i <= up_to ) && ( match[ 0..i ] == common[ 0..i ] )
198
+ i += 1
199
+ end
200
+ common = common[ 0...i ]
201
+ end
202
+ end
203
+ if common.nil?
204
+ File.open( @list_filename, "w" ) do |f|
205
+ f.puts "(no matches)"
206
+ end
207
+ else
208
+ @input = common
209
+ cursor_write_input
210
+ end
211
+ else
212
+ File.open( @list_filename, "w" ) do |f|
213
+ f.puts "(no matches)"
214
+ end
215
+ end
216
+ @list_manager.open_list_buffer
217
+ @window.setpos( @window.cury, @window.curx )
218
+ end
219
+
220
+ end
221
+
222
+ end
@@ -0,0 +1,58 @@
1
+ module Diakonos
2
+ class Diakonos
3
+
4
+ # @return [Integer] the number of replacements made
5
+ def find_( options = {} )
6
+ regexp_source, replacement = options.values_at( :regexp_source, :replacement )
7
+ return if regexp_source.nil? || regexp_source.empty?
8
+
9
+ rs_array = regexp_source.newline_split
10
+ regexps = Array.new
11
+ exception_thrown = nil
12
+
13
+ rs_array.each do |source|
14
+ begin
15
+ warning_verbosity = $VERBOSE
16
+ $VERBOSE = nil
17
+ regexps << Regexp.new(
18
+ source,
19
+ options[:case_sensitive] ? nil : Regexp::IGNORECASE
20
+ )
21
+ $VERBOSE = warning_verbosity
22
+ rescue RegexpError => e
23
+ if ! exception_thrown
24
+ exception_thrown = e
25
+ source = Regexp.escape( source )
26
+ retry
27
+ else
28
+ raise e
29
+ end
30
+ end
31
+ end
32
+
33
+ if replacement == ASK_REPLACEMENT
34
+ replacement = get_user_input( "Replace with: ", history: @rlh_search )
35
+ end
36
+
37
+ if exception_thrown && ! options[:quiet]
38
+ set_iline "Searching literally; #{exception_thrown.message}"
39
+ end
40
+
41
+ # The execution order of the #find and the @last_search_regexps assignment is likely deliberate
42
+ num_replacements = buffer_current.find(
43
+ regexps,
44
+ :direction => options[:direction],
45
+ :replacement => replacement,
46
+ :starting_row => options[:starting_row],
47
+ :starting_col => options[:starting_col],
48
+ :quiet => options[:quiet],
49
+ :show_context_after => @settings[ 'find.show_context_after' ],
50
+ :starting => true
51
+ )
52
+ @last_search_regexps = regexps
53
+
54
+ num_replacements
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,257 @@
1
+ module Diakonos
2
+ class Session
3
+ attr_reader :filename, :settings, :name, :dir, :buffers, :readline_histories
4
+ attr_accessor :buffer_current
5
+
6
+ def initialize(filepath, data = nil)
7
+ if data.nil?
8
+ @filename = File.expand_path(filepath)
9
+ @settings = Hash.new
10
+
11
+ basename = File.basename(filepath)
12
+ if ! Session.pid_session?(filepath)
13
+ @name = basename
14
+ end
15
+
16
+ @buffers = []
17
+ @buffer_current = 1
18
+ self.dir = Dir.getwd
19
+ else
20
+ @filename = data['filename']
21
+ @settings = data['settings']
22
+ @name = data['name']
23
+ @buffers = data['buffers']
24
+ @buffer_current = data['buffer_current'] || 1
25
+ self.dir = data['dir']
26
+ end
27
+ end
28
+
29
+ def to_yaml
30
+ {
31
+ 'filename' => @filename,
32
+ 'settings' => @settings,
33
+ 'name' => @name,
34
+ 'buffer_current' => @buffer_current,
35
+ 'dir' => @dir,
36
+ 'buffers' => @buffers,
37
+ 'readline_histories' => @readline_histories
38
+ }.to_yaml
39
+ end
40
+
41
+ def set_buffers(buffers)
42
+ @buffers = buffers.reject { |buffer|
43
+ buffer.name.nil?
44
+ }.collect { |buffer|
45
+ {
46
+ 'filepath' => buffer.name,
47
+ 'read_only' => buffer.read_only,
48
+ 'cursor' => {
49
+ 'row' => buffer.last_row,
50
+ 'col' => buffer.last_col,
51
+ },
52
+ 'display' => {
53
+ 'top_line' => buffer.top_line,
54
+ 'left_column' => buffer.left_column
55
+ },
56
+ 'last_search_regexps' => buffer.last_search_regexps.map { |r| r.to_s },
57
+ }
58
+ }.compact
59
+ end
60
+
61
+ def set_readline_histories(rlh_general, rlh_files, rlh_search, rlh_shell, rlh_help, rlh_sessions)
62
+ @readline_histories = {
63
+ 'general' => rlh_general,
64
+ 'files' => rlh_files,
65
+ 'search' => rlh_search,
66
+ 'shell' => rlh_shell,
67
+ 'help' => rlh_help,
68
+ 'sessions' => rlh_sessions,
69
+ }
70
+ end
71
+
72
+ def dir=(new_dir)
73
+ @dir = new_dir
74
+ Dir.chdir new_dir
75
+ end
76
+
77
+ # @return [Session] The Session created from the YAML data in the specified file
78
+ # or nil on failure to load
79
+ def self.from_yaml_file(yaml_filename)
80
+ return nil if ! File.exist?(yaml_filename)
81
+ session = nil
82
+
83
+ File.open(yaml_filename) do |f|
84
+ loaded = YAML::load(f) or break
85
+
86
+ if(
87
+ loaded[ 'filename' ] &&
88
+ loaded[ 'settings' ] &&
89
+ loaded[ 'settings' ].respond_to?( :values ) &&
90
+ loaded.has_key?( 'name' ) &&
91
+ (
92
+ loaded[ 'files' ] &&
93
+ loaded[ 'files' ].respond_to?( :each ) ||
94
+ loaded[ 'buffers' ] &&
95
+ loaded[ 'buffers' ].respond_to?( :each )
96
+ )
97
+ )
98
+ # Convert old sessions
99
+ if loaded[ 'files' ]
100
+ loaded[ 'buffers' ] = loaded[ 'files' ].map { |f|
101
+ Session.file_hash_for f
102
+ }
103
+ loaded.delete 'files'
104
+ end
105
+
106
+ session = Session.new(loaded['filename'], loaded)
107
+ end
108
+ end
109
+
110
+ session
111
+ end
112
+
113
+ def self.pid_session?(path)
114
+ %r{/\d+$} === path
115
+ end
116
+
117
+ def self.file_hash_for(filepath)
118
+ filepath, line_number = ::Diakonos.parse_filename_and_line_number(filepath)
119
+ {
120
+ 'filepath' => filepath,
121
+ 'read_only' => false,
122
+ 'cursor' => {
123
+ 'row' => line_number || 0,
124
+ 'col' => 0,
125
+ },
126
+ 'display' => {
127
+ 'top_line' => 0,
128
+ 'left_column' => 0
129
+ },
130
+ }
131
+ end
132
+
133
+ end
134
+
135
+ class Diakonos
136
+ attr_reader :session
137
+
138
+ def initialize_session
139
+ @session_dir = "#{@diakonos_home}/sessions"
140
+ mkdir @session_dir
141
+ @session = Session.new("#{@session_dir}/#{Process.pid}")
142
+ end
143
+
144
+ def load_session( session_file )
145
+ cleanup_session
146
+ @session = Session.from_yaml_file(session_file)
147
+ if @session
148
+ @files.concat @session.buffers
149
+ rlh = @session.readline_histories
150
+ if rlh
151
+ @rlh_general = rlh['general'] || @rlh_general
152
+ @rlh_files = rlh['files'] || @rlh_files
153
+ @rlh_search = rlh['search'] || @rlh_search
154
+ @rlh_shell = rlh['shell'] || @rlh_shell
155
+ @rlh_help = rlh['help'] || @rlh_help
156
+ @rlh_sessions = rlh['sessions'] || @rlh_sessions
157
+ end
158
+ merge_session_settings
159
+ end
160
+ end
161
+
162
+ def save_session( session_file = @session.filename )
163
+ return if session_file.nil?
164
+ return if @testing && Session.pid_session?(session_file)
165
+
166
+ @session.set_buffers(@buffers)
167
+ @session.set_readline_histories(@rlh_general, @rlh_files, @rlh_search, @rlh_shell, @rlh_help, @rlh_sessions)
168
+
169
+ File.open( session_file, 'w' ) do |f|
170
+ f.puts @session.to_yaml
171
+ end
172
+ end
173
+
174
+ def session_filepath_for( session_id )
175
+ if session_id && session_id !~ %r{/}
176
+ "#{@session_dir}/#{session_id}"
177
+ else
178
+ session_id
179
+ end
180
+ end
181
+
182
+ def session_startup
183
+ @stale_session_files = []
184
+
185
+ if @session_to_load
186
+ pid_session = @session
187
+ @session = nil
188
+ session_path = session_filepath_for( @session_to_load )
189
+ load_session session_path
190
+ if ! @session
191
+ @session = Session.new(session_path)
192
+ end
193
+ else
194
+ session_files = Dir[ "#{@session_dir}/*" ].grep( %r{/\d+$} )
195
+ session_files.each do |sf|
196
+ pid = sf[ %r{/(\d+)$}, 1 ].to_i
197
+
198
+ # Check if the process is still alive
199
+ begin
200
+ Process.kill 0, pid
201
+ rescue Errno::ESRCH, Errno::EPERM
202
+ if Session.pid_session?(sf)
203
+ @stale_session_files << sf
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ # We have to do this separately and later (as opposed to inside #session_startup)
211
+ # because we have to wait for the display to get initialized in order to
212
+ # prompt the user for input, etc.
213
+ def handle_stale_session_files
214
+ return if @testing
215
+ return if @stale_session_files.empty?
216
+
217
+ session_buffers = []
218
+ @stale_session_files.each_with_index do |session_file,index|
219
+ session_buffers << open_file( session_file )
220
+
221
+ choice = get_choice(
222
+ "#{@stale_session_files.size} unclosed session(s) found. Open the above files? (session #{index+1} of #{@stale_session_files.size})",
223
+ [ CHOICE_YES, CHOICE_NO, CHOICE_DELETE ],
224
+ index > 0 ? CHOICE_NO : nil
225
+ )
226
+
227
+ case choice
228
+ when CHOICE_YES
229
+ load_session session_file
230
+ if @session
231
+ File.delete session_file
232
+ break
233
+ end
234
+ when CHOICE_DELETE
235
+ File.delete session_file
236
+ end
237
+ end
238
+
239
+ if session_buffers.empty? && @files.empty? && @settings[ 'session.default_session' ]
240
+ session_file = session_filepath_for( @settings[ 'session.default_session' ] )
241
+ if File.exist? session_file
242
+ load_session session_file
243
+ end
244
+ end
245
+
246
+ session_buffers.each do |buffer|
247
+ close_buffer buffer
248
+ end
249
+ end
250
+
251
+ def cleanup_session
252
+ if @session && Session.pid_session?(@session.filename) && File.exists?(@session.filename)
253
+ File.delete @session.filename
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,48 @@
1
+ class SizedArray < Array
2
+ attr_reader :capacity
3
+
4
+ def initialize( capacity = 10, *args )
5
+ @capacity = capacity
6
+ super( *args )
7
+ end
8
+
9
+ def resize
10
+ if size > @capacity
11
+ slice!( (0...-@capacity) )
12
+ end
13
+ end
14
+ private :resize
15
+
16
+ def concat( other_array )
17
+ super( other_array )
18
+ resize
19
+ self
20
+ end
21
+
22
+ def fill( *args )
23
+ retval = super( *args )
24
+ resize
25
+ self
26
+ end
27
+
28
+ def <<( item )
29
+ retval = super( item )
30
+ if size > @capacity
31
+ retval = shift
32
+ end
33
+ retval
34
+ end
35
+
36
+ def push( item )
37
+ self << item
38
+ end
39
+
40
+ def unshift( item )
41
+ retval = super( item )
42
+ if size > @capacity
43
+ retval = pop
44
+ end
45
+ retval
46
+ end
47
+ end
48
+
@@ -0,0 +1,19 @@
1
+ require 'diakonos/range'
2
+
3
+ module Diakonos
4
+
5
+ class TextMark
6
+ attr_reader :formatting
7
+ include RangeDelegator
8
+
9
+ def initialize( range, formatting )
10
+ @range = range
11
+ @formatting = formatting
12
+ end
13
+
14
+ def to_s
15
+ "(#{@range.start_row},#{@range.start_col})-(#{@range.end_row},#{@range.end_col}) #{formatting}"
16
+ end
17
+ end
18
+
19
+ end