diakonos 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # Author:: Pistos (irc.freenode.net)
9
9
  # http://purepistos.net/diakonos
10
- # Copyright (c) 2004-2008 Pistos
10
+ # Copyright (c) 2004-2009 Pistos
11
11
  #
12
12
  # This software is released under the MIT licence.
13
13
  # See the LICENCE file included with this program, or
@@ -18,6 +18,8 @@ require 'open3'
18
18
  require 'thread'
19
19
  require 'English'
20
20
  require 'set'
21
+ require 'yaml'
22
+ require 'digest/md5'
21
23
 
22
24
  require 'diakonos/object'
23
25
  require 'diakonos/enumerable'
@@ -27,9 +29,23 @@ require 'diakonos/hash'
27
29
  require 'diakonos/buffer-hash'
28
30
  require 'diakonos/array'
29
31
  require 'diakonos/string'
30
- require 'diakonos/keycode'
31
32
  require 'diakonos/fixnum'
32
33
  require 'diakonos/bignum'
34
+
35
+ require 'diakonos/config'
36
+ require 'diakonos/functions'
37
+ require 'diakonos/help'
38
+ require 'diakonos/display'
39
+ require 'diakonos/interaction'
40
+ require 'diakonos/hooks'
41
+ require 'diakonos/keying'
42
+ require 'diakonos/logging'
43
+ require 'diakonos/list'
44
+ require 'diakonos/buffer-management'
45
+ require 'diakonos/sessions'
46
+ require 'diakonos/grep'
47
+
48
+ require 'diakonos/keycode'
33
49
  require 'diakonos/text-mark'
34
50
  require 'diakonos/bookmark'
35
51
  require 'diakonos/ctag'
@@ -39,251 +55,122 @@ require 'diakonos/window'
39
55
  require 'diakonos/clipboard'
40
56
  require 'diakonos/readline'
41
57
 
58
+ require 'diakonos/vendor/fuzzy_file_finder'
59
+
42
60
  #$profiling = true
43
61
 
44
62
  #if $profiling
45
- #require 'ruby-prof'
63
+ #require 'ruby-prof'
46
64
  #end
47
65
 
48
66
  module Diakonos
49
67
 
50
- VERSION = '0.8.6'
51
- LAST_MODIFIED = 'October 31, 2008'
52
-
53
- DONT_ADJUST_ROW = false
54
- ADJUST_ROW = true
55
- PROMPT_OVERWRITE = true
56
- DONT_PROMPT_OVERWRITE = false
57
- DO_REDRAW = true
58
- DONT_REDRAW = false
59
- QUIET = true
60
- NOISY = false
61
-
62
- TAB = 9
63
- ENTER = 13
64
- ESCAPE = 27
65
- BACKSPACE = 127
66
- CTRL_C = 3
67
- CTRL_D = 4
68
- CTRL_K = 11
69
- CTRL_Q = 17
70
- CTRL_H = 263
71
- RESIZE2 = 4294967295
72
-
73
- DEFAULT_TAB_SIZE = 8
74
-
75
- CHOICE_NO = 0
76
- CHOICE_YES = 1
77
- CHOICE_ALL = 2
78
- CHOICE_CANCEL = 3
79
- CHOICE_YES_TO_ALL = 4
80
- CHOICE_NO_TO_ALL = 5
81
- CHOICE_YES_AND_STOP = 6
82
- CHOICE_KEYS = [
83
- [ ?n, ?N ],
84
- [ ?y, ?Y ],
85
- [ ?a, ?A ],
86
- [ ?c, ?C, ESCAPE, CTRL_C, CTRL_D, CTRL_Q ],
87
- [ ?e ],
88
- [ ?o ],
89
- [ ?s ],
90
- ]
91
- CHOICE_STRINGS = [ '(n)o', '(y)es', '(a)ll', '(c)ancel', 'y(e)s to all', 'n(o) to all', 'yes and (s)top' ]
92
-
93
- BOL_ZERO = 0
94
- BOL_FIRST_CHAR = 1
95
- BOL_ALT_ZERO = 2
96
- BOL_ALT_FIRST_CHAR = 3
97
-
98
- EOL_END = 0
99
- EOL_LAST_CHAR = 1
100
- EOL_ALT_END = 2
101
- EOL_ALT_LAST_CHAR = 3
102
-
103
- FORCE_REVERT = true
104
- ASK_REVERT = false
105
-
106
- ASK_REPLACEMENT = true
107
-
108
- CASE_SENSITIVE = true
109
- CASE_INSENSITIVE = false
110
-
111
- FUNCTIONS = [
112
- 'addNamedBookmark',
113
- 'anchorSelection',
114
- 'backspace',
115
- 'carriageReturn',
116
- 'changeSessionSetting',
117
- 'clearMatches',
118
- 'closeFile',
119
- 'close_code',
120
- 'collapseWhitespace',
121
- 'columnize',
122
- 'comment_out',
123
- 'copySelection',
124
- 'copy_selection_to_klipper',
125
- 'cursorBOF',
126
- 'cursorBOL',
127
- 'cursorBOV',
128
- 'cursorDown',
129
- 'cursorEOF',
130
- 'cursorEOL',
131
- 'cursorLeft',
132
- 'cursorReturn',
133
- 'cursorRight',
134
- 'cursorTOV',
135
- 'cursorUp',
136
- 'cutSelection',
137
- 'cut_selection_to_klipper',
138
- 'delete',
139
- 'deleteAndStoreLine',
140
- 'deleteLine',
141
- 'deleteToEOL',
142
- 'delete_and_store_line_to_klipper',
143
- 'delete_line_to_klipper',
144
- 'delete_to_EOL_to_klipper',
145
- 'evaluate',
146
- 'execute',
147
- 'find',
148
- 'findAgain',
149
- 'findAndReplace',
150
- 'findExact',
151
- 'goToLineAsk',
152
- 'goToNamedBookmark',
153
- 'goToNextBookmark',
154
- 'goToPreviousBookmark',
155
- 'goToTag',
156
- 'goToTagUnderCursor',
157
- 'help',
158
- 'indent',
159
- 'insertSpaces',
160
- 'insertTab',
161
- 'joinLines',
162
- 'list_buffers',
163
- 'loadConfiguration',
164
- 'loadScript',
165
- 'newFile',
166
- 'openFile',
167
- 'openFileAsk',
168
- 'operateOnEachLine',
169
- 'operateOnLines',
170
- 'operateOnString',
171
- 'pageDown',
172
- 'pageUp',
173
- 'parsedIndent',
174
- 'paste',
175
- 'pasteShellResult',
176
- 'paste_from_klipper',
177
- 'playMacro',
178
- 'popTag',
179
- 'print_mapped_function',
180
- 'printKeychain',
181
- 'quit',
182
- 'redraw',
183
- 'removeNamedBookmark',
184
- 'removeSelection',
185
- 'repeatLast',
186
- 'revert',
187
- 'saveFile',
188
- 'saveFileAs',
189
- 'scrollDown',
190
- 'scrollUp',
191
- 'searchAndReplace',
192
- 'seek',
193
- 'select_all',
194
- 'select_block',
195
- 'setBufferType',
196
- 'setReadOnly',
197
- 'shell',
198
- 'showClips',
199
- 'suspend',
200
- 'switchToBufferNumber',
201
- 'switchToNextBuffer',
202
- 'switchToPreviousBuffer',
203
- 'toggleBookmark',
204
- 'toggleMacroRecording',
205
- 'toggleSelection',
206
- 'toggleSessionSetting',
207
- 'uncomment',
208
- 'undo',
209
- 'unindent',
210
- 'unundo',
211
- 'wrap_paragraph',
212
- ]
213
- LANG_TEXT = 'text'
214
-
215
- NUM_LAST_COMMANDS = 2
216
-
217
- class Diakonos
218
- attr_reader :win_main, :settings, :token_regexps, :close_token_regexps,
219
- :token_formats, :diakonos_home, :script_dir, :diakonos_conf, :display_mutex,
220
- :indenters, :unindenters, :closers, :clipboard, :do_display,
221
- :current_buffer, :list_filename, :hooks, :last_commands, :there_was_non_movement
68
+ VERSION = '0.8.7'
69
+ LAST_MODIFIED = 'February 20, 2009'
70
+
71
+ DONT_ADJUST_ROW = false
72
+ ADJUST_ROW = true
73
+ PROMPT_OVERWRITE = true
74
+ DONT_PROMPT_OVERWRITE = false
75
+ QUIET = true
76
+ NOISY = false
77
+
78
+ DEFAULT_TAB_SIZE = 8
79
+
80
+ FORCE_REVERT = true
81
+ ASK_REVERT = false
222
82
 
83
+ ASK_REPLACEMENT = true
84
+
85
+ CASE_SENSITIVE = true
86
+ CASE_INSENSITIVE = false
87
+
88
+ LANG_TEXT = 'text'
89
+
90
+ NUM_LAST_COMMANDS = 2
91
+
92
+ class Diakonos
93
+
94
+ attr_reader :diakonos_home, :script_dir, :clipboard,
95
+ :list_filename, :hooks, :indenters, :unindenters, :closers,
96
+ :last_commands, :there_was_non_movement, :do_display
97
+
98
+ include ::Diakonos::Functions
223
99
 
224
100
  def initialize( argv = [] )
225
- @diakonos_home = ( ( ENV[ 'HOME' ] or '' ) + '/.diakonos' ).subHome
226
- mkdir @diakonos_home
227
- @script_dir = "#{@diakonos_home}/scripts"
228
- mkdir @script_dir
229
-
230
- init_help
231
-
232
- @debug = File.new( "#{@diakonos_home}/debug.log", 'w' )
233
- @list_filename = @diakonos_home + '/listing.txt'
234
- @diff_filename = @diakonos_home + '/text.diff'
235
- @help_filename = "#{@help_dir}/about-help.dhf"
236
- @error_filename = "#{@diakonos_home}/diakonos.err"
237
-
238
- @files = Array.new
239
- @read_only_files = Array.new
240
- @config_filename = nil
241
-
242
- parseOptions argv
243
-
244
- @session_settings = Hash.new
245
- @win_main = nil
246
- @win_context = nil
247
- @win_status = nil
248
- @win_interaction = nil
249
- @buffers = BufferHash.new
250
-
251
- loadConfiguration
252
-
253
- @quitting = false
254
- @untitled_id = 0
255
-
256
- @x = 0
257
- @y = 0
258
-
259
- @buffer_stack = Array.new
260
- @current_buffer = nil
261
- @bookmarks = Hash.new
262
- @macro_history = nil
263
- @macro_input_history = nil
264
- @macros = Hash.new
265
- @last_commands = SizedArray.new( NUM_LAST_COMMANDS )
266
- @playing_macro = false
267
- @display_mutex = Mutex.new
268
- @display_queue_mutex = Mutex.new
269
- @display_queue = nil
270
- @do_display = true
271
- @iline_mutex = Mutex.new
272
- @tag_stack = Array.new
273
- @last_search_regexps = nil
274
- @iterated_choice = nil
275
- @choice_iterations = 0
276
- @there_was_non_movement = false
277
- @status_vars = Hash.new
278
-
279
- # Readline histories
280
- @rlh_general = Array.new
281
- @rlh_files = Array.new
282
- @rlh_search = Array.new
283
- @rlh_shell = Array.new
284
- @rlh_help = Array.new
101
+ @diakonos_home = ( ( ENV[ 'HOME' ] or '' ) + '/.diakonos' ).subHome
102
+ mkdir @diakonos_home
103
+ @script_dir = "#{@diakonos_home}/scripts"
104
+ mkdir @script_dir
105
+ @session_dir = "#{@diakonos_home}/sessions"
106
+ mkdir @session_dir
107
+ new_session "#{@session_dir}/#{Process.pid}"
108
+
109
+ @files = Array.new
110
+ @read_only_files = Array.new
111
+ @config_filename = nil
112
+ parseOptions argv
113
+
114
+ init_help
115
+
116
+ @debug = File.new( "#{@diakonos_home}/debug.log", 'w' )
117
+ @list_filename = @diakonos_home + '/listing.txt'
118
+ @diff_filename = @diakonos_home + '/text.diff'
119
+ @help_filename = "#{@help_dir}/about-help.dhf"
120
+ @error_filename = "#{@diakonos_home}/diakonos.err"
121
+
122
+ @win_main = nil
123
+ @win_context = nil
124
+ @win_status = nil
125
+ @win_interaction = nil
126
+ @buffers = BufferHash.new
127
+
128
+ loadConfiguration
129
+
130
+ @quitting = false
131
+ @untitled_id = 0
132
+
133
+ @x = 0
134
+ @y = 0
135
+
136
+ @buffer_stack = Array.new
137
+ @current_buffer = nil
138
+ @buffer_history = Array.new
139
+ @buffer_history_pointer = nil
140
+ @bookmarks = Hash.new
141
+ @macro_history = nil
142
+ @macro_input_history = nil
143
+ @macros = Hash.new
144
+ @last_commands = SizedArray.new( NUM_LAST_COMMANDS )
145
+ @playing_macro = false
146
+ @display_mutex = Mutex.new
147
+ @display_queue_mutex = Mutex.new
148
+ @display_queue = nil
149
+ @do_display = true
150
+ @iline_mutex = Mutex.new
151
+ @tag_stack = Array.new
152
+ @last_search_regexps = nil
153
+ @iterated_choice = nil
154
+ @choice_iterations = 0
155
+ @there_was_non_movement = false
156
+ @status_vars = Hash.new
157
+
158
+ # Readline histories
159
+ @rlh_general = Array.new
160
+ @rlh_files = Array.new
161
+ @rlh_search = Array.new
162
+ @rlh_shell = Array.new
163
+ @rlh_help = Array.new
164
+ @rlh_sessions = Array.new
165
+
166
+ @hooks = {
167
+ :after_buffer_switch => [],
168
+ :after_open => [],
169
+ :after_save => [],
170
+ :after_startup => [],
171
+ }
285
172
  end
286
-
173
+
287
174
  def mkdir( dir )
288
175
  if not FileTest.exists? dir
289
176
  Dir.mkdir dir
@@ -292,1458 +179,378 @@ class Diakonos
292
179
 
293
180
  def parseOptions( argv )
294
181
  @post_load_script = ""
295
- while argv.length > 0
296
- arg = argv.shift
297
- case arg
298
- when '-h', '--help'
299
- printUsage
300
- exit 1
301
- when '-ro'
302
- filename = argv.shift
303
- if filename == nil
304
- printUsage
305
- exit 1
306
- else
307
- @read_only_files.push filename
308
- end
309
- when '-c', '--config'
310
- @config_filename = argv.shift
311
- if @config_filename == nil
312
- printUsage
313
- exit 1
314
- end
315
- when '-e', '--execute'
316
- post_load_script = argv.shift
317
- if post_load_script.nil?
318
- printUsage
319
- exit 1
320
- else
321
- @post_load_script << "\n#{post_load_script}"
322
- end
323
- when '-m', '--open-matching'
324
- regexp = argv.shift
325
- files = `egrep -rl '#{regexp}' *`.split( /\n/ )
326
- if files.any?
327
- @files.concat files
328
- script = "\nfind 'down', CASE_SENSITIVE, '#{regexp}'"
329
- @post_load_script << script
330
- end
331
- else
332
- # a name of a file to open
333
- @files.push arg
334
- end
335
- end
336
- end
337
- protected :parseOptions
338
-
339
- def printUsage
340
- puts "Usage: #{$0} [options] [file] [file...]"
341
- puts "\t--help\tDisplay usage"
342
- puts "\t-c <config file>\tLoad this config file instead of ~/.diakonos/diakonos.conf"
343
- puts "\t-e, --execute <Ruby code>\tExecute Ruby code (such as Diakonos commands) after startup"
344
- puts "\t-m, --open-matching <regular expression>\tOpen all matching files under current directory"
345
- puts "\t-ro <file>\tLoad file as read-only"
346
- end
347
- protected :printUsage
348
-
349
- def init_help
350
- @base_help_dir = "#{@diakonos_home}/help"
351
- mkdir @base_help_dir
352
-
353
- @help_dir = "#{@diakonos_home}/help/#{VERSION}"
354
- if not File.exist?( @help_dir )
355
- puts "Help files for this Diakonos version were not found (#{@help_dir})."
356
-
357
- $stdout.puts "Would you like to download the help files right now from the Diakonos website? (y/n)"; $stdout.flush
358
- answer = $stdin.gets
359
- case answer
360
- when /^y/i
361
- if not fetch_help
362
- $stderr.puts "Failed to get help for version #{VERSION}."
182
+ while argv.length > 0
183
+ arg = argv.shift
184
+ case arg
185
+ when '-c', '--config'
186
+ @config_filename = argv.shift
187
+ if @config_filename.nil?
188
+ printUsage
189
+ exit 1
363
190
  end
364
- end
365
-
366
- if not FileTest.exists?( @help_dir ) or Dir[ "#{@help_dir}/*" ].size == 0
367
- $stderr.puts "Terminating..."
191
+ when '-e', '--execute'
192
+ post_load_script = argv.shift
193
+ if post_load_script.nil?
194
+ printUsage
195
+ exit 1
196
+ else
197
+ @post_load_script << "\n#{post_load_script}"
198
+ end
199
+ when '-h', '--help'
200
+ printUsage
368
201
  exit 1
369
- end
370
- end
371
-
372
- @help_tags = `grep -h Tags #{@help_dir}/* | cut -d ' ' -f 2-`.split.uniq
373
- end
374
-
375
- def fetch_help
376
- require 'open-uri'
377
- success = false
378
- puts "Fetching help documents for version #{VERSION}..."
379
-
380
- filename = "diakonos-help-#{VERSION}.tar.gz"
381
- uri = "http://purepistos.net/diakonos/#{filename}"
382
- tarball = "#{@base_help_dir}/#{filename}"
383
- begin
384
- open( uri ) do |http|
385
- bytes = http.read
386
- File.open( tarball, 'w' ) do |f|
387
- f.print bytes
202
+ when '-m', '--open-matching'
203
+ regexp = argv.shift
204
+ files = `egrep -rl '#{regexp}' *`.split( /\n/ )
205
+ if files.any?
206
+ @files.concat files
207
+ script = "\nfind 'down', CASE_SENSITIVE, '#{regexp}'"
208
+ @post_load_script << script
388
209
  end
389
- end
390
- mkdir @help_dir
391
- `tar zxf #{tarball} -C #{@base_help_dir}`
392
- success = true
393
- rescue OpenURI::HTTPError => e
394
- $stderr.puts "Failed to fetch from #{uri} ."
395
- end
396
-
397
- success
398
- end
399
-
400
- def initializeDisplay
401
- if @win_main != nil
402
- @win_main.close
403
- end
404
- if @win_status != nil
405
- @win_status.close
406
- end
407
- if @win_interaction != nil
408
- @win_interaction.close
409
- end
410
- if @win_context != nil
411
- @win_context.close
412
- end
413
-
414
- Curses::init_screen
415
- Curses::nonl
416
- Curses::raw
417
- Curses::noecho
418
-
419
- if Curses::has_colors?
420
- Curses::start_color
421
- Curses::init_pair( Curses::COLOR_BLACK, Curses::COLOR_BLACK, Curses::COLOR_BLACK )
422
- Curses::init_pair( Curses::COLOR_RED, Curses::COLOR_RED, Curses::COLOR_BLACK )
423
- Curses::init_pair( Curses::COLOR_GREEN, Curses::COLOR_GREEN, Curses::COLOR_BLACK )
424
- Curses::init_pair( Curses::COLOR_YELLOW, Curses::COLOR_YELLOW, Curses::COLOR_BLACK )
425
- Curses::init_pair( Curses::COLOR_BLUE, Curses::COLOR_BLUE, Curses::COLOR_BLACK )
426
- Curses::init_pair( Curses::COLOR_MAGENTA, Curses::COLOR_MAGENTA, Curses::COLOR_BLACK )
427
- Curses::init_pair( Curses::COLOR_CYAN, Curses::COLOR_CYAN, Curses::COLOR_BLACK )
428
- Curses::init_pair( Curses::COLOR_WHITE, Curses::COLOR_WHITE, Curses::COLOR_BLACK )
429
- @colour_pairs.each do |cp|
430
- Curses::init_pair( cp[ :number ], cp[ :fg ], cp[ :bg ] )
431
- end
432
- end
433
-
434
- @win_main = Curses::Window.new( main_window_height, Curses::cols, 0, 0 )
435
- @win_main.keypad( true )
436
- @win_status = Curses::Window.new( 1, Curses::cols, Curses::lines - 2, 0 )
437
- @win_status.keypad( true )
438
- @win_status.attrset @settings[ 'status.format' ]
439
- @win_interaction = Curses::Window.new( 1, Curses::cols, Curses::lines - 1, 0 )
440
- @win_interaction.keypad( true )
441
-
442
- if @settings[ 'context.visible' ]
443
- if @settings[ 'context.combined' ]
444
- pos = 1
445
- else
446
- pos = 3
447
- end
448
- @win_context = Curses::Window.new( 1, Curses::cols, Curses::lines - pos, 0 )
449
- @win_context.keypad( true )
450
- else
451
- @win_context = nil
452
- end
453
-
454
- @win_interaction.refresh
455
- @win_main.refresh
456
-
457
- @buffers.each_value do |buffer|
458
- buffer.reset_win_main
459
- end
460
- end
461
-
462
- def fetch_conf( location = "v#{VERSION}" )
463
- require 'open-uri'
464
- found = false
465
- puts "Fetching configuration from #{location}..."
466
-
467
- begin
468
- open( "http://github.com/Pistos/diakonos/tree/#{location}/diakonos.conf?raw=true" ) do |http|
469
- text = http.read
470
- if text =~ /key/ and text =~ /colour/ and text =~ /lang/
471
- found = true
472
- File.open( @diakonos_conf, 'w' ) do |f|
473
- f.puts text
474
- end
210
+ when '-ro'
211
+ filename = argv.shift
212
+ if filename.nil?
213
+ printUsage
214
+ exit 1
215
+ else
216
+ @read_only_files.push filename
475
217
  end
476
- end
477
- rescue OpenURI::HTTPError => e
478
- $stderr.puts "Failed to fetch from #{location}."
479
- end
480
-
481
- found
482
- end
483
-
484
- def loadConfiguration
485
- # Set defaults first
486
-
487
- existent = 0
488
- conf_dirs = [
489
- '/usr/local/etc/diakonos.conf',
490
- '/usr/etc/diakonos.conf',
491
- '/etc/diakonos.conf',
492
- '/usr/local/share/diakonos/diakonos.conf',
493
- '/usr/share/diakonos/diakonos.conf'
494
- ]
495
-
496
- conf_dirs.each do |conf_dir|
497
- @global_diakonos_conf = conf_dir
498
- if FileTest.exists? @global_diakonos_conf
499
- existent += 1
500
- break
501
- end
502
- end
503
-
504
- @diakonos_conf = ( @config_filename or ( @diakonos_home + '/diakonos.conf' ) )
505
- existent += 1 if FileTest.exists? @diakonos_conf
506
-
507
- if existent < 1
508
- puts "diakonos.conf not found in any of:"
509
- conf_dirs.each do |conf_dir|
510
- puts " #{conf_dir}"
511
- end
512
- puts " ~/.diakonos/"
513
- puts "At least one configuration file must exist."
514
- $stdout.puts "Would you like to download one right now from the Diakonos repository? (y/n)"; $stdout.flush
515
- answer = $stdin.gets
516
- case answer
517
- when /^y/i
518
- if not fetch_conf
519
- fetch_conf 'master'
520
- end
521
- end
522
-
523
- if not FileTest.exists?( @diakonos_conf )
524
- puts "Terminating..."
525
- exit 1
526
- end
527
- end
528
-
529
- @logfilename = @diakonos_home + "/diakonos.log"
530
- @keychains = Hash.new
531
- @token_regexps = Hash.new
532
- @close_token_regexps = Hash.new
533
- @token_formats = Hash.new
534
- @indenters = Hash.new
535
- @unindenters = Hash.new
536
- @filemasks = Hash.new
537
- @bangmasks = Hash.new
538
- @closers = Hash.new
539
-
540
- @settings = Hash.new
541
- # Setup some defaults
542
- @settings[ "context.format" ] = Curses::A_REVERSE
543
-
544
- @keychains[ Curses::KEY_RESIZE ] = [ "redraw", nil ]
545
- @keychains[ RESIZE2 ] = [ "redraw", nil ]
546
-
547
- @colour_pairs = Array.new
548
-
549
- begin
550
- parseConfigurationFile( @global_diakonos_conf )
551
- parseConfigurationFile( @diakonos_conf )
552
-
553
- # Session settings override config file settings.
554
-
555
- @session_settings.each do |key,value|
556
- @settings[ key ] = value
557
- end
558
-
559
- @clipboard = Clipboard.new @settings[ "max_clips" ]
560
- @log = File.open( @logfilename, "a" )
561
-
562
- if @buffers != nil
563
- @buffers.each_value do |buffer|
564
- buffer.configure
565
- end
566
- end
567
- rescue Errno::ENOENT
568
- # No config file found or readable
569
- end
570
- end
571
-
572
- def parseConfigurationFile( filename )
573
- return if not FileTest.exists? filename
574
-
575
- lines = IO.readlines( filename ).collect { |l| l.chomp }
576
- lines.each do |line|
577
- # Skip comments
578
- next if line[ 0 ] == ?#
579
-
580
- command, arg = line.split( /\s+/, 2 )
581
- next if command == nil
582
- command = command.downcase
583
- case command
584
- when "include"
585
- parseConfigurationFile arg.subHome
586
- when "key"
587
- if arg != nil
588
- if / / === arg
589
- keystrings, function_and_args = arg.split( / {2,}/, 2 )
590
- else
591
- keystrings, function_and_args = arg.split( /;/, 2 )
592
- end
593
- keystrokes = Array.new
594
- keystrings.split( /\s+/ ).each do |ks_str|
595
- code = ks_str.keyCode
596
- if code
597
- keystrokes.concat code
598
- else
599
- puts "unknown keystring: #{ks_str}"
600
- end
601
- end
602
- if function_and_args.nil?
603
- @keychains.deleteKeyPath( keystrokes )
604
- else
605
- function, function_args = function_and_args.split( /\s+/, 2 )
606
- if FUNCTIONS.include? function
607
- @keychains.setKeyPath(
608
- keystrokes,
609
- [ function, function_args ]
610
- )
611
- end
612
- end
613
- end
614
- when /^lang\.(.+?)\.tokens\.([^.]+)(\.case_insensitive)?$/
615
- getTokenRegexp( @token_regexps, arg, Regexp.last_match )
616
- when /^lang\.(.+?)\.tokens\.([^.]+)\.open(\.case_insensitive)?$/
617
- getTokenRegexp( @token_regexps, arg, Regexp.last_match )
618
- when /^lang\.(.+?)\.tokens\.([^.]+)\.close(\.case_insensitive)?$/
619
- getTokenRegexp( @close_token_regexps, arg, Regexp.last_match )
620
- when /^lang\.(.+?)\.tokens\.(.+?)\.format$/
621
- language = $1
622
- token_class = $2
623
- @token_formats[ language ] = ( @token_formats[ language ] or Hash.new )
624
- @token_formats[ language ][ token_class ] = arg.toFormatting
625
- when /^lang\.(.+?)\.format\..+$/
626
- @settings[ command ] = arg.toFormatting
627
- when /^colou?r$/
628
- number, fg, bg = arg.split( /\s+/ )
629
- number = number.to_i
630
- fg = fg.toColourConstant
631
- bg = bg.toColourConstant
632
- @colour_pairs << {
633
- :number => number,
634
- :fg => fg,
635
- :bg => bg
636
- }
637
- when /^lang\.(.+?)\.indent\.indenters(\.case_insensitive)?$/
638
- case_insensitive = ( $2 != nil )
639
- if case_insensitive
640
- @indenters[ $1 ] = Regexp.new( arg, Regexp::IGNORECASE )
641
- else
642
- @indenters[ $1 ] = Regexp.new arg
643
- end
644
- when /^lang\.(.+?)\.indent\.unindenters(\.case_insensitive)?$/
645
- case_insensitive = ( $2 != nil )
646
- if case_insensitive
647
- @unindenters[ $1 ] = Regexp.new( arg, Regexp::IGNORECASE )
648
- else
649
- @unindenters[ $1 ] = Regexp.new arg
650
- end
651
- when /^lang\.(.+?)\.indent\.preventers(\.case_insensitive)?$/,
652
- /^lang\.(.+?)\.indent\.ignore(\.case_insensitive)?$/,
653
- /^lang\.(.+?)\.context\.ignore(\.case_insensitive)?$/
654
- case_insensitive = ( $2 != nil )
655
- if case_insensitive
656
- @settings[ command ] = Regexp.new( arg, Regexp::IGNORECASE )
657
- else
658
- @settings[ command ] = Regexp.new arg
659
- end
660
- when /^lang\.(.+?)\.filemask$/
661
- @filemasks[ $1 ] = Regexp.new arg
662
- when /^lang\.(.+?)\.bangmask$/
663
- @bangmasks[ $1 ] = Regexp.new arg
664
- when /^lang\.(.+?)\.closers\.(.+?)\.(.+?)$/
665
- @closers[ $1 ] ||= Hash.new
666
- @closers[ $1 ][ $2 ] ||= Hash.new
667
- @closers[ $1 ][ $2 ][ $3.to_sym ] = case $3
668
- when 'regexp'
669
- Regexp.new arg
670
- when 'closer'
671
- begin
672
- eval( "Proc.new " + arg )
673
- rescue Exception => e
674
- showException(
675
- e,
676
- [
677
- "Failed to process Proc for #{command}.",
678
- ]
679
- )
680
- end
681
- end
682
- when "context.visible", "context.combined", "eof_newline", "view.nonfilelines.visible",
683
- /^lang\.(.+?)\.indent\.(?:auto|roundup|using_tabs|closers)$/,
684
- "found_cursor_start", "convert_tabs", 'delete_newline_on_delete_to_eol',
685
- 'suppress_welcome'
686
- @settings[ command ] = arg.to_b
687
- when "context.format", "context.separator.format", "status.format"
688
- @settings[ command ] = arg.toFormatting
689
- when "logfile"
690
- @logfilename = arg.subHome
691
- when "context.separator", "status.left", "status.right", "status.filler",
692
- "status.modified_str", "status.unnamed_str", "status.selecting_str",
693
- "status.read_only_str", /^lang\..+?\.indent\.ignore\.charset$/,
694
- /^lang\.(.+?)\.tokens\.([^.]+)\.change_to$/,
695
- /^lang\.(.+?)\.column_delimiters$/,
696
- "view.nonfilelines.character",
697
- 'interaction.blink_string', 'diff_command'
698
- @settings[ command ] = arg
699
- when /^lang\..+?\.comment_(?:close_)?string$/
700
- @settings[ command ] = arg.gsub( /^["']|["']$/, '' )
701
- when "status.vars"
702
- @settings[ command ] = arg.split( /\s+/ )
703
- when /^lang\.(.+?)\.indent\.size$/, /^lang\.(.+?)\.(?:tabsize|wrap_margin)$/
704
- @settings[ command ] = arg.to_i
705
- when "context.max_levels", "context.max_segment_width", "max_clips", "max_undo_lines",
706
- "view.margin.x", "view.margin.y", "view.scroll_amount", "view.lookback"
707
- @settings[ command ] = arg.to_i
708
- when "view.jump.x", "view.jump.y"
709
- value = arg.to_i
710
- if value < 1
711
- value = 1
712
- end
713
- @settings[ command ] = value
714
- when "bol_behaviour", "bol_behavior"
715
- case arg.downcase
716
- when "zero"
717
- @settings[ "bol_behaviour" ] = BOL_ZERO
718
- when "first-char"
719
- @settings[ "bol_behaviour" ] = BOL_FIRST_CHAR
720
- when "alternating-zero"
721
- @settings[ "bol_behaviour" ] = BOL_ALT_ZERO
722
- else # default
723
- @settings[ "bol_behaviour" ] = BOL_ALT_FIRST_CHAR
724
- end
725
- when "eol_behaviour", "eol_behavior"
726
- case arg.downcase
727
- when "end"
728
- @settings[ "eol_behaviour" ] = EOL_END
729
- when "last-char"
730
- @settings[ "eol_behaviour" ] = EOL_LAST_CHAR
731
- when "alternating-last-char"
732
- @settings[ "eol_behaviour" ] = EOL_ALT_FIRST_CHAR
733
- else # default
734
- @settings[ "eol_behaviour" ] = EOL_ALT_END
735
- end
736
- when "context.delay", 'interaction.blink_duration', 'interaction.choice_delay'
737
- @settings[ command ] = arg.to_f
738
- end
739
- end
740
- end
741
- protected :parseConfigurationFile
742
-
743
- def getTokenRegexp( hash, arg, match )
744
- language = match[ 1 ]
745
- token_class = match[ 2 ]
746
- case_insensitive = ( match[ 3 ] != nil )
747
- hash[ language ] = ( hash[ language ] or Hash.new )
748
- if case_insensitive
749
- hash[ language ][ token_class ] = Regexp.new( arg, Regexp::IGNORECASE )
218
+ when '-s', '--load-session'
219
+ @session_to_load = session_filepath_for( argv.shift )
220
+ when '--test', '--testing'
221
+ @testing = true
750
222
  else
751
- hash[ language ][ token_class ] = Regexp.new arg
223
+ # a name of a file to open
224
+ @files.push arg
752
225
  end
226
+ end
753
227
  end
228
+ protected :parseOptions
754
229
 
755
- def redraw
756
- loadConfiguration
757
- initializeDisplay
758
- updateStatusLine
759
- updateContextLine
760
- @current_buffer.display
230
+ def printUsage
231
+ puts "Usage: #{$0} [options] [file] [file...]"
232
+ puts "\t--help\tDisplay usage"
233
+ puts "\t-c <config file>\tLoad this config file instead of ~/.diakonos/diakonos.conf"
234
+ puts "\t-e, --execute <Ruby code>\tExecute Ruby code (such as Diakonos commands) after startup"
235
+ puts "\t-m, --open-matching <regular expression>\tOpen all matching files under current directory"
236
+ puts "\t-ro <file>\tLoad file as read-only"
237
+ puts "\t-s, --load-session <session identifier>\tLoad a session"
761
238
  end
239
+ protected :printUsage
762
240
 
763
- def log( string )
764
- @log.puts string
765
- @log.flush
766
- end
767
-
768
- def debugLog( string )
769
- @debug.puts( Time.now.strftime( "[%a %H:%M:%S] #{string}" ) )
770
- @debug.flush
771
- end
772
-
773
- def register_proc( the_proc, hook_name, priority = 0 )
774
- @hooks[ hook_name ] << { :proc => the_proc, :priority => priority }
775
- end
776
-
777
241
  def clearNonMovementFlag
778
- @there_was_non_movement = false
779
- end
780
-
781
- # -----------------------------------------------------------------------
782
-
783
- def main_window_height
784
- # One line for the status line
785
- # One line for the input line
786
- # One line for the context line
787
- retval = Curses::lines - 2
788
- if @settings[ "context.visible" ] and not @settings[ "context.combined" ]
789
- retval = retval - 1
790
- end
791
- retval
242
+ @there_was_non_movement = false
792
243
  end
793
244
 
794
- def main_window_width
795
- return Curses::cols
796
- end
245
+ # -----------------------------------------------------------------------
797
246
 
798
247
  def start
799
- initializeDisplay
800
-
801
- @hooks = {
802
- :after_buffer_switch => [],
803
- :after_open => [],
804
- :after_save => [],
805
- :after_startup => [],
806
- }
807
- Dir[ "#{@script_dir}/*" ].each do |script|
808
- begin
809
- require script
810
- rescue Exception => e
811
- showException(
812
- e,
813
- [
814
- "There is a syntax error in the script.",
815
- "An invalid hook name was used."
816
- ]
817
- )
818
- end
819
- end
820
- @hooks.each do |hook_name, hook|
821
- hook.sort { |a,b| a[ :priority ] <=> b[ :priority ] }
822
- end
248
+ initializeDisplay
823
249
 
824
- setILine "Diakonos #{VERSION} (#{LAST_MODIFIED}) F1 for help F12 to configure Ctrl-Q to quit"
825
-
826
- num_opened = 0
827
- if @files.length == 0 and @read_only_files.length == 0
828
- num_opened += 1 if openFile
829
- else
830
- @files.each do |file|
831
- num_opened += 1 if openFile file
832
- end
833
- @read_only_files.each do |file|
834
- num_opened += 1 if openFile( file, Buffer::READ_ONLY )
835
- end
836
- end
837
-
838
- if num_opened > 0
839
- switchToBufferNumber 1
840
-
841
- updateStatusLine
842
- updateContextLine
843
-
844
- if @post_load_script != nil
845
- eval @post_load_script
846
- end
847
-
848
- runHookProcs :after_startup
849
-
850
- if not @settings[ 'suppress_welcome' ]
851
- openFile "#{@help_dir}/welcome.dhf"
852
- end
853
-
854
- begin
855
- # Main keyboard loop.
856
- while not @quitting
857
- processKeystroke
858
- @win_main.refresh
859
- end
860
- rescue SignalException => e
861
- debugLog "Terminated by signal (#{e.message})"
862
- end
863
-
864
- @debug.close
865
- end
866
- end
867
-
868
- def capture_keychain( c, context )
869
- if c == ENTER
870
- @capturing_keychain = false
871
- @current_buffer.deleteSelection
872
- str = context.to_keychain_s.strip
873
- @current_buffer.insertString str
874
- cursorRight( Buffer::STILL_TYPING, str.length )
250
+ if ENV[ 'COLORTERM' ] == 'gnome-terminal'
251
+ help_key = 'Shift-F1'
875
252
  else
876
- keychain_pressed = context.concat [ c ]
877
-
878
- function_and_args = @keychains.getLeaf( keychain_pressed )
879
-
880
- if function_and_args
881
- function, args = function_and_args
882
- end
883
-
884
- partial_keychain = @keychains.getNode( keychain_pressed )
885
- if partial_keychain
886
- setILine( "Part of existing keychain: " + keychain_pressed.to_keychain_s + "..." )
887
- else
888
- setILine keychain_pressed.to_keychain_s + "..."
889
- end
890
- processKeystroke( keychain_pressed )
253
+ help_key = 'F1'
891
254
  end
892
- end
893
-
894
- def capture_mapping( c, context )
895
- if c == ENTER
896
- @capturing_mapping = false
897
- @current_buffer.deleteSelection
898
- setILine
899
- else
900
- keychain_pressed = context.concat [ c ]
901
-
902
- function_and_args = @keychains.getLeaf( keychain_pressed )
903
-
904
- if function_and_args
905
- function, args = function_and_args
906
- setILine "#{keychain_pressed.to_keychain_s.strip} -> #{function}( #{args} )"
255
+ setILine "Diakonos #{VERSION} (#{LAST_MODIFIED}) #{help_key} for help F12 to configure Ctrl-Q to quit"
256
+
257
+ if @session_to_load
258
+ pid_session = @session
259
+ @session = nil
260
+ session_path = session_filepath_for( @session_to_load )
261
+ load_session_data session_path
262
+ if @session
263
+ @files.concat @session[ 'files' ]
907
264
  else
908
- partial_keychain = @keychains.getNode( keychain_pressed )
909
- if partial_keychain
910
- setILine( "Several mappings start with: " + keychain_pressed.to_keychain_s + "..." )
911
- processKeystroke( keychain_pressed )
912
- else
913
- setILine "There is no mapping for " + keychain_pressed.to_keychain_s
914
- end
265
+ new_session session_path
915
266
  end
916
- end
917
- end
918
-
919
- # context is an array of characters (bytes) which are keystrokes previously
920
- # typed (in a chain of keystrokes)
921
- def processKeystroke( context = [] )
922
- c = @win_main.getch
923
-
924
- if @capturing_keychain
925
- capture_keychain c, context
926
- elsif @capturing_mapping
927
- capture_mapping c, context
928
267
  else
929
-
930
- if context.empty?
931
- if c > 31 and c < 255 and c != BACKSPACE
932
- if @macro_history
933
- @macro_history.push "typeCharacter #{c}"
934
- end
935
- @there_was_non_movement = true
936
- typeCharacter c
937
- return
268
+ session_buffers = []
269
+
270
+ session_files = Dir[ "#{@session_dir}/*" ].grep( %r{/\d+$} )
271
+ pids = session_files.map { |sf| sf[ %r{/(\d+)$}, 1 ].to_i }
272
+ pids.each do |pid|
273
+ begin
274
+ Process.kill 0, pid
275
+ session_files.reject! { |sf| pid_session? sf }
276
+ rescue Errno::ESRCH, Errno::EPERM
277
+ # Process is no longer alive, so we consider the session stale
938
278
  end
939
279
  end
940
- keychain_pressed = context.concat [ c ]
941
-
942
- function_and_args = @keychains.getLeaf( keychain_pressed )
943
-
944
- if function_and_args
945
- function, args = function_and_args
946
- setILine if not @settings[ "context.combined" ]
947
-
948
- if args
949
- to_eval = "#{function}( #{args} )"
950
- else
951
- to_eval = function
952
- end
953
-
954
- if @macro_history
955
- @macro_history.push to_eval
280
+
281
+ session_files.each_with_index do |session_file,index|
282
+ session_buffers << openFile( session_file )
283
+
284
+ choice = getChoice(
285
+ "#{session_files.size} unclosed session(s) found. Open the above files? (session #{index+1} of #{session_files.size})",
286
+ [ CHOICE_YES, CHOICE_NO, CHOICE_DELETE ]
287
+ )
288
+
289
+ case choice
290
+ when CHOICE_YES
291
+ load_session_data session_file
292
+ if @session
293
+ @files.concat @session[ 'files' ]
294
+ File.delete session_file
295
+ break
296
+ end
297
+ when CHOICE_DELETE
298
+ File.delete session_file
956
299
  end
957
-
958
- begin
959
- eval to_eval, nil, "eval"
960
- @last_commands << to_eval unless to_eval == "repeatLast"
961
- if not @there_was_non_movement
962
- @there_was_non_movement = ( not to_eval.movement? )
300
+ end
301
+
302
+ if session_buffers.empty? and @files.empty? and @settings[ 'session.default_session' ]
303
+ session_file = session_filepath_for( @settings[ 'session.default_session' ] )
304
+ if File.exist? session_file
305
+ load_session_data session_file
306
+ if @session
307
+ @files.concat @session[ 'files' ]
963
308
  end
964
- rescue Exception => e
965
- debugLog e.message
966
- debugLog e.backtrace.join( "\n\t" )
967
- showException e
968
- end
969
- else
970
- partial_keychain = @keychains.getNode( keychain_pressed )
971
- if partial_keychain
972
- setILine( keychain_pressed.to_keychain_s + "..." )
973
- processKeystroke( keychain_pressed )
974
- else
975
- setILine "Nothing assigned to #{keychain_pressed.to_keychain_s}"
976
309
  end
977
310
  end
978
311
  end
979
- end
980
- protected :processKeystroke
981
-
982
- # Display text on the interaction line.
983
- def setILine( string = "" )
984
- Curses::curs_set 0
985
- @win_interaction.setpos( 0, 0 )
986
- @win_interaction.addstr( "%-#{Curses::cols}s" % string )
987
- @win_interaction.refresh
988
- Curses::curs_set 1
989
- string.length
990
- end
991
-
992
- def showClips
993
- clip_filename = @diakonos_home + "/clips.txt"
994
- File.open( clip_filename, "w" ) do |f|
995
- @clipboard.each do |clip|
996
- f.puts clip
997
- f.puts "---------------------------"
998
- end
999
- end
1000
- openFile clip_filename
1001
- end
1002
312
 
1003
- def switchTo( buffer )
1004
- switched = false
1005
- if buffer
1006
- @buffer_stack -= [ @current_buffer ]
1007
- if @current_buffer
1008
- @buffer_stack.push @current_buffer
313
+ Dir[ "#{@script_dir}/*" ].each do |script|
314
+ begin
315
+ require script
316
+ rescue Exception => e
317
+ showException(
318
+ e,
319
+ [
320
+ "There is a syntax error in the script.",
321
+ "An invalid hook name was used."
322
+ ]
323
+ )
1009
324
  end
1010
- @current_buffer = buffer
1011
- runHookProcs( :after_buffer_switch, buffer )
1012
- updateStatusLine
1013
- updateContextLine
1014
- buffer.display
1015
- switched = true
1016
325
  end
1017
-
1018
- switched
1019
- end
1020
- protected :switchTo
1021
-
1022
- def set_status_variable( identifier, value )
1023
- @status_vars[ identifier ] = value
1024
- end
326
+ @hooks.each do |hook_name, hook|
327
+ hook.sort { |a,b| a[ :priority ] <=> b[ :priority ] }
328
+ end
1025
329
 
1026
- def buildStatusLine( truncation = 0 )
1027
- var_array = Array.new
1028
- @settings[ "status.vars" ].each do |var|
1029
- case var
1030
- when "buffer_number"
1031
- var_array.push bufferToNumber( @current_buffer )
1032
- when "col"
1033
- var_array.push( @current_buffer.last_screen_col + 1 )
1034
- when "filename"
1035
- name = @current_buffer.nice_name
1036
- var_array.push( name[ ([ truncation, name.length ].min)..-1 ] )
1037
- when "modified"
1038
- if @current_buffer.modified
1039
- var_array.push @settings[ "status.modified_str" ]
1040
- else
1041
- var_array.push ""
1042
- end
1043
- when "num_buffers"
1044
- var_array.push @buffers.length
1045
- when "num_lines"
1046
- var_array.push @current_buffer.length
1047
- when "row", "line"
1048
- var_array.push( @current_buffer.last_row + 1 )
1049
- when "read_only"
1050
- if @current_buffer.read_only
1051
- var_array.push @settings[ "status.read_only_str" ]
1052
- else
1053
- var_array.push ""
1054
- end
1055
- when "selecting"
1056
- if @current_buffer.changing_selection
1057
- var_array.push @settings[ "status.selecting_str" ]
1058
- else
1059
- var_array.push ""
1060
- end
1061
- when "type"
1062
- var_array.push @current_buffer.original_language
1063
- when /^@/
1064
- var_array.push @status_vars[ var ]
1065
- end
330
+ num_opened = 0
331
+ if @files.length == 0 and @read_only_files.length == 0
332
+ num_opened += 1 if openFile
333
+ else
334
+ @files.each do |file|
335
+ num_opened += 1 if openFile file
1066
336
  end
1067
- str = nil
1068
- begin
1069
- status_left = @settings[ "status.left" ]
1070
- field_count = status_left.count "%"
1071
- status_left = status_left % var_array[ 0...field_count ]
1072
- status_right = @settings[ "status.right" ] % var_array[ field_count..-1 ]
1073
- filler_string = @settings[ "status.filler" ]
1074
- fill_amount = (Curses::cols - status_left.length - status_right.length) / filler_string.length
1075
- if fill_amount > 0
1076
- filler = filler_string * fill_amount
1077
- else
1078
- filler = ""
1079
- end
1080
- str = status_left + filler + status_right
1081
- rescue ArgumentError => e
1082
- str = "%-#{Curses::cols}s" % "(status line configuration error)"
337
+ @read_only_files.each do |file|
338
+ num_opened += 1 if openFile( file, Buffer::READ_ONLY )
1083
339
  end
1084
- return str
1085
- end
1086
- protected :buildStatusLine
340
+ end
1087
341
 
1088
- def updateStatusLine
1089
- str = buildStatusLine
1090
- if str.length > Curses::cols
1091
- str = buildStatusLine( str.length - Curses::cols )
342
+ if session_buffers
343
+ session_buffers.each do |buffer|
344
+ closeFile buffer
1092
345
  end
1093
- Curses::curs_set 0
1094
- @win_status.setpos( 0, 0 )
1095
- @win_status.addstr str
1096
- @win_status.refresh
1097
- Curses::curs_set 1
1098
- end
346
+ end
1099
347
 
1100
- def updateContextLine
1101
- if @win_context != nil
1102
- @context_thread.exit if @context_thread != nil
1103
- @context_thread = Thread.new do ||
1104
-
1105
- context = @current_buffer.context
1106
-
1107
- Curses::curs_set 0
1108
- @win_context.setpos( 0, 0 )
1109
- chars_printed = 0
1110
- if context.length > 0
1111
- truncation = [ @settings[ "context.max_levels" ], context.length ].min
1112
- max_length = [
1113
- ( Curses::cols / truncation ) - @settings[ "context.separator" ].length,
1114
- ( @settings[ "context.max_segment_width" ] or Curses::cols )
1115
- ].min
1116
- line = nil
1117
- context_subset = context[ 0...truncation ]
1118
- context_subset = context_subset.collect do |line|
1119
- line.strip[ 0...max_length ]
1120
- end
1121
-
1122
- context_subset.each do |line|
1123
- @win_context.attrset @settings[ "context.format" ]
1124
- @win_context.addstr line
1125
- chars_printed += line.length
1126
- @win_context.attrset @settings[ "context.separator.format" ]
1127
- @win_context.addstr @settings[ "context.separator" ]
1128
- chars_printed += @settings[ "context.separator" ].length
1129
- end
1130
- end
1131
-
1132
- @iline_mutex.synchronize do
1133
- @win_context.attrset @settings[ "context.format" ]
1134
- @win_context.addstr( " " * ( Curses::cols - chars_printed ) )
1135
- @win_context.refresh
1136
- end
1137
- @display_mutex.synchronize do
1138
- @win_main.setpos( @current_buffer.last_screen_y, @current_buffer.last_screen_x )
1139
- @win_main.refresh
1140
- end
1141
- Curses::curs_set 1
1142
- end
1143
-
1144
- @context_thread.priority = -2
348
+ if num_opened > 0
349
+ switchToBufferNumber 1
350
+
351
+ updateStatusLine
352
+ updateContextLine
353
+
354
+ if @post_load_script
355
+ eval @post_load_script
1145
356
  end
1146
- end
1147
-
1148
- def displayEnqueue( buffer )
1149
- @display_queue_mutex.synchronize do
1150
- @display_queue = buffer
357
+
358
+ runHookProcs :after_startup
359
+
360
+ if not @settings[ 'suppress_welcome' ]
361
+ openFile "#{@help_dir}/welcome.dhf"
1151
362
  end
1152
- end
1153
-
1154
- def displayDequeue
1155
- @display_queue_mutex.synchronize do
1156
- if @display_queue
1157
- Thread.new( @display_queue ) do |b|
1158
- @display_mutex.lock
1159
- @display_mutex.unlock
1160
- b.display
363
+
364
+ begin
365
+ # Main keyboard loop.
366
+ while not @quitting
367
+ processKeystroke
368
+ @win_main.refresh
1161
369
  end
1162
- @display_queue = nil
370
+ rescue SignalException => e
371
+ debugLog "Terminated by signal (#{e.message})"
372
+ end
373
+
374
+ if pid_session?
375
+ File.delete @session[ 'filename' ]
1163
376
  end
377
+
378
+ @debug.close
1164
379
  end
1165
380
  end
1166
381
 
1167
- # completion_array is the array of strings that tab completion can use
1168
- def getUserInput( prompt, history = @rlh_general, initial_text = "", completion_array = nil, &block )
1169
- if @playing_macro
1170
- retval = @macro_input_history.shift
1171
- else
1172
- retval = Readline.new( self, @win_interaction, prompt, initial_text, completion_array, history, &block ).readline
1173
- if @macro_history
1174
- @macro_input_history.push retval
1175
- end
1176
- setILine
382
+ def showClips
383
+ clip_filename = @diakonos_home + "/clips.txt"
384
+ File.open( clip_filename, "w" ) do |f|
385
+ @clipboard.each do |clip|
386
+ f.puts clip
387
+ f.puts "---------------------------"
1177
388
  end
1178
- retval
389
+ end
390
+ openFile clip_filename
1179
391
  end
1180
392
 
1181
393
  def getLanguageFromName( name )
1182
- retval = nil
1183
- @filemasks.each do |language,filemask|
1184
- if name =~ filemask
1185
- retval = language
1186
- break
1187
- end
394
+ retval = nil
395
+ @filemasks.each do |language,filemask|
396
+ if name =~ filemask
397
+ retval = language
398
+ break
1188
399
  end
1189
- retval
400
+ end
401
+ retval
1190
402
  end
1191
-
403
+
1192
404
  def getLanguageFromShaBang( first_line )
1193
- retval = nil
1194
- @bangmasks.each do |language,bangmask|
1195
- if first_line =~ /^#!/ and first_line =~ bangmask
1196
- retval = language
1197
- break
1198
- end
405
+ retval = nil
406
+ @bangmasks.each do |language,bangmask|
407
+ if first_line =~ bangmask
408
+ retval = language
409
+ break
1199
410
  end
1200
- retval
411
+ end
412
+ retval
1201
413
  end
1202
-
414
+
1203
415
  def showException( e, probable_causes = [ "Unknown" ] )
1204
- begin
1205
- File.open( @error_filename, "w" ) do |f|
1206
- f.puts "Diakonos Error:"
1207
- f.puts
1208
- f.puts e.message
1209
- f.puts
1210
- f.puts "Probable Causes:"
1211
- f.puts
1212
- probable_causes.each do |pc|
1213
- f.puts "- #{pc}"
1214
- end
1215
- f.puts
1216
- f.puts "----------------------------------------------------"
1217
- f.puts "If you can reproduce this error, please report it at"
1218
- f.puts "http://linis.purepistos.net/ticket/list/Diakonos !"
1219
- f.puts "----------------------------------------------------"
1220
- f.puts e.backtrace
1221
- end
1222
- openFile( @error_filename )
1223
- rescue Exception => e2
1224
- debugLog "EXCEPTION: #{e.message}"
1225
- debugLog "\t#{e.backtrace}"
1226
- end
1227
- end
1228
-
1229
- def logBacktrace
1230
- begin
1231
- raise Exception
1232
- rescue Exception => e
1233
- e.backtrace[ 1..-1 ].each do |x|
1234
- debugLog x
1235
- end
416
+ begin
417
+ File.open( @error_filename, "w" ) do |f|
418
+ f.puts "Diakonos Error:"
419
+ f.puts
420
+ f.puts "#{e.class}: #{e.message}"
421
+ f.puts
422
+ f.puts "Probable Causes:"
423
+ f.puts
424
+ probable_causes.each do |pc|
425
+ f.puts "- #{pc}"
426
+ end
427
+ f.puts
428
+ f.puts "----------------------------------------------------"
429
+ f.puts "If you can reproduce this error, please report it at"
430
+ f.puts "http://linis.purepistos.net/ticket/list/Diakonos !"
431
+ f.puts "----------------------------------------------------"
432
+ f.puts e.backtrace
1236
433
  end
434
+ openFile( @error_filename )
435
+ rescue Exception => e2
436
+ debugLog "EXCEPTION: #{e.message}"
437
+ debugLog "\t#{e.backtrace}"
438
+ end
1237
439
  end
1238
440
 
1239
- # The given buffer_number should be 1-based, not zero-based.
1240
- # Returns nil if no such buffer exists.
1241
- def bufferNumberToName( buffer_number )
1242
- return nil if buffer_number < 1
1243
-
1244
- number = 1
1245
- buffer_name = nil
1246
- @buffers.each_key do |name|
1247
- if number == buffer_number
1248
- buffer_name = name
1249
- break
1250
- end
1251
- number += 1
1252
- end
1253
- return buffer_name
1254
- end
441
+ def subShellVariables( string )
442
+ return nil if string.nil?
1255
443
 
1256
- # The returned value is 1-based, not zero-based.
1257
- # Returns nil if no such buffer exists.
1258
- def bufferToNumber( buffer )
1259
- number = 1
1260
- buffer_number = nil
1261
- @buffers.each_value do |b|
1262
- if b == buffer
1263
- buffer_number = number
1264
- break
1265
- end
1266
- number += 1
1267
- end
1268
- buffer_number
1269
- end
444
+ retval = string
445
+ retval = retval.subHome
1270
446
 
1271
- def subShellVariables( string )
1272
- return nil if string == nil
1273
-
1274
- retval = string
1275
- retval = retval.subHome
1276
-
1277
- # Current buffer filename
1278
- retval.gsub!( /\$f/, ( $1 or "" ) + ( @current_buffer.name or "" ) )
1279
-
1280
- # space-separated list of all buffer filenames
1281
- name_array = Array.new
1282
- @buffers.each_value do |b|
1283
- name_array.push b.name
1284
- end
1285
- retval.gsub!( /\$F/, ( $1 or "" ) + ( name_array.join(' ') or "" ) )
1286
-
1287
- # Get user input, sub it in
1288
- if retval =~ /\$i/
1289
- user_input = getUserInput( "Argument: ", @rlh_shell )
1290
- retval.gsub!( /\$i/, user_input )
1291
- end
1292
-
1293
- # Current clipboard text
1294
- if retval =~ /\$c/
1295
- clip_filename = @diakonos_home + "/clip.txt"
1296
- File.open( clip_filename, "w" ) do |clipfile|
1297
- if @clipboard.clip != nil
1298
- clipfile.puts( @clipboard.clip.join( "\n" ) )
1299
- end
1300
- end
1301
- retval.gsub!( /\$c/, clip_filename )
1302
- end
1303
-
1304
- # Current klipper (KDE clipboard) text
1305
- if retval =~ /\$k/
1306
- clip_filename = @diakonos_home + "/clip.txt"
1307
- File.open( clip_filename, "w" ) do |clipfile|
1308
- clipfile.puts( `dcop klipper klipper getClipboardContents` )
1309
- end
1310
- retval.gsub!( /\$k/, clip_filename )
1311
- end
1312
-
1313
- # Currently selected text
1314
- if retval =~ /\$s/
1315
- text_filename = @diakonos_home + "/selected.txt"
1316
-
1317
- File.open( text_filename, "w" ) do |textfile|
1318
- selected_text = @current_buffer.selected_text
1319
- if selected_text != nil
1320
- textfile.puts( selected_text.join( "\n" ) )
1321
- end
1322
- end
1323
- retval.gsub!( /\$s/, text_filename )
1324
- end
1325
-
1326
- retval
1327
- end
1328
-
1329
- def showMessage( message, non_interaction_duration = @settings[ 'interaction.choice_delay' ] )
1330
- terminateMessage
1331
-
1332
- @message_expiry = Time.now + non_interaction_duration
1333
- @message_thread = Thread.new do
1334
- time_left = @message_expiry - Time.now
1335
- while time_left > 0
1336
- setILine "(#{time_left.round}) #{message}"
1337
- @win_main.setpos( @saved_main_y, @saved_main_x )
1338
- sleep 1
1339
- time_left = @message_expiry - Time.now
1340
- end
1341
- setILine message
1342
- @win_main.setpos( @saved_main_y, @saved_main_x )
1343
- end
1344
- end
1345
-
1346
- def terminateMessage
1347
- if @message_thread != nil and @message_thread.alive?
1348
- @message_thread.terminate
1349
- @message_thread = nil
1350
- end
1351
- end
1352
-
1353
- def interactionBlink( message = nil )
1354
- terminateMessage
1355
- setILine @settings[ 'interaction.blink_string' ]
1356
- sleep @settings[ 'interaction.blink_duration' ]
1357
- setILine message if message != nil
1358
- end
1359
-
1360
- # choices should be an array of CHOICE_* constants.
1361
- # default is what is returned when Enter is pressed.
1362
- def getChoice( prompt, choices, default = nil )
1363
- retval = @iterated_choice
1364
- if retval != nil
1365
- @choice_iterations -= 1
1366
- if @choice_iterations < 1
1367
- @iterated_choice = nil
1368
- @do_display = true
1369
- end
1370
- return retval
1371
- end
1372
-
1373
- @saved_main_x = @win_main.curx
1374
- @saved_main_y = @win_main.cury
447
+ # Current buffer filename
448
+ retval.gsub!( /\$f/, ( $1 or "" ) + ( @current_buffer.name or "" ) )
1375
449
 
1376
- msg = prompt + " "
1377
- choice_strings = choices.collect do |choice|
1378
- CHOICE_STRINGS[ choice ]
1379
- end
1380
- msg << choice_strings.join( ", " )
1381
-
1382
- if default.nil?
1383
- showMessage msg
1384
- else
1385
- setILine msg
450
+ # space-separated list of all buffer filenames
451
+ name_array = Array.new
452
+ @buffers.each_value do |b|
453
+ name_array.push b.name
454
+ end
455
+ retval.gsub!( /\$F/, ( $1 or "" ) + ( name_array.join(' ') or "" ) )
456
+
457
+ # Get user input, sub it in
458
+ if retval =~ /\$i/
459
+ user_input = getUserInput( "Argument: ", @rlh_shell )
460
+ retval.gsub!( /\$i/, user_input )
461
+ end
462
+
463
+ # Current clipboard text
464
+ if retval =~ /\$c/
465
+ clip_filename = @diakonos_home + "/clip.txt"
466
+ File.open( clip_filename, "w" ) do |clipfile|
467
+ if @clipboard.clip
468
+ clipfile.puts( @clipboard.clip.join( "\n" ) )
469
+ end
1386
470
  end
1387
-
1388
- c = nil
1389
- while retval.nil?
1390
- c = @win_interaction.getch
1391
-
1392
- case c
1393
- when Curses::KEY_NPAGE
1394
- pageDown
1395
- when Curses::KEY_PPAGE
1396
- pageUp
1397
- else
1398
- if @message_expiry != nil and Time.now < @message_expiry
1399
- interactionBlink
1400
- showMessage msg
1401
- else
1402
- case c
1403
- when ENTER
1404
- retval = default
1405
- when ?0..?9
1406
- if @choice_iterations < 1
1407
- @choice_iterations = ( c - ?0 )
1408
- else
1409
- @choice_iterations = @choice_iterations * 10 + ( c - ?0 )
1410
- end
1411
- else
1412
- choices.each do |choice|
1413
- if CHOICE_KEYS[ choice ].include? c
1414
- retval = choice
1415
- break
1416
- end
1417
- end
1418
- end
1419
-
1420
- if retval.nil?
1421
- interactionBlink( msg )
1422
- end
1423
- end
1424
- end
471
+ retval.gsub!( /\$c/, clip_filename )
472
+ end
473
+
474
+ # Current klipper (KDE clipboard) text
475
+ if retval =~ /\$k/
476
+ clip_filename = @diakonos_home + "/clip.txt"
477
+ File.open( clip_filename, "w" ) do |clipfile|
478
+ clipfile.puts( `dcop klipper klipper getClipboardContents` )
1425
479
  end
1426
-
1427
- terminateMessage
1428
- setILine
1429
-
1430
- if @choice_iterations > 0
1431
- @choice_iterations -= 1
1432
- @iterated_choice = retval
1433
- @do_display = false
480
+ retval.gsub!( /\$k/, clip_filename )
481
+ end
482
+
483
+ # Currently selected text
484
+ if retval =~ /\$s/
485
+ text_filename = @diakonos_home + "/selected.txt"
486
+
487
+ File.open( text_filename, "w" ) do |textfile|
488
+ selected_text = @current_buffer.selected_text
489
+ if selected_text
490
+ textfile.puts( selected_text.join( "\n" ) )
491
+ end
1434
492
  end
1435
-
1436
- retval
493
+ retval.gsub!( /\$s/, text_filename )
494
+ end
495
+
496
+ retval
1437
497
  end
1438
498
 
1439
499
  def startRecordingMacro( name = nil )
1440
- return if @macro_history != nil
1441
- @macro_name = name
1442
- @macro_history = Array.new
1443
- @macro_input_history = Array.new
1444
- setILine "Started macro recording."
500
+ return if @macro_history
501
+ @macro_name = name
502
+ @macro_history = Array.new
503
+ @macro_input_history = Array.new
504
+ setILine "Started macro recording."
1445
505
  end
1446
506
  protected :startRecordingMacro
1447
507
 
1448
508
  def stopRecordingMacro
1449
- @macro_history.pop # Remove the stopRecordingMacro command itself
1450
- @macros[ @macro_name ] = [ @macro_history, @macro_input_history ]
1451
- @macro_history = nil
1452
- @macro_input_history = nil
1453
- setILine "Stopped macro recording."
509
+ @macro_history.pop # Remove the stopRecordingMacro command itself
510
+ @macros[ @macro_name ] = [ @macro_history, @macro_input_history ]
511
+ @macro_history = nil
512
+ @macro_input_history = nil
513
+ setILine "Stopped macro recording."
1454
514
  end
1455
515
  protected :stopRecordingMacro
1456
516
 
1457
- def typeCharacter( c )
1458
- @current_buffer.deleteSelection( Buffer::DONT_DISPLAY )
1459
- @current_buffer.insertChar c
1460
- cursorRight( Buffer::STILL_TYPING )
1461
- end
1462
-
1463
517
  def loadTags
1464
- @tags = Hash.new
1465
- if @current_buffer != nil and @current_buffer.name != nil
1466
- path = File.expand_path( File.dirname( @current_buffer.name ) )
1467
- tagfile = path + "/tags"
1468
- else
1469
- tagfile = "./tags"
1470
- end
1471
- if FileTest.exists? tagfile
1472
- IO.foreach( tagfile ) do |line_|
1473
- line = line_.chomp
1474
- # <tagname>\t<filepath>\t<line number or regexp>\t<kind of tag>
1475
- tag, file, command, kind, rest = line.split( /\t/ )
1476
- command.gsub!( /;"$/, "" )
1477
- if command =~ /^\/.*\/$/
1478
- command = command[ 1...-1 ]
1479
- end
1480
- @tags[ tag ] ||= Array.new
1481
- @tags[ tag ].push CTag.new( file, command, kind, rest )
1482
- end
1483
- else
1484
- setILine "(tags file not found)"
1485
- end
1486
- end
1487
-
1488
- def refreshAll
1489
- @win_main.refresh
1490
- if @win_context != nil
1491
- @win_context.refresh
518
+ @tags = Hash.new
519
+ if @current_buffer and @current_buffer.name
520
+ path = File.expand_path( File.dirname( @current_buffer.name ) )
521
+ tagfile = path + "/tags"
522
+ else
523
+ tagfile = "./tags"
524
+ end
525
+ if FileTest.exists? tagfile
526
+ IO.foreach( tagfile ) do |line_|
527
+ line = line_.chomp
528
+ # <tagname>\t<filepath>\t<line number or regexp>\t<kind of tag>
529
+ tag, file, command, kind, rest = line.split( /\t/ )
530
+ command.gsub!( /;"$/, "" )
531
+ if command =~ /^\/.*\/$/
532
+ command = command[ 1...-1 ]
533
+ end
534
+ @tags[ tag ] ||= Array.new
535
+ @tags[ tag ].push CTag.new( file, command, kind, rest )
1492
536
  end
1493
- @win_status.refresh
1494
- @win_interaction.refresh
1495
- end
1496
-
1497
- def openListBuffer
1498
- @list_buffer = openFile( @list_filename )
1499
- end
1500
-
1501
- def closeListBuffer
1502
- closeFile( @list_buffer )
1503
- @list_buffer = nil
1504
- end
1505
- def showing_list?
1506
- @list_buffer
1507
- end
1508
- def list_item_selected?
1509
- @list_buffer and @list_buffer.selecting?
1510
- end
1511
- def current_list_item
1512
- if @list_buffer
1513
- @list_buffer.select_current_line
1514
- end
1515
- end
1516
- def select_list_item
1517
- if @list_buffer
1518
- line = @list_buffer.select_current_line
1519
- @list_buffer.display
1520
- line
1521
- end
1522
- end
1523
- def previous_list_item
1524
- if @list_buffer
1525
- cursorUp
1526
- @list_buffer[ @list_buffer.currentRow ]
537
+ else
538
+ setILine "(tags file not found)"
1527
539
  end
1528
540
  end
1529
- def next_list_item
1530
- if @list_buffer
1531
- cursorDown
1532
- @list_buffer[ @list_buffer.currentRow ]
541
+
542
+ def write_to_clip_file( text )
543
+ clip_filename = @diakonos_home + "/clip.txt"
544
+ File.open( clip_filename, "w" ) do |f|
545
+ f.print text
1533
546
  end
547
+ clip_filename
1534
548
  end
1535
-
1536
- def open_help_buffer
1537
- @help_buffer = openFile( @help_filename )
1538
- end
1539
- def close_help_buffer
1540
- closeFile @help_buffer
1541
- @help_buffer = nil
1542
- end
1543
-
1544
- def runHookProcs( hook_id, *args )
1545
- @hooks[ hook_id ].each do |hook_proc|
1546
- hook_proc[ :proc ].call( *args )
1547
- end
1548
- end
1549
-
1550
- # --------------------------------------------------------------------
1551
- #
1552
- # Program Functions
1553
-
1554
- def addNamedBookmark( name_ = nil )
1555
- if name_ == nil
1556
- name = getUserInput "Bookmark name: "
1557
- else
1558
- name = name_
1559
- end
1560
549
 
1561
- if name != nil
1562
- @bookmarks[ name ] = Bookmark.new( @current_buffer, @current_buffer.currentRow, @current_buffer.currentColumn, name )
1563
- setILine "Added bookmark #{@bookmarks[ name ].to_s}."
1564
- end
1565
- end
1566
-
1567
- def anchorSelection
1568
- @current_buffer.anchorSelection
1569
- updateStatusLine
1570
- end
1571
-
1572
- def backspace
1573
- delete if( @current_buffer.changing_selection or cursorLeft( Buffer::STILL_TYPING ) )
1574
- end
1575
-
1576
- def carriageReturn
1577
- @current_buffer.carriageReturn
1578
- @current_buffer.deleteSelection
1579
- end
1580
-
1581
- def changeSessionSetting( key_ = nil, value = nil, do_redraw = DONT_REDRAW )
1582
- if key_ == nil
1583
- key = getUserInput( "Setting: " )
1584
- else
1585
- key = key_
1586
- end
1587
-
1588
- if key != nil
1589
- if value == nil
1590
- value = getUserInput( "Value: " )
1591
- end
1592
- case @settings[ key ]
1593
- when String
1594
- value = value.to_s
1595
- when Fixnum
1596
- value = value.to_i
1597
- when TrueClass, FalseClass
1598
- value = value.to_b
1599
- end
1600
- @session_settings[ key ] = value
1601
- redraw if do_redraw
1602
- setILine "#{key} = #{value}"
1603
- end
1604
- end
1605
-
1606
- def clearMatches
1607
- @current_buffer.clearMatches Buffer::DO_DISPLAY
1608
- end
1609
-
1610
- def close_code
1611
- @current_buffer.close_code
1612
- end
1613
-
1614
- # Returns the choice the user made, or nil if the user was not prompted to choose.
1615
- def closeFile( buffer = @current_buffer, to_all = nil )
1616
- return nil if buffer == nil
1617
-
1618
- choice = nil
1619
- if @buffers.has_value?( buffer )
1620
- do_closure = true
1621
-
1622
- if buffer.modified
1623
- if not buffer.read_only
1624
- if to_all == nil
1625
- choices = [ CHOICE_YES, CHOICE_NO, CHOICE_CANCEL ]
1626
- if @quitting
1627
- choices.concat [ CHOICE_YES_TO_ALL, CHOICE_NO_TO_ALL ]
1628
- end
1629
- choice = getChoice(
1630
- "Save changes to #{buffer.nice_name}?",
1631
- choices,
1632
- CHOICE_CANCEL
1633
- )
1634
- else
1635
- choice = to_all
1636
- end
1637
- case choice
1638
- when CHOICE_YES, CHOICE_YES_TO_ALL
1639
- do_closure = true
1640
- saveFile( buffer )
1641
- when CHOICE_NO, CHOICE_NO_TO_ALL
1642
- do_closure = true
1643
- when CHOICE_CANCEL
1644
- do_closure = false
1645
- end
1646
- end
1647
- end
1648
-
1649
- if do_closure
1650
- del_buffer_key = nil
1651
- previous_buffer = nil
1652
- to_switch_to = nil
1653
- switching = false
1654
-
1655
- # Search the buffer hash for the buffer we want to delete,
1656
- # and mark the one we will switch to after deletion.
1657
- @buffers.each do |buffer_key,buf|
1658
- if switching
1659
- to_switch_to = buf
1660
- break
1661
- end
1662
- if buf == buffer
1663
- del_buffer_key = buffer_key
1664
- switching = true
1665
- next
1666
- end
1667
- previous_buffer = buf
1668
- end
1669
-
1670
- buf = nil
1671
- while(
1672
- ( not @buffer_stack.empty? ) and
1673
- ( not @buffers.values.include?( buf ) ) or
1674
- ( @buffers.index( buf ) == del_buffer_key )
1675
- ) do
1676
- buf = @buffer_stack.pop
1677
- end
1678
- if @buffers.values.include?( buf )
1679
- to_switch_to = buf
1680
- end
1681
-
1682
- if to_switch_to != nil
1683
- switchTo( to_switch_to )
1684
- elsif previous_buffer != nil
1685
- switchTo( previous_buffer )
1686
- else
1687
- # No buffers left. Open a new blank one.
1688
- openFile
1689
- end
1690
-
1691
- @buffers.delete del_buffer_key
1692
-
1693
- updateStatusLine
1694
- updateContextLine
1695
- end
1696
- else
1697
- log "No such buffer: #{buffer.name}"
1698
- end
1699
-
1700
- return choice
1701
- end
1702
-
1703
- def collapseWhitespace
1704
- @current_buffer.collapseWhitespace
1705
- end
1706
-
1707
- def columnize( delimiter = nil, num_spaces_padding = 0 )
1708
- if delimiter.nil?
1709
- delimiter = getUserInput(
1710
- "Column delimiter (regexp): ",
1711
- @rlh_general,
1712
- @settings[ "lang.#{@current_buffer.original_language}.column_delimiters" ] || ''
1713
- )
1714
- end
1715
- if delimiter and num_spaces_padding
1716
- @current_buffer.columnize Regexp.new( delimiter ), num_spaces_padding
1717
- end
1718
- end
1719
-
1720
- def comment_out
1721
- @current_buffer.comment_out
1722
- end
1723
-
1724
- def copySelection
1725
- @clipboard.addClip @current_buffer.copySelection
1726
- removeSelection
1727
- end
1728
-
1729
- def copy_selection_to_klipper
1730
- if send_to_klipper( @current_buffer.selected_text )
1731
- removeSelection
1732
- end
1733
- end
1734
-
1735
- def write_to_clip_file( text )
1736
- clip_filename = @diakonos_home + "/clip.txt"
1737
- File.open( clip_filename, "w" ) do |f|
1738
- f.print text
1739
- end
1740
- clip_filename
1741
- end
1742
-
1743
550
  # Returns true iff some text was copied to klipper.
1744
551
  def send_to_klipper( text )
1745
552
  return false if text.nil?
1746
-
553
+
1747
554
  clip_filename = write_to_clip_file( text.join( "\n" ) )
1748
555
  # A little shell sorcery to ensure the shell doesn't strip off trailing newlines.
1749
556
  # Thank you to pgas from irc.freenode.net#bash for help with this.
@@ -1751,185 +558,14 @@ class Diakonos
1751
558
  true
1752
559
  end
1753
560
 
1754
- # Returns true iff the cursor changed positions
1755
- def cursorDown
1756
- return @current_buffer.cursorTo( @current_buffer.last_row + 1, @current_buffer.last_col, Buffer::DO_DISPLAY, Buffer::STOPPED_TYPING, DONT_ADJUST_ROW )
1757
- end
1758
-
1759
- # Returns true iff the cursor changed positions
1760
- def cursorLeft( stopped_typing = Buffer::STOPPED_TYPING )
1761
- return @current_buffer.cursorTo( @current_buffer.last_row, @current_buffer.last_col - 1, Buffer::DO_DISPLAY, stopped_typing )
1762
- end
1763
-
1764
- def cursorRight( stopped_typing = Buffer::STOPPED_TYPING, amount = 1 )
1765
- return @current_buffer.cursorTo( @current_buffer.last_row, @current_buffer.last_col + amount, Buffer::DO_DISPLAY, stopped_typing )
1766
- end
1767
-
1768
- # Returns true iff the cursor changed positions
1769
- def cursorUp
1770
- return @current_buffer.cursorTo( @current_buffer.last_row - 1, @current_buffer.last_col, Buffer::DO_DISPLAY, Buffer::STOPPED_TYPING, DONT_ADJUST_ROW )
1771
- end
1772
-
1773
- def cursorBOF
1774
- @current_buffer.cursorTo( 0, 0, Buffer::DO_DISPLAY )
1775
- end
1776
-
1777
- def cursorBOL
1778
- @current_buffer.cursorToBOL
1779
- end
1780
-
1781
- def cursorEOL
1782
- @current_buffer.cursorToEOL
1783
- end
1784
-
1785
- def cursorEOF
1786
- @current_buffer.cursorToEOF
1787
- end
1788
-
1789
- # Top of view
1790
- def cursorTOV
1791
- @current_buffer.cursorToTOV
1792
- end
1793
-
1794
- # Bottom of view
1795
- def cursorBOV
1796
- @current_buffer.cursorToBOV
1797
- end
1798
-
1799
- def cursorReturn( dir_str = "backward" )
1800
- stack_pointer, stack_size = @current_buffer.cursorReturn( dir_str.toDirection( :backward ) )
1801
- setILine( "Location: #{stack_pointer+1}/#{stack_size}" )
1802
- end
1803
-
1804
- def cutSelection
1805
- delete if @clipboard.addClip( @current_buffer.copySelection )
1806
- end
1807
-
1808
- def cut_selection_to_klipper
1809
- if send_to_klipper( @current_buffer.selected_text )
1810
- delete
1811
- end
1812
- end
1813
-
1814
- def delete
1815
- @current_buffer.delete
1816
- end
1817
-
1818
- def delete_and_store_line_to_klipper
1819
- removed_text = @current_buffer.deleteLine
1820
- if removed_text
1821
- if @last_commands[ -1 ] =~ /^delete_and_store_line_to_klipper/
1822
- clip_filename = write_to_clip_file( removed_text << "\n" )
1823
- `clipping="$(dcop klipper klipper getClipboardContents)\n$(cat #{clip_filename};printf "_")"; dcop klipper klipper setClipboardContents "${clipping%_}"`
1824
- else
1825
- send_to_klipper [ removed_text, "" ]
1826
- end
1827
- end
1828
- end
1829
-
1830
- def deleteAndStoreLine
1831
- removed_text = @current_buffer.deleteLine
1832
- if removed_text
1833
- clip = [ removed_text, "" ]
1834
- if @last_commands[ -1 ] =~ /^deleteAndStoreLine/
1835
- @clipboard.appendToClip clip
1836
- else
1837
- @clipboard.addClip clip
1838
- end
1839
- end
1840
- end
1841
-
1842
- def delete_line_to_klipper
1843
- removed_text = @current_buffer.deleteLine
1844
- if removed_text
1845
- send_to_klipper [ removed_text, "" ]
1846
- end
1847
- end
1848
-
1849
- def deleteLine
1850
- removed_text = @current_buffer.deleteLine
1851
- @clipboard.addClip( [ removed_text, "" ] ) if removed_text
1852
- end
1853
-
1854
- def delete_to_EOL_to_klipper
1855
- removed_text = @current_buffer.deleteToEOL
1856
- if removed_text
1857
- send_to_klipper removed_text
1858
- end
1859
- end
1860
-
1861
- def deleteToEOL
1862
- removed_text = @current_buffer.deleteToEOL
1863
- @clipboard.addClip( removed_text ) if removed_text
1864
- end
1865
-
1866
- def evaluate( code_ = nil )
1867
- if code_ == nil
1868
- if @current_buffer.changing_selection
1869
- selected_text = @current_buffer.copySelection[ 0 ]
1870
- end
1871
- code = getUserInput( "Ruby code: ", @rlh_general, ( selected_text or "" ), FUNCTIONS )
1872
- else
1873
- code = code_
1874
- end
1875
-
1876
- if code != nil
1877
- begin
1878
- eval code
1879
- rescue Exception => e
1880
- showException(
1881
- e,
1882
- [
1883
- "The code given to evaluate has a syntax error.",
1884
- "The code given to evaluate refers to a Diakonos command which does not exist, or is misspelled.",
1885
- "The code given to evaluate refers to a Diakonos command with missing arguments.",
1886
- "The code given to evaluate refers to a variable or method which does not exist.",
1887
- ]
1888
- )
1889
- end
1890
- end
1891
- end
1892
-
1893
- def find( dir_str = "down", case_sensitive = CASE_INSENSITIVE, regexp_source_ = nil, replacement = nil )
1894
- direction = dir_str.toDirection
1895
- if regexp_source_.nil?
1896
- if @current_buffer.changing_selection
1897
- selected_text = @current_buffer.copySelection[ 0 ]
1898
- end
1899
- starting_row, starting_col = @current_buffer.last_row, @current_buffer.last_col
1900
-
1901
- regexp_source = getUserInput(
1902
- "Search regexp: ",
1903
- @rlh_search,
1904
- ( selected_text or "" )
1905
- ) { |input|
1906
- if input.length > 1
1907
- find_ direction, case_sensitive, input, nil, starting_row, starting_col, QUIET
1908
- else
1909
- @current_buffer.removeSelection Buffer::DONT_DISPLAY
1910
- @current_buffer.clearMatches Buffer::DO_DISPLAY
1911
- end
1912
- }
1913
- else
1914
- regexp_source = regexp_source_
1915
- end
1916
-
1917
- if regexp_source
1918
- find_ direction, case_sensitive, regexp_source, replacement, starting_row, starting_col, NOISY
1919
- elsif starting_row and starting_col
1920
- @current_buffer.clearMatches
1921
- @current_buffer.cursorTo starting_row, starting_col
1922
- end
1923
- end
1924
-
1925
561
  # Worker method for find function.
1926
562
  def find_( direction, case_sensitive, regexp_source, replacement, starting_row, starting_col, quiet )
1927
563
  return if( regexp_source.nil? or regexp_source.empty? )
1928
-
564
+
1929
565
  rs_array = regexp_source.newlineSplit
1930
566
  regexps = Array.new
1931
567
  exception_thrown = nil
1932
-
568
+
1933
569
  rs_array.each do |source|
1934
570
  begin
1935
571
  warning_verbosity = $VERBOSE
@@ -1949,925 +585,34 @@ class Diakonos
1949
585
  end
1950
586
  end
1951
587
  end
1952
-
588
+
1953
589
  if replacement == ASK_REPLACEMENT
1954
590
  replacement = getUserInput( "Replace with: ", @rlh_search )
1955
591
  end
1956
-
592
+
1957
593
  if exception_thrown and not quiet
1958
594
  setILine( "Searching literally; #{exception_thrown.message}" )
1959
595
  end
1960
-
596
+
1961
597
  @current_buffer.find(
1962
598
  regexps,
1963
- :direction => direction,
1964
- :replacement => replacement,
599
+ :direction => direction,
600
+ :replacement => replacement,
1965
601
  :starting_row => starting_row,
1966
602
  :starting_col => starting_col,
1967
- :quiet => quiet
603
+ :quiet => quiet
1968
604
  )
1969
605
  @last_search_regexps = regexps
1970
606
  end
1971
607
 
1972
- def findAgain( dir_str = nil )
1973
- if dir_str != nil
1974
- direction = dir_str.toDirection
1975
- @current_buffer.findAgain( @last_search_regexps, direction )
1976
- else
1977
- @current_buffer.findAgain( @last_search_regexps )
1978
- end
1979
- end
1980
-
1981
- def findAndReplace
1982
- searchAndReplace
1983
- end
1984
-
1985
- def findExact( dir_str = "down", search_term_ = nil )
1986
- if search_term_ == nil
1987
- if @current_buffer.changing_selection
1988
- selected_text = @current_buffer.copySelection[ 0 ]
1989
- end
1990
- search_term = getUserInput( "Search for: ", @rlh_search, ( selected_text or "" ) )
1991
- else
1992
- search_term = search_term_
1993
- end
1994
- if search_term != nil
1995
- direction = dir_str.toDirection
1996
- regexp = [ Regexp.new( Regexp.escape( search_term ) ) ]
1997
- @current_buffer.find( regexp, :direction => direction )
1998
- @last_search_regexps = regexp
1999
- end
2000
- end
2001
-
2002
- def goToLineAsk
2003
- input = getUserInput( "Go to [line number|+lines][,column number]: " )
2004
- if input != nil
2005
- row = nil
2006
-
2007
- if input =~ /([+-]\d+)/
2008
- row = @current_buffer.last_row + $1.to_i
2009
- col = @current_buffer.last_col
2010
- else
2011
- input = input.split( /\D+/ ).collect { |n| n.to_i }
2012
- if input.size > 0
2013
- if input[ 0 ] == 0
2014
- row = nil
2015
- else
2016
- row = input[ 0 ] - 1
2017
- end
2018
- if input[ 1 ] != nil
2019
- col = input[ 1 ] - 1
2020
- end
2021
- end
2022
- end
2023
-
2024
- if row
2025
- @current_buffer.goToLine( row, col )
2026
- end
2027
- end
2028
- end
2029
-
2030
- def goToNamedBookmark( name_ = nil )
2031
- if name_ == nil
2032
- name = getUserInput "Bookmark name: "
2033
- else
2034
- name = name_
2035
- end
2036
-
2037
- if name != nil
2038
- bookmark = @bookmarks[ name ]
2039
- if bookmark != nil
2040
- switchTo( bookmark.buffer )
2041
- bookmark.buffer.cursorTo( bookmark.row, bookmark.col, Buffer::DO_DISPLAY )
2042
- else
2043
- setILine "No bookmark named '#{name}'."
2044
- end
2045
- end
2046
- end
2047
-
2048
- def goToNextBookmark
2049
- @current_buffer.goToNextBookmark
2050
- end
2051
-
2052
- def goToPreviousBookmark
2053
- @current_buffer.goToPreviousBookmark
2054
- end
2055
-
2056
- def goToTag( tag_ = nil )
2057
- loadTags
2058
-
2059
- # If necessary, prompt for tag name.
2060
-
2061
- if tag_ == nil
2062
- if @current_buffer.changing_selection
2063
- selected_text = @current_buffer.copySelection[ 0 ]
2064
- end
2065
- tag_name = getUserInput( "Tag name: ", @rlh_general, ( selected_text or "" ), @tags.keys )
2066
- else
2067
- tag_name = tag_
2068
- end
2069
-
2070
- tag_array = @tags[ tag_name ]
2071
- if tag_array != nil and tag_array.length > 0
2072
- if i = tag_array.index( @last_tag )
2073
- tag = ( tag_array[ i + 1 ] or tag_array[ 0 ] )
2074
- else
2075
- tag = tag_array[ 0 ]
2076
- end
2077
- @last_tag = tag
2078
- @tag_stack.push [ @current_buffer.name, @current_buffer.last_row, @current_buffer.last_col ]
2079
- if switchTo( @buffers[ tag.file ] )
2080
- #@current_buffer.goToLine( 0 )
2081
- else
2082
- openFile( tag.file )
2083
- end
2084
- line_number = tag.command.to_i
2085
- if line_number > 0
2086
- @current_buffer.goToLine( line_number - 1 )
2087
- else
2088
- find( "down", CASE_SENSITIVE, tag.command )
2089
- end
2090
- elsif tag_name != nil
2091
- setILine "No such tag: '#{tag_name}'"
2092
- end
2093
- end
2094
-
2095
- def goToTagUnderCursor
2096
- goToTag @current_buffer.wordUnderCursor
2097
- end
2098
-
2099
- def with_list_file
2100
- File.open( @list_filename, "w" ) do |f|
2101
- yield f
2102
- end
2103
- end
2104
-
2105
- def matching_help_documents( str )
2106
- docs = []
2107
-
2108
- if str =~ %r{^/(.+)$}
2109
- regexp = $1
2110
- files = Dir[ "#{@help_dir}/*" ].select{ |f|
2111
- File.open( f ) { |io| io.grep( /#{regexp}/i ) }.any?
2112
- }
2113
- else
2114
- terms = str.gsub( /[^a-zA-Z0-9-]/, ' ' ).split.join( '|' )
2115
- file_grep = `egrep -i -l '^Tags.*\\b(#{terms})\\b' #{@help_dir}/*`
2116
- files = file_grep.split( /\s+/ )
2117
- end
2118
-
2119
- files.each do |file|
2120
- File.open( file ) do |f|
2121
- docs << ( "%-300s | %s" % [ f.gets.strip, file ] )
2122
- end
2123
- end
2124
-
2125
- docs.sort { |a,b| a.gsub( /^# (?:an?|the) */i, '# ' ) <=> b.gsub( /^# (?:an?|the) */i, '# ' ) }
2126
- end
2127
-
2128
- def open_help_document( selected_string )
2129
- help_file = selected_string.split( "| " )[ -1 ]
2130
- if File.exist? help_file
2131
- openFile help_file
2132
- end
2133
- end
2134
-
2135
- def help( prefill = '' )
2136
- open_help_buffer
2137
- matching_docs = nil
2138
-
2139
- selected = getUserInput(
2140
- "Search terms: ",
2141
- @rlh_help,
2142
- prefill,
2143
- @help_tags
2144
- ) { |input|
2145
- next if input.length < 3 and input[ 0..0 ] != '/'
2146
-
2147
- matching_docs = matching_help_documents( input )
2148
- with_list_file do |list|
2149
- list.puts matching_docs.join( "\n" )
2150
- end
2151
-
2152
- openListBuffer
2153
- }
2154
-
2155
- close_help_buffer
2156
-
2157
- case selected
2158
- when /\|/
2159
- open_help_document selected
2160
- when nil
2161
- # Help search aborted; do nothing
2162
- else
2163
- # Not a selected help document
2164
- if matching_docs.nil? or matching_docs.empty?
2165
- matching_docs = matching_help_documents( selected )
2166
- end
2167
-
2168
- case matching_docs.size
2169
- when 1
2170
- open_help_document matching_docs[ 0 ]
2171
- when 0
2172
- File.open( @error_filename, 'w' ) do |f|
2173
- f.puts "There were no help documents matching your search."
2174
- f.puts "(#{selected.strip})"
2175
- end
2176
- error_file = openFile @error_filename
2177
-
2178
- choice = getChoice(
2179
- "Send your search terms to purepistos.net to help improve Diakonos?",
2180
- [ CHOICE_YES, CHOICE_NO ]
2181
- )
2182
- case choice
2183
- when CHOICE_YES
2184
- require 'net/http'
2185
- require 'uri'
2186
-
2187
- res = Net::HTTP.post_form(
2188
- URI.parse( 'http://dh.purepistos.net/' ),
2189
- { 'q' => selected }
2190
- )
2191
- # TODO: let them choose "never" and "always"
2192
- end
2193
-
2194
- closeFile error_file
2195
- else
2196
- help selected
2197
- end
2198
- end
2199
- end
2200
-
2201
- def indent
2202
- if( @current_buffer.changing_selection )
2203
- @do_display = false
2204
- mark = @current_buffer.selection_mark
2205
- if mark.end_col > 0
2206
- end_row = mark.end_row
2207
- else
2208
- end_row = mark.end_row - 1
2209
- end
2210
- (mark.start_row..end_row).each do |row|
2211
- @current_buffer.indent row, Buffer::DONT_DISPLAY
2212
- end
2213
- @do_display = true
2214
- @current_buffer.display
2215
- else
2216
- @current_buffer.indent
2217
- end
2218
- end
2219
-
2220
- def insertSpaces( num_spaces )
2221
- if num_spaces > 0
2222
- @current_buffer.deleteSelection
2223
- @current_buffer.insertString( " " * num_spaces )
2224
- cursorRight( Buffer::STILL_TYPING, num_spaces )
2225
- end
2226
- end
2227
-
2228
- def insertTab
2229
- typeCharacter( TAB )
2230
- end
2231
-
2232
- def joinLines
2233
- @current_buffer.joinLines( @current_buffer.currentRow, Buffer::STRIP_LINE )
2234
- end
2235
-
2236
- def list_buffers
2237
- with_list_file do |f|
2238
- f.puts @buffers.keys.map { |name| "#{name}\n" }.sort
2239
- end
2240
- openListBuffer
2241
- filename = getUserInput( "Switch to buffer: " )
2242
- buffer = @buffers[ filename ]
2243
- if buffer
2244
- switchTo buffer
2245
- end
2246
- end
2247
-
2248
- def loadScript( name_ = nil )
2249
- if name_ == nil
2250
- name = getUserInput( "File to load as script: ", @rlh_files )
2251
- else
2252
- name = name_
2253
- end
2254
-
2255
- if name != nil
2256
- thread = Thread.new( name ) do |f|
2257
- begin
2258
- load( f )
2259
- rescue Exception => e
2260
- showException(
2261
- e,
2262
- [
2263
- "The filename given does not exist.",
2264
- "The filename given is not accessible or readable.",
2265
- "The loaded script does not reference Diakonos commands as members of the global Diakonos object. e.g. cursorBOL instead of $diakonos.cursorBOL",
2266
- "The loaded script has syntax errors.",
2267
- "The loaded script references objects or object members which do not exist."
2268
- ]
2269
- )
2270
- end
2271
- setILine "Loaded script '#{name}'."
2272
- end
2273
-
2274
- loop do
2275
- if thread.status != "run"
2276
- break
2277
- else
2278
- sleep 0.1
2279
- end
2280
- end
2281
- thread.join
2282
- end
2283
- end
2284
-
2285
- def newFile
2286
- openFile
2287
- end
2288
-
2289
- # Returns the buffer of the opened file, or nil.
2290
- def openFile( filename = nil, read_only = false, force_revert = ASK_REVERT )
2291
- do_open = true
2292
- buffer = nil
2293
- if filename.nil?
2294
- buffer_key = @untitled_id
2295
- @untitled_id += 1
2296
- else
2297
- if filename =~ /^(.+):(\d+)$/
2298
- filename, line_number = $1, ( $2.to_i - 1 )
2299
- end
2300
- buffer_key = filename
2301
- if(
2302
- (not force_revert) and
2303
- ( (existing_buffer = @buffers[ filename ]) != nil ) and
2304
- ( filename !~ /\.diakonos/ )
2305
- )
2306
- switchTo( existing_buffer )
2307
- choice = getChoice(
2308
- "Revert to on-disk version of #{existing_buffer.nice_name}?",
2309
- [ CHOICE_YES, CHOICE_NO ]
2310
- )
2311
- case choice
2312
- when CHOICE_NO
2313
- do_open = false
2314
- end
2315
- end
2316
-
2317
- if FileTest.exist?( filename )
2318
- # Don't try to open non-files (i.e. directories, pipes, sockets, etc.)
2319
- do_open &&= FileTest.file?( filename )
2320
- end
2321
- end
2322
-
2323
- if do_open
2324
- # Is file readable?
2325
-
2326
- # Does the "file" utility exist?
2327
- if(
2328
- filename and
2329
- @settings[ 'use_magic_file' ] and
2330
- FileTest.exist?( "/usr/bin/file" ) and
2331
- FileTest.exist?( filename ) and
2332
- /\blisting\.txt\b/ !~ filename
2333
- )
2334
- file_type = `/usr/bin/file -L #{filename}`
2335
- if file_type !~ /text/ and file_type !~ /empty$/
2336
- choice = getChoice(
2337
- "#{filename} does not appear to be readable. Try to open it anyway?",
2338
- [ CHOICE_YES, CHOICE_NO ],
2339
- CHOICE_NO
2340
- )
2341
- case choice
2342
- when CHOICE_NO
2343
- do_open = false
2344
- end
2345
-
2346
- end
2347
- end
2348
-
2349
- if do_open
2350
- buffer = Buffer.new( self, filename, buffer_key, read_only )
2351
- runHookProcs( :after_open, buffer )
2352
- @buffers[ buffer_key ] = buffer
2353
- if switchTo( buffer ) and line_number
2354
- @current_buffer.goToLine( line_number, 0 )
2355
- end
2356
- end
2357
- end
2358
-
2359
- buffer
2360
- end
2361
-
2362
- def openFileAsk
2363
- prefill = ''
2364
-
2365
- if @current_buffer
2366
- if @current_buffer.current_line =~ %r{/} and @current_buffer.current_line =~ %r{[/\w.]+}
2367
- prefill = $&
2368
- elsif @current_buffer.name
2369
- prefill = File.expand_path( File.dirname( @current_buffer.name ) ) + "/"
2370
- end
2371
- end
2372
-
2373
- file = getUserInput( "Filename: ", @rlh_files, prefill )
2374
-
2375
- if file
2376
- openFile file
2377
- updateStatusLine
2378
- updateContextLine
2379
- end
2380
- end
2381
-
2382
- def operateOnString(
2383
- ruby_code = getUserInput( 'Ruby code: ', @rlh_general, 'str.' )
2384
- )
2385
- if ruby_code != nil
2386
- str = @current_buffer.selected_string
2387
- if str != nil and not str.empty?
2388
- @current_buffer.paste eval( ruby_code )
2389
- end
2390
- end
2391
- end
2392
-
2393
- def operateOnLines(
2394
- ruby_code = getUserInput( 'Ruby code: ', @rlh_general, 'lines.collect { |l| l }' )
2395
- )
2396
- if ruby_code != nil
2397
- lines = @current_buffer.selected_text
2398
- if lines != nil and not lines.empty?
2399
- if lines[ -1 ].empty?
2400
- lines.pop
2401
- popped = true
2402
- end
2403
- new_lines = eval( ruby_code )
2404
- if popped
2405
- new_lines << ''
2406
- end
2407
- @current_buffer.paste new_lines
2408
- end
2409
- end
2410
- end
2411
-
2412
- def operateOnEachLine(
2413
- ruby_code = getUserInput( 'Ruby code: ', @rlh_general, 'line.' )
2414
- )
2415
- if ruby_code != nil
2416
- lines = @current_buffer.selected_text
2417
- if lines != nil and not lines.empty?
2418
- if lines[ -1 ].empty?
2419
- lines.pop
2420
- popped = true
2421
- end
2422
- new_lines = eval( "lines.collect { |line| #{ruby_code} }" )
2423
- if popped
2424
- new_lines << ''
2425
- end
2426
- @current_buffer.paste new_lines
2427
- end
2428
- end
2429
- end
2430
-
2431
- def pageUp
2432
- if @current_buffer.pitchView( -main_window_height, Buffer::DO_PITCH_CURSOR ) == 0
2433
- cursorBOF
2434
- end
2435
- updateStatusLine
2436
- updateContextLine
2437
- end
2438
-
2439
- def pageDown
2440
- if @current_buffer.pitchView( main_window_height, Buffer::DO_PITCH_CURSOR ) == 0
2441
- @current_buffer.cursorToEOF
2442
- end
2443
- updateStatusLine
2444
- updateContextLine
2445
- end
2446
-
2447
- def parsedIndent
2448
- if( @current_buffer.changing_selection )
2449
- @do_display = false
2450
- mark = @current_buffer.selection_mark
2451
- (mark.start_row..mark.end_row).each do |row|
2452
- @current_buffer.parsedIndent row, Buffer::DONT_DISPLAY
2453
- end
2454
- @do_display = true
2455
- @current_buffer.display
2456
- else
2457
- @current_buffer.parsedIndent
2458
- end
2459
- updateStatusLine
2460
- updateContextLine
2461
- end
2462
-
2463
- def paste
2464
- @current_buffer.paste @clipboard.clip
2465
- end
2466
-
2467
- def paste_from_klipper
2468
- text = `dcop klipper klipper getClipboardContents`.split( "\n", -1 )
2469
- text.pop # getClipboardContents puts an extra newline on end
2470
- @current_buffer.paste text
2471
- end
2472
-
2473
- def playMacro( name = nil )
2474
- macro, input_history = @macros[ name ]
2475
- if input_history != nil
2476
- @macro_input_history = input_history.deep_clone
2477
- if macro != nil
2478
- @playing_macro = true
2479
- macro.each do |command|
2480
- eval command
2481
- end
2482
- @playing_macro = false
2483
- @macro_input_history = nil
2484
- end
2485
- end
2486
- end
2487
-
2488
- def popTag
2489
- tag = @tag_stack.pop
2490
- if tag != nil
2491
- if not switchTo( @buffers[ tag[ 0 ] ] )
2492
- openFile( tag[ 0 ] )
2493
- end
2494
- @current_buffer.cursorTo( tag[ 1 ], tag[ 2 ], Buffer::DO_DISPLAY )
2495
- else
2496
- setILine "Tag stack empty."
2497
- end
2498
- end
2499
-
2500
- def print_mapped_function
2501
- @capturing_mapping = true
2502
- setILine "Type any chain of keystrokes or key chords, or press Enter to stop."
2503
- end
2504
-
2505
- def printKeychain
2506
- @capturing_keychain = true
2507
- setILine "Type any chain of keystrokes or key chords, then press Enter..."
2508
- end
2509
-
2510
- def quit
2511
- @quitting = true
2512
- to_all = nil
2513
- @buffers.each_value do |buffer|
2514
- if buffer.modified
2515
- switchTo buffer
2516
- closure_choice = closeFile( buffer, to_all )
2517
- case closure_choice
2518
- when CHOICE_CANCEL
2519
- @quitting = false
2520
- break
2521
- when CHOICE_YES_TO_ALL, CHOICE_NO_TO_ALL
2522
- to_all = closure_choice
2523
- end
2524
- end
2525
- end
2526
- end
2527
-
2528
- def removeNamedBookmark( name_ = nil )
2529
- if name_ == nil
2530
- name = getUserInput "Bookmark name: "
2531
- else
2532
- name = name_
2533
- end
2534
-
2535
- if name != nil
2536
- bookmark = @bookmarks.delete name
2537
- setILine "Removed bookmark #{bookmark.to_s}."
2538
- end
2539
- end
2540
-
2541
- def removeSelection
2542
- @current_buffer.removeSelection
2543
- updateStatusLine
2544
- end
2545
-
2546
- def repeatLast
2547
- eval @last_commands[ -1 ] if not @last_commands.empty?
2548
- end
2549
-
2550
- # If the prompt is non-nil, ask the user yes or no question first.
2551
- def revert( prompt = nil )
2552
- do_revert = true
2553
-
2554
- current_text_file = @diakonos_home + '/current-buffer'
2555
- @current_buffer.saveCopy( current_text_file )
2556
- `#{@settings[ 'diff_command' ]} #{current_text_file} #{@current_buffer.name} > #{@diff_filename}`
2557
- diff_buffer = openFile( @diff_filename )
2558
-
2559
- if prompt != nil
2560
- choice = getChoice(
2561
- prompt,
2562
- [ CHOICE_YES, CHOICE_NO ]
2563
- )
2564
- case choice
2565
- when CHOICE_NO
2566
- do_revert = false
2567
- end
2568
- end
2569
-
2570
- closeFile( diff_buffer )
2571
-
2572
- if do_revert
2573
- openFile( @current_buffer.name, Buffer::READ_WRITE, FORCE_REVERT )
2574
- end
2575
- end
2576
-
2577
- def saveFile( buffer = @current_buffer )
2578
- buffer.save
2579
- runHookProcs( :after_save, buffer )
2580
- end
2581
-
2582
- def saveFileAs
2583
- if @current_buffer != nil and @current_buffer.name != nil
2584
- path = File.expand_path( File.dirname( @current_buffer.name ) ) + "/"
2585
- file = getUserInput( "Filename: ", @rlh_files, path )
2586
- else
2587
- file = getUserInput( "Filename: ", @rlh_files )
2588
- end
2589
- if file != nil
2590
- #old_name = @current_buffer.name
2591
- @current_buffer.save( file, PROMPT_OVERWRITE )
2592
- #if not @current_buffer.modified
2593
- # Save was okay.
2594
- #@buffers.delete old_name
2595
- #@buffers[ @current_buffer.name ] = @current_buffer
2596
- #switchTo( @current_buffer )
2597
- #end
2598
- end
2599
- end
2600
-
2601
- def select_all
2602
- @current_buffer.select_all
2603
- end
2604
-
2605
- def select_block( beginning = nil, ending = nil, including_ending = true )
2606
- if beginning.nil?
2607
- input = getUserInput( "Start at regexp: " )
2608
- if input
2609
- beginning = Regexp.new input
2610
- end
2611
- end
2612
- if beginning and ending.nil?
2613
- input = getUserInput( "End before regexp: " )
2614
- if input
2615
- ending = Regexp.new input
2616
- end
2617
- end
2618
- if beginning and ending
2619
- @current_buffer.select( beginning, ending, including_ending )
2620
- end
2621
- end
2622
-
2623
- def scrollDown
2624
- @current_buffer.pitchView( @settings[ "view.scroll_amount" ] || 1 )
2625
- updateStatusLine
2626
- updateContextLine
2627
- end
2628
-
2629
- def scrollUp
2630
- if @settings[ "view.scroll_amount" ] != nil
2631
- @current_buffer.pitchView( -@settings[ "view.scroll_amount" ] )
2632
- else
2633
- @current_buffer.pitchView( -1 )
2634
- end
2635
- updateStatusLine
2636
- updateContextLine
2637
- end
2638
-
2639
- def searchAndReplace( case_sensitive = CASE_INSENSITIVE )
2640
- find( "down", case_sensitive, nil, ASK_REPLACEMENT )
608
+ def settings
609
+ @settings.merge @session[ 'settings' ]
2641
610
  end
2642
-
2643
- def seek( regexp_source, dir_str = "down" )
2644
- if regexp_source != nil
2645
- direction = dir_str.toDirection
2646
- regexp = Regexp.new( regexp_source )
2647
- @current_buffer.seek( regexp, direction )
2648
- end
2649
- end
2650
-
2651
- def setBufferType( type_ = nil )
2652
- if type_ == nil
2653
- type = getUserInput "Content type: "
2654
- else
2655
- type = type_
2656
- end
2657
-
2658
- if type != nil
2659
- if @current_buffer.setType( type )
2660
- updateStatusLine
2661
- updateContextLine
2662
- end
2663
- end
2664
- end
2665
-
2666
- # If read_only is nil, the read_only state of the current buffer is toggled.
2667
- # Otherwise, the read_only state of the current buffer is set to read_only.
2668
- def setReadOnly( read_only = nil )
2669
- if read_only != nil
2670
- @current_buffer.read_only = read_only
2671
- else
2672
- @current_buffer.read_only = ( not @current_buffer.read_only )
2673
- end
2674
- updateStatusLine
2675
- end
2676
-
2677
- def shell( command_ = nil, result_filename = 'shell-result.txt' )
2678
- if command_ == nil
2679
- command = getUserInput( "Command: ", @rlh_shell )
2680
- else
2681
- command = command_
2682
- end
2683
-
2684
- if command
2685
- command = subShellVariables( command )
2686
-
2687
- result_file = "#{@diakonos_home}/#{result_filename}"
2688
- File.open( result_file , "w" ) do |f|
2689
- f.puts command
2690
- f.puts
2691
- Curses::close_screen
2692
-
2693
- stdin, stdout, stderr = Open3.popen3( command )
2694
- t1 = Thread.new do
2695
- stdout.each_line do |line|
2696
- f.puts line
2697
- end
2698
- end
2699
- t2 = Thread.new do
2700
- stderr.each_line do |line|
2701
- f.puts line
2702
- end
2703
- end
2704
-
2705
- t1.join
2706
- t2.join
2707
-
2708
- Curses::init_screen
2709
- refreshAll
2710
- end
2711
- openFile result_file
2712
- end
2713
- end
2714
-
2715
- def execute( command_ = nil )
2716
- if command_ == nil
2717
- command = getUserInput( "Command: ", @rlh_shell )
2718
- else
2719
- command = command_
2720
- end
2721
-
2722
- if command != nil
2723
- command = subShellVariables( command )
2724
-
2725
- Curses::close_screen
2726
-
2727
- success = system( command )
2728
- if not success
2729
- result = "Could not execute: #{command}"
2730
- else
2731
- result = "Return code: #{$?}"
2732
- end
2733
-
2734
- Curses::init_screen
2735
- refreshAll
2736
-
2737
- setILine result
2738
- end
2739
- end
2740
-
2741
- def pasteShellResult( command_ = nil )
2742
- if command_ == nil
2743
- command = getUserInput( "Command: ", @rlh_shell )
2744
- else
2745
- command = command_
2746
- end
2747
-
2748
- if command != nil
2749
- command = subShellVariables( command )
2750
-
2751
- Curses::close_screen
2752
-
2753
- begin
2754
- @current_buffer.paste( `#{command} 2<&1`.split( /\n/, -1 ) )
2755
- rescue Exception => e
2756
- debugLog e.message
2757
- debugLog e.backtrace.join( "\n\t" )
2758
- showException e
2759
- end
2760
-
2761
- Curses::init_screen
2762
- refreshAll
2763
- end
2764
- end
2765
-
2766
- # Send the Diakonos job to background, as if with Ctrl-Z
2767
- def suspend
2768
- Curses::close_screen
2769
- Process.kill( "SIGSTOP", $PID )
2770
- Curses::init_screen
2771
- refreshAll
2772
- end
2773
-
2774
- def toggleMacroRecording( name = nil )
2775
- if @macro_history != nil
2776
- stopRecordingMacro
2777
- else
2778
- startRecordingMacro( name )
2779
- end
2780
- end
2781
-
2782
- def switchToBufferNumber( buffer_number_ )
2783
- buffer_number = buffer_number_.to_i
2784
- return if buffer_number < 1
2785
- buffer_name = bufferNumberToName( buffer_number )
2786
- if buffer_name
2787
- switchTo( @buffers[ buffer_name ] )
2788
- end
2789
- end
2790
-
2791
- def switchToNextBuffer
2792
- buffer_number = bufferToNumber( @current_buffer )
2793
- switchToBufferNumber( buffer_number + 1 )
2794
- end
2795
-
2796
- def switchToPreviousBuffer
2797
- buffer_number = bufferToNumber( @current_buffer )
2798
- switchToBufferNumber( buffer_number - 1 )
2799
- end
2800
-
2801
- def toggleBookmark
2802
- @current_buffer.toggleBookmark
2803
- end
2804
-
2805
- def toggleSelection
2806
- @current_buffer.toggleSelection
2807
- updateStatusLine
2808
- end
2809
-
2810
- def toggleSessionSetting( key_ = nil, do_redraw = DONT_REDRAW )
2811
- if key_ == nil
2812
- key = getUserInput( "Setting: " )
2813
- else
2814
- key = key_
2815
- end
2816
-
2817
- if key != nil
2818
- value = nil
2819
- if @session_settings[ key ].class == TrueClass or @session_settings[ key ].class == FalseClass
2820
- value = ! @session_settings[ key ]
2821
- elsif @settings[ key ].class == TrueClass or @settings[ key ].class == FalseClass
2822
- value = ! @settings[ key ]
2823
- end
2824
- if value != nil
2825
- @session_settings[ key ] = value
2826
- redraw if do_redraw
2827
- setILine "#{key} = #{value}"
2828
- end
2829
- end
2830
- end
2831
-
2832
- def uncomment
2833
- @current_buffer.uncomment
2834
- end
2835
-
2836
- def undo( buffer = @current_buffer )
2837
- buffer.undo
2838
- end
2839
-
2840
- def unindent
2841
- if( @current_buffer.changing_selection )
2842
- @do_display = false
2843
- mark = @current_buffer.selection_mark
2844
- if mark.end_col > 0
2845
- end_row = mark.end_row
2846
- else
2847
- end_row = mark.end_row - 1
2848
- end
2849
- (mark.start_row..end_row).each do |row|
2850
- @current_buffer.unindent row, Buffer::DONT_DISPLAY
2851
- end
2852
- @do_display = true
2853
- @current_buffer.display
2854
- else
2855
- @current_buffer.unindent
2856
- end
2857
- end
2858
-
2859
- def unundo( buffer = @current_buffer )
2860
- buffer.unundo
2861
- end
2862
-
2863
- def wrap_paragraph
2864
- @current_buffer.wrap_paragraph
2865
- end
2866
- end
611
+ end
2867
612
 
2868
613
  end
2869
614
 
2870
615
  if __FILE__ == $PROGRAM_NAME
2871
- $diakonos = Diakonos::Diakonos.new( ARGV )
2872
- $diakonos.start
616
+ $diakonos = Diakonos::Diakonos.new( ARGV )
617
+ $diakonos.start
2873
618
  end