class Diakonos::Diakonos
Attributes
Public Class Methods
# 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
Public Instance Methods
# 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: MIT Licence 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 } ### 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
# 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
@param [Integer] buffer_number should be 1-based, not zero-based. @return nil if no such buffer exists.
# 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
@return [Integer] 1-based, not zero-based. @return nil if no such buffer exists.
# File lib/diakonos/buffer-management.rb, line 42 def buffer_to_number( buffer ) i = @buffers.index( buffer ) if i i + 1 end end
# 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
# 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
# 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
# File lib/diakonos/sessions.rb, line 251 def cleanup_session if @session && Session.pid_session?(@session.filename) && File.exists?(@session.filename) File.delete @session.filename end end
# File lib/diakonos.rb, line 314 def clear_non_movement_flag @there_was_non_movement = false end
# File lib/diakonos/help.rb, line 11 def close_help_buffer close_buffer @help_buffer @help_buffer = nil end
# File lib/diakonos/list.rb, line 10 def close_list_buffer( opts = {} ) close_buffer @list_buffer, opts @list_buffer = nil end
# File lib/diakonos.rb, line 320 def create_buffers_from_files @files.each do |file_info| @buffers << Buffer.new(file_info) end end
# File lib/diakonos/list.rb, line 23 def current_list_item if @list_buffer @list_buffer.set_selection_current_line end end
# File lib/diakonos/cursor.rb, line 4 def cursor_stack_remove_buffer( buffer ) @cursor_stack.delete_if { |frame| frame[ :buffer ] == buffer } end
# File lib/diakonos/logging.rb, line 10 def debug_log( string ) @debug.puts( Time.now.strftime( "[%a %H:%M:%S] #{string}" ) ) @debug.flush end
# 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
# 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
# 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
@return [Integer] the number of replacements made
# 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
# File lib/diakonos/interaction.rb, line 48 def get_choice(*args) @interaction_handler.get_choice *args end
# 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
# 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
# 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
completion_array is the array of strings that tab completion can use @param options :initial_text, :completion_array, :history, :do_complete, :on_dirs
# 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
# 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 paste from a GUI (like x.org). i.e. Shift-Insert
# 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
# 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
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.
# 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
@param [Integer] c The ordinal (number) of a character @param [String] mode @return [Boolean] true iff c began a UTF-8 byte sequence
# 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
# 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
# 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
# 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
# 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
# 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
@return [ConfigFile, ConfigFileUnreadable]
# File lib/diakonos/config.rb, line 163 def legitimize_config_filename!(prospective_filename, including_config_file) if File.exists?(prospective_filename) ConfigFile.new( File.realpath(prospective_filename), including_config_file ) else ConfigFileUnreadable.new(prospective_filename, including_config_file) end end
# File lib/diakonos/list.rb, line 19 def list_item_selected? @list_buffer && @list_buffer.selecting? end
# 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.exists?( @diakonos_conf ) if FileTest.exists?( @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.exists?( @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
# 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
# File lib/diakonos/logging.rb, line 5 def log( string ) @log.puts string @log.flush end
# 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
# 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
# File lib/diakonos/display.rb, line 133 def main_window_width Curses::cols end
# 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
# 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
# File lib/diakonos.rb, line 239 def mkdir( dir ) if ! FileTest.exists?( dir ) Dir.mkdir dir end end
# File lib/diakonos/list.rb, line 44 def next_list_item if @list_buffer cursor_down @list_buffer[ @list_buffer.current_row ] end end
# File lib/diakonos/help.rb, line 8 def open_help_buffer @help_buffer = open_file( @help_filename ) end
# 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
# File lib/diakonos/list.rb, line 6 def open_list_buffer @list_buffer = open_file( @list_filename ) end
@param [String] filename the config file to parse @param [ConfigFile] including_config_file the config file which calls include on this one
# 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$/, "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
# 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
# File lib/diakonos/list.rb, line 37 def previous_list_item if @list_buffer cursor_up @list_buffer[ @list_buffer.current_row ] end end
# 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
context is an array of characters (bytes) which are keystrokes previously typed (in a chain of keystrokes)
# 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
# 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
# File lib/diakonos/display.rb, line 114 def redraw load_configuration initialize_display update_status_line update_context_line display_buffer buffer_current end
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# File lib/diakonos/display.rb, line 137 def set_iline(s = "") @interaction_handler.set_iline s end
# File lib/diakonos/display.rb, line 141 def set_iline_if_empty(s) @interaction_handler.set_iline_if_empty s end
# 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
# File lib/diakonos/display.rb, line 145 def set_status_variable( identifier, value ) @status_vars[ identifier ] = value end
# 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
# 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
# File lib/diakonos/list.rb, line 15 def showing_list? @list_buffer end
# 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
# 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
# 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
@param [Buffer] the Buffer
to switch to @option opts [Boolean] :do_display
Whether or not to update the display after closure
@return [Boolean] true iff the buffer was successfully switched to
# 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
# 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
# File lib/diakonos/keying.rb, line 239 def typeable?( char ) char > 31 && char < 255 && char != BACKSPACE end
# 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.exists? d $stderr.puts "(#{d} not removed)" end end exit 0 end
# 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
# 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
@param [Integer] c The first byte of a UTF-8 byte sequence @return [String] nil if c is not the beginning of a multi-byte sequence
# 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
# File lib/diakonos/list.rb, line 51 def with_list_file File.open( @list_filename, "w" ) do |f| yield f end end
Protected Instance Methods
# File lib/diakonos/display.rb, line 149 def build_status_line( truncation = 0 ) var_array = Array.new @settings[ "status.vars" ].each do |var| case var when "buffer_number" var_array.push buffer_to_number( buffer_current ) when "col" var_array.push( buffer_current.last_screen_col + 1 ) when "filename" name = buffer_current.nice_name var_array.push name[ ([ truncation, name.length ].min)..-1 ] when "modified" if buffer_current.modified? var_array.push @settings[ "status.modified_str" ] else var_array.push "" end when "num_buffers" var_array.push @buffers.length when "num_lines" var_array.push buffer_current.length when "row", "line" var_array.push( buffer_current.last_row + 1 ) when "read_only" if buffer_current.read_only var_array.push @settings[ "status.read_only_str" ] else var_array.push "" end when "selecting" if buffer_current.changing_selection var_array.push @settings[ "status.selecting_str" ] else var_array.push "" end when 'selection_mode' case buffer_current.selection_mode when :block var_array.push 'block' else var_array.push '' end when 'session_name' var_array.push @session.name when "type" var_array.push buffer_current.original_language when /^@/ var_array.push @status_vars[ var ] end end str = nil begin status_left = @settings[ "status.left" ] field_count = status_left.count "%" status_left = status_left % var_array[ 0...field_count ] status_right = @settings[ "status.right" ] % var_array[ field_count..-1 ] filler_string = @settings[ "status.filler" ] fill_amount = (Curses::cols - status_left.length - status_right.length) / filler_string.length if fill_amount > 0 filler = filler_string * fill_amount else filler = "" end str = status_left + filler + status_right rescue ArgumentError, TypeError => e debug_log e debug_log e.backtrace[ 0 ] debug_log "var_array: #{var_array.inspect}" str = "%-#{Curses::cols}s" % "(status line configuration error)" end str end