Class: Diakonos::Diakonos

Inherits:
Object show all
Includes:
Functions
Defined in:
lib/diakonos.rb,
lib/diakonos/grep.rb,
lib/diakonos/help.rb,
lib/diakonos/list.rb,
lib/diakonos/about.rb,
lib/diakonos/hooks.rb,
lib/diakonos/mouse.rb,
lib/diakonos/config.rb,
lib/diakonos/cursor.rb,
lib/diakonos/keying.rb,
lib/diakonos/search.rb,
lib/diakonos/display.rb,
lib/diakonos/logging.rb,
lib/diakonos/sessions.rb,
lib/diakonos/interaction.rb,
lib/diakonos/buffer-management.rb,
lib/diakonos/functions-deprecated.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Functions

#about, #addNamedBookmark, #add_named_bookmark, #anchor_selection, #anchor_unanchored_selection, #backspace, #carriage_return, #change_session_setting, #chdir, #clear_matches, #close_buffer, #close_code, #collapseWhitespace, #collapse_whitespace, #columnize, #comment_out, #complete_word, #copy_selection, #cursor_bof, #cursor_bol, #cursor_bov, #cursor_down, #cursor_eof, #cursor_eol, #cursor_left, #cursor_return, #cursor_right, #cursor_tov, #cursor_up, #cut_selection, #delete, #delete_and_store_line, #delete_from, #delete_line, #delete_to, #delete_to_and_from, #delete_to_eol, #evaluate, #execute, #find, #find_again, #find_clip, #find_exact, #goToNamedBookmark, #goToNextBookmark, #goToPreviousBookmark, #go_block_inner, #go_block_next, #go_block_outer, #go_block_previous, #go_to_char, #go_to_char_previous, #go_to_line_ask, #go_to_named_bookmark, #go_to_next_bookmark, #go_to_pair_match, #go_to_previous_bookmark, #go_to_tag, #go_to_tag_under_cursor, #grep, #grep_buffers, #grep_dir, #grep_session_dir, #help, #indent, #insertSpaces, #insertTab, #insert_spaces, #insert_tab, #joinLines, #join_lines, #join_lines_upward, #list_buffers, #load_script, #merge_session_settings, #move_lines, #name_session, #open_file, #open_file_ask, #open_matching_files, #operateOnEachLine, #operateOnLines, #operateOnString, #operate_on_each_line, #operate_on_lines, #operate_on_string, #page_down, #page_up, #parsedIndent, #parsed_indent, #paste, #paste_shell_result, #play_macro, #pop_tag, #print_keychain, #print_mapped_function, #quit, #readline_abort, #readline_accept, #readline_backspace, #readline_complete_input, #readline_cursor_bol, #readline_cursor_down, #readline_cursor_eol, #readline_cursor_left, #readline_cursor_right, #readline_cursor_up, #readline_delete, #readline_delete_line, #readline_delete_word, #readline_grep_context_decrease, #readline_grep_context_increase, #readline_page_down, #readline_page_up, #removeNamedBookmark, #remove_named_bookmark, #remove_selection, #renumber_buffer, #repeat_last, #revert, #save_file, #save_file_as, #scroll_down, #scroll_up, #search_and_replace, #seek, #select_all, #select_block, #select_line, #select_word, #select_word_another, #select_wrapping_block, #selection_mode_block, #selection_mode_normal, #set_buffer_type, #set_read_only, #set_session_dir, #shell, #show_clips, #show_number_of_matches_found, #spawn, #sub_shell_variables, #surround_line, #surround_paragraph, #surround_selection, #surround_word, #suspend, #switch_to_buffer_number, #switch_to_next_buffer, #switch_to_previous_buffer, #toggleBookmark, #toggle_bookmark, #toggle_macro_recording, #toggle_selection, #toggle_session_setting, #uncomment, #undo, #unindent, #unundo, #wrap_paragraph

Constructor Details

#initialize(argv = []) ⇒ Diakonos

Returns a new instance of Diakonos.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/diakonos.rb', line 156

def initialize( argv = [] )
  @diakonos_home = File.expand_path( ( ENV[ 'HOME' ] || '' ) + '/.diakonos' )
  mkdir @diakonos_home
  @script_dir = "#{@diakonos_home}/scripts"
  mkdir @script_dir
  @extensions = ExtensionSet.new( File.join( @diakonos_home, 'extensions' ) )
  initialize_session

  @files = Array.new
  @read_only_files = Array.new
  @config_filename = nil
  parse_options argv

  # These requires are down here instead of up with the others so that
  # uninstall can be done without needing the curses lib (which may not
  # be installed).
  require 'diakonos/display'
  require 'diakonos/display/format'

  init_help

  @debug          = File.new( File.join( @diakonos_home, 'debug.log' ), 'w' )
  @list_filename  = File.join( @diakonos_home, 'listing.txt' )
  @diff_filename  = File.join( @diakonos_home, 'text.diff' )
  @help_filename  = File.join( @help_dir, 'about-help.dhf' )
  @error_filename = File.join( @diakonos_home, 'diakonos.err' )
  @about_filename = File.join( @diakonos_home, 'about.dhf' )

  @win_main         = nil
  @win_context      = nil
  @win_status       = nil
  @win_interaction  = nil
  @win_line_numbers = nil
  @buffers          = Array.new

  load_configuration

  @quitting         = false

  @x = 0
  @y = 0

  @buffer_stack           = Array.new
  @buffer_current         = nil

  @cursor_stack           = Array.new
  @cursor_stack_pointer   = nil

  @bookmarks              = Hash.new

  @macro_history          = nil
  @macro_input_history    = nil
  @macros                 = Hash.new
  @functions_last         = SizedArray.new(2)
  @playing_macro          = false

  @display_mutex          = Mutex.new
  @display_queue_mutex    = Mutex.new
  @display_queue          = nil
  @do_display             = true
  @context_line_mutex     = Mutex.new

  @tag_stack              = Array.new
  @last_search_regexps    = nil
  @there_was_non_movement = false
  @status_vars            = Hash.new

  # Readline histories
  @rlh_general  = Array.new
  @rlh_files    = Array.new
  @rlh_search   = Array.new
  @rlh_shell    = Array.new
  @rlh_help     = Array.new
  @rlh_sessions = Array.new

  @hooks = {
    :after_buffer_switch => [],
    :after_open          => [],
    :after_save          => [],
    :after_startup       => [],
  }
end

Instance Attribute Details

#buffer_currentObject (readonly)

Returns the value of attribute buffer_current.



3
4
5
# File 'lib/diakonos/buffer-management.rb', line 3

def buffer_current
  @buffer_current
end

#buffersObject (readonly)

Returns the value of attribute buffers.



145
146
147
# File 'lib/diakonos.rb', line 145

def buffers
  @buffers
end

#clipboardObject (readonly)

Returns the value of attribute clipboard.



145
146
147
# File 'lib/diakonos.rb', line 145

def clipboard
  @clipboard
end

#close_token_regexpsObject (readonly)

Returns the value of attribute close_token_regexps.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def close_token_regexps
  @close_token_regexps
end

#closersObject (readonly)

Returns the value of attribute closers.



145
146
147
# File 'lib/diakonos.rb', line 145

def closers
  @closers
end

#column_markersObject (readonly)

Returns the value of attribute column_markers.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def column_markers
  @column_markers
end

#diakonos_confObject (readonly)

Returns the value of attribute diakonos_conf.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def diakonos_conf
  @diakonos_conf
end

#diakonos_homeObject (readonly)

Returns the value of attribute diakonos_home.



145
146
147
# File 'lib/diakonos.rb', line 145

def diakonos_home
  @diakonos_home
end

#display_mutexObject (readonly)

Returns the value of attribute display_mutex.



8
9
10
# File 'lib/diakonos/display.rb', line 8

def display_mutex
  @display_mutex
end

#do_displayObject

Returns the value of attribute do_display.



145
146
147
# File 'lib/diakonos.rb', line 145

def do_display
  @do_display
end

#functions_lastObject (readonly)

Returns the value of attribute functions_last.



145
146
147
# File 'lib/diakonos.rb', line 145

def functions_last
  @functions_last
end

#hooksObject (readonly)

Returns the value of attribute hooks.



145
146
147
# File 'lib/diakonos.rb', line 145

def hooks
  @hooks
end

#indentersObject (readonly)

Returns the value of attribute indenters.



145
146
147
# File 'lib/diakonos.rb', line 145

def indenters
  @indenters
end

#indenters_next_lineObject (readonly)

Returns the value of attribute indenters_next_line.



145
146
147
# File 'lib/diakonos.rb', line 145

def indenters_next_line
  @indenters_next_line
end

#list_bufferObject (readonly)

Returns the value of attribute list_buffer.



4
5
6
# File 'lib/diakonos/list.rb', line 4

def list_buffer
  @list_buffer
end

#list_filenameObject (readonly)

Returns the value of attribute list_filename.



145
146
147
# File 'lib/diakonos.rb', line 145

def list_filename
  @list_filename
end

#readlineObject (readonly)

Returns the value of attribute readline.



5
6
7
# File 'lib/diakonos/interaction.rb', line 5

def readline
  @readline
end

#script_dirObject (readonly)

Returns the value of attribute script_dir.



145
146
147
# File 'lib/diakonos.rb', line 145

def script_dir
  @script_dir
end

#sessionObject (readonly)

Returns the value of attribute session.



136
137
138
# File 'lib/diakonos/sessions.rb', line 136

def session
  @session
end

#settingsObject (readonly)

Returns the value of attribute settings.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def settings
  @settings
end

#surround_pairsObject (readonly)

Returns the value of attribute surround_pairs.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def surround_pairs
  @surround_pairs
end

#testingObject (readonly)

Returns the value of attribute testing.



145
146
147
# File 'lib/diakonos.rb', line 145

def testing
  @testing
end

#there_was_non_movementObject (readonly)

Returns the value of attribute there_was_non_movement.



145
146
147
# File 'lib/diakonos.rb', line 145

def there_was_non_movement
  @there_was_non_movement
end

#token_formatsObject (readonly)

Returns the value of attribute token_formats.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def token_formats
  @token_formats
end

#token_regexpsObject (readonly)

Returns the value of attribute token_regexps.



14
15
16
# File 'lib/diakonos/config.rb', line 14

def token_regexps
  @token_regexps
end

#unindentersObject (readonly)

Returns the value of attribute unindenters.



145
146
147
# File 'lib/diakonos.rb', line 145

def unindenters
  @unindenters
end

#win_line_numbersObject (readonly)

Returns the value of attribute win_line_numbers.



8
9
10
# File 'lib/diakonos/display.rb', line 8

def win_line_numbers
  @win_line_numbers
end

#win_mainObject (readonly)

Returns the value of attribute win_main.



8
9
10
# File 'lib/diakonos/display.rb', line 8

def win_main
  @win_main
end

Instance Method Details

#about_writeObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/diakonos/about.rb', line 4

def about_write
  File.open( @about_filename, "w" ) do |f|
    inst = ::Diakonos::INSTALL_SETTINGS

    configs = @configs.map(&:to_s).join("\n")

    ext_loaded = @extensions.loaded_extensions.sort_by { |e|
      e.name.downcase
    }.map { |e|
      %{
### #{e.name} #{e.version}
#{e.description}
      }.strip
    }.join( "\n\n" )

    ext_not_loaded = @extensions.not_loaded_extensions.sort.map { |e|
      "### #{e} (NOT LOADED)"
    }.join( "\n" )

    installation_artifact = File.join(inst[:lib_dir], 'diakonos', 'installation.rb')
    if File.exist?(installation_artifact)
      install_time = File.mtime(installation_artifact)
    else
      install_time = "--"
    end

    f.puts %{
# About Diakonos

Licence:        GNU GPL v3
Copyright:      Copyright (c) 2004-#{ Time.now.year } Pistos

## Version

Version:        #{ ::Diakonos::VERSION }
Code Date:      #{ ::Diakonos::LAST_MODIFIED }
Install Time:   #{ install_time }
Ruby Version:   #{ ::RUBY_VERSION }

## Paths

Home dir:       #{ @diakonos_home }
Session dir:    #{ @session.dir }

### Installation

Prefix:             #{ inst[ :prefix ] }
Executable dir:     #{ inst[ :bin_dir ] }
Help dir:           #{ inst[ :help_dir ] }
System config dir:  #{ inst[ :conf_dir ] }
System library dir: #{ inst[ :lib_dir ] }

### Configuration Files

#{ configs }

## Extensions

#{ ext_loaded }

#{ ext_not_loaded }
    }.strip
  end
end

#actually_grep(regexp_source, *buffers) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/diakonos/grep.rb', line 35

def actually_grep( regexp_source, *buffers )
  begin
    regexp = Regexp.new( regexp_source, Regexp::IGNORECASE )
    grep_results = buffers.map { |buffer| buffer.grep(regexp) }.flatten
    if settings[ 'grep.context' ] == 0
      join_str = "\n"
    else
      join_str = "\n---\n"
    end
    with_list_file do |list|
      list.puts grep_results.join( join_str )
    end
    list_buffer = open_list_buffer
    list_buffer.highlight_matches regexp
    display_buffer list_buffer
  rescue RegexpError
    # Do nothing
  end
end

#buffer_number_to_name(buffer_number) ⇒ Object

Returns nil if no such buffer exists.

Parameters:

  • buffer_number (Integer)

    should be 1-based, not zero-based.

Returns:

  • nil if no such buffer exists.



31
32
33
34
35
36
37
38
# File 'lib/diakonos/buffer-management.rb', line 31

def buffer_number_to_name( buffer_number )
  return nil  if buffer_number < 1

  b = @buffers[ buffer_number - 1 ]
  if b
    b.name
  end
end

#buffer_to_number(buffer) ⇒ Integer

Returns:

  • (Integer)

    1-based, not zero-based.

  • nil if no such buffer exists.



42
43
44
45
46
47
# File 'lib/diakonos/buffer-management.rb', line 42

def buffer_to_number( buffer )
  i = @buffers.index( buffer )
  if i
    i + 1
  end
end

#capture_keychain(c, context) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/diakonos/keying.rb', line 188

def capture_keychain( c, context )
  if c == ENTER
    @capturing_keychain = false
    buffer_current.delete_selection
    str = keychain_str_for( context )
    buffer_current.insert_string str
    cursor_right( Buffer::STILL_TYPING, str.length )
  else
    keychain_pressed = context.concat [ c ]

    function_and_args = @modes[ 'edit' ].keymap.get_leaf( keychain_pressed )

    if function_and_args
      function, args = function_and_args
    end

    partial_keychain = @modes[ 'edit' ].keymap.get_node( keychain_pressed )
    if partial_keychain
      set_iline( "Part of existing keychain: " + keychain_str_for( keychain_pressed ) + "..." )
    else
      set_iline keychain_str_for( keychain_pressed ) + "..."
    end
    process_keystroke keychain_pressed
  end
end

#capture_mapping(c, context) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/diakonos/keying.rb', line 214

def capture_mapping( c, context )
  if c == ENTER
    @capturing_mapping = false
    buffer_current.delete_selection
    set_iline
  else
    keychain_pressed = context.concat [ c ]

    function_and_args = @modes[ 'edit' ].keymap.get_leaf( keychain_pressed )

    if function_and_args
      function, args = function_and_args
      set_iline "#{keychain_str_for( keychain_pressed )}  ->  #{function}( #{args} )"
    else
      partial_keychain = @modes[ 'edit' ].keymap.get_node( keychain_pressed )
      if partial_keychain
        set_iline( "Several mappings start with: " + keychain_str_for( keychain_pressed ) + "..." )
        process_keystroke keychain_pressed
      else
        set_iline "There is no mapping for " + keychain_str_for( keychain_pressed )
      end
    end
  end
end

#cleanup_displayObject



10
11
12
13
14
15
16
17
18
19
20
# File 'lib/diakonos/display.rb', line 10

def cleanup_display
  return  if @testing

  @win_main.close          if @win_main
  @win_status.close        if @win_status
  @win_interaction.close   if @win_interaction
  @win_context.close       if @win_context
  @win_line_numbers.close  if @win_line_numbers

  Curses::close_screen
end

#cleanup_sessionObject



251
252
253
254
255
# File 'lib/diakonos/sessions.rb', line 251

def cleanup_session
  if @session && Session.pid_session?(@session.filename) && File.exist?(@session.filename)
    File.delete @session.filename
  end
end

#clear_non_movement_flagObject



314
315
316
# File 'lib/diakonos.rb', line 314

def clear_non_movement_flag
  @there_was_non_movement = false
end

#close_help_bufferObject



11
12
13
14
# File 'lib/diakonos/help.rb', line 11

def close_help_buffer
  close_buffer @help_buffer
  @help_buffer = nil
end

#close_list_buffer(opts = {}) ⇒ Object



10
11
12
13
# File 'lib/diakonos/list.rb', line 10

def close_list_buffer( opts = {} )
  close_buffer  @list_buffer, opts
  @list_buffer = nil
end

#create_buffers_from_filesObject




320
321
322
323
324
# File 'lib/diakonos.rb', line 320

def create_buffers_from_files
  @files.each do |file_info|
    @buffers << Buffer.new(file_info)
  end
end

#current_list_itemObject



23
24
25
26
27
# File 'lib/diakonos/list.rb', line 23

def current_list_item
  if @list_buffer
    @list_buffer.set_selection_current_line
  end
end

#cursor_stack_remove_buffer(buffer) ⇒ Object



4
5
6
7
8
# File 'lib/diakonos/cursor.rb', line 4

def cursor_stack_remove_buffer( buffer )
  @cursor_stack.delete_if { |frame|
    frame[ :buffer ] == buffer
  }
end

#debug_log(string) ⇒ Object



10
11
12
13
# File 'lib/diakonos/logging.rb', line 10

def debug_log( string )
  @debug.puts( Time.now.strftime( "[%a %H:%M:%S] #{string}" ) )
  @debug.flush
end

#decrease_grep_contextObject



89
90
91
92
93
94
95
# File 'lib/diakonos/grep.rb', line 89

def decrease_grep_context
  current = settings['grep.context']
  if current > 0
    @session.settings['grep.context'] = current - 1
    merge_session_settings
  end
end

#display_buffer(buffer) ⇒ Object



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/diakonos/display.rb', line 285

def display_buffer( buffer )
  return  if @testing
  return  if ! @do_display

  Thread.new do

    if ! @display_mutex.try_lock
      @display_queue_mutex.synchronize do
        @display_queue = buffer
      end
    else
      begin
        Curses::curs_set 0
        buffer.display
        Curses::curs_set 1
      rescue Exception => e
        $diakonos.log( "Display Exception:" )
        $diakonos.log( e.message )
        $diakonos.log( e.backtrace.join( "\n" ) )
        show_exception e
      end

      @display_mutex.unlock

      @display_queue_mutex.synchronize do
        if @display_queue
          b = @display_queue
          @display_queue = nil
          display_buffer b
        end
      end
    end

  end

end

#escape_quotes(str) ⇒ Object



570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/diakonos.rb', line 570

def escape_quotes( str )
  temp = ''
  str.each_byte do |b|
    if b == 39
      temp << 39
      temp << 92
      temp << 39
    end
    temp << b
  end
  temp
end

#find_(options = {}) ⇒ Integer

Returns the number of replacements made.

Returns:

  • (Integer)

    the number of replacements made



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/diakonos/search.rb', line 5

def find_( options = {} )
  regexp_source, replacement = options.values_at( :regexp_source, :replacement )
  return  if regexp_source.nil? || regexp_source.empty?

  rs_array = regexp_source.newline_split
  regexps = Array.new
  exception_thrown = nil

  rs_array.each do |source|
    begin
      warning_verbosity = $VERBOSE
      $VERBOSE = nil
      regexps << Regexp.new(
        source,
        options[:case_sensitive] ? nil : Regexp::IGNORECASE
      )
      $VERBOSE = warning_verbosity
    rescue RegexpError => e
      if ! exception_thrown
        exception_thrown = e
        source = Regexp.escape( source )
        retry
      else
        raise e
      end
    end
  end

  if replacement == ASK_REPLACEMENT
    replacement = get_user_input( "Replace with: ", history: @rlh_search )
  end

  if exception_thrown && ! options[:quiet]
    set_iline "Searching literally; #{exception_thrown.message}"
  end

  # The execution order of the #find and the @last_search_regexps assignment is likely deliberate
  num_replacements = buffer_current.find(
    regexps,
    :direction          => options[:direction],
    :replacement        => replacement,
    :starting_row       => options[:starting_row],
    :starting_col       => options[:starting_col],
    :quiet              => options[:quiet],
    :show_context_after => @settings[ 'find.show_context_after' ],
    :starting           => true
  )
  @last_search_regexps = regexps

  num_replacements
end

#get_choice(*args) ⇒ Object



48
49
50
# File 'lib/diakonos/interaction.rb', line 48

def get_choice(*args)
  @interaction_handler.get_choice *args
end

#get_language_from_name(name) ⇒ Object



484
485
486
487
488
489
490
491
# File 'lib/diakonos.rb', line 484

def get_language_from_name( name )
  @filemasks.each do |language,filemask|
    if name =~ filemask
      return language
    end
  end
  nil
end

#get_language_from_shabang(first_line) ⇒ Object



493
494
495
496
497
498
499
500
# File 'lib/diakonos.rb', line 493

def get_language_from_shabang( first_line )
  @bangmasks.each do |language,bangmask|
    if first_line =~ bangmask
      return language
    end
  end
  nil
end

#get_token_regexp(hash, arg, match) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
# File 'lib/diakonos/config.rb', line 120

def get_token_regexp( hash, arg, match )
  language = match[ 1 ]
  token_class = match[ 2 ]
  case_insensitive = ( match[ 3 ] != nil )
  hash[ language ] = ( hash[ language ] || Hash.new )
  if case_insensitive
    hash[ language ][ token_class ] = Regexp.new( arg, Regexp::IGNORECASE )
  else
    hash[ language ][ token_class ] = Regexp.new arg
  end
end

#get_user_input(prompt, options = {}, &block) ⇒ Object

completion_array is the array of strings that tab completion can use

Parameters:

  • options (defaults to: {})

    :initial_text, :completion_array, :history, :do_complete, :on_dirs



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/diakonos/interaction.rb', line 9

def get_user_input( prompt, options = {}, &block )
  if @playing_macro
    return @macro_input_history.shift
  end

  options[ :history ] ||= @rlh_general
  options[ :initial_text ] ||= ""
  options[ :do_complete ] ||= DONT_COMPLETE
  options[ :on_dirs ] ||= :go_into_dirs
  will_display_after_select = options.fetch( :will_display_after_select, false )

  cursor_pos = set_iline( prompt )
  @readline = Readline.new(
    list_manager: self,
    keystroke_processor: self,
    testing: @testing,
    window: @win_interaction,
    start_pos: cursor_pos,
    options: options,
    &block
  )

  retval = @readline.get_input
  if will_display_after_select
    close_list_buffer  do_display: ! retval
  else
    close_list_buffer
  end
  options[ :history ][ -1 ] = @readline.input
  @readline = nil

  if @macro_history
    @macro_input_history.push retval
  end
  set_iline

  retval
end

#grep_(regexp_source, *buffers) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/diakonos/grep.rb', line 55

def grep_( regexp_source, *buffers )
  original_buffer = buffer_current
  if buffer_current.changing_selection
    selected_text = buffer_current.copy_selection[ 0 ]
  end
  starting_row, starting_col = buffer_current.last_row, buffer_current.last_col

  selected = get_user_input(
    "Grep regexp: ",
    history: @rlh_search,
    initial_text: regexp_source || selected_text || "",
    will_display_after_select: true
  ) { |input|
    next  if input.length < 2
    actually_grep input, *buffers
  }

  if selected
    spl = selected.split( "| " )
    if spl.size > 1
      open_file spl[-1]
    else
      original_buffer.cursor_to starting_row, starting_col
    end
  else
    original_buffer.cursor_to starting_row, starting_col
  end
end

#handle_gui_paste(mode) ⇒ Object

Handle paste from a GUI (like x.org). i.e. Shift-Insert



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/diakonos/keying.rb', line 283

def handle_gui_paste(mode)
  s = ""
  ch = nil

  loop do
    ch = nil
    begin
      Timeout::timeout(0.02) do
        ch = @modes[mode].window.getch
      end
    rescue Timeout::Error => e
      break
    end
    break  if ch.nil?

    c = ch.ord
    utf_8_char = self.utf_8_bytes_to_char(c, mode)

    if utf_8_char
      s << utf_8_char
    elsif self.typeable?(c)
      s << c
    elsif c == ENTER && mode == 'edit'
      s << "\n"
    else
      break
    end
  end

  if ! s.empty?
    case mode
    when 'edit'
      buffer_current.paste s, Buffer::TYPING
    when 'input'
      @readline.paste s
    end
  end

  if ch
    process_keystroke( [], mode, ch )
  end
end

#handle_mouse_eventObject



3
4
5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/diakonos/mouse.rb', line 3

def handle_mouse_event
  event = Curses::getmouse
  return  if event.nil?

  if event.bstate & Curses::BUTTON1_CLICKED > 0
    buffer_current.cursor_to(
      buffer_current.top_line + event.y,
      buffer_current.left_column + event.x,
      Buffer::DO_DISPLAY
    )
  else
    $diakonos.debug_log "button state = #{'0x%x' % event.bstate}, "
  end
end

#handle_stale_session_filesObject

We have to do this separately and later (as opposed to inside #session_startup) because we have to wait for the display to get initialized in order to prompt the user for input, etc.



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/diakonos/sessions.rb', line 213

def handle_stale_session_files
  return  if @testing
  return  if @stale_session_files.empty?

  session_buffers = []
  @stale_session_files.each_with_index do |session_file,index|
    session_buffers << open_file( session_file )

    choice = get_choice(
      "#{@stale_session_files.size} unclosed session(s) found.  Open the above files?  (session #{index+1} of #{@stale_session_files.size})",
      [ CHOICE_YES, CHOICE_NO, CHOICE_DELETE ],
      index > 0 ?  CHOICE_NO : nil
    )

    case choice
    when CHOICE_YES
      load_session session_file
      if @session
        File.delete session_file
        break
      end
    when CHOICE_DELETE
      File.delete session_file
    end
  end

  if session_buffers.empty? && @files.empty? && @settings[ 'session.default_session' ]
    session_file = session_filepath_for( @settings[ 'session.default_session' ] )
    if File.exist? session_file
      load_session session_file
    end
  end

  session_buffers.each do |buffer|
    close_buffer buffer
  end
end

#handle_utf_8(c, mode) ⇒ Boolean

Returns true iff c began a UTF-8 byte sequence.

Parameters:

  • c (Integer)

    The ordinal (number) of a character

  • mode (String)

Returns:

  • (Boolean)

    true iff c began a UTF-8 byte sequence



274
275
276
277
278
279
280
# File 'lib/diakonos/keying.rb', line 274

def handle_utf_8(c, mode)
  utf_8_char = utf_8_bytes_to_char(c, mode)
  if utf_8_char
    self.type_character utf_8_char, mode
    true
  end
end

#increase_grep_contextObject



84
85
86
87
88
# File 'lib/diakonos/grep.rb', line 84

def increase_grep_context
  current = settings['grep.context']
  @session.settings['grep.context'] = current + 1
  merge_session_settings
end

#init_helpObject



3
4
5
6
# File 'lib/diakonos/help.rb', line 3

def init_help
  @help_dir = INSTALL_SETTINGS[ :help_dir ]
  @help_tags = `grep -h Tags #{@help_dir}/* | cut -d ' ' -f 2-`.split.uniq
end

#initialize_displayObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/diakonos/display.rb', line 22

def initialize_display
  if ! @testing
    cleanup_display

    Curses::init_screen
    Curses::nonl
    Curses::raw
    Curses::noecho
    if @settings['mouse']
      Curses::mousemask(Curses::ALL_MOUSE_EVENTS)
    end

    if Curses::has_colors?
      Curses::start_color
      Curses::use_default_colors

      # -1 means use the terminal's current/default background, which may even have some transparency
      background_colour = settings['colour.background'] || -1
      Curses::init_pair( Curses::COLOR_BLACK, Curses::COLOR_BLACK, background_colour )
      Curses::init_pair( Curses::COLOR_RED, Curses::COLOR_RED, background_colour )
      Curses::init_pair( Curses::COLOR_GREEN, Curses::COLOR_GREEN, background_colour )
      Curses::init_pair( Curses::COLOR_YELLOW, Curses::COLOR_YELLOW, background_colour )
      Curses::init_pair( Curses::COLOR_BLUE, Curses::COLOR_BLUE, background_colour )
      Curses::init_pair( Curses::COLOR_MAGENTA, Curses::COLOR_MAGENTA, background_colour )
      Curses::init_pair( Curses::COLOR_CYAN, Curses::COLOR_CYAN, background_colour )
      Curses::init_pair( Curses::COLOR_WHITE, Curses::COLOR_WHITE, background_colour )
      @colour_pairs.each do |cp|
        Curses::init_pair( cp[ :number ], cp[ :fg ], cp[ :bg ] )
      end
    end
  end

  if settings[ 'view.line_numbers' ]
    @win_line_numbers = ::Diakonos::Window.new( main_window_height, settings[ 'view.line_numbers.width' ], 0, 0 )
    @win_main = ::Diakonos::Window.new( main_window_height, Curses::cols - settings[ 'view.line_numbers.width' ], 0, settings[ 'view.line_numbers.width' ] )
  else
    @win_main = ::Diakonos::Window.new( main_window_height, Curses::cols, 0, 0 )
    @win_line_numbers = nil
  end
  @win_status = ::Diakonos::Window.new( 1, Curses::cols, Curses::lines - 2, 0 )
  @win_status.attrset @settings[ 'status.format' ]
  @win_interaction = ::Diakonos::Window.new( 1, Curses::cols, Curses::lines - 1, 0 )

  @interaction_handler = InteractionHandler.new(
    win_main: @win_main,
    win_interaction: @win_interaction,
    cursor_manager: self,
    testing: @testing,
    choice_delay: @settings['interaction.choice_delay'],
    blink_string: @settings['interaction.blink_string'],
    blink_duration: @settings['interaction.blink_duration']
  )

  if @settings['context.visible']
    if @settings['context.combined']
      pos = 1
    else
      pos = 3
    end
    @win_context = ::Diakonos::Window.new( 1, Curses::cols, Curses::lines - pos, 0 )
  else
    @win_context = nil
  end

  if ! @testing
    @win_main.keypad( true )
    @win_status.keypad( true )
    @win_interaction.keypad( true )
    if @win_line_numbers
      @win_line_numbers.keypad( true )
    end
    if @win_context
      @win_context.keypad( true )
    end
  end

  @modes[ 'edit' ].window = @win_main
  @modes[ 'input' ].window = @win_interaction

  @win_interaction.refresh
  @win_main.refresh
  if @win_line_numbers
    @win_line_numbers.refresh
  end

  if @buffers
    @buffers.each do |buffer|
      buffer.reset_display
    end
  end
end

#initialize_sessionObject



138
139
140
141
142
# File 'lib/diakonos/sessions.rb', line 138

def initialize_session
  @session_dir = "#{@diakonos_home}/sessions"
  mkdir @session_dir
  @session = Session.new("#{@session_dir}/#{Process.pid}")
end

#keychain_str_for(array) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/diakonos/keying.rb', line 175

def keychain_str_for( array )
  chain_str = ""
  array.each do |key|
    key_str = Keying.key_string_for( key )
    if key_str
      chain_str << key_str + " "
    else
      chain_str << key.to_s + " "
    end
  end
  chain_str.strip
end

#legitimize_config_filename!(prospective_filename, including_config_file) ⇒ ConfigFile, ConfigFileUnreadable



163
164
165
166
167
168
169
170
171
172
# File 'lib/diakonos/config.rb', line 163

def legitimize_config_filename!(prospective_filename, including_config_file)
  if File.exist?(prospective_filename)
    ConfigFile.new(
      File.realpath(prospective_filename),
      including_config_file
    )
  else
    ConfigFileUnreadable.new(prospective_filename, including_config_file)
  end
end

#list_item_selected?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/diakonos/list.rb', line 19

def list_item_selected?
  @list_buffer && @list_buffer.selecting?
end

#load_configurationObject Also known as: loadConfiguration



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/diakonos/config.rb', line 16

def load_configuration
  # Set defaults first

  conf_dir = INSTALL_SETTINGS[ :conf_dir ]
  @global_diakonos_conf = "#{conf_dir}/diakonos.conf"
  if ! @testing
    @diakonos_conf = @config_filename || "#{@diakonos_home}/diakonos.conf"

    if ! FileTest.exist?( @diakonos_conf )
      if FileTest.exist?( @global_diakonos_conf )
        puts "No personal configuration file found."
        puts "Would you like to copy the system-wide configuration file (#{@global_diakonos_conf}) to use"
        $stdout.print "as a basis for your personal configuration (recommended)? (y/n)"; $stdout.flush
        answer = $stdin.gets
        if answer =~ /^y/i
          FileUtils.cp @global_diakonos_conf, @diakonos_conf
        end
      else
        if @testing
          File.open( @diakonos_conf, 'w' ) do |f|
            f.puts File.read( './diakonos.conf' )
          end
        else
          puts "diakonos.conf not found in any of:"
          puts "  #{conf_dir}"
          puts "  #{@diakonos_home}"
          puts "At least one configuration file must exist."
          puts "You download one from https://git.sr.ht/~pistos/diakonos/blob/master/diakonos.conf"
        end

        if ! FileTest.exist?( @diakonos_conf )
          puts "Terminating due to lack of configuration file."
          exit 1
        end
      end
    end
  end

  @logfilename         = @diakonos_home + "/diakonos.log"
  @modes = {
    'edit'  => Mode.new,
    'input' => Mode.new,
  }
  @token_regexps       = Hash.new { |h,k| h[ k ] = Hash.new }
  @close_token_regexps = Hash.new { |h,k| h[ k ] = Hash.new }
  @token_formats       = Hash.new { |h,k| h[ k ] = Hash.new }
  @column_markers      = Hash.new { |h,k| h[ k ] = Hash.new }
  @indenters           = Hash.new
  @indenters_next_line = Hash.new
  @unindenters         = Hash.new
  @indent_triggers     = Hash.new
  @filemasks           = Hash.new
  @bangmasks           = Hash.new
  @closers             = Hash.new
  @surround_pairs      = Hash.new { |h,k| h[ k ] = Hash.new}
  @fuzzy_ignores       = Array.new

  @settings = Hash.new
  @setting_strings = Hash.new
  # Setup some defaults
  @settings[ "context.format" ] = Curses::A_REVERSE
  @settings['fuzzy_file_find.recursive'] = true

  @modes[ 'edit' ].keymap[ Curses::KEY_RESIZE ] = [ "redraw", nil ]
  @modes[ 'edit' ].keymap[ RESIZE2 ] = [ "redraw", nil ]

  @colour_pairs = Array.new

  @configs = Set.new
  parse_configuration_file @global_diakonos_conf
  parse_configuration_file @diakonos_conf  if @diakonos_conf

  languages = @surround_pairs.keys | @token_regexps.keys | @close_token_regexps.keys | @token_formats.keys

  languages.each do |language|
    @surround_pairs[ language ] = @surround_pairs[ 'all' ].merge( @surround_pairs[ language ] )
    @token_regexps[ language ] = @token_regexps[ 'all' ].merge( @token_regexps[ language ] )
    @close_token_regexps[ language ] = @close_token_regexps[ 'all' ].merge( @close_token_regexps[ language ] )
    @token_formats[ language ] = @token_formats[ 'all' ].merge( @token_formats[ language ] )
  end

  merge_session_settings

  case @settings[ 'clipboard.external' ]
  when 'klipper', 'klipper-dcop'
    @clipboard = ClipboardKlipper.new
  when 'klipper-dbus'
    @clipboard = ClipboardKlipperDBus.new
  when 'xclip'
    @clipboard = ClipboardXClip.new
  when 'osx'
    @clipboard = ClipboardOSX.new
  else
    @clipboard = Clipboard.new( @settings[ "max_clips" ] )
  end
  @log = File.open( @logfilename, "a" )

  if @buffers
    @buffers.each do |buffer|
      buffer.configure
    end
  end
end

#load_session(session_file) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/diakonos/sessions.rb', line 144

def load_session( session_file )
  cleanup_session
  @session = Session.from_yaml_file(session_file)
  if @session
    @files.concat @session.buffers
    rlh = @session.readline_histories
    if rlh
      @rlh_general  = rlh['general'] || @rlh_general
      @rlh_files    = rlh['files'] || @rlh_files
      @rlh_search   = rlh['search'] || @rlh_search
      @rlh_shell    = rlh['shell'] || @rlh_shell
      @rlh_help     = rlh['help'] || @rlh_help
      @rlh_sessions = rlh['sessions'] || @rlh_sessions
    end
    merge_session_settings
  end
end

#load_tagsObject



544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/diakonos.rb', line 544

def load_tags
  @tags = Hash.new
  if buffer_current && buffer_current.name
    path = File.expand_path( File.dirname( buffer_current.name ) )
    tagfile = path + "/tags"
  else
    tagfile = "./tags"
  end

  if ! FileTest.exist? tagfile
    set_iline "(tags file not found)"
  else
    IO.foreach( tagfile ) do |line_|
      line = line_.chomp
      # <tagname>\t<filepath>\t<line number or regexp>\t<kind of tag>
      tag, file, command, kind, rest = line.split( /\t/ )
      command.gsub!( /;"$/, "" )
      if command =~ /^\/.*\/$/
        command = command[ 1...-1 ]
      end
      @tags[ tag ] ||= Array.new
      @tags[ tag ].push CTag.new( file, command, kind, rest )
    end
  end
end

#log(string) ⇒ Object



5
6
7
8
# File 'lib/diakonos/logging.rb', line 5

def log( string )
  @log.puts string
  @log.flush
end

#log_backtraceObject



15
16
17
18
19
20
21
22
23
# File 'lib/diakonos/logging.rb', line 15

def log_backtrace
  begin
    raise Exception
  rescue Exception => e
    e.backtrace[ 1..-1 ].each do |x|
      debug_log x
    end
  end
end

#main_window_heightObject



122
123
124
125
126
127
128
129
130
131
# File 'lib/diakonos/display.rb', line 122

def main_window_height
  # One line for the status line
  # One line for the input line
  # One line for the context line
  retval = Curses::lines - 2
  if @settings['context.visible'] && ! @settings['context.combined']
    retval = retval - 1
  end
  retval
end

#main_window_widthObject



133
134
135
# File 'lib/diakonos/display.rb', line 133

def main_window_width
  Curses::cols
end

#map_key(arg, keymap = @modes['edit'].keymap) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/diakonos/config.rb', line 132

def map_key( arg, keymap = @modes['edit'].keymap )
  return  if arg.nil?

  if /  / === arg
    keystrings, function_and_args = arg.split( / {2,}/, 2 )
  else
    keystrings, function_and_args = arg.split( /;/, 2 )
  end

  keystrokes = Array.new
  keystrings.split( /\s+/ ).each do |ks_str|
    codes = Keying.keycodes_for( ks_str )
    if codes.empty?
      puts "Unknown keystring: #{ks_str}"
    else
      keystrokes.concat codes
    end
  end

  if function_and_args.nil?
    keymap.delete_key_path( keystrokes )
  else
    function, function_args = function_and_args.split( /\s+/, 2 )
    keymap.set_key_path(
      keystrokes,
      [ function, function_args ]
    )
  end
end

#matching_help_documents(str) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/diakonos/help.rb', line 16

def matching_help_documents( str )
  docs = []

  if str =~ %r{^/(.+)$}
    regexp = $1
    files = Dir[ "#{@help_dir}/*" ].select{ |f|
      File.open( f ) { |io| io.grep( /#{regexp}/i ) }.any?
    }
  else
    terms = str.gsub( /[^a-zA-Z0-9-]/, ' ' ).split.join( '|' )
    file_grep = `egrep -i -l '^Tags.*\\b(#{terms})\\b' #{@help_dir}/*`
    files = file_grep.split( /\s+/ )
  end

  files.each do |file|
    File.open( file ) do |f|
      docs << ( "%-300s | %s" % [ f.gets.strip, file ] )
    end
  end

  docs.sort { |a,b| a.gsub( /^# (?:an?|the) */i, '# ' ) <=> b.gsub( /^# (?:an?|the) */i, '# ' ) }
end

#mkdir(dir) ⇒ Object



239
240
241
242
243
# File 'lib/diakonos.rb', line 239

def mkdir( dir )
  if ! FileTest.exist?( dir )
    Dir.mkdir dir
  end
end

#next_list_itemObject



44
45
46
47
48
49
# File 'lib/diakonos/list.rb', line 44

def next_list_item
  if @list_buffer
    cursor_down
    @list_buffer[ @list_buffer.current_row ]
  end
end

#open_help_bufferObject



8
9
10
# File 'lib/diakonos/help.rb', line 8

def open_help_buffer
  @help_buffer = open_file( @help_filename )
end

#open_help_document(selected_string) ⇒ Object



39
40
41
42
43
44
# File 'lib/diakonos/help.rb', line 39

def open_help_document( selected_string )
  help_file = selected_string.split( "| " )[ -1 ]
  if File.exist? help_file
    open_file help_file
  end
end

#open_list_bufferObject



6
7
8
# File 'lib/diakonos/list.rb', line 6

def open_list_buffer
  @list_buffer = open_file( @list_filename )
end

#parse_configuration_file(filename, including_config_file = ConfigFileNull.new) ⇒ Object

Parameters:

  • filename (String)

    the config file to parse

  • including_config_file (ConfigFile) (defaults to: ConfigFileNull.new)

    the config file which calls include on this one



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/diakonos/config.rb', line 176

def parse_configuration_file( filename, including_config_file = ConfigFileNull.new )
  config_file = self.legitimize_config_filename!(filename, including_config_file)

  @configs << config_file

  config_file.each_line_with_index do |line, line_number|
    if line =~ /^\s*(\S+)\s*=\s*(\S+)\s*$/
      # Inheritance
      command, arg = $1, @setting_strings[ $2 ]
    end

    if arg.nil?
      command, arg = line.split( /\s+/, 2 )
      next  if command.nil?
      if arg.nil?
        config_file.problems << "error on line #{line_number+1}"
        next
      end
    end

    command = command.downcase

    @setting_strings[ command ] = arg

    case command
    when "include"
      self.parse_configuration_file( File.expand_path( arg ), config_file )
    when "load_extension"
      @extensions.load( arg ).each do |conf_file|
        parse_configuration_file conf_file
      end
    when /^lang\.(.+?)\.surround\.pair$/
      language = $1

      args = arg.split( /"\s+"/ )
      args.map! do |s|
        s.gsub( /(?<!\\)"/, '' ).gsub( /\\"/, '"' )
      end

      pair_key = args.shift

      if pair_key =~ /^\/.+\/$/
        pair_key = Regexp.new( pair_key[ 1..-2 ] )
      else
        pair_key = Regexp.new( "^#{Regexp.escape(pair_key)}$" )
      end

      pair_parens = args
      @surround_pairs[ language ][ pair_key ] = pair_parens
    when 'key'
      map_key arg
    when 'mkey'
      mode, arg_ = arg.split( /\s+/, 2 )
      map_key arg_, @modes[mode].keymap
    when 'key.after'
      function, args = arg.split( /\s+/, 2 )
      map_key args, @modes['edit'].keymap_after[function]
    when /^lang\.(.+?)\.tokens\.([^.]+)(\.case_insensitive)?$/, /^lang\.(.+?)\.tokens\.([^.]+)\.open(\.case_insensitive)?$/
      get_token_regexp( @token_regexps, arg, Regexp.last_match )
    when /^lang\.(.+?)\.tokens\.([^.]+)\.close(\.case_insensitive)?$/
      get_token_regexp( @close_token_regexps, arg, Regexp.last_match )
    when /^lang\.(.+?)\.tokens\.(.+?)\.format$/
      language = $1
      token_class = $2
      @token_formats[ language ][ token_class ] = Display.to_formatting( arg )
    when /^lang\.(.+?)\.format\..+$/
      @settings[ command ] = Display.to_formatting( arg )
    when /^colou?r$/
      number, fg, bg = arg.split( /\s+/ )
      number = number.to_i
      fg = Display.to_colour_constant( fg )
      bg = Display.to_colour_constant( bg )
      @colour_pairs << {
        :number => number,
        :fg => fg,
        :bg => bg
      }
    when /^lang\.(.+?)\.indent\.indenters(\.case_insensitive)?$/
      case_insensitive = ( $2 != nil )
      if case_insensitive
        @indenters[ $1 ] = Regexp.new( arg, Regexp::IGNORECASE )
      else
        @indenters[ $1 ] = Regexp.new arg
      end
    when /^lang\.(.+?)\.indent\.indenters_next_line(\.case_insensitive)?$/
      case_insensitive = ( $2 != nil )
      if case_insensitive
        @indenters_next_line[ $1 ] = Regexp.new( arg, Regexp::IGNORECASE )
      else
        @indenters_next_line[ $1 ] = Regexp.new arg
      end
    when /^lang\.(.+?)\.indent\.unindenters(\.case_insensitive)?$/
      case_insensitive = ( $2 != nil )
      if case_insensitive
        @unindenters[ $1 ] = Regexp.new( arg, Regexp::IGNORECASE )
      else
        @unindenters[ $1 ] = Regexp.new arg
      end
    when /^lang\.(.+?)\.indent\.(?:preventers|ignore|not_indented)(\.case_insensitive)?$/,
        /^lang\.(.+?)\.context\.ignore(\.case_insensitive)?$/
      case_insensitive = ( $2 != nil )
      if case_insensitive
        @settings[ command ] = Regexp.new( arg, Regexp::IGNORECASE )
      else
        @settings[ command ] = Regexp.new arg
      end
    when /^lang\.(.+?)\.indent\.triggers(\.case_insensitive)?$/
      case_insensitive = ( $2 != nil )
      if case_insensitive
        @indent_triggers[$1] = Regexp.new( arg, Regexp::IGNORECASE )
      else
        @indent_triggers[$1] = Regexp.new arg
      end
    when /^lang\.(.+?)\.filemask$/
      @filemasks[ $1 ] = Regexp.new arg
    when /^lang\.(.+?)\.bangmask$/
      @bangmasks[ $1 ] = Regexp.new arg
    when /^lang\.(.+?)\.closers\.(.+?)\.(.+?)$/
      @closers[ $1 ] ||= Hash.new
      @closers[ $1 ][ $2 ] ||= Hash.new
      @closers[ $1 ][ $2 ][ $3.to_sym ] = case $3
      when 'regexp'
        Regexp.new arg
      when 'closer'
        begin
          if arg =~ /^\{.+\}$/
            eval( "Proc.new " + arg )
          else
            arg
          end
        rescue Exception => e
          show_exception(
            e,
            [ "Failed to process Proc for #{command}.", ]
          )
        end
      end
    when "context.visible", "context.combined", "eof_newline", "view.nonfilelines.visible",
        /^lang\.(.+?)\.indent\.(?:auto|roundup|using_tabs|closers)$/,
        "found_cursor_start", "convert_tabs", 'delete_newline_on_delete_to_eol',
        'suppress_welcome', 'strip_trailing_whitespace_on_save', 'save_backup_files',
        'find.return_on_abort', 'fuzzy_file_find', 'fuzzy_file_find.recursive', 'view.line_numbers',
        'find.show_context_after', 'view.pairs.highlight', 'open_as_first_buffer', 'mouse'
      @settings[ command ] = arg.to_b
    when "context.format", "context.separator.format", "status.format", 'view.line_numbers.format',
        'view.non_search_area.format'
      @settings[ command ] = Display.to_formatting( arg )
    when /view\.column_markers\.(.+?)\.format/
      @column_markers[ $1 ][ :format ] = Display.to_formatting( arg )
    when "logfile"
      @logfilename = File.expand_path( arg )
    when "context.separator", /^lang\..+?\.indent\.ignore\.charset$/,
        /^lang\.(.+?)\.tokens\.([^.]+)\.change_to$/,
        /^lang\.(.+?)\.column_delimiters$/,
        /^extension\.(.+?)\.(.+?)/,
        "view.nonfilelines.character",
        'diff_command', 'session.default_session',
        'clipboard.external'
      @settings[ command ] = arg
    when /^lang\..+?\.comment_(?:close_)?string$/, 'view.line_numbers.number_format',
        "status.filler", "status.left", "status.right",
        "status.modified_str", "status.unnamed_str", "status.selecting_str",
        "status.read_only_str", 'interaction.blink_string'
      @settings[ command ] = arg.gsub( /^["']|["']$/, '' )
    when "status.vars"
      @settings[ command ] = arg.split( /\s+/ )
    when /^lang\.(.+?)\.indent\.size$/, /^lang\.(.+?)\.(?:tabsize|wrap_margin)$/,
        "context.max_levels", "context.max_segment_width", "max_clips", "max_undo_lines",
        "view.margin.x", "view.margin.y", "view.scroll_amount", "view.lookback", 'grep.context',
        'view.line_numbers.width', 'fuzzy_file_find.max_files', 'colour.background'
      @settings[ command ] = arg.to_i
    when "view.jump.x", "view.jump.y"
      @settings[ command ] = [ arg.to_i, 1 ].max
    when /view\.column_markers\.(.+?)\.column/
      @column_markers[ $1 ][ :column ] = [ arg.to_i, 1 ].max
    when "bol_behaviour", "bol_behavior"
      case arg.downcase
      when "zero"
        @settings[ "bol_behaviour" ] = BOL_ZERO
      when "first-char"
        @settings[ "bol_behaviour" ] = BOL_FIRST_CHAR
      when "alternating-zero"
        @settings[ "bol_behaviour" ] = BOL_ALT_ZERO
      else # default
        @settings[ "bol_behaviour" ] = BOL_ALT_FIRST_CHAR
      end
    when "eol_behaviour", "eol_behavior"
      case arg.downcase
      when "end"
        @settings[ "eol_behaviour" ] = EOL_END
      when "last-char"
        @settings[ "eol_behaviour" ] = EOL_LAST_CHAR
      when "alternating-last-char"
        @settings[ "eol_behaviour" ] = EOL_ALT_FIRST_CHAR
      else # default
        @settings[ "eol_behaviour" ] = EOL_ALT_END
      end
    when "context.delay", 'interaction.blink_duration', 'interaction.choice_delay'
      @settings[ command ] = arg.to_f
    when 'fuzzy_file_find.ignore'
      @fuzzy_ignores << arg
    end
  end
end

#parse_options(argv) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/diakonos.rb', line 245

def parse_options( argv )
  @post_load_script = ""
  while argv.length > 0
    arg = argv.shift
    case arg
    when '-c', '--config'
      @config_filename = argv.shift
      if @config_filename.nil?
        print_usage
        exit 1
      end
    when '-e', '--execute'
      post_load_script = argv.shift
      if post_load_script.nil?
        print_usage
        exit 1
      else
        @post_load_script << "\n#{post_load_script}"
      end
    when '-h', '--help'
      print_usage
      exit 1
    when '-m', '--open-matching'
      regexp = argv.shift
      files = `egrep -rl '#{regexp}' *`.split( /\n/ )
      if files.any?
        @files.concat( files.map { |f| Session.file_hash_for f } )
        script = "\nfind '#{regexp}', case_sensitive: true"
        @post_load_script << script
      end
    when '-ro'
      filename = argv.shift
      if filename.nil?
        print_usage
        exit 1
      else
        h = Session.file_hash_for( filename )
        h[ 'read_only' ] = true
        @read_only_files.push h
      end
    when '-s', '--load-session'
      @session_to_load = session_filepath_for( argv.shift )
    when '--test', '--testing'
      @testing = true
    when '--uninstall'
      uninstall
    when '--uninstall-without-confirmation'
      uninstall false
    when '--version'
      puts "Diakonos #{::Diakonos::VERSION} (#{::Diakonos::LAST_MODIFIED})"
      exit 0
    else
      # a name of a file to open
      @files.push Session.file_hash_for( arg )
    end
  end
end

#previous_list_itemObject



37
38
39
40
41
42
# File 'lib/diakonos/list.rb', line 37

def previous_list_item
  if @list_buffer
    cursor_up
    @list_buffer[ @list_buffer.current_row ]
  end
end


303
304
305
306
307
308
309
310
311
312
# File 'lib/diakonos.rb', line 303

def print_usage
  puts "Usage: #{$0} [options] [file] [file...]"
  puts "\t--help\tDisplay usage"
  puts "\t-c <config file>\tLoad this config file instead of ~/.diakonos/diakonos.conf"
  puts "\t-e, --execute <Ruby code>\tExecute Ruby code (such as Diakonos commands) after startup"
  puts "\t-m, --open-matching <regular expression>\tOpen all matching files under current directory"
  puts "\t-ro <file>\tLoad file as read-only"
  puts "\t-s, --load-session <session identifier>\tLoad a session"
  puts "\t--uninstall[-without-confirmation]\tUninstall Diakonos"
end

#process_keystroke(context = [], mode = 'edit', ch = nil) ⇒ Object

context is an array of characters (bytes) which are keystrokes previously typed (in a chain of keystrokes)



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/diakonos/keying.rb', line 328

def process_keystroke( context = [], mode = 'edit', ch = nil )
  ch ||= @modes[ mode ].window.getch
  return  if ch.nil?

  if ch == Curses::KEY_MOUSE
    handle_mouse_event
    return
  end

  c = ch.ord

  self.handle_utf_8(c, mode) and return

  if @capturing_keychain
    capture_keychain c, context
  elsif @capturing_mapping
    capture_mapping c, context
  else

    if context.empty? && typeable?( c )
      self.type_character ch, mode
      self.handle_gui_paste(mode)
      return
    end

    keychain_pressed = context.concat [ c ]

    function_and_args = (
      @modes[mode].keymap_after[@function_last].get_leaf( keychain_pressed ) ||
      @modes[mode].keymap.get_leaf( keychain_pressed )
    )

    if function_and_args
      function, args = function_and_args
      @function_last = function

      if mode != 'input' && ! @settings[ "context.combined" ]
        set_iline
      end

      if args
        to_eval = "#{function}( #{args} )"
      else
        to_eval = function
      end

      if @macro_history
        @macro_history.push to_eval
      end

      begin
        if buffer_current.search_area? && ! ( /^(?:find|readline)/ === to_eval )
          buffer_current.clear_search_area
        end
        eval to_eval, nil, "eval"
        @functions_last << to_eval  unless to_eval == "repeat_last"
        if ! @there_was_non_movement
          @there_was_non_movement = !( /^((cursor|page|scroll)_?(up|down|left|right)|find|seek)/i === to_eval )
        end
      rescue Exception => e
        debug_log e.message
        debug_log e.backtrace.join( "\n\t" )
        show_exception e
      end
    else
      partial_keychain = @modes[ mode ].keymap.get_node( keychain_pressed )
      if partial_keychain
        if mode != 'input'
          set_iline( keychain_str_for( keychain_pressed ) + "..." )
        end
        process_keystroke keychain_pressed, mode
      elsif mode != 'input'
        set_iline "Nothing assigned to #{keychain_str_for( keychain_pressed )}"
      end
    end
  end
end

#push_cursor_state(top_line, row, col, clear_stack_pointer = CLEAR_STACK_POINTER) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/diakonos/cursor.rb', line 10

def push_cursor_state( top_line, row, col, clear_stack_pointer = CLEAR_STACK_POINTER )
  new_state = {
    buffer: buffer_current,
    top_line: top_line,
    row: row,
    col: col
  }
  if ! @cursor_stack.include? new_state
    @cursor_stack << new_state
    if clear_stack_pointer
      @cursor_stack_pointer = nil
    end
    clear_non_movement_flag
  end
end

#redrawObject



114
115
116
117
118
119
120
# File 'lib/diakonos/display.rb', line 114

def redraw
  load_configuration
  initialize_display
  update_status_line
  update_context_line
  display_buffer buffer_current
end

#refresh_allObject



322
323
324
325
326
327
328
329
330
331
332
# File 'lib/diakonos/display.rb', line 322

def refresh_all
  @win_main.refresh
  if @win_context
    @win_context.refresh
  end
  @win_status.refresh
  @win_interaction.refresh
  if @win_line_numbers
    @win_line_numbers.refresh
  end
end

#register_proc(the_proc, hook_name, priority = 0) ⇒ Object



3
4
5
# File 'lib/diakonos/hooks.rb', line 3

def register_proc( the_proc, hook_name, priority = 0 )
  @hooks[ hook_name ] << { :proc => the_proc, :priority => priority }
end

#run_hook_procs(hook_id, *args) ⇒ Object



7
8
9
10
11
# File 'lib/diakonos/hooks.rb', line 7

def run_hook_procs( hook_id, *args )
  @hooks[ hook_id ].each do |hook_proc|
    hook_proc[ :proc ].call( *args )
  end
end

#run_scriptsObject



432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/diakonos.rb', line 432

def run_scripts
  scripts = @extensions.scripts + Dir[ "#{@script_dir}/*" ]
  scripts.each do |script|
    begin
      require script
    rescue Exception => e
      show_exception(
        e,
        [
          "There is a syntax error in the script.",
          "An invalid hook name was used."
        ]
      )
    end
  end
end

#save_session(session_file = @session.filename) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/diakonos/sessions.rb', line 162

def save_session( session_file = @session.filename )
  return  if session_file.nil?
  return  if @testing && Session.pid_session?(session_file)

  @session.set_buffers(@buffers)
  @session.set_readline_histories(@rlh_general, @rlh_files, @rlh_search, @rlh_shell, @rlh_help, @rlh_sessions)

  File.open( session_file, 'w' ) do |f|
    f.puts @session.to_yaml
  end
end

#select_list_itemObject



29
30
31
32
33
34
35
# File 'lib/diakonos/list.rb', line 29

def select_list_item
  if @list_buffer
    line = @list_buffer.set_selection_current_line
    display_buffer @list_buffer
    line
  end
end

#session_filepath_for(session_id) ⇒ Object



174
175
176
177
178
179
180
# File 'lib/diakonos/sessions.rb', line 174

def session_filepath_for( session_id )
  if session_id && session_id !~ %r{/}
    "#{@session_dir}/#{session_id}"
  else
    session_id
  end
end

#session_startupObject



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/diakonos/sessions.rb', line 182

def session_startup
  @stale_session_files = []

  if @session_to_load
    pid_session = @session
    @session = nil
    session_path = session_filepath_for( @session_to_load )
    load_session session_path
    if ! @session
      @session = Session.new(session_path)
    end
  else
    session_files = Dir[ "#{@session_dir}/*" ].grep( %r{/\d+$} )
    session_files.each do |sf|
      pid = sf[ %r{/(\d+)$}, 1 ].to_i

      # Check if the process is still alive
      begin
        Process.kill 0, pid
      rescue Errno::ESRCH, Errno::EPERM
        if Session.pid_session?(sf)
          @stale_session_files << sf
        end
      end
    end
  end
end

#set_iline(s = "") ⇒ Object



137
138
139
# File 'lib/diakonos/display.rb', line 137

def set_iline(s = "")
  @interaction_handler.set_iline s
end

#set_iline_if_empty(s) ⇒ Object



141
142
143
# File 'lib/diakonos/display.rb', line 141

def set_iline_if_empty(s)
  @interaction_handler.set_iline_if_empty s
end

#set_initial_ilineObject



423
424
425
426
427
428
429
430
# File 'lib/diakonos.rb', line 423

def set_initial_iline
  if ENV['COLORTERM'] == 'gnome-terminal'
    help_key = 'Shift-F1'
  else
    help_key = 'F1'
  end
  set_iline "Diakonos #{VERSION} (#{LAST_MODIFIED})   #{help_key} for help  F12 to configure  Ctrl-Q to quit"
end

#set_status_variable(identifier, value) ⇒ Object



145
146
147
# File 'lib/diakonos/display.rb', line 145

def set_status_variable( identifier, value )
  @status_vars[ identifier ] = value
end

#show_buffer_file_diff(buffer = @buffer_current) {|diff_buffer| ... } ⇒ Object

Yields:

  • (diff_buffer)


49
50
51
52
53
54
55
56
# File 'lib/diakonos/buffer-management.rb', line 49

def show_buffer_file_diff( buffer = @buffer_current )
  current_text_file = @diakonos_home + '/current-buffer'
  buffer.save_copy( current_text_file )
  `#{@settings[ 'diff_command' ]} #{current_text_file} #{buffer.name} > #{@diff_filename}`
  diff_buffer = open_file( @diff_filename )
  yield diff_buffer
  close_buffer diff_buffer
end

#show_exception(e, probable_causes = [ "Unknown" ]) ⇒ Object



502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/diakonos.rb', line 502

def show_exception( e, probable_causes = [ "Unknown" ] )
  begin
    File.open( @error_filename, "w" ) do |f|
      f.puts "Diakonos Error:"
      f.puts
      f.puts "#{e.class}: #{e.message}"
      f.puts
      f.puts "Probable Causes:"
      f.puts
      probable_causes.each do |pc|
        f.puts "- #{pc}"
      end
      f.puts
      f.puts "----------------------------------------------------"
      f.puts "If you can reproduce this error, please report it at"
      f.puts "https://github.com/Pistos/diakonos/issues !"
      f.puts "----------------------------------------------------"
      f.puts e.backtrace
    end
    open_file @error_filename
  rescue Exception => e2
    debug_log "EXCEPTION: #{e.message}"
    debug_log "\t#{e.backtrace}"
  end
end

#showing_list?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/diakonos/list.rb', line 15

def showing_list?
  @list_buffer
end

#startObject



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/diakonos.rb', line 326

def start
  require 'diakonos/window'

  create_buffers_from_files
  @files = []
  @read_only_files.each do |file|
    @buffers << Buffer.new( file )
  end
  if ! @testing
    session_startup
  end
  create_buffers_from_files
  @files = []
  if @buffers.empty?
    @buffers << Buffer.new
  end

  initialize_display
  @buffers.each do |buffer|
    buffer.reset_display
  end

  set_initial_iline

  run_scripts

  @hooks.each do |hook_name, hook|
    hook.sort { |a,b| a[ :priority ] <=> b[ :priority ] }
  end

  handle_stale_session_files

  create_buffers_from_files

  session_buffer_number = @session.buffer_current || 1
  if ! switch_to_buffer_number( session_buffer_number )
    debug_log "Failed to switch to buffer #{session_buffer_number.inspect}"
    switch_to_buffer_number 1
  end

  run_hook_procs :after_startup
  if @post_load_script
    begin
      eval @post_load_script
    rescue Exception => e
      show_exception(
        e,
        [ "There is an error in the post-load script:\n#{@post_load_script}" ]
      )
    end
  end

  @buffers.each do |b|
    run_hook_procs :after_open, b
    b.cursor_to( b.last_row, b.last_col, Buffer::DONT_DISPLAY )
  end
  buffer_current.cursor_to( buffer_current.last_row, buffer_current.last_col, Buffer::DONT_DISPLAY )

  if @configs.any? { |c| c.problems.any? }
    File.open( @error_filename, "w" ) do |f|
      f.puts "There are problems with the configuration file(s):"
      @configs.each do |c|
        next  if c.problems.empty?

        f.puts
        f.print "#{c}:\n\t"
        f.puts c.problems.join("\n\t")
      end
    end
    open_file @error_filename
  end

  if ! @testing && ! @settings[ 'suppress_welcome' ]
    open_file "#{@help_dir}/welcome.dhf"
  else
    conflict_regexp_source = '^<{4,}'
    if seek(conflict_regexp_source)
      find conflict_regexp_source
    end
  end

  begin
    # Main keyboard loop.
    while ! @quitting
      process_keystroke
      @win_main.refresh
    end
  rescue SignalException => e
    debug_log "Terminated by signal (#{e.message})"
  end

  cleanup_display
  cleanup_session

  @debug.close
end

#start_recording_macro(name = nil) ⇒ Object



528
529
530
531
532
533
534
# File 'lib/diakonos.rb', line 528

def start_recording_macro( name = nil )
  return if @macro_history
  @macro_name = name
  @macro_history = Array.new
  @macro_input_history = Array.new
  set_iline "Started macro recording."
end

#stop_recording_macroObject



536
537
538
539
540
541
542
# File 'lib/diakonos.rb', line 536

def stop_recording_macro
  @macro_history.pop  # Remove the stop_recording_macro command itself
  @macros[ @macro_name ] = [ @macro_history, @macro_input_history ]
  @macro_history = nil
  @macro_input_history = nil
  set_iline "Stopped macro recording."
end

#switch_to(buffer, opts = {}) ⇒ Boolean

Returns true iff the buffer was successfully switched to.

Parameters:

  • the (Buffer)

    Buffer to switch to

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :do_display (Boolean)

    Whether or not to update the display after closure

Returns:

  • (Boolean)

    true iff the buffer was successfully switched to



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/diakonos/buffer-management.rb', line 9

def switch_to( buffer, opts = {} )
  return false  if buffer.nil?
  do_display = opts.fetch( :do_display, true )

  @buffer_stack -= [ @buffer_current ]
  if @buffer_current
    @buffer_stack.push @buffer_current
  end
  @buffer_current = buffer
  @session.buffer_current = buffer_to_number( buffer )
  run_hook_procs( :after_buffer_switch, buffer )
  if do_display
    update_status_line
    update_context_line
    display_buffer buffer
  end

  true
end

#type_character(c, mode = 'edit') ⇒ Object



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/diakonos/keying.rb', line 406

def type_character( c, mode = 'edit' )
  if @macro_history
    @macro_history.push "type_character #{c.inspect}, #{mode.inspect}"
  end
  @there_was_non_movement = true

  case mode
  when 'edit'
    buffer_current.delete_selection Buffer::DONT_DISPLAY
    buffer_current.insert_string c
    cursor_right Buffer::STILL_TYPING
    if c =~ @indent_triggers[buffer_current.language]
      buffer_current.parsed_indent cursor_eol: true
    end
  when 'input'
    if ! @readline.numbered_list?
      @readline.paste c
    else
      if(
        showing_list? &&
        ( (48..57).include?( c.ord ) || (97..122).include?( c.ord ) )
      )
        line = list_buffer.to_a.select { |l|
          l =~ /^#{c}  /
        }[ 0 ]

        if line
          @readline.list_sync line
          @readline.finish
        end
      end
    end
  end
end

#typeable?(char) ⇒ Boolean

Returns:

  • (Boolean)


239
240
241
# File 'lib/diakonos/keying.rb', line 239

def typeable?( char )
  char > 31 && char < 255 && char != BACKSPACE
end

#uninstall(confirm = true) ⇒ Object



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/diakonos.rb', line 449

def uninstall( confirm = true )
  inst = ::Diakonos::INSTALL_SETTINGS[ :installed ]

  if confirm
    puts inst[ :files ].sort.join( "\n" )
    puts
    puts inst[ :dirs ].sort.map { |d| "#{d}/" }.join( "\n" )
    puts
    puts "The above files will be removed.  The above directories will be removed if they are empty.  Proceed?  (y/n)"
    answer = $stdin.gets
    case answer
    when /^y/i
      puts "Deleting..."
    else
      puts "Uninstallation aborted."
      exit 1
    end
  end

  inst[ :files ].each do |f|
    FileUtils.rm f
  end
  inst[ :dirs ].sort { |d1,d2| d2.length <=> d1.length }.each do |d|
    begin
      FileUtils.rmdir d
    rescue Errno::ENOTEMPTY
    end
    if File.exist? d
      $stderr.puts "(#{d} not removed)"
    end
  end

  exit 0
end

#update_context_lineObject



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/diakonos/display.rb', line 237

def update_context_line
  return  if @testing
  return  if @win_context.nil?

  @context_thread.exit  if @context_thread
  @context_thread = Thread.new do
    context = buffer_current.context

    Curses::curs_set 0
    @win_context.setpos( 0, 0 )
    chars_printed = 0
    if context.length > 0
      truncation = [ @settings[ "context.max_levels" ], context.length ].min
      max_length = [
        ( Curses::cols / truncation ) - @settings[ "context.separator" ].length,
        ( @settings[ "context.max_segment_width" ] || Curses::cols )
      ].min
      line = nil
      context_subset = context[ 0...truncation ]
      context_subset = context_subset.collect do |line|
        line.strip[ 0...max_length ]
      end

      context_subset.each do |line|
        @win_context.attrset @settings[ "context.format" ]
        @win_context.addstr line
        chars_printed += line.length
        @win_context.attrset @settings[ "context.separator.format" ]
        @win_context.addstr @settings[ "context.separator" ]
        chars_printed += @settings[ "context.separator" ].length
      end
    end

    @context_line_mutex.synchronize do
      @win_context.attrset @settings[ "context.format" ]
      @win_context.addstr( " " * ( Curses::cols - chars_printed ) )
      @win_context.refresh
    end
    @display_mutex.synchronize do
      @win_main.setpos( buffer_current.last_screen_y, buffer_current.last_screen_x )
      @win_main.refresh
    end
    Curses::curs_set 1
  end

  @context_thread.priority = -2
end

#update_status_lineObject



223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/diakonos/display.rb', line 223

def update_status_line
  return  if @testing

  str = build_status_line
  if str.length > Curses::cols
    str = build_status_line( str.length - Curses::cols )
  end
  Curses::curs_set 0
  @win_status.setpos( 0, 0 )
  @win_status.addstr str
  @win_status.refresh
  Curses::curs_set 1
end

#utf_8_bytes_to_char(c, mode) ⇒ String

Returns nil if c is not the beginning of a multi-byte sequence.

Parameters:

  • c (Integer)

    The first byte of a UTF-8 byte sequence

Returns:

  • (String)

    nil if c is not the beginning of a multi-byte sequence



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/diakonos/keying.rb', line 245

def utf_8_bytes_to_char(c, mode)
  if Keying::UTF_8_2_BYTE_BEGIN <= c && c <= Keying::UTF_8_2_BYTE_END
    # 2-byte character
    byte_array = [c, @modes[mode].window.getch.ord]
  elsif Keying::UTF_8_3_BYTE_BEGIN <= c && c <= Keying::UTF_8_3_BYTE_END
    # 3-byte character
    byte_array = [
      c,
      @modes[mode].window.getch.ord,
      @modes[mode].window.getch.ord,
    ]
  elsif Keying::UTF_8_4_BYTE_BEGIN <= c && c <= Keying::UTF_8_4_BYTE_END
    # 4-byte character
    byte_array = [
      c,
      @modes[mode].window.getch.ord,
      @modes[mode].window.getch.ord,
      @modes[mode].window.getch.ord,
    ]
  else
    return nil
  end

  byte_array.pack('C*').force_encoding('utf-8')
end

#with_list_fileObject



51
52
53
54
55
# File 'lib/diakonos/list.rb', line 51

def with_list_file
  File.open( @list_filename, "w" ) do |f|
    yield f
  end
end