diakonos 0.8.7 → 0.8.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. metadata +38 -59
  2. data/CHANGELOG +0 -238
  3. data/LICENCE +0 -21
  4. data/README +0 -75
  5. data/bin/diakonos +0 -6
  6. data/diakonos-256-colour.conf +0 -102
  7. data/diakonos.conf +0 -1233
  8. data/lib/diakonos.rb +0 -618
  9. data/lib/diakonos/array.rb +0 -15
  10. data/lib/diakonos/bignum.rb +0 -9
  11. data/lib/diakonos/bookmark.rb +0 -50
  12. data/lib/diakonos/buffer-hash.rb +0 -60
  13. data/lib/diakonos/buffer-management.rb +0 -73
  14. data/lib/diakonos/buffer.rb +0 -2044
  15. data/lib/diakonos/clipboard.rb +0 -47
  16. data/lib/diakonos/config.rb +0 -304
  17. data/lib/diakonos/ctag.rb +0 -28
  18. data/lib/diakonos/display.rb +0 -288
  19. data/lib/diakonos/enumerable.rb +0 -15
  20. data/lib/diakonos/finding.rb +0 -32
  21. data/lib/diakonos/fixnum.rb +0 -17
  22. data/lib/diakonos/functions.rb +0 -1420
  23. data/lib/diakonos/grep.rb +0 -78
  24. data/lib/diakonos/hash.rb +0 -108
  25. data/lib/diakonos/help.rb +0 -92
  26. data/lib/diakonos/hooks.rb +0 -13
  27. data/lib/diakonos/interaction.rb +0 -139
  28. data/lib/diakonos/keycode.rb +0 -110
  29. data/lib/diakonos/keying.rb +0 -124
  30. data/lib/diakonos/list.rb +0 -55
  31. data/lib/diakonos/logging.rb +0 -24
  32. data/lib/diakonos/object.rb +0 -6
  33. data/lib/diakonos/readline.rb +0 -274
  34. data/lib/diakonos/regexp.rb +0 -6
  35. data/lib/diakonos/sessions.rb +0 -70
  36. data/lib/diakonos/sized-array.rb +0 -48
  37. data/lib/diakonos/string.rb +0 -326
  38. data/lib/diakonos/text-mark.rb +0 -19
  39. data/lib/diakonos/vendor/fuzzy_file_finder.rb +0 -353
  40. data/lib/diakonos/window.rb +0 -32
  41. data/test/buffer-test.rb +0 -53
  42. data/test/clipboard-test.rb +0 -70
  43. data/test/diakonos-test.rb +0 -14
  44. data/test/hash-test.rb +0 -404
  45. data/test/regexp-test.rb +0 -26
  46. data/test/sizedarray-test.rb +0 -113
  47. data/test/string-test.rb +0 -160
@@ -1,15 +0,0 @@
1
- class Array
2
- def to_keychain_s
3
- chain_str = ""
4
- each do |key|
5
- key_str = key.keyString
6
- if key_str
7
- chain_str << key_str + " "
8
- else
9
- chain_str << key.to_s + " "
10
- end
11
- end
12
- chain_str
13
- end
14
- end
15
-
@@ -1,9 +0,0 @@
1
- require 'diakonos/keycode'
2
-
3
- class Bignum
4
- include Diakonos::KeyCode
5
- def ord
6
- self
7
- end
8
- end
9
-
@@ -1,50 +0,0 @@
1
- module Diakonos
2
-
3
- class Bookmark
4
- attr_reader :buffer, :row, :col, :name
5
-
6
- def initialize( buffer, row, col, name = nil )
7
- @buffer = buffer
8
- @row = row
9
- @col = col
10
- @name = name
11
- end
12
-
13
- def == (other)
14
- return false if other.nil?
15
- ( @buffer == other.buffer and @row == other.row and @col == other.col )
16
- end
17
-
18
- def <=> (other)
19
- return nil if other.nil?
20
- comparison = ( $diakonos.bufferToNumber( @buffer ) <=> $diakonos.bufferToNumber( other.buffer ) )
21
- return comparison if comparison != 0
22
- comparison = ( @row <=> other.row )
23
- return comparison if comparison != 0
24
- @col <=> other.col
25
- end
26
-
27
- def < (other)
28
- ( ( self <=> other ) < 0 )
29
- end
30
- def > (other)
31
- ( ( self <=> other ) > 0 )
32
- end
33
-
34
- def incRow( increment )
35
- row += increment
36
- end
37
- def incCol( increment )
38
- col += increment
39
- end
40
- def shift( row_inc, col_inc )
41
- row += row_inc
42
- col += col_inc
43
- end
44
-
45
- def to_s
46
- "[#{@name}|#{@buffer.name}:#{@row+1},#{@col+1}]"
47
- end
48
- end
49
-
50
- end
@@ -1,60 +0,0 @@
1
- # A Hash which is iterated in insertion order.
2
- # Keys are assumed to be paths; these paths are expanded on read and write.
3
- class BufferHash < Hash
4
- def initialize
5
- @keys_ = []
6
- end
7
-
8
- def [] ( key )
9
- super File.expand_path( key.to_s )
10
- end
11
-
12
- def []= ( key, value )
13
- key = File.expand_path( key.to_s )
14
- if not @keys_.include?( key )
15
- @keys_ << key
16
- end
17
- super key, value
18
- end
19
-
20
- def each
21
- @keys_.each do |key|
22
- yield key, self[ key ]
23
- end
24
- end
25
-
26
- def each_key
27
- @keys_.each do |key|
28
- yield key
29
- end
30
- end
31
-
32
- def each_value
33
- @keys_.each do |key|
34
- yield self[ key ]
35
- end
36
- end
37
-
38
- def clear
39
- @keys_ = []
40
- super
41
- end
42
-
43
- def delete( key )
44
- @keys_.delete key
45
- super
46
- end
47
-
48
- def keys
49
- @keys_.dup
50
- end
51
-
52
- def values
53
- @keys_.map { |key| self[ key ] }
54
- end
55
-
56
- def length
57
- @keys_.length
58
- end
59
- end
60
-
@@ -1,73 +0,0 @@
1
- module Diakonos
2
- class Diakonos
3
- attr_reader :current_buffer
4
-
5
- def switchTo( buffer )
6
- switched = false
7
- if buffer
8
- @buffer_stack -= [ @current_buffer ]
9
- if @current_buffer
10
- @buffer_stack.push @current_buffer
11
- end
12
- @current_buffer = buffer
13
- runHookProcs( :after_buffer_switch, buffer )
14
- updateStatusLine
15
- updateContextLine
16
- buffer.display
17
- switched = true
18
- end
19
-
20
- switched
21
- end
22
- protected :switchTo
23
-
24
- def remember_buffer( buffer )
25
- if @buffer_history.last != buffer
26
- @buffer_history << buffer
27
- @buffer_history_pointer = @buffer_history.size - 1
28
- end
29
- end
30
-
31
- # The given buffer_number should be 1-based, not zero-based.
32
- # Returns nil if no such buffer exists.
33
- def bufferNumberToName( buffer_number )
34
- return nil if buffer_number < 1
35
-
36
- number = 1
37
- buffer_name = nil
38
- @buffers.each_key do |name|
39
- if number == buffer_number
40
- buffer_name = name
41
- break
42
- end
43
- number += 1
44
- end
45
- buffer_name
46
- end
47
-
48
- # The returned value is 1-based, not zero-based.
49
- # Returns nil if no such buffer exists.
50
- def bufferToNumber( buffer )
51
- number = 1
52
- buffer_number = nil
53
- @buffers.each_value do |b|
54
- if b == buffer
55
- buffer_number = number
56
- break
57
- end
58
- number += 1
59
- end
60
- buffer_number
61
- end
62
-
63
- def show_buffer_file_diff( buffer = @current_buffer )
64
- current_text_file = @diakonos_home + '/current-buffer'
65
- buffer.saveCopy( current_text_file )
66
- `#{@settings[ 'diff_command' ]} #{current_text_file} #{buffer.name} > #{@diff_filename}`
67
- diff_buffer = openFile( @diff_filename )
68
- yield diff_buffer
69
- closeFile diff_buffer
70
- end
71
-
72
- end
73
- end
@@ -1,2044 +0,0 @@
1
- module Diakonos
2
-
3
- class Buffer
4
- attr_reader :name, :key, :original_language, :changing_selection, :read_only,
5
- :last_col, :last_row, :tab_size, :last_screen_x, :last_screen_y, :last_screen_col
6
- attr_writer :desired_column, :read_only
7
-
8
- SELECTION = 0
9
- TYPING = true
10
- STOPPED_TYPING = true
11
- STILL_TYPING = false
12
- NO_SNAPSHOT = true
13
- DO_DISPLAY = true
14
- DONT_DISPLAY = false
15
- READ_ONLY = true
16
- READ_WRITE = false
17
- ROUND_DOWN = false
18
- ROUND_UP = true
19
- PAD_END = true
20
- DONT_PAD_END = false
21
- MATCH_CLOSE = true
22
- MATCH_ANY = false
23
- START_FROM_BEGINNING = -1
24
- DO_PITCH_CURSOR = true
25
- DONT_PITCH_CURSOR = false
26
- CLEAR_STACK_POINTER = true
27
- DONT_CLEAR_STACK_POINTER = false
28
- STRIP_LINE = true
29
- DONT_STRIP_LINE = false
30
-
31
- # Set name to nil to create a buffer that is not associated with a file.
32
- def initialize( diakonos, name, key, read_only = false )
33
- @diakonos = diakonos
34
- @name = name
35
- @key = key
36
- @modified = false
37
- @last_modification_check = Time.now
38
-
39
- @buffer_states = Array.new
40
- @cursor_states = Array.new
41
- if @name
42
- @name = @name.subHome
43
- if FileTest.exists? @name
44
- @lines = IO.readlines( @name )
45
- if ( @lines.length == 0 ) or ( @lines[ -1 ][ -1..-1 ] == "\n" )
46
- @lines.push ""
47
- end
48
- @lines = @lines.collect do |line|
49
- line.chomp
50
- end
51
- else
52
- @lines = Array.new
53
- @lines[ 0 ] = ""
54
- end
55
- else
56
- @lines = Array.new
57
- @lines[ 0 ] = ""
58
- end
59
- @current_buffer_state = 0
60
-
61
- @top_line = 0
62
- @left_column = 0
63
- @desired_column = 0
64
- @mark_anchor = nil
65
- @text_marks = Array.new
66
- @last_search_regexps = nil
67
- @highlight_regexp = nil
68
- @last_search = nil
69
- @changing_selection = false
70
- @typing = false
71
- @last_col = 0
72
- @last_screen_col = 0
73
- @last_screen_y = 0
74
- @last_screen_x = 0
75
- @last_row = 0
76
- @read_only = read_only
77
- @bookmarks = Array.new
78
- @lang_stack = Array.new
79
- @cursor_stack = Array.new
80
- @cursor_stack_pointer = nil
81
-
82
- configure
83
-
84
- if @settings[ "convert_tabs" ]
85
- tabs_subbed = false
86
- @lines.collect! do |line|
87
- new_line = line.expandTabs( @tab_size )
88
- tabs_subbed = ( tabs_subbed or new_line != line )
89
- # Return value for collect:
90
- new_line
91
- end
92
- @modified = ( @modified or tabs_subbed )
93
- if tabs_subbed
94
- @diakonos.setILine "(spaces substituted for tab characters)"
95
- end
96
- end
97
-
98
- @buffer_states[ @current_buffer_state ] = @lines
99
- @cursor_states[ @current_buffer_state ] = [ @last_row, @last_col ]
100
- end
101
-
102
- def configure(
103
- language = (
104
- @diakonos.getLanguageFromShaBang( @lines[ 0 ] ) or
105
- @diakonos.getLanguageFromName( @name ) or
106
- LANG_TEXT
107
- )
108
- )
109
- reset_win_main
110
- setLanguage language
111
- @original_language = @language
112
- end
113
-
114
- def reset_win_main
115
- @win_main = @diakonos.win_main
116
- end
117
-
118
- def setLanguage( language )
119
- @settings = @diakonos.settings
120
- @language = language
121
- @token_regexps = ( @diakonos.token_regexps[ @language ] or Hash.new )
122
- @close_token_regexps = ( @diakonos.close_token_regexps[ @language ] or Hash.new )
123
- @token_formats = ( @diakonos.token_formats[ @language ] or Hash.new )
124
- @indenters = @diakonos.indenters[ @language ]
125
- @unindenters = @diakonos.unindenters[ @language ]
126
- @preventers = @settings[ "lang.#{@language}.indent.preventers" ]
127
- @closers = @diakonos.closers[ @language ] || Hash.new
128
- @auto_indent = @settings[ "lang.#{@language}.indent.auto" ]
129
- @indent_size = ( @settings[ "lang.#{@language}.indent.size" ] or 4 )
130
- @indent_roundup = @settings[ "lang.#{@language}.indent.roundup" ].nil? ? true : @settings[ "lang.#{@language}.indent.roundup" ]
131
- @indent_closers = @settings[ "lang.#{@language}.indent.closers" ].nil? ? false : @settings[ "lang.#{@language}.indent.closers" ]
132
- @default_formatting = ( @settings[ "lang.#{@language}.format.default" ] or Curses::A_NORMAL )
133
- @selection_formatting = ( @settings[ "lang.#{@language}.format.selection" ] or Curses::A_REVERSE )
134
- @indent_ignore_charset = ( @settings[ "lang.#{@language}.indent.ignore.charset" ] or "" )
135
- @tab_size = ( @settings[ "lang.#{@language}.tabsize" ] or DEFAULT_TAB_SIZE )
136
- end
137
- protected :setLanguage
138
-
139
- def [] ( arg )
140
- @lines[ arg ]
141
- end
142
-
143
- def == (other)
144
- return false if other.nil?
145
- key == other.key
146
- end
147
-
148
- def length
149
- @lines.length
150
- end
151
-
152
- def modified?
153
- @modified
154
- end
155
-
156
- def nice_name
157
- @name || @settings[ "status.unnamed_str" ]
158
- end
159
-
160
- def display
161
- return if not @diakonos.do_display
162
-
163
- Thread.new do
164
- #if $profiling
165
- #RubyProf.start
166
- #end
167
-
168
- if @diakonos.display_mutex.try_lock
169
- begin
170
- Curses::curs_set 0
171
-
172
- @continued_format_class = nil
173
-
174
- @pen_down = true
175
-
176
- # First, we have to "draw" off-screen, in order to check for opening of
177
- # multi-line highlights.
178
-
179
- # So, first look backwards from the @top_line to find the first opening
180
- # regexp match, if any.
181
- index = @top_line - 1
182
- @lines[ [ 0, @top_line - @settings[ "view.lookback" ] ].max...@top_line ].reverse_each do |line|
183
- open_index = -1
184
- open_token_class = nil
185
- open_match_text = nil
186
-
187
- open_index, open_token_class, open_match_text = findOpeningMatch( line )
188
-
189
- if open_token_class
190
- @pen_down = false
191
- @lines[ index...@top_line ].each do |line|
192
- printLine line
193
- end
194
- @pen_down = true
195
-
196
- break
197
- end
198
-
199
- index = index - 1
200
- end
201
-
202
- # Draw each on-screen line.
203
- y = 0
204
- @lines[ @top_line...(@diakonos.main_window_height + @top_line) ].each_with_index do |line, row|
205
- @win_main.setpos( y, 0 )
206
- printLine line.expandTabs( @tab_size )
207
- @win_main.setpos( y, 0 )
208
- paintMarks @top_line + row
209
- y += 1
210
- end
211
-
212
- # Paint the empty space below the file if the file is too short to fit in one screen.
213
- ( y...@diakonos.main_window_height ).each do |y|
214
- @win_main.setpos( y, 0 )
215
- @win_main.attrset @default_formatting
216
- linestr = " " * Curses::cols
217
- if @settings[ "view.nonfilelines.visible" ]
218
- linestr[ 0 ] = ( @settings[ "view.nonfilelines.character" ] or "~" )
219
- end
220
-
221
- @win_main.addstr linestr
222
- end
223
-
224
- @win_main.setpos( @last_screen_y , @last_screen_x )
225
- @win_main.refresh
226
-
227
- if @language != @original_language
228
- setLanguage( @original_language )
229
- end
230
-
231
- Curses::curs_set 1
232
- rescue Exception => e
233
- @diakonos.log( "Display Exception:" )
234
- @diakonos.log( e.message )
235
- @diakonos.log( e.backtrace.join( "\n" ) )
236
- showException e
237
- end
238
- @diakonos.display_mutex.unlock
239
- @diakonos.displayDequeue
240
- else
241
- @diakonos.displayEnqueue( self )
242
- end
243
-
244
- #if $profiling
245
- #result = RubyProf.stop
246
- #printer = RubyProf::GraphHtmlPrinter.new( result )
247
- #File.open( "#{ENV['HOME']}/svn/diakonos/profiling/diakonos-profile-#{Time.now.to_i}.html", 'w' ) do |f|
248
- #printer.print( f )
249
- #end
250
- #end
251
- end
252
-
253
- end
254
-
255
- def findOpeningMatch( line, match_close = true, bos_allowed = true )
256
- open_index = line.length
257
- open_token_class = nil
258
- open_match_text = nil
259
- match = nil
260
- match_text = nil
261
- @token_regexps.each do |token_class,regexp|
262
- if match = regexp.match( line )
263
- if match.length > 1
264
- index = match.begin 1
265
- match_text = match[ 1 ]
266
- whole_match_index = match.begin 0
267
- else
268
- whole_match_index = index = match.begin( 0 )
269
- match_text = match[ 0 ]
270
- end
271
- if ( not regexp.uses_bos ) or ( bos_allowed and ( whole_match_index == 0 ) )
272
- if index < open_index
273
- if ( ( not match_close ) or @close_token_regexps[ token_class ] )
274
- open_index = index
275
- open_token_class = token_class
276
- open_match_text = match_text
277
- end
278
- end
279
- end
280
- end
281
- end
282
-
283
- [ open_index, open_token_class, open_match_text ]
284
- end
285
-
286
- def findClosingMatch( line_, regexp, bos_allowed = true, start_at = 0 )
287
- close_match_text = nil
288
- close_index = nil
289
- if start_at > 0
290
- line = line_[ start_at..-1 ]
291
- else
292
- line = line_
293
- end
294
- line.scan( regexp ) do |m|
295
- match = Regexp.last_match
296
- if match.length > 1
297
- index = match.begin 1
298
- match_text = match[ 1 ]
299
- else
300
- index = match.begin 0
301
- match_text = match[ 0 ]
302
- end
303
- if ( not regexp.uses_bos ) or ( bos_allowed and ( index == 0 ) )
304
- close_index = index
305
- close_match_text = match_text
306
- break
307
- end
308
- end
309
-
310
- [ close_index, close_match_text ]
311
- end
312
- protected :findClosingMatch
313
-
314
- # @mark_start[ "col" ] is inclusive,
315
- # @mark_end[ "col" ] is exclusive.
316
- def recordMarkStartAndEnd
317
- if @mark_anchor
318
- crow = @last_row
319
- ccol = @last_col
320
- anchor_first = true
321
- if crow < @mark_anchor[ "row" ]
322
- anchor_first = false
323
- elsif crow > @mark_anchor[ "row" ]
324
- anchor_first = true
325
- else
326
- if ccol < @mark_anchor[ "col" ]
327
- anchor_first = false
328
- end
329
- end
330
- if anchor_first
331
- @text_marks[ SELECTION ] = TextMark.new(
332
- @mark_anchor[ "row" ],
333
- @mark_anchor[ "col" ],
334
- crow,
335
- ccol,
336
- @selection_formatting
337
- )
338
- else
339
- @text_marks[ SELECTION ] = TextMark.new(
340
- crow,
341
- ccol,
342
- @mark_anchor[ "row" ],
343
- @mark_anchor[ "col" ],
344
- @selection_formatting
345
- )
346
- end
347
- else
348
- @text_marks[ SELECTION ] = nil
349
- end
350
- end
351
-
352
- def selection_mark
353
- @text_marks[ SELECTION ]
354
- end
355
- def selecting?
356
- !!selection_mark
357
- end
358
-
359
- def select_current_line
360
- @text_marks[ SELECTION ] = TextMark.new(
361
- @last_row,
362
- 0,
363
- @last_row,
364
- @lines[ @last_row ].size,
365
- @selection_formatting
366
- )
367
- @lines[ @last_row ]
368
- end
369
-
370
- def select_all
371
- anchorSelection( 0, 0, DONT_DISPLAY )
372
- cursorTo( @lines.length - 1, @lines[ -1 ].length, DO_DISPLAY )
373
- end
374
-
375
- def select( from_regexp, to_regexp, include_ending = true )
376
- start_row = nil
377
-
378
- @lines[ 0..@last_row ].reverse.each_with_index do |line,index|
379
- if line =~ from_regexp
380
- start_row = @last_row - index
381
- break
382
- end
383
- end
384
- if start_row
385
- end_row = nil
386
- @lines[ start_row..-1 ].each_with_index do |line,index|
387
- if line =~ to_regexp
388
- end_row = start_row + index
389
- break
390
- end
391
- end
392
- if end_row
393
- if include_ending
394
- end_row += 1
395
- end
396
- anchorSelection( start_row, 0, DONT_DISPLAY )
397
- cursorTo( end_row, 0 )
398
- display
399
- end
400
- end
401
- end
402
-
403
- # Prints text to the screen, truncating where necessary.
404
- # Returns nil if the string is completely off-screen.
405
- # write_cursor_col is buffer-relative, not screen-relative
406
- def truncateOffScreen( string, write_cursor_col )
407
- retval = string
408
-
409
- # Truncate based on left edge of display area
410
- if write_cursor_col < @left_column
411
- retval = retval[ (@left_column - write_cursor_col)..-1 ]
412
- write_cursor_col = @left_column
413
- end
414
-
415
- if retval
416
- # Truncate based on right edge of display area
417
- if write_cursor_col + retval.length > @left_column + Curses::cols - 1
418
- new_length = ( @left_column + Curses::cols - write_cursor_col )
419
- if new_length <= 0
420
- retval = nil
421
- else
422
- retval = retval[ 0...new_length ]
423
- end
424
- end
425
- end
426
-
427
- retval == "" ? nil : retval
428
- end
429
-
430
- # For debugging purposes
431
- def quotedOrNil( str )
432
- if str.nil?
433
- "nil"
434
- else
435
- "'#{str}'"
436
- end
437
- end
438
-
439
- def paintMarks( row )
440
- string = @lines[ row ][ @left_column ... @left_column + Curses::cols ]
441
- return if string.nil? or string == ""
442
- string = string.expandTabs( @tab_size )
443
- cury = @win_main.cury
444
- curx = @win_main.curx
445
-
446
- @text_marks.reverse_each do |text_mark|
447
- if text_mark
448
- @win_main.attrset text_mark.formatting
449
- if ( (text_mark.start_row + 1) .. (text_mark.end_row - 1) ) === row
450
- @win_main.setpos( cury, curx )
451
- @win_main.addstr string
452
- elsif row == text_mark.start_row and row == text_mark.end_row
453
- expanded_col = tabExpandedColumn( text_mark.start_col, row )
454
- if expanded_col < @left_column + Curses::cols
455
- left = [ expanded_col - @left_column, 0 ].max
456
- right = tabExpandedColumn( text_mark.end_col, row ) - @left_column
457
- if left < right
458
- @win_main.setpos( cury, curx + left )
459
- @win_main.addstr string[ left...right ]
460
- end
461
- end
462
- elsif row == text_mark.start_row
463
- expanded_col = tabExpandedColumn( text_mark.start_col, row )
464
- if expanded_col < @left_column + Curses::cols
465
- left = [ expanded_col - @left_column, 0 ].max
466
- @win_main.setpos( cury, curx + left )
467
- @win_main.addstr string[ left..-1 ]
468
- end
469
- elsif row == text_mark.end_row
470
- right = tabExpandedColumn( text_mark.end_col, row ) - @left_column
471
- @win_main.setpos( cury, curx )
472
- @win_main.addstr string[ 0...right ]
473
- else
474
- # This row not in selection.
475
- end
476
- end
477
- end
478
- end
479
-
480
- def printString( string, formatting = ( @token_formats[ @continued_format_class ] or @default_formatting ) )
481
- return if not @pen_down
482
- return if string.nil?
483
-
484
- @win_main.attrset formatting
485
- @win_main.addstr string
486
- end
487
-
488
- # This method assumes that the cursor has been setup already at
489
- # the left-most column of the correct on-screen row.
490
- # It merely unintelligently prints the characters on the current curses line,
491
- # refusing to print characters of the in-buffer line which are offscreen.
492
- def printLine( line )
493
- i = 0
494
- substr = nil
495
- index = nil
496
- while i < line.length
497
- substr = line[ i..-1 ]
498
- if @continued_format_class
499
- close_index, close_match_text = findClosingMatch( substr, @close_token_regexps[ @continued_format_class ], i == 0 )
500
-
501
- if close_match_text.nil?
502
- printString truncateOffScreen( substr, i )
503
- printPaddingFrom( line.length )
504
- i = line.length
505
- else
506
- end_index = close_index + close_match_text.length
507
- printString truncateOffScreen( substr[ 0...end_index ], i )
508
- @continued_format_class = nil
509
- i += end_index
510
- end
511
- else
512
- first_index, first_token_class, first_word = findOpeningMatch( substr, MATCH_ANY, i == 0 )
513
-
514
- if @lang_stack.length > 0
515
- prev_lang, close_token_class = @lang_stack[ -1 ]
516
- close_index, close_match_text = findClosingMatch( substr, @diakonos.close_token_regexps[ prev_lang ][ close_token_class ], i == 0 )
517
- if close_match_text and close_index <= first_index
518
- if close_index > 0
519
- # Print any remaining text in the embedded language
520
- printString truncateOffScreen( substr[ 0...close_index ], i )
521
- i += substr[ 0...close_index ].length
522
- end
523
-
524
- @lang_stack.pop
525
- setLanguage prev_lang
526
-
527
- printString(
528
- truncateOffScreen( substr[ close_index...(close_index + close_match_text.length) ], i ),
529
- @token_formats[ close_token_class ]
530
- )
531
- i += close_match_text.length
532
-
533
- # Continue printing from here.
534
- next
535
- end
536
- end
537
-
538
- if first_word
539
- if first_index > 0
540
- # Print any preceding text in the default format
541
- printString truncateOffScreen( substr[ 0...first_index ], i )
542
- i += substr[ 0...first_index ].length
543
- end
544
- printString( truncateOffScreen( first_word, i ), @token_formats[ first_token_class ] )
545
- i += first_word.length
546
- if @close_token_regexps[ first_token_class ]
547
- if change_to = @settings[ "lang.#{@language}.tokens.#{first_token_class}.change_to" ]
548
- @lang_stack.push [ @language, first_token_class ]
549
- setLanguage change_to
550
- else
551
- @continued_format_class = first_token_class
552
- end
553
- end
554
- else
555
- printString truncateOffScreen( substr, i )
556
- i += substr.length
557
- break
558
- end
559
- end
560
- end
561
-
562
- printPaddingFrom i
563
- end
564
-
565
- def printPaddingFrom( col )
566
- return if not @pen_down
567
-
568
- if col < @left_column
569
- remainder = Curses::cols
570
- else
571
- remainder = @left_column + Curses::cols - col
572
- end
573
-
574
- if remainder > 0
575
- printString( " " * remainder )
576
- end
577
- end
578
-
579
- def save( filename = nil, prompt_overwrite = DONT_PROMPT_OVERWRITE )
580
- if filename
581
- name = filename.subHome
582
- else
583
- name = @name
584
- end
585
-
586
- if @read_only and FileTest.exists?( @name ) and FileTest.exists?( name ) and ( File.stat( @name ).ino == File.stat( name ).ino )
587
- @diakonos.setILine "#{name} cannot be saved since it is read-only."
588
- else
589
- @read_only = false
590
- if name.nil?
591
- @diakonos.saveFileAs
592
- else
593
- proceed = true
594
-
595
- if prompt_overwrite and FileTest.exists? name
596
- proceed = false
597
- choice = @diakonos.getChoice(
598
- "Overwrite existing '#{name}'?",
599
- [ CHOICE_YES, CHOICE_NO ],
600
- CHOICE_NO
601
- )
602
- case choice
603
- when CHOICE_YES
604
- proceed = true
605
- when CHOICE_NO
606
- proceed = false
607
- end
608
- end
609
-
610
- if file_modified?
611
- proceed = ! @diakonos.revert( "File has been altered externally. Load on-disk version?" )
612
- end
613
-
614
- if proceed
615
- File.open( name, "w" ) do |f|
616
- @lines[ 0..-2 ].each do |line|
617
- if @settings[ 'strip_trailing_whitespace_on_save' ]
618
- line.rstrip!
619
- end
620
- f.puts line
621
- end
622
-
623
- line = @lines[ -1 ]
624
- if @settings[ 'strip_trailing_whitespace_on_save' ]
625
- line.rstrip!
626
- end
627
- if line != ""
628
- # No final newline character
629
- f.print line
630
- f.print "\n" if @settings[ "eof_newline" ]
631
- end
632
-
633
- if @settings[ 'strip_trailing_whitespace_on_save' ]
634
- if @last_col > @lines[ @last_row ].size
635
- cursorTo @last_row, @lines[ @last_row ].size
636
- end
637
- end
638
- end
639
- @name = name
640
- @last_modification_check = File.mtime( @name )
641
- saved = true
642
-
643
- if @name == @diakonos.diakonos_conf
644
- @diakonos.loadConfiguration
645
- @diakonos.initializeDisplay
646
- end
647
-
648
- @modified = false
649
-
650
- display
651
- @diakonos.updateStatusLine
652
- end
653
- end
654
- end
655
-
656
- saved
657
- end
658
-
659
- # Returns true on successful write.
660
- def saveCopy( filename )
661
- return false if filename.nil?
662
-
663
- name = filename.subHome
664
-
665
- File.open( name, "w" ) do |f|
666
- @lines[ 0..-2 ].each do |line|
667
- f.puts line
668
- end
669
- if @lines[ -1 ] != ""
670
- # No final newline character
671
- f.print @lines[ -1 ]
672
- f.print "\n" if @settings[ "eof_newline" ]
673
- end
674
- end
675
-
676
- true
677
- end
678
-
679
- def replaceChar( c )
680
- row = @last_row
681
- col = @last_col
682
- takeSnapshot( TYPING )
683
- @lines[ row ][ col ] = c
684
- setModified
685
- end
686
-
687
- def insertChar( c )
688
- row = @last_row
689
- col = @last_col
690
- takeSnapshot( TYPING )
691
- line = @lines[ row ]
692
- @lines[ row ] = line[ 0...col ] + c.chr + line[ col..-1 ]
693
- setModified
694
- end
695
-
696
- def insertString( str )
697
- row = @last_row
698
- col = @last_col
699
- takeSnapshot( TYPING )
700
- line = @lines[ row ]
701
- @lines[ row ] = line[ 0...col ] + str + line[ col..-1 ]
702
- setModified
703
- end
704
-
705
- # x and y are given window-relative, not buffer-relative.
706
- def delete
707
- if selection_mark
708
- deleteSelection
709
- else
710
- row = @last_row
711
- col = @last_col
712
- if ( row >= 0 ) and ( col >= 0 )
713
- line = @lines[ row ]
714
- if col == line.length
715
- if row < @lines.length - 1
716
- # Delete newline, and concat next line
717
- joinLines( row )
718
- cursorTo( @last_row, @last_col )
719
- end
720
- else
721
- takeSnapshot( TYPING )
722
- @lines[ row ] = line[ 0...col ] + line[ (col + 1)..-1 ]
723
- setModified
724
- end
725
- end
726
- end
727
- end
728
-
729
- def joinLines( row = @last_row, strip = DONT_STRIP_LINE )
730
- takeSnapshot( TYPING )
731
- next_line = @lines.delete_at( row + 1 )
732
- if strip
733
- next_line = ' ' + next_line.strip
734
- end
735
- @lines[ row ] << next_line
736
- setModified
737
- end
738
-
739
- def close_code
740
- line = @lines[ @last_row ]
741
- @closers.each_value do |h|
742
- h[ :regexp ] =~ line
743
- lm = Regexp.last_match
744
- if lm
745
- str = h[ :closer ].call( lm ).to_s
746
- r, c = @last_row, @last_col
747
- paste str, @indent_closers
748
- cursorTo r, c
749
- if /%_/ === str
750
- find( [ /%_/ ], :direction => :down, :replacement => '', :auto_choice => CHOICE_YES_AND_STOP )
751
- end
752
- else
753
- @diakonos.log h[ :regexp ].inspect + " does not match '#{line}'"
754
- end
755
- end
756
- end
757
-
758
- def collapseWhitespace
759
- if selection_mark
760
- removeSelection DONT_DISPLAY
761
- end
762
-
763
- line = @lines[ @last_row ]
764
- head = line[ 0...@last_col ]
765
- tail = line[ @last_col..-1 ]
766
- new_head = head.sub( /\s+$/, '' )
767
- new_line = new_head + tail.sub( /^\s+/, ' ' )
768
- if new_line != line
769
- takeSnapshot( TYPING )
770
- @lines[ @last_row ] = new_line
771
- cursorTo( @last_row, @last_col - ( head.length - new_head.length ) )
772
- setModified
773
- end
774
- end
775
-
776
- def selected_lines
777
- selection = selection_mark
778
- if selection
779
- if selection.end_col == 0
780
- end_row = selection.end_row - 1
781
- else
782
- end_row = selection.end_row
783
- end
784
- @lines[ selection.start_row..end_row ]
785
- else
786
- [ @lines[ @last_row ] ]
787
- end
788
- end
789
-
790
- def columnize( delimiter = /=>?|:|,/, num_spaces_padding = 1 )
791
- takeSnapshot
792
-
793
- lines = selected_lines
794
- column_width = 0
795
- lines.each do |line|
796
- pos = ( line =~ delimiter )
797
- if pos
798
- column_width = [ pos, column_width ].max
799
- end
800
- end
801
-
802
- padding = ' ' * num_spaces_padding
803
- one_modified = false
804
-
805
- lines.each do |line|
806
- old_line = line.dup
807
- if line =~ /^(.+?)(#{delimiter.source})(.*)$/
808
- pre = $1
809
- del = $2
810
- post = $3
811
- if pre !~ /\s$/
812
- del = " #{del}"
813
- end
814
- if post !~ /^\s/
815
- del = "#{del} "
816
- end
817
- del.sub!( /^\s+/, ' ' * num_spaces_padding )
818
- del.sub!( /\s+$/, ' ' * num_spaces_padding )
819
- line.replace( ( "%-#{column_width}s" % pre ) + del + post )
820
- end
821
- one_modified ||= ( line != old_line )
822
- end
823
-
824
- if one_modified
825
- setModified
826
- end
827
- end
828
-
829
- def comment_out
830
- takeSnapshot
831
- one_modified = false
832
- selected_lines.each do |line|
833
- old_line = line.dup
834
- line.gsub!( /^(\s*)/, "\\1" + @settings[ "lang.#{@language}.comment_string" ].to_s )
835
- line << @settings[ "lang.#{@language}.comment_close_string" ].to_s
836
- one_modified ||= ( line != old_line )
837
- end
838
- if one_modified
839
- setModified
840
- end
841
- end
842
-
843
- def uncomment
844
- takeSnapshot
845
- comment_string = Regexp.escape( @settings[ "lang.#{@language}.comment_string" ].to_s )
846
- comment_close_string = Regexp.escape( @settings[ "lang.#{@language}.comment_close_string" ].to_s )
847
- one_modified = false
848
- selected_lines.each do |line|
849
- old_line = line.dup
850
- line.gsub!( /^(\s*)#{comment_string}/, "\\1" )
851
- line.gsub!( /#{comment_close_string}$/, '' )
852
- one_modified ||= ( line != old_line )
853
- end
854
- if one_modified
855
- setModified
856
- end
857
- end
858
-
859
- def deleteLine
860
- removeSelection( DONT_DISPLAY ) if selection_mark
861
-
862
- row = @last_row
863
- takeSnapshot
864
- retval = nil
865
- if @lines.length == 1
866
- retval = @lines[ 0 ]
867
- @lines[ 0 ] = ""
868
- else
869
- retval = @lines[ row ]
870
- @lines.delete_at row
871
- end
872
- cursorTo( row, 0 )
873
- setModified
874
-
875
- retval
876
- end
877
-
878
- def deleteToEOL
879
- removeSelection( DONT_DISPLAY ) if selection_mark
880
-
881
- row = @last_row
882
- col = @last_col
883
-
884
- takeSnapshot
885
- if @settings[ 'delete_newline_on_delete_to_eol' ] and col == @lines[ row ].size
886
- next_line = @lines.delete_at( row + 1 )
887
- @lines[ row ] << next_line
888
- retval = ''
889
- else
890
- retval = [ @lines[ row ][ col..-1 ] ]
891
- @lines[ row ] = @lines[ row ][ 0...col ]
892
- end
893
- setModified
894
-
895
- retval
896
- end
897
-
898
- def delete_to( char )
899
- removeSelection( DONT_DISPLAY ) if selection_mark
900
- takeSnapshot
901
- index = @lines[ @last_row ].index( char, @last_col )
902
- if index
903
- retval = @lines[ @last_row ].slice!( @last_col, index - @last_col )
904
- setModified
905
- retval
906
- end
907
- end
908
-
909
- def delete_to_and_from( char )
910
- removeSelection( DONT_DISPLAY ) if selection_mark
911
- takeSnapshot
912
- index_before = @lines[ @last_row ].rindex( char, @last_col )
913
- index_after = @lines[ @last_row ].index( char, @last_col )
914
- if index_before && index_after
915
- index_before += 1
916
- retval = @lines[ @last_row ].slice!( index_before, index_after - index_before )
917
- cursorTo( @last_row, index_before )
918
- setModified
919
- retval
920
- end
921
- end
922
-
923
- def carriageReturn
924
- takeSnapshot
925
- row = @last_row
926
- col = @last_col
927
- @lines = @lines[ 0...row ] +
928
- [ @lines[ row ][ 0...col ] ] +
929
- [ @lines[ row ][ col..-1 ] ] +
930
- @lines[ (row+1)..-1 ]
931
- cursorTo( row + 1, 0 )
932
- parsedIndent if @auto_indent
933
- setModified
934
- end
935
-
936
- def lineAt( y )
937
- row = @top_line + y
938
- if row < 0
939
- nil
940
- else
941
- @lines[ row ]
942
- end
943
- end
944
-
945
- def current_line
946
- @lines[ @last_row ]
947
- end
948
-
949
- # Returns true iff the given column, x, is less than the length of the given line, y.
950
- def inLine( x, y )
951
- x + @left_column < lineAt( y ).length
952
- end
953
-
954
- # Translates the window column, x, to a buffer-relative column index.
955
- def columnOf( x )
956
- @left_column + x
957
- end
958
-
959
- # Translates the window row, y, to a buffer-relative row index.
960
- def rowOf( y )
961
- @top_line + y
962
- end
963
-
964
- # Returns nil if the row is off-screen.
965
- def rowToY( row )
966
- return nil if row.nil?
967
- y = row - @top_line
968
- y = nil if ( y < 0 ) or ( y > @top_line + @diakonos.main_window_height - 1 )
969
- y
970
- end
971
-
972
- # Returns nil if the column is off-screen.
973
- def columnToX( col )
974
- return nil if col.nil?
975
- x = col - @left_column
976
- x = nil if ( x < 0 ) or ( x > @left_column + Curses::cols - 1 )
977
- x
978
- end
979
-
980
- def currentRow
981
- @last_row
982
- end
983
-
984
- def currentColumn
985
- @last_col
986
- end
987
-
988
- # Returns the amount the view was actually panned.
989
- def panView( x = 1, do_display = DO_DISPLAY )
990
- old_left_column = @left_column
991
- @left_column = [ @left_column + x, 0 ].max
992
- recordMarkStartAndEnd
993
- display if do_display
994
- @left_column - old_left_column
995
- end
996
-
997
- # Returns the amount the view was actually pitched.
998
- def pitchView( y = 1, do_pitch_cursor = DONT_PITCH_CURSOR, do_display = DO_DISPLAY )
999
- old_top_line = @top_line
1000
- new_top_line = @top_line + y
1001
-
1002
- if new_top_line < 0
1003
- @top_line = 0
1004
- elsif new_top_line + @diakonos.main_window_height > @lines.length
1005
- @top_line = [ @lines.length - @diakonos.main_window_height, 0 ].max
1006
- else
1007
- @top_line = new_top_line
1008
- end
1009
-
1010
- old_row = @last_row
1011
- old_col = @last_col
1012
-
1013
- changed = ( @top_line - old_top_line )
1014
- if changed != 0 and do_pitch_cursor
1015
- @last_row += changed
1016
- end
1017
-
1018
- height = [ @diakonos.main_window_height, @lines.length ].min
1019
-
1020
- @last_row = @last_row.fit( @top_line, @top_line + height - 1 )
1021
- if @last_row - @top_line < @settings[ "view.margin.y" ]
1022
- @last_row = @top_line + @settings[ "view.margin.y" ]
1023
- @last_row = @last_row.fit( @top_line, @top_line + height - 1 )
1024
- elsif @top_line + height - 1 - @last_row < @settings[ "view.margin.y" ]
1025
- @last_row = @top_line + height - 1 - @settings[ "view.margin.y" ]
1026
- @last_row = @last_row.fit( @top_line, @top_line + height - 1 )
1027
- end
1028
- @last_col = @last_col.fit( @left_column, [ @left_column + Curses::cols - 1, @lines[ @last_row ].length ].min )
1029
- @last_screen_y = @last_row - @top_line
1030
- @last_screen_x = tabExpandedColumn( @last_col, @last_row ) - @left_column
1031
-
1032
- recordMarkStartAndEnd
1033
-
1034
- if changed != 0
1035
- highlightMatches
1036
- if @diakonos.there_was_non_movement
1037
- pushCursorState( old_top_line, old_row, old_col )
1038
- end
1039
- end
1040
-
1041
- display if do_display
1042
-
1043
- changed
1044
- end
1045
-
1046
- def pushCursorState( top_line, row, col, clear_stack_pointer = CLEAR_STACK_POINTER )
1047
- new_state = {
1048
- :top_line => top_line,
1049
- :row => row,
1050
- :col => col
1051
- }
1052
- if not @cursor_stack.include? new_state
1053
- @cursor_stack << new_state
1054
- if clear_stack_pointer
1055
- @cursor_stack_pointer = nil
1056
- end
1057
- @diakonos.clearNonMovementFlag
1058
- end
1059
- end
1060
-
1061
- # Returns true iff the cursor changed positions in the buffer.
1062
- def cursorTo( row, col, do_display = DONT_DISPLAY, stopped_typing = STOPPED_TYPING, adjust_row = ADJUST_ROW )
1063
- old_last_row = @last_row
1064
- old_last_col = @last_col
1065
-
1066
- row = row.fit( 0, @lines.length - 1 )
1067
-
1068
- if col < 0
1069
- if adjust_row
1070
- if row > 0
1071
- row = row - 1
1072
- col = @lines[ row ].length
1073
- else
1074
- col = 0
1075
- end
1076
- else
1077
- col = 0
1078
- end
1079
- elsif col > @lines[ row ].length
1080
- if adjust_row
1081
- if row < @lines.length - 1
1082
- row = row + 1
1083
- col = 0
1084
- else
1085
- col = @lines[ row ].length
1086
- end
1087
- else
1088
- col = @lines[ row ].length
1089
- end
1090
- end
1091
-
1092
- if adjust_row
1093
- @desired_column = col
1094
- else
1095
- goto_col = [ @desired_column, @lines[ row ].length ].min
1096
- if col < goto_col
1097
- col = goto_col
1098
- end
1099
- end
1100
-
1101
- new_col = tabExpandedColumn( col, row )
1102
- view_changed = showCharacter( row, new_col )
1103
- @last_screen_y = row - @top_line
1104
- @last_screen_x = new_col - @left_column
1105
-
1106
- @typing = false if stopped_typing
1107
- @last_row = row
1108
- @last_col = col
1109
- @last_screen_col = new_col
1110
- changed = ( @last_row != old_last_row or @last_col != old_last_col )
1111
- if changed
1112
- recordMarkStartAndEnd
1113
-
1114
- removed = false
1115
- if not @changing_selection and selection_mark
1116
- removeSelection( DONT_DISPLAY )
1117
- removed = true
1118
- end
1119
- if removed or ( do_display and ( selection_mark or view_changed ) )
1120
- display
1121
- else
1122
- @diakonos.display_mutex.synchronize do
1123
- @win_main.setpos( @last_screen_y, @last_screen_x )
1124
- end
1125
- end
1126
- @diakonos.updateStatusLine
1127
- @diakonos.updateContextLine
1128
-
1129
- @diakonos.remember_buffer self
1130
- end
1131
-
1132
- changed
1133
- end
1134
-
1135
- def cursorReturn( direction )
1136
- delta = 0
1137
- if @cursor_stack_pointer.nil?
1138
- pushCursorState( @top_line, @last_row, @last_col, DONT_CLEAR_STACK_POINTER )
1139
- delta = 1
1140
- end
1141
- case direction
1142
- when :forward
1143
- @cursor_stack_pointer = ( @cursor_stack_pointer || 0 ) + 1
1144
- #when :backward
1145
- else
1146
- @cursor_stack_pointer = ( @cursor_stack_pointer || @cursor_stack.length ) - 1 - delta
1147
- end
1148
-
1149
- return_pointer = @cursor_stack_pointer
1150
-
1151
- if @cursor_stack_pointer < 0
1152
- return_pointer = @cursor_stack_pointer = 0
1153
- elsif @cursor_stack_pointer >= @cursor_stack.length
1154
- return_pointer = @cursor_stack_pointer = @cursor_stack.length - 1
1155
- else
1156
- cursor_state = @cursor_stack[ @cursor_stack_pointer ]
1157
- if cursor_state
1158
- pitchView( cursor_state[ :top_line ] - @top_line, DONT_PITCH_CURSOR, DO_DISPLAY )
1159
- cursorTo( cursor_state[ :row ], cursor_state[ :col ] )
1160
- @diakonos.updateStatusLine
1161
- end
1162
- end
1163
-
1164
- [ return_pointer, @cursor_stack.size ]
1165
- end
1166
-
1167
- def tabExpandedColumn( col, row )
1168
- delta = 0
1169
- line = @lines[ row ]
1170
- for i in 0...col
1171
- if line[ i ] == TAB
1172
- delta += ( @tab_size - ( (i+delta) % @tab_size ) ) - 1
1173
- end
1174
- end
1175
- col + delta
1176
- end
1177
-
1178
- def cursorToEOF
1179
- cursorTo( @lines.length - 1, @lines[ -1 ].length, DO_DISPLAY )
1180
- end
1181
-
1182
- def cursorToBOL
1183
- row = @last_row
1184
- case @settings[ "bol_behaviour" ]
1185
- when BOL_ZERO
1186
- col = 0
1187
- when BOL_FIRST_CHAR
1188
- col = ( ( @lines[ row ] =~ /\S/ ) or 0 )
1189
- when BOL_ALT_ZERO
1190
- if @last_col == 0
1191
- col = ( @lines[ row ] =~ /\S/ )
1192
- else
1193
- col = 0
1194
- end
1195
- #when BOL_ALT_FIRST_CHAR
1196
- else
1197
- first_char_col = ( ( @lines[ row ] =~ /\S/ ) or 0 )
1198
- if @last_col == first_char_col
1199
- col = 0
1200
- else
1201
- col = first_char_col
1202
- end
1203
- end
1204
- cursorTo( row, col, DO_DISPLAY )
1205
- end
1206
-
1207
- def cursorToEOL
1208
- y = @win_main.cury
1209
- end_col = lineAt( y ).length
1210
- last_char_col = lineAt( y ).rstrip.length
1211
- case @settings[ 'eol_behaviour' ]
1212
- when EOL_END
1213
- col = end_col
1214
- when EOL_LAST_CHAR
1215
- col = last_char_col
1216
- when EOL_ALT_LAST_CHAR
1217
- if @last_col == last_char_col
1218
- col = end_col
1219
- else
1220
- col = last_char_col
1221
- end
1222
- else
1223
- if @last_col == end_col
1224
- col = last_char_col
1225
- else
1226
- col = end_col
1227
- end
1228
- end
1229
- cursorTo( @last_row, col, DO_DISPLAY )
1230
- end
1231
-
1232
- # Top of view
1233
- def cursorToTOV
1234
- cursorTo( rowOf( 0 ), @last_col, DO_DISPLAY )
1235
- end
1236
- # Bottom of view
1237
- def cursorToBOV
1238
- cursorTo( rowOf( 0 + @diakonos.main_window_height - 1 ), @last_col, DO_DISPLAY )
1239
- end
1240
-
1241
- # col and row are given relative to the buffer, not any window or screen.
1242
- # Returns true if the view changed positions.
1243
- def showCharacter( row, col )
1244
- old_top_line = @top_line
1245
- old_left_column = @left_column
1246
-
1247
- while row < @top_line + @settings[ "view.margin.y" ]
1248
- amount = (-1) * @settings[ "view.jump.y" ]
1249
- break if( pitchView( amount, DONT_PITCH_CURSOR, DONT_DISPLAY ) != amount )
1250
- end
1251
- while row > @top_line + @diakonos.main_window_height - 1 - @settings[ "view.margin.y" ]
1252
- amount = @settings[ "view.jump.y" ]
1253
- break if( pitchView( amount, DONT_PITCH_CURSOR, DONT_DISPLAY ) != amount )
1254
- end
1255
-
1256
- while col < @left_column + @settings[ "view.margin.x" ]
1257
- amount = (-1) * @settings[ "view.jump.x" ]
1258
- break if( panView( amount, DONT_DISPLAY ) != amount )
1259
- end
1260
- while col > @left_column + @diakonos.main_window_width - @settings[ "view.margin.x" ] - 2
1261
- amount = @settings[ "view.jump.x" ]
1262
- break if( panView( amount, DONT_DISPLAY ) != amount )
1263
- end
1264
-
1265
- @top_line != old_top_line or @left_column != old_left_column
1266
- end
1267
-
1268
- def setIndent( row, level, do_display = DO_DISPLAY )
1269
- @lines[ row ] =~ /^([\s#{@indent_ignore_charset}]*)(.*)$/
1270
- current_indent_text = ( $1 or "" )
1271
- rest = ( $2 or "" )
1272
- current_indent_text.gsub!( /\t/, ' ' * @tab_size )
1273
- indentation = @indent_size * [ level, 0 ].max
1274
- if current_indent_text.length >= indentation
1275
- indent_text = current_indent_text[ 0...indentation ]
1276
- else
1277
- indent_text = current_indent_text + " " * ( indentation - current_indent_text.length )
1278
- end
1279
- if @settings[ "lang.#{@language}.indent.using_tabs" ]
1280
- num_tabs = 0
1281
- indent_text.gsub!( / {#{@tab_size}}/ ) { |match|
1282
- num_tabs += 1
1283
- "\t"
1284
- }
1285
- indentation -= num_tabs * ( @tab_size - 1 )
1286
- end
1287
-
1288
- takeSnapshot( TYPING ) if do_display
1289
- @lines[ row ] = indent_text + rest
1290
- cursorTo( row, indentation ) if do_display
1291
- setModified
1292
- end
1293
-
1294
- def parsedIndent( row = @last_row, do_display = DO_DISPLAY )
1295
- if row == 0
1296
- level = 0
1297
- else
1298
- # Look upwards for the nearest line on which to base this line's indentation.
1299
- i = 1
1300
- while ( @lines[ row - i ] =~ /^[\s#{@indent_ignore_charset}]*$/ ) or
1301
- ( @lines[ row - i ] =~ @settings[ "lang.#{@language}.indent.ignore" ] )
1302
- i += 1
1303
- end
1304
- if row - i < 0
1305
- level = 0
1306
- else
1307
- prev_line = @lines[ row - i ]
1308
- level = prev_line.indentation_level( @indent_size, @indent_roundup, @tab_size, @indent_ignore_charset )
1309
-
1310
- line = @lines[ row ]
1311
- if @preventers
1312
- prev_line = prev_line.gsub( @preventers, "" )
1313
- line = line.gsub( @preventers, "" )
1314
- end
1315
-
1316
- indenter_index = ( prev_line =~ @indenters )
1317
- if indenter_index
1318
- level += 1
1319
- unindenter_index = (prev_line =~ @unindenters)
1320
- if unindenter_index and unindenter_index != indenter_index
1321
- level += -1
1322
- end
1323
- end
1324
- if line =~ @unindenters
1325
- level += -1
1326
- end
1327
- end
1328
- end
1329
-
1330
- setIndent( row, level, do_display )
1331
-
1332
- end
1333
-
1334
- def indent( row = @last_row, do_display = DO_DISPLAY )
1335
- level = @lines[ row ].indentation_level( @indent_size, @indent_roundup, @tab_size )
1336
- setIndent( row, level + 1, do_display )
1337
- end
1338
-
1339
- def unindent( row = @last_row, do_display = DO_DISPLAY )
1340
- level = @lines[ row ].indentation_level( @indent_size, @indent_roundup, @tab_size )
1341
- setIndent( row, level - 1, do_display )
1342
- end
1343
-
1344
- def anchorSelection( row = @last_row, col = @last_col, do_display = DO_DISPLAY )
1345
- @mark_anchor = ( @mark_anchor or Hash.new )
1346
- @mark_anchor[ "row" ] = row
1347
- @mark_anchor[ "col" ] = col
1348
- recordMarkStartAndEnd
1349
- @changing_selection = true
1350
- display if do_display
1351
- end
1352
-
1353
- def removeSelection( do_display = DO_DISPLAY )
1354
- return if selection_mark.nil?
1355
- @mark_anchor = nil
1356
- recordMarkStartAndEnd
1357
- @changing_selection = false
1358
- @last_finding = nil
1359
- display if do_display
1360
- end
1361
-
1362
- def toggleSelection
1363
- if @changing_selection
1364
- removeSelection
1365
- else
1366
- anchorSelection
1367
- end
1368
- end
1369
-
1370
- def copySelection
1371
- selected_text
1372
- end
1373
- def selected_text
1374
- selection = selection_mark
1375
- if selection.nil?
1376
- nil
1377
- elsif selection.start_row == selection.end_row
1378
- [ @lines[ selection.start_row ][ selection.start_col...selection.end_col ] ]
1379
- else
1380
- [ @lines[ selection.start_row ][ selection.start_col..-1 ] ] +
1381
- ( @lines[ (selection.start_row + 1) .. (selection.end_row - 1) ] or [] ) +
1382
- [ @lines[ selection.end_row ][ 0...selection.end_col ] ]
1383
- end
1384
- end
1385
- def selected_string
1386
- lines = selected_text
1387
- if lines
1388
- lines.join( "\n" )
1389
- else
1390
- nil
1391
- end
1392
- end
1393
-
1394
- def deleteSelection( do_display = DO_DISPLAY )
1395
- return if @text_marks[ SELECTION ].nil?
1396
-
1397
- takeSnapshot
1398
-
1399
- selection = @text_marks[ SELECTION ]
1400
- start_row = selection.start_row
1401
- start_col = selection.start_col
1402
- start_line = @lines[ start_row ]
1403
-
1404
- if selection.end_row == selection.start_row
1405
- @lines[ start_row ] = start_line[ 0...start_col ] + start_line[ selection.end_col..-1 ]
1406
- else
1407
- end_line = @lines[ selection.end_row ]
1408
- @lines[ start_row ] = start_line[ 0...start_col ] + end_line[ selection.end_col..-1 ]
1409
- @lines = @lines[ 0..start_row ] + @lines[ (selection.end_row + 1)..-1 ]
1410
- end
1411
-
1412
- cursorTo( start_row, start_col )
1413
- removeSelection( DONT_DISPLAY )
1414
- setModified( do_display )
1415
- end
1416
-
1417
- # text is an array of Strings, or a String with zero or more newlines ("\n")
1418
- def paste( text, do_parsed_indent = false )
1419
- return if text.nil?
1420
-
1421
- if not text.kind_of? Array
1422
- s = text.to_s
1423
- if s.include?( "\n" )
1424
- text = s.split( "\n", -1 )
1425
- else
1426
- text = [ s ]
1427
- end
1428
- end
1429
-
1430
- takeSnapshot
1431
-
1432
- deleteSelection( DONT_DISPLAY )
1433
-
1434
- row = @last_row
1435
- col = @last_col
1436
- line = @lines[ row ]
1437
- if text.length == 1
1438
- @lines[ row ] = line[ 0...col ] + text[ 0 ] + line[ col..-1 ]
1439
- if do_parsed_indent
1440
- parsedIndent row, DONT_DISPLAY
1441
- end
1442
- cursorTo( @last_row, @last_col + text[ 0 ].length )
1443
- elsif text.length > 1
1444
- @lines[ row ] = line[ 0...col ] + text[ 0 ]
1445
- @lines[ row + 1, 0 ] = text[ -1 ] + line[ col..-1 ]
1446
- @lines[ row + 1, 0 ] = text[ 1..-2 ]
1447
- new_row = @last_row + text.length - 1
1448
- if do_parsed_indent
1449
- ( row..new_row ).each do |r|
1450
- parsedIndent r, DONT_DISPLAY
1451
- end
1452
- end
1453
- cursorTo( new_row, columnOf( text[ -1 ].length ) )
1454
- end
1455
-
1456
- setModified
1457
- end
1458
-
1459
- # Takes an array of Regexps, which represents a user-provided regexp,
1460
- # split across newline characters. Once the first element is found,
1461
- # each successive element must match against lines following the first
1462
- # element.
1463
- def find( regexps, options = {} )
1464
- return if regexps.nil?
1465
- regexp = regexps[ 0 ]
1466
- return if regexp.nil? or regexp == //
1467
-
1468
- direction = options[ :direction ]
1469
- replacement = options[ :replacement ]
1470
- auto_choice = options[ :auto_choice ]
1471
- from_row = options[ :starting_row ] || @last_row
1472
- from_col = options[ :starting_col ] || @last_col
1473
-
1474
- if direction == :opposite
1475
- case @last_search_direction
1476
- when :up
1477
- direction = :down
1478
- else
1479
- direction = :up
1480
- end
1481
- end
1482
- @last_search_regexps = regexps
1483
- @last_search_direction = direction
1484
-
1485
- finding = nil
1486
- wrapped = false
1487
- match = nil
1488
-
1489
- catch :found do
1490
-
1491
- if direction == :down
1492
- # Check the current row first.
1493
-
1494
- if index = @lines[ from_row ].index( regexp, ( @last_finding ? @last_finding.start_col : from_col ) + 1 )
1495
- match = Regexp.last_match
1496
- found_text = match[ 0 ]
1497
- finding = Finding.new( from_row, index, from_row, index + found_text.length )
1498
- if finding.match( regexps, @lines )
1499
- throw :found
1500
- else
1501
- finding = nil
1502
- end
1503
- end
1504
-
1505
- # Check below the cursor.
1506
-
1507
- ( (from_row + 1)...@lines.length ).each do |i|
1508
- if index = @lines[ i ].index( regexp )
1509
- match = Regexp.last_match
1510
- found_text = match[ 0 ]
1511
- finding = Finding.new( i, index, i, index + found_text.length )
1512
- if finding.match( regexps, @lines )
1513
- throw :found
1514
- else
1515
- finding = nil
1516
- end
1517
- end
1518
- end
1519
-
1520
- # Wrap around.
1521
-
1522
- wrapped = true
1523
-
1524
- ( 0...from_row ).each do |i|
1525
- if index = @lines[ i ].index( regexp )
1526
- match = Regexp.last_match
1527
- found_text = match[ 0 ]
1528
- finding = Finding.new( i, index, i, index + found_text.length )
1529
- if finding.match( regexps, @lines )
1530
- throw :found
1531
- else
1532
- finding = nil
1533
- end
1534
- end
1535
- end
1536
-
1537
- # And finally, the other side of the current row.
1538
-
1539
- #if index = @lines[ from_row ].index( regexp, ( @last_finding ? @last_finding.start_col : from_col ) - 1 )
1540
- if index = @lines[ from_row ].index( regexp )
1541
- if index <= ( @last_finding ? @last_finding.start_col : from_col )
1542
- match = Regexp.last_match
1543
- found_text = match[ 0 ]
1544
- finding = Finding.new( from_row, index, from_row, index + found_text.length )
1545
- if finding.match( regexps, @lines )
1546
- throw :found
1547
- else
1548
- finding = nil
1549
- end
1550
- end
1551
- end
1552
-
1553
- elsif direction == :up
1554
- # Check the current row first.
1555
-
1556
- col_to_check = ( @last_finding ? @last_finding.end_col : from_col ) - 1
1557
- if ( col_to_check >= 0 ) and ( index = @lines[ from_row ][ 0...col_to_check ].rindex( regexp ) )
1558
- match = Regexp.last_match
1559
- found_text = match[ 0 ]
1560
- finding = Finding.new( from_row, index, from_row, index + found_text.length )
1561
- if finding.match( regexps, @lines )
1562
- throw :found
1563
- else
1564
- finding = nil
1565
- end
1566
- end
1567
-
1568
- # Check above the cursor.
1569
-
1570
- (from_row - 1).downto( 0 ) do |i|
1571
- if index = @lines[ i ].rindex( regexp )
1572
- match = Regexp.last_match
1573
- found_text = match[ 0 ]
1574
- finding = Finding.new( i, index, i, index + found_text.length )
1575
- if finding.match( regexps, @lines )
1576
- throw :found
1577
- else
1578
- finding = nil
1579
- end
1580
- end
1581
- end
1582
-
1583
- # Wrap around.
1584
-
1585
- wrapped = true
1586
-
1587
- (@lines.length - 1).downto(from_row + 1) do |i|
1588
- if index = @lines[ i ].rindex( regexp )
1589
- match = Regexp.last_match
1590
- found_text = match[ 0 ]
1591
- finding = Finding.new( i, index, i, index + found_text.length )
1592
- if finding.match( regexps, @lines )
1593
- throw :found
1594
- else
1595
- finding = nil
1596
- end
1597
- end
1598
- end
1599
-
1600
- # And finally, the other side of the current row.
1601
-
1602
- search_col = ( @last_finding ? @last_finding.start_col : from_col ) + 1
1603
- if index = @lines[ from_row ].rindex( regexp )
1604
- if index > search_col
1605
- match = Regexp.last_match
1606
- found_text = match[ 0 ]
1607
- finding = Finding.new( from_row, index, from_row, index + found_text.length )
1608
- if finding.match( regexps, @lines )
1609
- throw :found
1610
- else
1611
- finding = nil
1612
- end
1613
- end
1614
- end
1615
- end
1616
- end
1617
-
1618
- if finding
1619
- if wrapped and not options[ :quiet ]
1620
- @diakonos.setILine( "(search wrapped around BOF/EOF)" )
1621
- end
1622
-
1623
- removeSelection( DONT_DISPLAY )
1624
- @last_finding = finding
1625
- if @settings[ "found_cursor_start" ]
1626
- anchorSelection( finding.end_row, finding.end_col, DONT_DISPLAY )
1627
- cursorTo( finding.start_row, finding.start_col )
1628
- else
1629
- anchorSelection( finding.start_row, finding.start_col, DONT_DISPLAY )
1630
- cursorTo( finding.end_row, finding.end_col )
1631
- end
1632
-
1633
- @changing_selection = false
1634
-
1635
- if regexps.length == 1
1636
- @highlight_regexp = regexp
1637
- highlightMatches
1638
- else
1639
- clearMatches
1640
- end
1641
- display
1642
-
1643
- if replacement
1644
- # Substitute placeholders (e.g. \1) in str for the group matches of the last match.
1645
- actual_replacement = replacement.dup
1646
- actual_replacement.gsub!( /\\(\\|\d+)/ ) { |m|
1647
- ref = $1
1648
- if ref == "\\"
1649
- "\\"
1650
- else
1651
- match[ ref.to_i ]
1652
- end
1653
- }
1654
-
1655
- choice = auto_choice || @diakonos.getChoice(
1656
- "Replace?",
1657
- [ CHOICE_YES, CHOICE_NO, CHOICE_ALL, CHOICE_CANCEL, CHOICE_YES_AND_STOP ],
1658
- CHOICE_YES
1659
- )
1660
- case choice
1661
- when CHOICE_YES
1662
- paste [ actual_replacement ]
1663
- find( regexps, :direction => direction, :replacement => replacement )
1664
- when CHOICE_ALL
1665
- replaceAll( regexp, replacement )
1666
- when CHOICE_NO
1667
- find( regexps, :direction => direction, :replacement => replacement )
1668
- when CHOICE_CANCEL
1669
- # Do nothing further.
1670
- when CHOICE_YES_AND_STOP
1671
- paste [ actual_replacement ]
1672
- # Do nothing further.
1673
- end
1674
- end
1675
- else
1676
- removeSelection DONT_DISPLAY
1677
- clearMatches DO_DISPLAY
1678
- if not options[ :quiet ]
1679
- @diakonos.setILine "/#{regexp.source}/ not found."
1680
- end
1681
- end
1682
- end
1683
-
1684
- def replaceAll( regexp, replacement )
1685
- return if( regexp.nil? or replacement.nil? )
1686
-
1687
- @lines = @lines.collect { |line|
1688
- line.gsub( regexp, replacement )
1689
- }
1690
- setModified
1691
-
1692
- clearMatches
1693
-
1694
- display
1695
- end
1696
-
1697
- def highlightMatches( regexp = @highlight_regexp )
1698
- @highlight_regexp = regexp
1699
- return if @highlight_regexp.nil?
1700
- found_marks = @lines[ @top_line...(@top_line + @diakonos.main_window_height) ].grep_indices( @highlight_regexp ).collect do |line_index, start_col, end_col|
1701
- TextMark.new( @top_line + line_index, start_col, @top_line + line_index, end_col, @settings[ "lang.#{@language}.format.found" ] )
1702
- end
1703
- @text_marks = [ @text_marks[ 0 ] ] + found_marks
1704
- end
1705
-
1706
- def clearMatches( do_display = DONT_DISPLAY )
1707
- selection = @text_marks[ SELECTION ]
1708
- @text_marks = Array.new
1709
- @text_marks[ SELECTION ] = selection
1710
- @highlight_regexp = nil
1711
- display if do_display
1712
- end
1713
-
1714
- def findAgain( last_search_regexps, direction = @last_search_direction )
1715
- if @last_search_regexps.nil?
1716
- @last_search_regexps = last_search_regexps
1717
- end
1718
- if @last_search_regexps
1719
- find( @last_search_regexps, :direction => direction )
1720
- end
1721
- end
1722
-
1723
- def seek( regexp, direction = :down )
1724
- return if regexp.nil? or regexp == //
1725
-
1726
- found_row = nil
1727
- found_col = nil
1728
- found_text = nil
1729
- wrapped = false
1730
-
1731
- catch :found do
1732
- if direction == :down
1733
- # Check the current row first.
1734
-
1735
- index, match_text = @lines[ @last_row ].group_index( regexp, @last_col + 1 )
1736
- if index
1737
- found_row = @last_row
1738
- found_col = index
1739
- found_text = match_text
1740
- throw :found
1741
- end
1742
-
1743
- # Check below the cursor.
1744
-
1745
- ( (@last_row + 1)...@lines.length ).each do |i|
1746
- index, match_text = @lines[ i ].group_index( regexp )
1747
- if index
1748
- found_row = i
1749
- found_col = index
1750
- found_text = match_text
1751
- throw :found
1752
- end
1753
- end
1754
-
1755
- else
1756
- # Check the current row first.
1757
-
1758
- #col_to_check = ( @last_found_col or @last_col ) - 1
1759
- col_to_check = @last_col - 1
1760
- if col_to_check >= 0
1761
- index, match_text = @lines[ @last_row ].group_rindex( regexp, col_to_check )
1762
- if index
1763
- found_row = @last_row
1764
- found_col = index
1765
- found_text = match_text
1766
- throw :found
1767
- end
1768
- end
1769
-
1770
- # Check above the cursor.
1771
-
1772
- (@last_row - 1).downto( 0 ) do |i|
1773
- index, match_text = @lines[ i ].group_rindex( regexp )
1774
- if index
1775
- found_row = i
1776
- found_col = index
1777
- found_text = match_text
1778
- throw :found
1779
- end
1780
- end
1781
- end
1782
- end
1783
-
1784
- if found_text
1785
- #@last_found_row = found_row
1786
- #@last_found_col = found_col
1787
- cursorTo( found_row, found_col )
1788
-
1789
- display
1790
- end
1791
- end
1792
-
1793
- # Returns an Array of results, where each result is a String usually
1794
- # containing \n's due to context
1795
- def grep( regexp_source )
1796
- ::Diakonos.grep_array(
1797
- Regexp.new( regexp_source ),
1798
- @lines,
1799
- @diakonos.settings[ 'grep.context' ],
1800
- "#{File.basename( @name )}:",
1801
- @key
1802
- )
1803
- end
1804
-
1805
- def setModified( do_display = DO_DISPLAY )
1806
- if @read_only
1807
- @diakonos.setILine "Warning: Modifying a read-only file."
1808
- end
1809
-
1810
- fmod = false
1811
- if not @modified
1812
- @modified = true
1813
- fmod = file_modified?
1814
- end
1815
-
1816
- reverted = false
1817
- if fmod
1818
- reverted = @diakonos.revert( "File has been altered externally. Load on-disk version?" )
1819
- end
1820
-
1821
- if not reverted
1822
- clearMatches
1823
- if do_display
1824
- @diakonos.updateStatusLine
1825
- display
1826
- end
1827
- end
1828
- end
1829
-
1830
- # Check if the file which is being edited has been modified since
1831
- # the last time we checked it; return true if so, false otherwise.
1832
- def file_modified?
1833
- modified = false
1834
-
1835
- if @name
1836
- begin
1837
- mtime = File.mtime( @name )
1838
-
1839
- if mtime > @last_modification_check
1840
- modified = true
1841
- @last_modification_check = mtime
1842
- end
1843
- rescue Errno::ENOENT
1844
- # Ignore if file doesn't exist
1845
- end
1846
- end
1847
-
1848
- modified
1849
- end
1850
-
1851
- # Compares MD5 sums of buffer and actual file on disk.
1852
- # Returns true if there is no file on disk.
1853
- def file_different?
1854
- if @name
1855
- Digest::MD5.hexdigest(
1856
- @lines.join( "\n" )
1857
- ) != Digest::MD5.hexdigest(
1858
- File.read( @name )
1859
- )
1860
- else
1861
- true
1862
- end
1863
- end
1864
-
1865
- def takeSnapshot( typing = false )
1866
- take_snapshot = false
1867
- if @typing != typing
1868
- @typing = typing
1869
- # If we just started typing, take a snapshot, but don't continue
1870
- # taking snapshots for every keystroke
1871
- if typing
1872
- take_snapshot = true
1873
- end
1874
- end
1875
- if not @typing
1876
- take_snapshot = true
1877
- end
1878
-
1879
- if take_snapshot
1880
- undo_size = 0
1881
- @buffer_states[ 1..-1 ].each do |state|
1882
- undo_size += state.length
1883
- end
1884
- while ( ( undo_size + @lines.length ) >= @settings[ "max_undo_lines" ] ) and @buffer_states.length > 1
1885
- @cursor_states.pop
1886
- popped_state = @buffer_states.pop
1887
- undo_size = undo_size - popped_state.length
1888
- end
1889
- if @current_buffer_state > 0
1890
- @buffer_states.unshift @lines.deep_clone
1891
- @cursor_states.unshift [ @last_row, @last_col ]
1892
- end
1893
- @buffer_states.unshift @lines.deep_clone
1894
- @cursor_states.unshift [ @last_row, @last_col ]
1895
- @current_buffer_state = 0
1896
- @lines = @buffer_states[ @current_buffer_state ]
1897
- end
1898
- end
1899
-
1900
- def undo
1901
- if @current_buffer_state < @buffer_states.length - 1
1902
- @current_buffer_state += 1
1903
- @lines = @buffer_states[ @current_buffer_state ]
1904
- cursorTo( @cursor_states[ @current_buffer_state - 1 ][ 0 ], @cursor_states[ @current_buffer_state - 1 ][ 1 ] )
1905
- @diakonos.setILine "Undo level: #{@current_buffer_state} of #{@buffer_states.length - 1}"
1906
- setModified
1907
- end
1908
- end
1909
-
1910
- # Since redo is a Ruby keyword...
1911
- def unundo
1912
- if @current_buffer_state > 0
1913
- @current_buffer_state += -1
1914
- @lines = @buffer_states[ @current_buffer_state ]
1915
- cursorTo( @cursor_states[ @current_buffer_state ][ 0 ], @cursor_states[ @current_buffer_state ][ 1 ] )
1916
- @diakonos.setILine "Undo level: #{@current_buffer_state} of #{@buffer_states.length - 1}"
1917
- setModified
1918
- end
1919
- end
1920
-
1921
- def wrap_paragraph
1922
- start_row = end_row = @last_row
1923
- until start_row == 0 || @lines[ start_row - 1 ].strip == ''
1924
- start_row -= 1
1925
- end
1926
- until end_row == @lines.size || @lines[ end_row ].strip == ''
1927
- end_row += 1
1928
- end
1929
-
1930
- lines = []
1931
- line = ''
1932
- words = @lines[ start_row...end_row ].join( ' ' ).scan( /\S+/ )
1933
- words.each do |word|
1934
- if word =~ /^[a-z']+[.!?]$/
1935
- word = "#{word} "
1936
- end
1937
- if line.length + word.length + 1 > ( @settings[ "lang.#{@language}.wrap_margin" ] || 80 )
1938
- lines << line.strip
1939
- line = ''
1940
- end
1941
- line << " #{word}"
1942
- end
1943
- line.strip!
1944
- if not line.empty?
1945
- lines << line
1946
- end
1947
- if @lines[ start_row...end_row ] != lines
1948
- @lines[ start_row...end_row ] = lines
1949
- setModified
1950
- end
1951
- end
1952
-
1953
- def goToLine( line = nil, column = nil )
1954
- cursorTo( line || @last_row, column || 0, DO_DISPLAY )
1955
- end
1956
-
1957
- def goToNextBookmark
1958
- cur_pos = Bookmark.new( self, @last_row, @last_col )
1959
- next_bm = @bookmarks.find do |bm|
1960
- bm > cur_pos
1961
- end
1962
- if next_bm
1963
- cursorTo( next_bm.row, next_bm.col, DO_DISPLAY )
1964
- end
1965
- end
1966
-
1967
- def goToPreviousBookmark
1968
- cur_pos = Bookmark.new( self, @last_row, @last_col )
1969
- # There's no reverse_find method, so, we have to do this manually.
1970
- prev = nil
1971
- @bookmarks.reverse_each do |bm|
1972
- if bm < cur_pos
1973
- prev = bm
1974
- break
1975
- end
1976
- end
1977
- if prev
1978
- cursorTo( prev.row, prev.col, DO_DISPLAY )
1979
- end
1980
- end
1981
-
1982
- def toggleBookmark
1983
- bookmark = Bookmark.new( self, @last_row, @last_col )
1984
- existing = @bookmarks.find do |bm|
1985
- bm == bookmark
1986
- end
1987
- if existing
1988
- @bookmarks.delete existing
1989
- @diakonos.setILine "Bookmark #{existing.to_s} deleted."
1990
- else
1991
- @bookmarks.push bookmark
1992
- @bookmarks.sort
1993
- @diakonos.setILine "Bookmark #{bookmark.to_s} set."
1994
- end
1995
- end
1996
-
1997
- def context
1998
- retval = Array.new
1999
- row = @last_row
2000
- clevel = @lines[ row ].indentation_level( @indent_size, @indent_roundup, @tab_size, @indent_ignore_charset )
2001
- while row > 0 and clevel < 0
2002
- row = row - 1
2003
- clevel = @lines[ row ].indentation_level( @indent_size, @indent_roundup, @tab_size, @indent_ignore_charset )
2004
- end
2005
- clevel = 0 if clevel < 0
2006
- while row > 0
2007
- row = row - 1
2008
- line = @lines[ row ]
2009
- if line !~ @settings[ "lang.#{@language}.context.ignore" ]
2010
- level = line.indentation_level( @indent_size, @indent_roundup, @tab_size, @indent_ignore_charset )
2011
- if level < clevel and level > -1
2012
- retval.unshift line
2013
- clevel = level
2014
- break if clevel == 0
2015
- end
2016
- end
2017
- end
2018
- retval
2019
- end
2020
-
2021
- def setType( type )
2022
- if type
2023
- configure( type )
2024
- display
2025
- true
2026
- end
2027
- end
2028
-
2029
- def wordUnderCursor
2030
- word = nil
2031
-
2032
- @lines[ @last_row ].scan( /\w+/ ) do |match_text|
2033
- last_match = Regexp.last_match
2034
- if last_match.begin( 0 ) <= @last_col and @last_col < last_match.end( 0 )
2035
- word = match_text
2036
- break
2037
- end
2038
- end
2039
-
2040
- word
2041
- end
2042
- end
2043
-
2044
- end