diakonos 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,10 +6,10 @@ module Enumerable
6
6
  element.scan( regexp ) do |match_text|
7
7
  match = Regexp.last_match
8
8
  strindex = match.begin( 0 )
9
- array.push [ index, strindex, strindex + match_text.length ]
9
+ array.push [ index, strindex, strindex + match[ 0 ].length ]
10
10
  end
11
11
  end
12
- return array
12
+ array
13
13
  end
14
14
  end
15
15
 
@@ -1,13 +1,17 @@
1
1
  require 'diakonos/keycode'
2
2
 
3
3
  class Fixnum
4
- include Diakonos::KeyCode
5
-
6
- def fit( min, max )
7
- return self if max < min
8
- return min if self < min
9
- return max if self > max
10
- return self
11
- end
4
+ include Diakonos::KeyCode
5
+
6
+ def fit( min, max )
7
+ return self if max < min
8
+ return min if self < min
9
+ return max if self > max
10
+ return self
11
+ end
12
+
13
+ def ord
14
+ self
15
+ end
12
16
  end
13
17
 
@@ -0,0 +1,1420 @@
1
+ module Diakonos
2
+ module Functions
3
+ def addNamedBookmark( name_ = nil )
4
+ if name_.nil?
5
+ name = getUserInput "Bookmark name: "
6
+ else
7
+ name = name_
8
+ end
9
+
10
+ if name
11
+ @bookmarks[ name ] = Bookmark.new( @current_buffer, @current_buffer.currentRow, @current_buffer.currentColumn, name )
12
+ setILine "Added bookmark #{@bookmarks[ name ].to_s}."
13
+ end
14
+ end
15
+
16
+ def anchorSelection
17
+ @current_buffer.anchorSelection
18
+ updateStatusLine
19
+ end
20
+
21
+ def backspace
22
+ delete if( @current_buffer.changing_selection or cursorLeft( Buffer::STILL_TYPING ) )
23
+ end
24
+
25
+ def carriageReturn
26
+ @current_buffer.carriageReturn
27
+ @current_buffer.deleteSelection
28
+ end
29
+
30
+ def changeSessionSetting( key_ = nil, value = nil, do_redraw = DONT_REDRAW )
31
+ if key_.nil?
32
+ key = getUserInput( "Setting: " )
33
+ else
34
+ key = key_
35
+ end
36
+
37
+ if key
38
+ if value.nil?
39
+ value = getUserInput( "Value: " )
40
+ end
41
+ case @settings[ key ]
42
+ when String
43
+ value = value.to_s
44
+ when Fixnum
45
+ value = value.to_i
46
+ when TrueClass, FalseClass
47
+ value = value.to_b
48
+ end
49
+ @session[ 'settings' ][ key ] = value
50
+ redraw if do_redraw
51
+ setILine "#{key} = #{value}"
52
+ end
53
+ end
54
+
55
+ def clearMatches
56
+ @current_buffer.clearMatches Buffer::DO_DISPLAY
57
+ end
58
+
59
+ def close_code
60
+ @current_buffer.close_code
61
+ end
62
+
63
+ # Returns the choice the user made, or nil if the user was not prompted to choose.
64
+ def closeFile( buffer = @current_buffer, to_all = nil )
65
+ return nil if buffer.nil?
66
+
67
+ choice = nil
68
+ if @buffers.has_value?( buffer )
69
+ do_closure = true
70
+
71
+ if buffer.modified?
72
+ if not buffer.read_only
73
+ if to_all.nil?
74
+ choices = [ CHOICE_YES, CHOICE_NO, CHOICE_CANCEL ]
75
+ if @quitting
76
+ choices.concat [ CHOICE_YES_TO_ALL, CHOICE_NO_TO_ALL ]
77
+ end
78
+ choice = getChoice(
79
+ "Save changes to #{buffer.nice_name}?",
80
+ choices,
81
+ CHOICE_CANCEL
82
+ )
83
+ else
84
+ choice = to_all
85
+ end
86
+ case choice
87
+ when CHOICE_YES, CHOICE_YES_TO_ALL
88
+ do_closure = true
89
+ saveFile( buffer )
90
+ when CHOICE_NO, CHOICE_NO_TO_ALL
91
+ do_closure = true
92
+ when CHOICE_CANCEL
93
+ do_closure = false
94
+ end
95
+ end
96
+ end
97
+
98
+ if do_closure
99
+ del_buffer_key = nil
100
+ previous_buffer = nil
101
+ to_switch_to = nil
102
+ switching = false
103
+
104
+ # Search the buffer hash for the buffer we want to delete,
105
+ # and mark the one we will switch to after deletion.
106
+ @buffers.each do |buffer_key,buf|
107
+ if switching
108
+ to_switch_to = buf
109
+ break
110
+ end
111
+ if buf == buffer
112
+ del_buffer_key = buffer_key
113
+ switching = true
114
+ next
115
+ end
116
+ previous_buffer = buf
117
+ end
118
+
119
+ buf = nil
120
+ while(
121
+ ( not @buffer_stack.empty? ) and
122
+ ( not @buffers.values.include?( buf ) ) or
123
+ ( @buffers.key( buf ) == del_buffer_key )
124
+ ) do
125
+ buf = @buffer_stack.pop
126
+ end
127
+ if @buffers.values.include?( buf )
128
+ to_switch_to = buf
129
+ end
130
+
131
+ if to_switch_to
132
+ switchTo( to_switch_to )
133
+ elsif previous_buffer
134
+ switchTo( previous_buffer )
135
+ else
136
+ # No buffers left. Open a new blank one.
137
+ openFile
138
+ end
139
+
140
+ @buffers.delete del_buffer_key
141
+ save_session
142
+
143
+ updateStatusLine
144
+ updateContextLine
145
+ end
146
+ else
147
+ log "No such buffer: #{buffer.name}"
148
+ end
149
+
150
+ choice
151
+ end
152
+
153
+ def collapseWhitespace
154
+ @current_buffer.collapseWhitespace
155
+ end
156
+
157
+ def columnize( delimiter = nil, num_spaces_padding = 0 )
158
+ if delimiter.nil?
159
+ delimiter = getUserInput(
160
+ "Column delimiter (regexp): ",
161
+ @rlh_general,
162
+ @settings[ "lang.#{@current_buffer.original_language}.column_delimiters" ] || ''
163
+ )
164
+ end
165
+ if delimiter and num_spaces_padding
166
+ @current_buffer.columnize Regexp.new( delimiter ), num_spaces_padding
167
+ end
168
+ end
169
+
170
+ def comment_out
171
+ @current_buffer.comment_out
172
+ end
173
+
174
+ def copySelection
175
+ @clipboard.addClip @current_buffer.copySelection
176
+ removeSelection
177
+ end
178
+
179
+ def copy_selection_to_klipper
180
+ if send_to_klipper( @current_buffer.selected_text )
181
+ removeSelection
182
+ end
183
+ end
184
+
185
+ # Returns true iff the cursor changed positions
186
+ def cursorDown
187
+ @current_buffer.cursorTo( @current_buffer.last_row + 1, @current_buffer.last_col, Buffer::DO_DISPLAY, Buffer::STOPPED_TYPING, DONT_ADJUST_ROW )
188
+ end
189
+
190
+ # Returns true iff the cursor changed positions
191
+ def cursorLeft( stopped_typing = Buffer::STOPPED_TYPING )
192
+ @current_buffer.cursorTo( @current_buffer.last_row, @current_buffer.last_col - 1, Buffer::DO_DISPLAY, stopped_typing )
193
+ end
194
+
195
+ def cursorRight( stopped_typing = Buffer::STOPPED_TYPING, amount = 1 )
196
+ @current_buffer.cursorTo( @current_buffer.last_row, @current_buffer.last_col + amount, Buffer::DO_DISPLAY, stopped_typing )
197
+ end
198
+
199
+ # Returns true iff the cursor changed positions
200
+ def cursorUp
201
+ @current_buffer.cursorTo( @current_buffer.last_row - 1, @current_buffer.last_col, Buffer::DO_DISPLAY, Buffer::STOPPED_TYPING, DONT_ADJUST_ROW )
202
+ end
203
+
204
+ def cursorBOF
205
+ @current_buffer.cursorTo( 0, 0, Buffer::DO_DISPLAY )
206
+ end
207
+
208
+ def cursorBOL
209
+ @current_buffer.cursorToBOL
210
+ end
211
+
212
+ def cursorEOL
213
+ @current_buffer.cursorToEOL
214
+ end
215
+
216
+ def cursorEOF
217
+ @current_buffer.cursorToEOF
218
+ end
219
+
220
+ # Top of view
221
+ def cursorTOV
222
+ @current_buffer.cursorToTOV
223
+ end
224
+
225
+ # Bottom of view
226
+ def cursorBOV
227
+ @current_buffer.cursorToBOV
228
+ end
229
+
230
+ def cursorReturn( dir_str = "backward" )
231
+ stack_pointer, stack_size = @current_buffer.cursorReturn( dir_str.toDirection( :backward ) )
232
+ setILine( "Location: #{stack_pointer+1}/#{stack_size}" )
233
+ end
234
+
235
+ def cutSelection
236
+ delete if @clipboard.addClip( @current_buffer.copySelection )
237
+ end
238
+
239
+ def cut_selection_to_klipper
240
+ if send_to_klipper( @current_buffer.selected_text )
241
+ delete
242
+ end
243
+ end
244
+
245
+ def delete
246
+ @current_buffer.delete
247
+ end
248
+
249
+ def delete_and_store_line_to_klipper
250
+ removed_text = @current_buffer.deleteLine
251
+ if removed_text
252
+ if @last_commands[ -1 ] =~ /^delete_and_store_line_to_klipper/
253
+ clip_filename = write_to_clip_file( removed_text << "\n" )
254
+ `clipping="$(dcop klipper klipper getClipboardContents)\n$(cat #{clip_filename};printf "_")"; dcop klipper klipper setClipboardContents "${clipping%_}"`
255
+ else
256
+ send_to_klipper [ removed_text, "" ]
257
+ end
258
+ end
259
+ end
260
+
261
+ def deleteAndStoreLine
262
+ removed_text = @current_buffer.deleteLine
263
+ if removed_text
264
+ clip = [ removed_text, "" ]
265
+ if @last_commands[ -1 ] =~ /^deleteAndStoreLine/
266
+ @clipboard.appendToClip clip
267
+ else
268
+ @clipboard.addClip clip
269
+ end
270
+ end
271
+ end
272
+
273
+ def delete_line_to_klipper
274
+ removed_text = @current_buffer.deleteLine
275
+ if removed_text
276
+ send_to_klipper [ removed_text, "" ]
277
+ end
278
+ end
279
+
280
+ def deleteLine
281
+ removed_text = @current_buffer.deleteLine
282
+ @clipboard.addClip( [ removed_text, "" ] ) if removed_text
283
+ end
284
+
285
+ def delete_to( char = nil )
286
+ if char.nil?
287
+ setILine "Type character to delete to..."
288
+ char = @win_main.getch
289
+ setILine
290
+ end
291
+ if char
292
+ removed_text = @current_buffer.delete_to char
293
+ if removed_text
294
+ @clipboard.addClip removed_text
295
+ else
296
+ setILine "'#{char}' not found."
297
+ end
298
+ end
299
+ end
300
+
301
+ def delete_to_and_from( char = nil )
302
+ if char.nil?
303
+ setILine "Type character to delete to and from..."
304
+ char = @win_main.getch
305
+ setILine
306
+ end
307
+ if char
308
+ removed_text = @current_buffer.delete_to_and_from char
309
+ if removed_text
310
+ @clipboard.addClip removed_text
311
+ else
312
+ setILine "'#{char}' not found."
313
+ end
314
+ end
315
+ end
316
+
317
+ def delete_to_EOL_to_klipper
318
+ removed_text = @current_buffer.deleteToEOL
319
+ if removed_text
320
+ send_to_klipper removed_text
321
+ end
322
+ end
323
+
324
+ def deleteToEOL
325
+ removed_text = @current_buffer.deleteToEOL
326
+ @clipboard.addClip( removed_text ) if removed_text
327
+ end
328
+
329
+ def evaluate( code_ = nil )
330
+ if code_.nil?
331
+ if @current_buffer.changing_selection
332
+ selected_text = @current_buffer.copySelection[ 0 ]
333
+ end
334
+ code = getUserInput( "Ruby code: ", @rlh_general, ( selected_text or "" ), ::Diakonos::Functions.public_instance_methods )
335
+ else
336
+ code = code_
337
+ end
338
+
339
+ if code
340
+ begin
341
+ eval code
342
+ rescue Exception => e
343
+ showException(
344
+ e,
345
+ [
346
+ "The code given to evaluate has a syntax error.",
347
+ "The code given to evaluate refers to a Diakonos command which does not exist, or is misspelled.",
348
+ "The code given to evaluate refers to a Diakonos command with missing arguments.",
349
+ "The code given to evaluate refers to a variable or method which does not exist.",
350
+ ]
351
+ )
352
+ end
353
+ end
354
+ end
355
+
356
+ def find( dir_str = "down", case_sensitive = CASE_INSENSITIVE, regexp_source_ = nil, replacement = nil )
357
+ direction = dir_str.toDirection
358
+ if regexp_source_.nil?
359
+ if @current_buffer.changing_selection
360
+ selected_text = @current_buffer.copySelection[ 0 ]
361
+ end
362
+ starting_row, starting_col = @current_buffer.last_row, @current_buffer.last_col
363
+
364
+ regexp_source = getUserInput(
365
+ "Search regexp: ",
366
+ @rlh_search,
367
+ ( selected_text or "" )
368
+ ) { |input|
369
+ if input.length > 1
370
+ find_ direction, case_sensitive, input, nil, starting_row, starting_col, QUIET
371
+ else
372
+ @current_buffer.removeSelection Buffer::DONT_DISPLAY
373
+ @current_buffer.clearMatches Buffer::DO_DISPLAY
374
+ end
375
+ }
376
+ else
377
+ regexp_source = regexp_source_
378
+ end
379
+
380
+ if regexp_source
381
+ find_ direction, case_sensitive, regexp_source, replacement, starting_row, starting_col, NOISY
382
+ elsif starting_row and starting_col
383
+ @current_buffer.clearMatches
384
+ if @settings[ 'find.return_on_abort' ]
385
+ @current_buffer.cursorTo starting_row, starting_col
386
+ end
387
+ end
388
+ end
389
+
390
+ def findAgain( dir_str = nil )
391
+ if dir_str
392
+ direction = dir_str.toDirection
393
+ @current_buffer.findAgain( @last_search_regexps, direction )
394
+ else
395
+ @current_buffer.findAgain( @last_search_regexps )
396
+ end
397
+ end
398
+
399
+ def findAndReplace
400
+ searchAndReplace
401
+ end
402
+
403
+ def findExact( dir_str = "down", search_term_ = nil )
404
+ if search_term_.nil?
405
+ if @current_buffer.changing_selection
406
+ selected_text = @current_buffer.copySelection[ 0 ]
407
+ end
408
+ search_term = getUserInput( "Search for: ", @rlh_search, ( selected_text or "" ) )
409
+ else
410
+ search_term = search_term_
411
+ end
412
+ if search_term
413
+ direction = dir_str.toDirection
414
+ regexp = [ Regexp.new( Regexp.escape( search_term ) ) ]
415
+ @current_buffer.find( regexp, :direction => direction )
416
+ @last_search_regexps = regexp
417
+ end
418
+ end
419
+
420
+ def goToLineAsk
421
+ input = getUserInput( "Go to [line number|+lines][,column number]: " )
422
+ if input
423
+ row = nil
424
+
425
+ if input =~ /([+-]\d+)/
426
+ row = @current_buffer.last_row + $1.to_i
427
+ col = @current_buffer.last_col
428
+ else
429
+ input = input.split( /\D+/ ).collect { |n| n.to_i }
430
+ if input.size > 0
431
+ if input[ 0 ] == 0
432
+ row = nil
433
+ else
434
+ row = input[ 0 ] - 1
435
+ end
436
+ if input[ 1 ]
437
+ col = input[ 1 ] - 1
438
+ end
439
+ end
440
+ end
441
+
442
+ if row
443
+ @current_buffer.goToLine( row, col )
444
+ end
445
+ end
446
+ end
447
+
448
+ def goToNamedBookmark( name_ = nil )
449
+ if name_.nil?
450
+ name = getUserInput "Bookmark name: "
451
+ else
452
+ name = name_
453
+ end
454
+
455
+ if name
456
+ bookmark = @bookmarks[ name ]
457
+ if bookmark
458
+ switchTo( bookmark.buffer )
459
+ bookmark.buffer.cursorTo( bookmark.row, bookmark.col, Buffer::DO_DISPLAY )
460
+ else
461
+ setILine "No bookmark named '#{name}'."
462
+ end
463
+ end
464
+ end
465
+
466
+ def goToNextBookmark
467
+ @current_buffer.goToNextBookmark
468
+ end
469
+
470
+ def goToPreviousBookmark
471
+ @current_buffer.goToPreviousBookmark
472
+ end
473
+
474
+ def goToTag( tag_ = nil )
475
+ loadTags
476
+
477
+ # If necessary, prompt for tag name.
478
+
479
+ if tag_.nil?
480
+ if @current_buffer.changing_selection
481
+ selected_text = @current_buffer.copySelection[ 0 ]
482
+ end
483
+ tag_name = getUserInput( "Tag name: ", @rlh_general, ( selected_text or "" ), @tags.keys )
484
+ else
485
+ tag_name = tag_
486
+ end
487
+
488
+ tag_array = @tags[ tag_name ]
489
+ if tag_array and tag_array.length > 0
490
+ if i = tag_array.index( @last_tag )
491
+ tag = ( tag_array[ i + 1 ] or tag_array[ 0 ] )
492
+ else
493
+ tag = tag_array[ 0 ]
494
+ end
495
+ @last_tag = tag
496
+ @tag_stack.push [ @current_buffer.name, @current_buffer.last_row, @current_buffer.last_col ]
497
+ if switchTo( @buffers[ tag.file ] )
498
+ #@current_buffer.goToLine( 0 )
499
+ else
500
+ openFile( tag.file )
501
+ end
502
+ line_number = tag.command.to_i
503
+ if line_number > 0
504
+ @current_buffer.goToLine( line_number - 1 )
505
+ else
506
+ find( "down", CASE_SENSITIVE, tag.command )
507
+ end
508
+ elsif tag_name
509
+ setILine "No such tag: '#{tag_name}'"
510
+ end
511
+ end
512
+
513
+ def goToTagUnderCursor
514
+ goToTag @current_buffer.wordUnderCursor
515
+ end
516
+
517
+ def grep( regexp_source = nil )
518
+ grep_( regexp_source, @current_buffer )
519
+ end
520
+
521
+ def grep_buffers( regexp_source = nil )
522
+ grep_( regexp_source, *@buffers.values )
523
+ end
524
+
525
+ def grep_session_dir( regexp_source = nil )
526
+ grep_dir regexp_source, @session[ 'dir' ]
527
+ end
528
+
529
+ def grep_dir( regexp_source = nil, dir = nil )
530
+ if dir.nil?
531
+ dir = getUserInput( "Grep directory: ", @rlh_files, @session[ 'dir' ], nil, DONT_COMPLETE, :accept_dirs )
532
+ return if dir.nil?
533
+ end
534
+ dir = File.expand_path( dir )
535
+
536
+ original_buffer = @current_buffer
537
+ if @current_buffer.changing_selection
538
+ selected_text = @current_buffer.copySelection[ 0 ]
539
+ end
540
+ starting_row, starting_col = @current_buffer.last_row, @current_buffer.last_col
541
+
542
+ selected = getUserInput(
543
+ "Grep regexp: ",
544
+ @rlh_search,
545
+ regexp_source || selected_text || ""
546
+ ) { |input|
547
+ next if input.length < 2
548
+ escaped_input = input.gsub( /'/ ) { "\\047" }
549
+ matching_files = `egrep '#{escaped_input}' -rniIl #{dir}`.split( /\n/ )
550
+
551
+ grep_results = matching_files.map { |f|
552
+ ::Diakonos.grep_array(
553
+ Regexp.new( input ),
554
+ File.read( f ).split( /\n/ ),
555
+ settings[ 'grep.context' ],
556
+ "#{File.basename( f )}:",
557
+ f
558
+ )
559
+ }.flatten
560
+ if settings[ 'grep.context' ] == 0
561
+ join_str = "\n"
562
+ else
563
+ join_str = "\n---\n"
564
+ end
565
+ with_list_file do |list|
566
+ list.puts grep_results.join( join_str )
567
+ end
568
+
569
+ list_buffer = openListBuffer
570
+ regexp = nil
571
+ begin
572
+ list_buffer.highlightMatches Regexp.new( input )
573
+ rescue RegexpError => e
574
+ # ignore
575
+ end
576
+ list_buffer.display
577
+ }
578
+
579
+ if selected
580
+ spl = selected.split( "| " )
581
+ if spl.size > 1
582
+ openFile spl[ -1 ]
583
+ end
584
+ else
585
+ original_buffer.cursorTo starting_row, starting_col
586
+ end
587
+ end
588
+
589
+ def help( prefill = '' )
590
+ if ! File.exist?( @help_dir ) || Dir[ "#{@help_dir}/*" ].size == 0
591
+ setILine 'There are no help files installed.'
592
+ return
593
+ end
594
+
595
+ open_help_buffer
596
+ matching_docs = nil
597
+
598
+ selected = getUserInput(
599
+ "Search terms: ",
600
+ @rlh_help,
601
+ prefill,
602
+ @help_tags
603
+ ) { |input|
604
+ next if input.length < 3 and input[ 0..0 ] != '/'
605
+
606
+ matching_docs = matching_help_documents( input )
607
+ with_list_file do |list|
608
+ list.puts matching_docs.join( "\n" )
609
+ end
610
+
611
+ openListBuffer
612
+ }
613
+
614
+ close_help_buffer
615
+
616
+ case selected
617
+ when /\|/
618
+ open_help_document selected
619
+ when nil
620
+ # Help search aborted; do nothing
621
+ else
622
+ # Not a selected help document
623
+ if matching_docs.nil? or matching_docs.empty?
624
+ matching_docs = matching_help_documents( selected )
625
+ end
626
+
627
+ case matching_docs.size
628
+ when 1
629
+ open_help_document matching_docs[ 0 ]
630
+ when 0
631
+ File.open( @error_filename, 'w' ) do |f|
632
+ f.puts "There were no help documents matching your search."
633
+ f.puts "(#{selected.strip})"
634
+ end
635
+ error_file = openFile @error_filename
636
+
637
+ choice = getChoice(
638
+ "Send your search terms to purepistos.net to help improve Diakonos?",
639
+ [ CHOICE_YES, CHOICE_NO ]
640
+ )
641
+ case choice
642
+ when CHOICE_YES
643
+ require 'net/http'
644
+ require 'uri'
645
+
646
+ res = Net::HTTP.post_form(
647
+ URI.parse( 'http://dh.purepistos.net/' ),
648
+ { 'q' => selected }
649
+ )
650
+ # TODO: let them choose "never" and "always"
651
+ end
652
+
653
+ closeFile error_file
654
+ else
655
+ help selected
656
+ end
657
+ end
658
+ end
659
+
660
+ def indent
661
+ if( @current_buffer.changing_selection )
662
+ @do_display = false
663
+ mark = @current_buffer.selection_mark
664
+ if mark.end_col > 0
665
+ end_row = mark.end_row
666
+ else
667
+ end_row = mark.end_row - 1
668
+ end
669
+ (mark.start_row..end_row).each do |row|
670
+ @current_buffer.indent row, Buffer::DONT_DISPLAY
671
+ end
672
+ @do_display = true
673
+ @current_buffer.display
674
+ else
675
+ @current_buffer.indent
676
+ end
677
+ end
678
+
679
+ def insertSpaces( num_spaces )
680
+ if num_spaces > 0
681
+ @current_buffer.deleteSelection
682
+ @current_buffer.insertString( " " * num_spaces )
683
+ cursorRight( Buffer::STILL_TYPING, num_spaces )
684
+ end
685
+ end
686
+
687
+ def insertTab
688
+ typeCharacter( TAB )
689
+ end
690
+
691
+ def joinLines
692
+ @current_buffer.joinLines( @current_buffer.currentRow, Buffer::STRIP_LINE )
693
+ end
694
+
695
+ def list_buffers
696
+ with_list_file do |f|
697
+ f.puts @buffers.keys.map { |name| "#{name}\n" }.sort
698
+ end
699
+ openListBuffer
700
+ filename = getUserInput( "Switch to buffer: " )
701
+ buffer = @buffers[ filename ]
702
+ if buffer
703
+ switchTo buffer
704
+ end
705
+ end
706
+
707
+ def loadScript( name_ = nil )
708
+ if name_.nil?
709
+ name = getUserInput( "File to load as script: ", @rlh_files )
710
+ else
711
+ name = name_
712
+ end
713
+
714
+ if name
715
+ thread = Thread.new( name ) do |f|
716
+ begin
717
+ load( f )
718
+ rescue Exception => e
719
+ showException(
720
+ e,
721
+ [
722
+ "The filename given does not exist.",
723
+ "The filename given is not accessible or readable.",
724
+ "The loaded script does not reference Diakonos commands as members of the global Diakonos object. e.g. cursorBOL instead of $diakonos.cursorBOL",
725
+ "The loaded script has syntax errors.",
726
+ "The loaded script references objects or object members which do not exist."
727
+ ]
728
+ )
729
+ end
730
+ setILine "Loaded script '#{name}'."
731
+ end
732
+
733
+ loop do
734
+ if thread.status != "run"
735
+ break
736
+ else
737
+ sleep 0.1
738
+ end
739
+ end
740
+ thread.join
741
+ end
742
+ end
743
+
744
+ def load_session( session_id = nil )
745
+ if session_id.nil?
746
+ session_id = getUserInput( "Session: ", @rlh_sessions, @session_dir, nil, DO_COMPLETE )
747
+ end
748
+ return if session_id.nil? or session_id.empty?
749
+
750
+ path = session_filepath_for( session_id )
751
+ if not File.exist?( path )
752
+ setILine "No such session: #{session_id}"
753
+ else
754
+ if pid_session?( @session[ 'filename' ] )
755
+ File.delete @session[ 'filename' ]
756
+ end
757
+ @session = nil
758
+ @buffers.each_value do |buffer|
759
+ closeFile buffer
760
+ end
761
+ new_session( path )
762
+ @session[ 'files' ].each do |file|
763
+ openFile file
764
+ end
765
+ end
766
+ end
767
+
768
+ def name_session
769
+ name = getUserInput( 'Session name: ' )
770
+ if name
771
+ new_session "#{@session_dir}/#{name}"
772
+ save_session
773
+ end
774
+ end
775
+
776
+ def newFile
777
+ openFile
778
+ end
779
+
780
+ # Returns the buffer of the opened file, or nil.
781
+ def openFile( filename = nil, read_only = false, force_revert = ASK_REVERT )
782
+ do_open = true
783
+ buffer = nil
784
+ if filename.nil?
785
+ buffer_key = @untitled_id
786
+ @untitled_id += 1
787
+ else
788
+ if filename =~ /^(.+):(\d+)$/
789
+ filename, line_number = $1, ( $2.to_i - 1 )
790
+ end
791
+ buffer_key = filename
792
+ if(
793
+ ( not force_revert ) and
794
+ ( (existing_buffer = @buffers[ filename ]) != nil ) and
795
+ ( filename !~ /\.diakonos/ ) and
796
+ existing_buffer.file_different?
797
+ )
798
+ show_buffer_file_diff( existing_buffer ) do
799
+ choice = getChoice(
800
+ "Load on-disk version of #{existing_buffer.nice_name}?",
801
+ [ CHOICE_YES, CHOICE_NO ]
802
+ )
803
+ case choice
804
+ when CHOICE_NO
805
+ do_open = false
806
+ end
807
+ end
808
+ end
809
+
810
+ if FileTest.exist?( filename )
811
+ # Don't try to open non-files (i.e. directories, pipes, sockets, etc.)
812
+ do_open &&= FileTest.file?( filename )
813
+ end
814
+ end
815
+
816
+ if do_open
817
+ # Is file readable?
818
+
819
+ # Does the "file" utility exist?
820
+ if(
821
+ filename and
822
+ @settings[ 'use_magic_file' ] and
823
+ FileTest.exist?( "/usr/bin/file" ) and
824
+ FileTest.exist?( filename ) and
825
+ /\blisting\.txt\b/ !~ filename
826
+ )
827
+ file_type = `/usr/bin/file -L #{filename}`
828
+ if file_type !~ /text/ and file_type !~ /empty$/
829
+ choice = getChoice(
830
+ "#{filename} does not appear to be readable. Try to open it anyway?",
831
+ [ CHOICE_YES, CHOICE_NO ],
832
+ CHOICE_NO
833
+ )
834
+ case choice
835
+ when CHOICE_NO
836
+ do_open = false
837
+ end
838
+
839
+ end
840
+ end
841
+
842
+ if do_open
843
+ buffer = Buffer.new( self, filename, buffer_key, read_only )
844
+ runHookProcs( :after_open, buffer )
845
+ @buffers[ buffer_key ] = buffer
846
+ save_session
847
+ if switchTo( buffer ) and line_number
848
+ @current_buffer.goToLine( line_number, 0 )
849
+ end
850
+ end
851
+ end
852
+
853
+ buffer
854
+ end
855
+
856
+ def openFileAsk
857
+ prefill = ''
858
+
859
+ if @current_buffer
860
+ if @current_buffer.current_line =~ %r#(/\w+)+/\w+\.\w+#
861
+ prefill = $&
862
+ elsif @current_buffer.name
863
+ prefill = File.expand_path( File.dirname( @current_buffer.name ) ) + "/"
864
+ end
865
+ end
866
+
867
+ if @settings[ 'fuzzy_file_find' ]
868
+ prefill = ''
869
+ finder_block = lambda { |input|
870
+ finder = FuzzyFileFinder.new( @session[ 'dir' ] )
871
+ matches = finder.find( input ).sort_by { |m| [ -m[:score], m[:path] ] }
872
+ with_list_file do |list|
873
+ list.puts matches.map { |m| m[ :path ] }
874
+ end
875
+ openListBuffer
876
+ }
877
+ end
878
+ file = getUserInput( "Filename: ", @rlh_files, prefill, &finder_block )
879
+
880
+ if file
881
+ openFile file
882
+ updateStatusLine
883
+ updateContextLine
884
+ end
885
+ end
886
+
887
+ def open_matching_files( regexp = nil, search_root = nil )
888
+ regexp ||= getUserInput( "Regexp: ", @rlh_search )
889
+ return if regexp.nil?
890
+
891
+ if @current_buffer.current_line =~ %r{\w*/[/\w.]+}
892
+ prefill = $&
893
+ else
894
+ prefill = File.expand_path( File.dirname( @current_buffer.name ) ) + "/"
895
+ end
896
+ search_root ||= getUserInput( "Search within: ", @rlh_files, prefill )
897
+ return if search_root.nil?
898
+
899
+ files = `egrep -rl '#{regexp.gsub( /'/, "'\\\\''" )}' #{search_root}/*`.split( /\n/ )
900
+ if files.any?
901
+ if files.size > 5
902
+ choice = getChoice( "Open #{files.size} files?", [ CHOICE_YES, CHOICE_NO ] )
903
+ return if choice == CHOICE_NO
904
+ end
905
+ files.each do |f|
906
+ openFile f
907
+ end
908
+ find 'down', CASE_SENSITIVE, regexp
909
+ end
910
+ end
911
+
912
+ def operateOnString(
913
+ ruby_code = getUserInput( 'Ruby code: ', @rlh_general, 'str.' )
914
+ )
915
+ if ruby_code
916
+ str = @current_buffer.selected_string
917
+ if str and not str.empty?
918
+ @current_buffer.paste eval( ruby_code )
919
+ end
920
+ end
921
+ end
922
+
923
+ def operateOnLines(
924
+ ruby_code = getUserInput( 'Ruby code: ', @rlh_general, 'lines.collect { |l| l }' )
925
+ )
926
+ if ruby_code
927
+ lines = @current_buffer.selected_text
928
+ if lines and not lines.empty?
929
+ if lines[ -1 ].empty?
930
+ lines.pop
931
+ popped = true
932
+ end
933
+ new_lines = eval( ruby_code )
934
+ if popped
935
+ new_lines << ''
936
+ end
937
+ @current_buffer.paste new_lines
938
+ end
939
+ end
940
+ end
941
+
942
+ def operateOnEachLine(
943
+ ruby_code = getUserInput( 'Ruby code: ', @rlh_general, 'line.' )
944
+ )
945
+ if ruby_code
946
+ lines = @current_buffer.selected_text
947
+ if lines and not lines.empty?
948
+ if lines[ -1 ].empty?
949
+ lines.pop
950
+ popped = true
951
+ end
952
+ new_lines = eval( "lines.collect { |line| #{ruby_code} }" )
953
+ if popped
954
+ new_lines << ''
955
+ end
956
+ @current_buffer.paste new_lines
957
+ end
958
+ end
959
+ end
960
+
961
+ def pageUp
962
+ if @current_buffer.pitchView( -main_window_height, Buffer::DO_PITCH_CURSOR ) == 0
963
+ cursorBOF
964
+ end
965
+ updateStatusLine
966
+ updateContextLine
967
+ end
968
+
969
+ def pageDown
970
+ if @current_buffer.pitchView( main_window_height, Buffer::DO_PITCH_CURSOR ) == 0
971
+ @current_buffer.cursorToEOF
972
+ end
973
+ updateStatusLine
974
+ updateContextLine
975
+ end
976
+
977
+ def parsedIndent
978
+ if( @current_buffer.changing_selection )
979
+ @do_display = false
980
+ mark = @current_buffer.selection_mark
981
+ (mark.start_row..mark.end_row).each do |row|
982
+ @current_buffer.parsedIndent row, Buffer::DONT_DISPLAY
983
+ end
984
+ @do_display = true
985
+ @current_buffer.display
986
+ else
987
+ @current_buffer.parsedIndent
988
+ end
989
+ updateStatusLine
990
+ updateContextLine
991
+ end
992
+
993
+ def paste
994
+ @current_buffer.paste @clipboard.clip
995
+ end
996
+
997
+ def paste_from_klipper
998
+ text = `dcop klipper klipper getClipboardContents`.split( "\n", -1 )
999
+ text.pop # getClipboardContents puts an extra newline on end
1000
+ @current_buffer.paste text
1001
+ end
1002
+
1003
+ def playMacro( name = nil )
1004
+ macro, input_history = @macros[ name ]
1005
+ if input_history
1006
+ @macro_input_history = input_history.deep_clone
1007
+ if macro
1008
+ @playing_macro = true
1009
+ macro.each do |command|
1010
+ eval command
1011
+ end
1012
+ @playing_macro = false
1013
+ @macro_input_history = nil
1014
+ end
1015
+ end
1016
+ end
1017
+
1018
+ def popTag
1019
+ tag = @tag_stack.pop
1020
+ if tag
1021
+ if not switchTo( @buffers[ tag[ 0 ] ] )
1022
+ openFile( tag[ 0 ] )
1023
+ end
1024
+ @current_buffer.cursorTo( tag[ 1 ], tag[ 2 ], Buffer::DO_DISPLAY )
1025
+ else
1026
+ setILine "Tag stack empty."
1027
+ end
1028
+ end
1029
+
1030
+ def print_mapped_function
1031
+ @capturing_mapping = true
1032
+ setILine "Type any chain of keystrokes or key chords, or press Enter to stop."
1033
+ end
1034
+
1035
+ def printKeychain
1036
+ @capturing_keychain = true
1037
+ setILine "Type any chain of keystrokes or key chords, then press Enter..."
1038
+ end
1039
+
1040
+ def quit
1041
+ @quitting = true
1042
+ to_all = nil
1043
+ @buffers.each_value do |buffer|
1044
+ if buffer.modified?
1045
+ switchTo buffer
1046
+ closure_choice = closeFile( buffer, to_all )
1047
+ case closure_choice
1048
+ when CHOICE_CANCEL
1049
+ @quitting = false
1050
+ break
1051
+ when CHOICE_YES_TO_ALL, CHOICE_NO_TO_ALL
1052
+ to_all = closure_choice
1053
+ end
1054
+ end
1055
+ end
1056
+ end
1057
+
1058
+ def removeNamedBookmark( name_ = nil )
1059
+ if name_.nil?
1060
+ name = getUserInput "Bookmark name: "
1061
+ else
1062
+ name = name_
1063
+ end
1064
+
1065
+ if name
1066
+ bookmark = @bookmarks.delete name
1067
+ setILine "Removed bookmark #{bookmark.to_s}."
1068
+ end
1069
+ end
1070
+
1071
+ def removeSelection
1072
+ @current_buffer.removeSelection
1073
+ updateStatusLine
1074
+ end
1075
+
1076
+ def repeatLast
1077
+ eval @last_commands[ -1 ] if not @last_commands.empty?
1078
+ end
1079
+
1080
+ # If the prompt is non-nil, ask the user yes or no question first.
1081
+ def revert( prompt = nil )
1082
+ do_revert = true
1083
+
1084
+ if prompt
1085
+ show_buffer_file_diff do
1086
+ choice = getChoice(
1087
+ prompt,
1088
+ [ CHOICE_YES, CHOICE_NO ]
1089
+ )
1090
+ case choice
1091
+ when CHOICE_NO
1092
+ do_revert = false
1093
+ end
1094
+ end
1095
+ end
1096
+
1097
+ if do_revert
1098
+ openFile( @current_buffer.name, Buffer::READ_WRITE, FORCE_REVERT )
1099
+ end
1100
+ end
1101
+
1102
+ def saveFile( buffer = @current_buffer )
1103
+ buffer.save
1104
+ runHookProcs( :after_save, buffer )
1105
+ end
1106
+
1107
+ def saveFileAs
1108
+ if @current_buffer and @current_buffer.name
1109
+ path = File.expand_path( File.dirname( @current_buffer.name ) ) + "/"
1110
+ file = getUserInput( "Filename: ", @rlh_files, path )
1111
+ else
1112
+ file = getUserInput( "Filename: ", @rlh_files )
1113
+ end
1114
+ if file
1115
+ old_name = @current_buffer.name
1116
+ if @current_buffer.save( file, PROMPT_OVERWRITE )
1117
+ @buffers.delete old_name
1118
+ @buffers[ @current_buffer.name ] = @current_buffer
1119
+ save_session
1120
+ end
1121
+ end
1122
+ end
1123
+
1124
+ def select_all
1125
+ @current_buffer.select_all
1126
+ end
1127
+
1128
+ def select_block( beginning = nil, ending = nil, including_ending = true )
1129
+ if beginning.nil?
1130
+ input = getUserInput( "Start at regexp: " )
1131
+ if input
1132
+ beginning = Regexp.new input
1133
+ end
1134
+ end
1135
+ if beginning and ending.nil?
1136
+ input = getUserInput( "End before regexp: " )
1137
+ if input
1138
+ ending = Regexp.new input
1139
+ end
1140
+ end
1141
+ if beginning and ending
1142
+ @current_buffer.select( beginning, ending, including_ending )
1143
+ end
1144
+ end
1145
+
1146
+ def scrollDown
1147
+ @current_buffer.pitchView( @settings[ "view.scroll_amount" ] || 1 )
1148
+ updateStatusLine
1149
+ updateContextLine
1150
+ end
1151
+
1152
+ def scrollUp
1153
+ if @settings[ "view.scroll_amount" ]
1154
+ @current_buffer.pitchView( -@settings[ "view.scroll_amount" ] )
1155
+ else
1156
+ @current_buffer.pitchView( -1 )
1157
+ end
1158
+ updateStatusLine
1159
+ updateContextLine
1160
+ end
1161
+
1162
+ def searchAndReplace( case_sensitive = CASE_INSENSITIVE )
1163
+ find( "down", case_sensitive, nil, ASK_REPLACEMENT )
1164
+ end
1165
+
1166
+ def seek( regexp_source, dir_str = "down" )
1167
+ if regexp_source
1168
+ direction = dir_str.toDirection
1169
+ regexp = Regexp.new( regexp_source )
1170
+ @current_buffer.seek( regexp, direction )
1171
+ end
1172
+ end
1173
+
1174
+ def setBufferType( type_ = nil )
1175
+ if type_.nil?
1176
+ type = getUserInput "Content type: "
1177
+ else
1178
+ type = type_
1179
+ end
1180
+
1181
+ if type
1182
+ if @current_buffer.setType( type )
1183
+ updateStatusLine
1184
+ updateContextLine
1185
+ end
1186
+ end
1187
+ end
1188
+
1189
+ # If read_only is nil, the read_only state of the current buffer is toggled.
1190
+ # Otherwise, the read_only state of the current buffer is set to read_only.
1191
+ def setReadOnly( read_only = nil )
1192
+ if read_only
1193
+ @current_buffer.read_only = read_only
1194
+ else
1195
+ @current_buffer.read_only = ( not @current_buffer.read_only )
1196
+ end
1197
+ updateStatusLine
1198
+ end
1199
+
1200
+ def set_session_dir
1201
+ path = getUserInput( "Session directory: ", @rlh_files, @session[ 'dir' ], nil, DONT_COMPLETE, :accept_dirs )
1202
+ if path
1203
+ @session[ 'dir' ] = File.expand_path( path )
1204
+ save_session
1205
+ setILine "Session dir changed to: #{@session['dir']}"
1206
+ else
1207
+ setILine "(Session dir is: #{@session['dir']})"
1208
+ end
1209
+ end
1210
+
1211
+ def shell( command_ = nil, result_filename = 'shell-result.txt' )
1212
+ if command_.nil?
1213
+ command = getUserInput( "Command: ", @rlh_shell )
1214
+ else
1215
+ command = command_
1216
+ end
1217
+
1218
+ if command
1219
+ command = subShellVariables( command )
1220
+
1221
+ result_file = "#{@diakonos_home}/#{result_filename}"
1222
+ File.open( result_file , "w" ) do |f|
1223
+ f.puts command
1224
+ f.puts
1225
+ Curses::close_screen
1226
+
1227
+ stdin, stdout, stderr = Open3.popen3( command )
1228
+ t1 = Thread.new do
1229
+ stdout.each_line do |line|
1230
+ f.puts line
1231
+ end
1232
+ end
1233
+ t2 = Thread.new do
1234
+ stderr.each_line do |line|
1235
+ f.puts line
1236
+ end
1237
+ end
1238
+
1239
+ t1.join
1240
+ t2.join
1241
+
1242
+ Curses::init_screen
1243
+ refreshAll
1244
+ end
1245
+ openFile result_file
1246
+ end
1247
+ end
1248
+
1249
+ def execute( command_ = nil )
1250
+ if command_.nil?
1251
+ command = getUserInput( "Command: ", @rlh_shell )
1252
+ else
1253
+ command = command_
1254
+ end
1255
+
1256
+ if command
1257
+ command = subShellVariables( command )
1258
+
1259
+ Curses::close_screen
1260
+
1261
+ success = system( command )
1262
+ if not success
1263
+ result = "Could not execute: #{command}"
1264
+ else
1265
+ result = "Return code: #{$?}"
1266
+ end
1267
+
1268
+ Curses::init_screen
1269
+ refreshAll
1270
+
1271
+ setILine result
1272
+ end
1273
+ end
1274
+
1275
+ def pasteShellResult( command_ = nil )
1276
+ if command_.nil?
1277
+ command = getUserInput( "Command: ", @rlh_shell )
1278
+ else
1279
+ command = command_
1280
+ end
1281
+
1282
+ if command
1283
+ command = subShellVariables( command )
1284
+
1285
+ Curses::close_screen
1286
+
1287
+ begin
1288
+ @current_buffer.paste( `#{command} 2<&1`.split( /\n/, -1 ) )
1289
+ rescue Exception => e
1290
+ debugLog e.message
1291
+ debugLog e.backtrace.join( "\n\t" )
1292
+ showException e
1293
+ end
1294
+
1295
+ Curses::init_screen
1296
+ refreshAll
1297
+ end
1298
+ end
1299
+
1300
+ # Send the Diakonos job to background, as if with Ctrl-Z
1301
+ def suspend
1302
+ Curses::close_screen
1303
+ Process.kill( "SIGSTOP", $PID )
1304
+ Curses::init_screen
1305
+ refreshAll
1306
+ end
1307
+
1308
+ def toggleMacroRecording( name = nil )
1309
+ if @macro_history
1310
+ stopRecordingMacro
1311
+ else
1312
+ startRecordingMacro( name )
1313
+ end
1314
+ end
1315
+
1316
+ def switchToBufferNumber( buffer_number_ )
1317
+ buffer_number = buffer_number_.to_i
1318
+ return if buffer_number < 1
1319
+ buffer_name = bufferNumberToName( buffer_number )
1320
+ if buffer_name
1321
+ switchTo( @buffers[ buffer_name ] )
1322
+ end
1323
+ end
1324
+
1325
+ def switchToNextBuffer
1326
+ if @buffer_history.any?
1327
+ @buffer_history_pointer += 1
1328
+ if @buffer_history_pointer >= @buffer_history_pointer.size
1329
+ @buffer_history_pointer = @buffer_history_pointer.size - 1
1330
+ switchToBufferNumber( bufferToNumber( @current_buffer ) + 1 )
1331
+ else
1332
+ switchTo @buffer_history[ @buffer_history_pointer ]
1333
+ end
1334
+ else
1335
+ switchToBufferNumber( bufferToNumber( @current_buffer ) + 1 )
1336
+ end
1337
+ end
1338
+
1339
+ def switchToPreviousBuffer
1340
+ if @buffer_history.any?
1341
+ @buffer_history_pointer -= 1
1342
+ if @buffer_history_pointer < 0
1343
+ @buffer_history_pointer = 0
1344
+ switchToBufferNumber( bufferToNumber( @current_buffer ) - 1 )
1345
+ else
1346
+ switchTo @buffer_history[ @buffer_history_pointer ]
1347
+ end
1348
+ else
1349
+ switchToBufferNumber( bufferToNumber( @current_buffer ) - 1 )
1350
+ end
1351
+ end
1352
+
1353
+ def toggleBookmark
1354
+ @current_buffer.toggleBookmark
1355
+ end
1356
+
1357
+ def toggleSelection
1358
+ @current_buffer.toggleSelection
1359
+ updateStatusLine
1360
+ end
1361
+
1362
+ def toggleSessionSetting( key_ = nil, do_redraw = DONT_REDRAW )
1363
+ if key_.nil?
1364
+ key = getUserInput( "Setting: " )
1365
+ else
1366
+ key = key_
1367
+ end
1368
+
1369
+ if key
1370
+ value = nil
1371
+ if @session[ 'settings' ][ key ].class == TrueClass or @session[ 'settings' ][ key ].class == FalseClass
1372
+ value = ! @session[ 'settings' ][ key ]
1373
+ elsif @settings[ key ].class == TrueClass or @settings[ key ].class == FalseClass
1374
+ value = ! @settings[ key ]
1375
+ end
1376
+ if value != nil # explicitly true or false
1377
+ @session[ 'settings' ][ key ] = value
1378
+ redraw if do_redraw
1379
+ setILine "#{key} = #{value}"
1380
+ end
1381
+ end
1382
+ end
1383
+
1384
+ def uncomment
1385
+ @current_buffer.uncomment
1386
+ end
1387
+
1388
+ def undo( buffer = @current_buffer )
1389
+ buffer.undo
1390
+ end
1391
+
1392
+ def unindent
1393
+ if( @current_buffer.changing_selection )
1394
+ @do_display = false
1395
+ mark = @current_buffer.selection_mark
1396
+ if mark.end_col > 0
1397
+ end_row = mark.end_row
1398
+ else
1399
+ end_row = mark.end_row - 1
1400
+ end
1401
+ (mark.start_row..end_row).each do |row|
1402
+ @current_buffer.unindent row, Buffer::DONT_DISPLAY
1403
+ end
1404
+ @do_display = true
1405
+ @current_buffer.display
1406
+ else
1407
+ @current_buffer.unindent
1408
+ end
1409
+ end
1410
+
1411
+ def unundo( buffer = @current_buffer )
1412
+ buffer.unundo
1413
+ end
1414
+
1415
+ def wrap_paragraph
1416
+ @current_buffer.wrap_paragraph
1417
+ end
1418
+
1419
+ end
1420
+ end