module Diakonos::Functions
The Diakonos::Functions
module contains all the methods that can be mapped to keys in Diakonos
. New methods can be added to this module by extensions.
Public Instance Methods
Shows the About page, which gives information on Diakonos
.
# File lib/diakonos/functions.rb, line 10 def about about_write open_file @about_filename end
# File lib/diakonos/functions/bookmarking.rb, line 4 def add_named_bookmark( name_ = nil ) if name_.nil? name = get_user_input "Bookmark name: " else name = name_ end if name @bookmarks[ name ] = Bookmark.new( buffer_current, buffer_current.current_row, buffer_current.current_column, name ) set_iline "Added bookmark #{@bookmarks[ name ].to_s}." end end
Begins selecting text by anchoring (marking) the start of a selection.
# File lib/diakonos/functions/selection.rb, line 5 def anchor_selection buffer_current.anchor_selection update_status_line end
Used for “shift+arrow” style selection.
# File lib/diakonos/functions/selection.rb, line 11 def anchor_unanchored_selection( *method_and_args ) buffer_current.anchor_unanchored_selection if method_and_args[0] self.send method_and_args[0], *method_and_args[1..-1] end update_status_line end
Move one character left, then delete one character.
# File lib/diakonos/functions/basics.rb, line 7 def backspace if( buffer_current.changing_selection || cursor_left( Buffer::STILL_TYPING ) ) delete end end
Insert a carriage return (newline) at the current cursor location. Deletes any currently selected text.
# File lib/diakonos/functions/basics.rb, line 15 def carriage_return buffer_current.carriage_return buffer_current.delete_selection end
# File lib/diakonos/functions/sessions.rb, line 8 def change_session_setting( key_ = nil, value = nil, do_redraw = DONT_REDRAW ) if key_.nil? key = get_user_input( "Setting: " ) else key = key_ end if key if value.nil? value = get_user_input( "Value: " ) end case @settings[ key ] when String value = value.to_s when Integer value = value.to_i when TrueClass, FalseClass value = value.to_b end @session.settings[ key ] = value merge_session_settings redraw if do_redraw set_iline "#{key} = #{value}" end end
Change the current working directory (CWD) of the Diakonos
process. @param [String] dir The directory to change to
# File lib/diakonos/functions/shell.rb, line 6 def chdir( dir = nil ) dir ||= get_user_input( "Change to directory: ", initial_text: Dir.pwd ) if dir Dir.chdir dir end end
Removes the highlighting from any text that matches the most recent search.
# File lib/diakonos/functions/selection.rb, line 21 def clear_matches buffer_current.clear_matches Buffer::DO_DISPLAY end
Closes a buffer.
@param [Diakonos::Buffer] buffer
The buffer to close. If no buffer is provided, defaults to the current buffer.
@option opts [Integer] :to_all
The CHOICE to assume for the prompt.
@option opts [Boolean] :do_display
Whether or not to update the display after closure
@return [Integer] the choice the user made, or nil if the user was not prompted to choose. @see Diakonos::CHOICE_YES @see Diakonos::CHOICE_NO
# File lib/diakonos/functions/buffers.rb, line 15 def close_buffer( buffer = buffer_current, opts = {} ) return nil if buffer.nil? to_all = opts[:to_all] do_display = opts.fetch( :do_display, true ) choice = nil if ! @buffers.include?( buffer ) log "No such buffer: #{buffer.name}" return nil end do_closure = true if buffer.modified? && ! buffer.read_only if to_all choice = to_all else choices = [ CHOICE_YES, CHOICE_NO, CHOICE_CANCEL ] if @quitting choices.concat [ CHOICE_YES_TO_ALL, CHOICE_NO_TO_ALL ] end choice = get_choice( "Save changes to #{buffer.nice_name}?", choices, CHOICE_CANCEL ) end case choice when CHOICE_YES, CHOICE_YES_TO_ALL do_closure = true save_file buffer when CHOICE_NO, CHOICE_NO_TO_ALL do_closure = true when CHOICE_CANCEL do_closure = false end end if do_closure del_buffer = nil previous_buffer = nil to_switch_to = nil switching = false # Search the buffer hash for the buffer we want to delete, # and mark the one we will switch to after deletion. @buffers.each do |b| if switching to_switch_to = b break end if b == buffer del_buffer = b switching = true next end previous_buffer = b end buf = nil while( @buffer_stack.any? && ! @buffers.include?( buf ) || buf == del_buffer ) do buf = @buffer_stack.pop end if @buffers.include?( buf ) to_switch_to = buf end if to_switch_to switch_to to_switch_to, do_display: do_display elsif previous_buffer switch_to previous_buffer, do_display: do_display end @buffer_closed = del_buffer @buffers.delete del_buffer cursor_stack_remove_buffer del_buffer if @buffer_stack.empty? # No buffers left. Open a new blank one. open_file end save_session update_status_line update_context_line end choice end # Opens the special "buffer selection" buffer, and prompts the user # to select a buffer. The user can select a buffer either with the # arrow keys and the Enter key, or by pressing the key corresponding # to an index presented in a left-hand column in the list. def list_buffers bullets = ( ('0'..'9').to_a + ('a'..'z').to_a ).map { |s| "#{s} " } buffers_unnamed = @buffers.find_all { |b| b.name.nil? } buffers_named = @buffers.find_all { |b| b.name } with_list_file do |f| if buffers_unnamed.size == 1 bullet = bullets.shift f.puts "#{bullet}(unnamed buffer)" else buffers_unnamed.each_with_index do |b,i| bullet = bullets.shift f.puts "#{bullet}(unnamed buffer #{i+1})" end end buffers_named.collect { |b| b.name }.sort.each_with_index do |name, index| bullet = bullets.shift f.puts "#{bullet}#{name}" end end open_list_buffer filename = get_user_input( "Switch to buffer: ", numbered_list: true ) buffer = buffers_named.find { |b| b.name == filename } if buffer switch_to buffer elsif filename =~ /\(unnamed buffer( \d+)?/ switch_to( buffers_unnamed[ $1.to_i - 1 ] ) end end # Opens a file into a new Buffer. # @param filename # The file to open. If nil, an empty, unnamed buffer is opened. # @param [Hash] meta # metadata containing additional information on how to open the file # @option meta [Hash] 'cursor' (nil) # A Hash containing the 'row' and 'col' to position the cursor after opening. # @option meta [Hash] 'display' (nil) # A Hash containing the 'top_line' and 'left_column' to use to position # the view after opening. # @option meta [Boolean] 'read_only' (false) # Whether to open the file in read-only (unmodifiable) mode # @option meta [Boolean] 'revert' (false) # Whether to skip asking about reverting to on-disk file contents (if different) # @return [Buffer] the buffer of the opened file # @return [NilClass] nil on failure def open_file( filename = nil, meta = {} ) read_only = !!meta[ 'read_only' ] force_revert = meta[ 'revert' ] || ASK_REVERT if meta[ 'cursor' ] last_row = meta[ 'cursor' ][ 'row' ] last_col = meta[ 'cursor' ][ 'col' ] end if meta[ 'display' ] top_line = meta[ 'display' ][ 'top_line' ] left_column = meta[ 'display' ][ 'left_column' ] end do_open = true buffer = nil if filename filename, last_row_ = ::Diakonos.parse_filename_and_line_number( filename ) last_row = last_row_ || last_row if filename =~ /\(unnamed buffer (\d+)\)/ existing_buffer = @buffers.find { |b| b.object_id == $1.to_i } filename = nil do_open = false else existing_buffer = @buffers.find { |b| b.name == filename } end if filename if existing_buffer do_open = force_revert || ( filename =~ /\.diakonos/ ) switch_to existing_buffer, do_display: false if ! do_open && existing_buffer.file_different? show_buffer_file_diff( existing_buffer ) do choice = get_choice( "Load on-disk version of #{existing_buffer.nice_name}?", [ CHOICE_YES, CHOICE_NO ] ) case choice when CHOICE_YES do_open = true when CHOICE_NO do_open = false end end end end if FileTest.exist?( filename ) # Don't try to open non-files (i.e. directories, pipes, sockets, etc.) do_open &&= FileTest.file?( filename ) end end end if do_open # Is file readable? # Does the "file" utility exist? if( filename && @settings[ 'use_magic_file' ] && FileTest.exist?( "/usr/bin/file" ) && FileTest.exist?( filename ) && /\blisting\.txt\b/ !~ filename ) file_type = `/usr/bin/file -L #{filename}` if file_type !~ /text/ && file_type !~ /empty$/ choice = get_choice( "#{filename} does not appear to be readable. Try to open it anyway?", [ CHOICE_YES, CHOICE_NO ], CHOICE_NO ) case choice when CHOICE_NO do_open = false end end end if do_open buffer = Buffer.new( 'filepath' => filename, 'read_only' => read_only, 'display' => { 'top_line' => top_line, 'left_column' => left_column, }, 'cursor' => { 'row' => last_row, 'col' => last_col, } ) if existing_buffer @buffers[ @buffers.index( existing_buffer ) ] = buffer else if @settings['open_as_first_buffer'] @buffers.unshift buffer else @buffers << buffer end end run_hook_procs( :after_open, buffer ) save_session if switch_to( buffer, do_display: false ) if last_row buffer.cursor_to last_row, last_col || 0, Buffer::DONT_DISPLAY end display_buffer buffer end end elsif existing_buffer if switch_to( existing_buffer, do_display: false ) if last_row existing_buffer.cursor_to last_row, last_col || 0, Buffer::DONT_DISPLAY end display_buffer existing_buffer end end buffer || existing_buffer end alias_method :new_file, :open_file # Prompts the user for a file to open, then opens it with #open_file . # @see #open_file def open_file_ask prefill = '' if buffer_current if buffer_current.current_line =~ %r#(/\w+)+/\w+\.\w+# prefill = $& elsif buffer_current.name prefill = File.expand_path( File.dirname( buffer_current.name ) ) + "/" end end if @settings[ 'fuzzy_file_find' ] prefill = '' finder = FuzzyFileFinder.new( directories: @session.dir, ceiling: @settings['fuzzy_file_find.max_files'] || 8192, ignores: @fuzzy_ignores, recursive: @settings['fuzzy_file_find.recursive'] ) finder_block = lambda { |input| break if input =~ %r{^/} matches = finder.find(input).sort_by { |m| m[:path] } with_list_file do |list| list.puts matches.map { |m| m[:path] } end open_list_buffer } end file = get_user_input( "Filename: ", history: @rlh_files, initial_text: prefill, &finder_block ) if file && ! file.empty? open_file file update_status_line update_context_line end end # Opens all files within a directory whose contents match a regular # expression. # @param regexp [String] # The regular expression used to match against. If nil, the user is # prompted for a value. # @param search_root [String] # The directory under which to recursively search for matches. If nil, # the user is prompted for a value. def open_matching_files( regexp = nil, search_root = nil ) regexp ||= get_user_input( "Regexp: ", history: @rlh_search ) return if regexp.nil? if buffer_current.current_line =~ %r{\w*/[/\w.]+} prefill = $& else prefill = File.expand_path( File.dirname( buffer_current.name ) ) + "/" end search_root ||= get_user_input( "Search within: ", history: @rlh_files, initial_text: prefill ) return if search_root.nil? files = `egrep -rl '#{regexp.gsub( /'/, "'\\\\''" )}' #{search_root}/*`.split( /\n/ ) if files.any? if files.size > 5 choice = get_choice( "Open #{files.size} files?", [ CHOICE_YES, CHOICE_NO ] ) return if choice == CHOICE_NO end files.each do |f| open_file f end find regexp, direction: :down, case_sensitive: true end end # Places a buffer at a new position in the array of Buffers # after shifting down (index+1) all existing Buffers from that position onwards. # @param to [Integer] The new 1-based position of the buffer to move # @param from [Integer] The original 1-based position of the buffer to move. Default: current buffer def renumber_buffer( to, from = nil ) if to < 1 raise "Invalid buffer index: #{to.inspect}" end if from && from < 1 raise "Invalid buffer index: #{from.inspect}" end from ||= buffer_to_number( buffer_current ) from_ = from - 1 to_ = to - 1 b = @buffers[from_] @buffers.delete_at from_ @buffers.insert( to_, b ) @buffers.compact! update_status_line end # If the prompt is non-nil, ask the user yes or no question first. def revert( prompt = nil ) do_revert = true if prompt show_buffer_file_diff do choice = get_choice( prompt, [ CHOICE_YES, CHOICE_NO ] ) case choice when CHOICE_NO do_revert = false end end end if do_revert open_file( buffer_current.name, 'read_only' => false, 'revert' => FORCE_REVERT, 'cursor' => { 'row' => buffer_current.last_row, 'col' => buffer_current.last_col } ) end end # Saves a buffer, then runs the :after_save hook on it. # @param [Buffer] buffer # The buffer to save. If nil, defaults to the current buffer. def save_file( buffer = buffer_current ) buffer.save run_hook_procs( :after_save, buffer ) end def save_file_as if buffer_current && buffer_current.name path = File.expand_path( File.dirname( buffer_current.name ) ) + "/" file = get_user_input( "Filename: ", history: @rlh_files, initial_text: path ) else file = get_user_input( "Filename: ", history: @rlh_files ) end if file old_name = buffer_current.name if buffer_current.save( file, PROMPT_OVERWRITE ) save_session end end end # Sets the type (language) of the current buffer. # @param [String] type_ # The type to set the current buffer to. # If nil, the user is prompted for a value. def set_buffer_type( type_ = nil ) type = type_ || get_user_input( "Content type: " ) if type if buffer_current.set_type( type ) update_status_line update_context_line end end end # If read_only is nil, the read_only state of the current buffer is toggled. # Otherwise, the read_only state of the current buffer is set to read_only. def set_read_only( read_only = nil ) if read_only buffer_current.read_only = read_only else buffer_current.read_only = ( ! buffer_current.read_only ) end update_status_line end def switch_to_buffer_number( buffer_number_ ) buffer_number = buffer_number_.to_i return if buffer_number < 1 if @buffer_number_last && buffer_number == buffer_to_number(buffer_current) buffer_number = @buffer_number_last end @buffer_number_last = buffer_to_number(buffer_current) switch_to @buffers[ buffer_number - 1 ] end def switch_to_next_buffer switch_to_buffer_number( buffer_to_number( buffer_current ) + 1 ) end def switch_to_previous_buffer switch_to_buffer_number( buffer_to_number( buffer_current ) - 1 ) end end
# File lib/diakonos/functions/text-manipulation.rb, line 6 def close_code buffer_current.close_code end
# File lib/diakonos/functions/text-manipulation.rb, line 10 def collapse_whitespace buffer_current.collapse_whitespace end
# File lib/diakonos/functions/text-manipulation.rb, line 15 def columnize( delimiter = nil, num_spaces_padding = 0 ) delimiter ||= get_user_input( "Column delimiter (regexp): ", history: @rlh_general, initial_text: @settings[ "lang.#{buffer_current.original_language}.column_delimiters" ] || '' ) if delimiter && num_spaces_padding buffer_current.columnize Regexp.new( delimiter ), num_spaces_padding end end
# File lib/diakonos/functions/text-manipulation.rb, line 26 def comment_out buffer_current.comment_out end
# File lib/diakonos/functions/text-manipulation.rb, line 30 def complete_word( direction = :down ) b = buffer_current if b.selecting? old_word = b.word_before_cursor b.delete_selection end partial = b.word_before_cursor return if partial.nil? all_words = @buffers.find_all { |b_| b_.original_language == b.original_language }.collect { |b_| b_.words( /^#{Regexp.escape(partial)}./ ) }.flatten if all_words.any? words = all_words.uniq.sort if old_word i = ( ( direction == :up ? words.size - 1 : 1 ) + words.find_index { |w| w == old_word } ) % words.size else freq_word = words.sort_by { |word| all_words.find_all { |w| w == word }.size }[ -1 ] i = words.find_index { |w| w == freq_word } end word = words[ i ] b.insert_string word[ partial.length..-1 ] r, c = b.last_row, b.last_col b.cursor_to( b.last_row, b.last_col + word.length - partial.length ) b.set_selection( r, c, r, c + word.length - partial.length ) n = words.size middle_word = words[ i ].center( Curses::cols / 4, ' ' ) shown_words = [ words[ ( n+i-2 ) % n ], words[ ( n+i-1 ) % n ], middle_word, words[ ( n+i+1 ) % n ], words[ ( n+i+2 ) % n ], ].compact.uniq.reject { |w| w == middle_word.strip }.join( ' ' ) mi = shown_words.index( middle_word ) padding = " " * ( Curses::cols / 2 - mi - ( middle_word.length / 2 ) ) set_iline padding + shown_words end end
Copies the currently selected text to clipboard then unselects.
# File lib/diakonos/functions/clipboard.rb, line 5 def copy_selection @clipboard.add_clip buffer_current.copy_selection remove_selection end
Moves the cursor to the beginning of the current buffer. @return [true,false] true iff the cursor changed positions
# File lib/diakonos/functions/cursor.rb, line 110 def cursor_bof buffer_current.cursor_to( 0, 0, Buffer::DO_DISPLAY ) end
Moves the cursor to the beginning of the current line.
# File lib/diakonos/functions/cursor.rb, line 115 def cursor_bol buffer_current.cursor_to_bol end
Moves the cursor to the bottom of the viewport of the current buffer.
# File lib/diakonos/functions/cursor.rb, line 135 def cursor_bov buffer_current.cursor_to_bov end
@return [true,false] true iff the cursor changed positions
# File lib/diakonos/functions/cursor.rb, line 11 def cursor_down buffer_current.cursor_to( buffer_current.last_row + 1, buffer_current.last_col, Buffer::DO_DISPLAY, Buffer::STOPPED_TYPING, DONT_ADJUST_ROW ) end
Moves the cursor to the end of the current buffer.
# File lib/diakonos/functions/cursor.rb, line 125 def cursor_eof buffer_current.cursor_to_eof end
Moves the cursor to the end of the current line.
# File lib/diakonos/functions/cursor.rb, line 120 def cursor_eol buffer_current.cursor_to_eol end
@return [true,false] true iff the cursor changed positions
# File lib/diakonos/functions/cursor.rb, line 22 def cursor_left( stopped_typing = Buffer::STOPPED_TYPING ) buffer_current.cursor_to( buffer_current.last_row, buffer_current.last_col - 1, Buffer::DO_DISPLAY, stopped_typing ) end
Pops the cursor stack. @param [Symbol] direction
Either :backward (default) or :forward.
@param [Boolean] different_file
Whether to pop just one frame (default), or many frames until a different file is reached.
@see Diakonos::DIFFERENT_FILE @see Diakonos::NOT_DIFFERENT_FILE
# File lib/diakonos/functions/cursor.rb, line 38 def cursor_return( direction = :backward, different_file = NOT_DIFFERENT_FILE ) delta = 0 if @cursor_stack_pointer.nil? push_cursor_state( buffer_current.top_line, buffer_current.last_row, buffer_current.last_col, DONT_CLEAR_STACK_POINTER ) delta = 1 end orig_ptr = @cursor_stack_pointer case direction when :backward @cursor_stack_pointer = ( @cursor_stack_pointer || @cursor_stack.length ) - 1 - delta while different_file && @cursor_stack[ @cursor_stack_pointer ] && @cursor_stack[ @cursor_stack_pointer ][ :buffer ] == buffer_current @cursor_stack_pointer -= 1 end when :forward @cursor_stack_pointer = ( @cursor_stack_pointer || 0 ) + 1 while different_file && @cursor_stack[ @cursor_stack_pointer ] && @cursor_stack[ @cursor_stack_pointer ][ :buffer ] == buffer_current @cursor_stack_pointer += 1 end end if @cursor_stack[ @cursor_stack_pointer ].nil? && orig_ptr @cursor_stack_pointer = orig_ptr end return_pointer = @cursor_stack_pointer if @cursor_stack_pointer < 0 return_pointer = @cursor_stack_pointer = 0 elsif @cursor_stack_pointer >= @cursor_stack.length return_pointer = @cursor_stack_pointer = @cursor_stack.length - 1 else cursor_state = @cursor_stack[ @cursor_stack_pointer ] if cursor_state buffer = cursor_state[ :buffer ] switch_to buffer buffer.pitch_view( cursor_state[ :top_line ] - buffer.top_line, Buffer::DONT_PITCH_CURSOR, Buffer::DO_DISPLAY ) buffer.cursor_to( cursor_state[ :row ], cursor_state[ :col ] ) update_status_line end end set_iline "Location: #{return_pointer+1}/#{@cursor_stack.size}" end
@return [true,false] true iff the cursor changed positions
# File lib/diakonos/functions/cursor.rb, line 88 def cursor_right( stopped_typing = Buffer::STOPPED_TYPING, amount = 1 ) buffer_current.cursor_to( buffer_current.last_row, buffer_current.last_col + amount, Buffer::DO_DISPLAY, stopped_typing ) end
Moves the cursor to the top of the viewport of the current buffer.
# File lib/diakonos/functions/cursor.rb, line 130 def cursor_tov buffer_current.cursor_to_tov end
@return [true,false] true iff the cursor changed positions
# File lib/diakonos/functions/cursor.rb, line 98 def cursor_up buffer_current.cursor_to( buffer_current.last_row - 1, buffer_current.last_col, Buffer::DO_DISPLAY, Buffer::STOPPED_TYPING, DONT_ADJUST_ROW ) end
Copies the currently selected text to clipboard, then deletes it.
# File lib/diakonos/functions/clipboard.rb, line 11 def cut_selection if @clipboard.add_clip( buffer_current.copy_selection ) delete end end
Calls Buffer#delete
on the current buffer.
# File lib/diakonos/functions/basics.rb, line 21 def delete buffer_current.delete end
Deletes the current line, and adds it to the clipboard. If the previous command was also delete_and_store_line
, append the line to the previous clip instead of making a new clip.
# File lib/diakonos/functions/clipboard.rb, line 21 def delete_and_store_line removed_text = buffer_current.delete_line if removed_text clip = [ removed_text, "" ] if @functions_last[ -1 ] =~ /^delete_and_store_line/ @clipboard.append_to_clip clip else @clipboard.add_clip clip end end end
Deletes characters starting from (but not including) a given character up to (but not including) the current cursor position. Also puts the deleted text into the clipboard.
# File lib/diakonos/functions.rb, line 36 def delete_from( char = nil ) if char.nil? set_iline "Type character to delete from..." char = @win_main.getch set_iline end if char removed_text = buffer_current.delete_from(char) if removed_text @clipboard.add_clip removed_text else set_iline "'#{char}' not found." end end end
Deletes the current line and adds it to the clipboard.
# File lib/diakonos/functions/basics.rb, line 26 def delete_line removed_text = buffer_current.delete_line if removed_text @clipboard.add_clip( [ removed_text, "" ] ) end end
Deletes characters up to, but not including, a given character. Also puts the deleted text into the clipboard.
# File lib/diakonos/functions.rb, line 17 def delete_to( char = nil ) if char.nil? set_iline "Type character to delete to..." char = @win_main.getch set_iline end if char removed_text = buffer_current.delete_to char if removed_text @clipboard.add_clip removed_text else set_iline "'#{char}' not found." end end end
Deletes characters between, but not including, a given pair of characters. Also puts the deleted text into the clipboard. Brace characters are intelligently matched with their opposite-side counterparts if the left-side brace is given (e.g. ‘[’).
# File lib/diakonos/functions.rb, line 56 def delete_to_and_from( inclusive = nil, char = nil ) if char.nil? set_iline "Type character to delete to and from..." char = @win_main.getch set_iline end if char removed_text = buffer_current.delete_to_and_from( char, inclusive == :inclusive ? INCLUSIVE : NOT_INCLUSIVE ) if removed_text @clipboard.add_clip( [ removed_text ] ) else set_iline "'#{char}' not found." end end end
Deletes the text from the current cursor position to the end of the line, then adds the deleted text to the clipboard.
# File lib/diakonos/functions/clipboard.rb, line 35 def delete_to_eol removed_text = buffer_current.delete_to_eol if removed_text @clipboard.add_clip removed_text end end
Evaluates (executes) Ruby code.
# File lib/diakonos/functions.rb, line 76 def evaluate( code_ = nil ) if code_.nil? if buffer_current.changing_selection selected_text = buffer_current.copy_selection[ 0 ] end code = get_user_input( "Ruby code: ", history: @rlh_general, initial_text: selected_text || "", completion_array: ::Diakonos::Functions.public_instance_methods.map { |m| m.to_s } ) else code = code_ end if code begin eval code rescue Exception => e show_exception( e, [ "The code given to evaluate has a syntax error.", "The code given to evaluate refers to a Diakonos command which does not exist, or is misspelled.", "The code given to evaluate refers to a Diakonos command with missing arguments.", "The code given to evaluate refers to a variable or method which does not exist.", ] ) end end end
Executes a command in a shell, and displays the exit code. Results of the shell command are discarded. Substitutes Diakonos
shell variables. Interaction with Diakonos
is not possible while the shell is running. For asynchronous shelling, use spawn
. The execute
function allows interaction with shell programs that accept keyboard interaction.
@param [String] command_
The shell command to execute
@see sub_shell_variables
@see shell
@see spawn
@see paste_shell_result
# File lib/diakonos/functions/shell.rb, line 166 def execute( command_ = nil ) command = command_ || get_user_input( "Command: ", history: @rlh_shell ) return if command.nil? command = sub_shell_variables( command ) Curses::close_screen success = system( command ) if ! success result = "Could not execute: #{command}" else result = "Exit code: #{$?}" end Curses::init_screen refresh_all set_iline result end
Searches for matches of a regular expression in the current buffer. @param [String] regexp_source_
The regular expression to search for.
@param [Hash] options
Options that alter how the search is performed
@option options [Symbol] :direction (:down)
The direction to search; :down or :up.
@option options [Boolean] :case_sensitive (false)
Whether or not the search should be case_sensitive.
@option options [String] replacement
If provided, do a find and replace, and replace matches with replacement.
@option options [Boolean] :word_only (false)
Whether or not to search with word boundaries
@see find_exact
@see find_again
@see find_clip
# File lib/diakonos/functions/search.rb, line 20 def find( regexp_source_ = nil, options = {} ) direction = options[:direction] || :down case_sensitive = options[:case_sensitive] replacement = options[:replacement] word_only = options[:word_only] if regexp_source_ regexp_source = regexp_source_ else buffer_current.clear_search_area m = buffer_current.selection_mark if m if m.start_row != m.end_row buffer_current.set_search_area buffer_current.selection_mark buffer_current.remove_selection else selected_text = buffer_current.copy_selection[ 0 ] end end starting_row, starting_col = buffer_current.last_row, buffer_current.last_col regexp_source = get_user_input( "Search regexp: ", history: @rlh_search, initial_text: selected_text || "" ) { |input| if input.length > 1 regexp_source = word_only ? "\\b#{input}\\b" : input find_( direction: direction, case_sensitive: case_sensitive, regexp_source: regexp_source, starting_row: starting_row, starting_col: starting_col, quiet: true ) else buffer_current.remove_selection Buffer::DONT_DISPLAY buffer_current.clear_matches Buffer::DO_DISPLAY end } end if regexp_source if word_only regexp_source = "\\b#{regexp_source}\\b" end num_replacements = find_( direction: direction, case_sensitive: case_sensitive, regexp_source: regexp_source, replacement: replacement, starting_row: starting_row, starting_col: starting_col, quiet: false ) show_number_of_matches_found( replacement ? num_replacements : nil ) elsif starting_row && starting_col buffer_current.clear_matches if @settings[ 'find.return_on_abort' ] buffer_current.cursor_to starting_row, starting_col, Buffer::DO_DISPLAY end end end
Search again for the most recently sought search term. @param [String] direction
The direction to search; :down or :up.
@see find
@see find_exact
# File lib/diakonos/functions/search.rb, line 102 def find_again( direction = :down ) if direction buffer_current.find_again( @last_search_regexps, direction ) else buffer_current.find_again( @last_search_regexps ) end show_number_of_matches_found end
Searches for matches of the latest clipboard item in the current buffer. Note that the clipboard item is interpreted as a regular expression. Only the last line of multi-line clipboard items is used. @param [String] direction
The direction to search. :down (default) or :up.
@param [Boolean] case_sensitive
Whether or not the search should be case_sensitive. Default is insensitive.
@see find
# File lib/diakonos/functions/search.rb, line 93 def find_clip( direction = :down, case_sensitive = CASE_INSENSITIVE ) find @clipboard.clip[-1], direction: direction, case_sensitive: case_sensitive end
Search for an exact string (not a regular expression). @param [Symbol] direction
The direction to search; :down (default) or :up.
@param [String] search_term_
The thing to search for.
@see find
@see find_again
# File lib/diakonos/functions/search.rb, line 118 def find_exact( direction = :down, search_term_ = nil ) buffer_current.clear_search_area if search_term_.nil? if buffer_current.changing_selection selected_text = buffer_current.copy_selection[ 0 ] end search_term = get_user_input( "Search for: ", history: @rlh_search, initial_text: selected_text || "" ) else search_term = search_term_ end if search_term regexp = [ Regexp.new( Regexp.escape( search_term ) ) ] buffer_current.find( regexp, :direction => direction ) @last_search_regexps = regexp end end
Moves the cursor to the beginning of the first child code block.
# File lib/diakonos/functions/cursor.rb, line 144 def go_block_inner buffer_current.go_block_inner end
Moves the cursor to the beginning of the next code block at the same indentation level as the current one.
# File lib/diakonos/functions/cursor.rb, line 149 def go_block_next buffer_current.go_block_next end
Moves the cursor to the beginning of the parent code block.
# File lib/diakonos/functions/cursor.rb, line 140 def go_block_outer buffer_current.go_block_outer end
Moves the cursor to the beginning of the previous code block at the same indentation level as the current one.
# File lib/diakonos/functions/cursor.rb, line 154 def go_block_previous buffer_current.go_block_previous end
Moves the cursor to the next occurrence of the given character. @param [String] char The character to go to
# File lib/diakonos/functions/cursor.rb, line 160 def go_to_char( after = nil, char = nil ) char ||= @interaction_handler.get_char( "Type character to go to..." ) if char begin moved = buffer_current.go_to_char( char, after == :after ? AFTER_CHAR : ON_CHAR ) if ! moved set_iline "'#{char}' not found." end rescue TypeError # User pressed Esc, or Ctrl-C, or similar. # Quietly continue. end end end
Moves the cursor to the closest previous occurrence of the given character. @param [String] char The character to go to
# File lib/diakonos/functions/cursor.rb, line 178 def go_to_char_previous( after = nil, char = nil ) char ||= @interaction_handler.get_char( "Type character to go to..." ) if char begin moved = buffer_current.go_to_char_previous( char, after == :after ? AFTER_CHAR : ON_CHAR ) if ! moved set_iline "'#{char}' not found." end rescue TypeError # User pressed Esc, or Ctrl-C, or similar. # Quietly continue. end end end
Prompts the user for a line number or line delta, with optional column number. Moves the cursor there.
# File lib/diakonos/functions/cursor.rb, line 196 def go_to_line_ask input = get_user_input( "Go to [line number|+lines][,column number]: " ) if input row = nil col = 0 if input =~ /([+-]\d+)/ row = buffer_current.last_row + $1.to_i col = buffer_current.last_col else input = input.split( /\D+/ ).collect { |n| n.to_i } if input.size > 0 if input[ 0 ] == 0 row = nil else row = input[ 0 ] - 1 end if input[ 1 ] col = input[ 1 ] - 1 end end end if row buffer_current.go_to_line( row, col ) end end end
# File lib/diakonos/functions/bookmarking.rb, line 17 def go_to_named_bookmark( name_ = nil ) if name_.nil? name = get_user_input "Bookmark name: " else name = name_ end if name bookmark = @bookmarks[ name ] if bookmark switch_to( bookmark.buffer ) bookmark.buffer.cursor_to( bookmark.row, bookmark.col, Buffer::DO_DISPLAY ) else set_iline "No bookmark named '#{name}'." end end end
# File lib/diakonos/functions/bookmarking.rb, line 35 def go_to_next_bookmark buffer_current.go_to_next_bookmark end
Moves the cursor to the pair match of the current character, if any.
# File lib/diakonos/functions/search.rb, line 140 def go_to_pair_match buffer_current.go_to_pair_match end
# File lib/diakonos/functions/bookmarking.rb, line 39 def go_to_previous_bookmark buffer_current.go_to_previous_bookmark end
# File lib/diakonos/functions/tags.rb, line 4 def go_to_tag( tag_ = nil ) load_tags # If necessary, prompt for tag name. if tag_.nil? if buffer_current.changing_selection selected_text = buffer_current.copy_selection[ 0 ] end tag_name = get_user_input( "Tag name: ", history: @rlh_general, initial_text: selected_text || "", completion_array: @tags.keys ) else tag_name = tag_ end tag_array = @tags[ tag_name ] if tag_array && tag_array.length > 0 if i = tag_array.index( @last_tag ) tag = ( tag_array[ i + 1 ] || tag_array[ 0 ] ) else tag = tag_array[ 0 ] end @last_tag = tag @tag_stack.push [ buffer_current.name, buffer_current.last_row, buffer_current.last_col ] if switch_to( @buffers.find { |b| b.name == tag.file } ) #buffer_current.go_to_line( 0 ) else open_file tag.file end line_number = tag.command.to_i if line_number > 0 buffer_current.go_to_line( line_number - 1 ) else find tag.command case_sensitive: true end elsif tag_name set_iline "No such tag: '#{tag_name}'" end end
# File lib/diakonos/functions/tags.rb, line 48 def go_to_tag_under_cursor go_to_tag buffer_current.word_under_cursor end
# File lib/diakonos/functions/grepping.rb, line 4 def grep( regexp_source = nil ) grep_( regexp_source, buffer_current ) end
# File lib/diakonos/functions/grepping.rb, line 8 def grep_buffers( regexp_source = nil ) grep_( regexp_source, *@buffers ) end
# File lib/diakonos/functions/grepping.rb, line 16 def grep_dir( regexp_source = nil, dir = nil ) if dir.nil? dir = get_user_input( "Grep directory: ", history: @rlh_files, initial_text: @session.dir, do_complete: DONT_COMPLETE, on_dirs: :accept_dirs ) return if dir.nil? end dir = File.expand_path( dir ) 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 || "" ) { |input| next if input.length < 2 escaped_input = input.gsub( /'/ ) { "\\047" } matching_files = `egrep '#{escaped_input}' -rniIl #{dir}`.split( /\n/ ) grep_results = matching_files.map { |f| ::Diakonos.grep_array( Regexp.new( input ), File.read( f ).split( /\n/ ), settings[ 'grep.context' ], "#{File.basename( f )}:", f ) }.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 regexp = nil begin list_buffer.highlight_matches Regexp.new( input ) rescue RegexpError => e # ignore end display_buffer list_buffer } if selected spl = selected.split( "| " ) if spl.size > 1 open_file spl[ -1 ] end else original_buffer.cursor_to starting_row, starting_col end end
# File lib/diakonos/functions/grepping.rb, line 12 def grep_session_dir( regexp_source = nil ) grep_dir regexp_source, @session.dir end
Starts the interactive help system.
# File lib/diakonos/functions.rb, line 109 def help( prefill = '' ) if ! File.exist?( @help_dir ) || Dir[ "#{@help_dir}/*" ].size == 0 set_iline 'There are no help files installed.' return end open_help_buffer matching_docs = nil selected = get_user_input( "Search terms: ", history: @rlh_help, initial_text: prefill, completion_array: @help_tags ) { |input| next if input.length < 3 && input[ 0..0 ] != '/' matching_docs = matching_help_documents( input ) with_list_file do |list| list.puts matching_docs.join( "\n" ) end open_list_buffer } close_help_buffer case selected when /\|/ open_help_document selected when nil # Help search aborted; do nothing else # Not a selected help document if matching_docs.nil? || matching_docs.empty? matching_docs = matching_help_documents( selected ) end case matching_docs.size when 1 open_help_document matching_docs[ 0 ] when 0 File.open( @error_filename, 'w' ) do |f| f.puts "There were no help documents matching your search." f.puts "(#{selected.strip})" f.puts "Close this message with Ctrl-W (default keychord)." end error_file = open_file( @error_filename ) else help selected end end end
# File lib/diakonos/functions/indentation.rb, line 4 def indent if ! buffer_current.changing_selection buffer_current.indent else @do_display = false mark = buffer_current.selection_mark if mark.end_col > 0 end_row = mark.end_row else end_row = mark.end_row - 1 end (mark.start_row..end_row).each do |row| buffer_current.indent row, Buffer::DONT_DISPLAY end @do_display = true display_buffer buffer_current end end
# File lib/diakonos/functions/indentation.rb, line 23 def insert_spaces( num_spaces ) if num_spaces > 0 buffer_current.delete_selection buffer_current.insert_string( " " * num_spaces ) cursor_right( Buffer::STILL_TYPING, num_spaces ) end end
# File lib/diakonos/functions/indentation.rb, line 31 def insert_tab type_character "\t" end
# File lib/diakonos/functions/text-manipulation.rb, line 83 def join_lines buffer_current.join_lines( buffer_current.current_row, Buffer::STRIP_LINE ) end
# File lib/diakonos/functions/text-manipulation.rb, line 79 def join_lines_upward buffer_current.join_lines_upward( buffer_current.current_row, Buffer::STRIP_LINE ) end
Opens the special “buffer selection” buffer, and prompts the user to select a buffer. The user can select a buffer either with the arrow keys and the Enter key, or by pressing the key corresponding to an index presented in a left-hand column in the list.
# File lib/diakonos/functions/buffers.rb, line 118 def list_buffers bullets = ( ('0'..'9').to_a + ('a'..'z').to_a ).map { |s| "#{s} " } buffers_unnamed = @buffers.find_all { |b| b.name.nil? } buffers_named = @buffers.find_all { |b| b.name } with_list_file do |f| if buffers_unnamed.size == 1 bullet = bullets.shift f.puts "#{bullet}(unnamed buffer)" else buffers_unnamed.each_with_index do |b,i| bullet = bullets.shift f.puts "#{bullet}(unnamed buffer #{i+1})" end end buffers_named.collect { |b| b.name }.sort.each_with_index do |name, index| bullet = bullets.shift f.puts "#{bullet}#{name}" end end open_list_buffer filename = get_user_input( "Switch to buffer: ", numbered_list: true ) buffer = buffers_named.find { |b| b.name == filename } if buffer switch_to buffer elsif filename =~ /\(unnamed buffer( \d+)?/ switch_to( buffers_unnamed[ $1.to_i - 1 ] ) end end
Loads Ruby code from file using Kernel#load.
# File lib/diakonos/functions.rb, line 164 def load_script( name_ = nil ) if name_.nil? name = get_user_input( "File to load as script: ", history: @rlh_files ) else name = name_ end if name thread = Thread.new( name ) do |f| begin load( f ) rescue Exception => e show_exception( e, [ "The filename given does not exist.", "The filename given is not accessible or readable.", "The loaded script does not reference Diakonos commands as members of the global Diakonos object. e.g. cursor_bol instead of $diakonos.cursor_bol", "The loaded script has syntax errors.", "The loaded script references objects or object members which do not exist." ] ) end set_iline "Loaded script '#{name}'." end loop do if thread.status != "run" break else sleep 0.1 end end thread.join end end
# File lib/diakonos/functions/sessions.rb, line 4 def merge_session_settings @settings.merge! @session.settings end
# File lib/diakonos/functions/text-manipulation.rb, line 87 def move_lines(direction:) mover = LineMover.new(buffer: buffer_current) mover.move_selected_lines(direction: direction) end
# File lib/diakonos/functions/sessions.rb, line 34 def name_session name = get_user_input( 'Session name: ' ) if name @session = Session.new("#{@session_dir}/#{name}") save_session end end
Opens a file into a new Buffer
. @param filename
The file to open. If nil, an empty, unnamed buffer is opened.
@param [Hash] meta
metadata containing additional information on how to open the file
@option meta [Hash] ‘cursor’ (nil)
A Hash containing the 'row' and 'col' to position the cursor after opening.
@option meta [Hash] ‘display’ (nil)
A Hash containing the 'top_line' and 'left_column' to use to position the view after opening.
@option meta [Boolean] ‘read_only’ (false)
Whether to open the file in read-only (unmodifiable) mode
@option meta [Boolean] ‘revert’ (false)
Whether to skip asking about reverting to on-disk file contents (if different)
@return [Buffer] the buffer of the opened file @return [NilClass] nil on failure
# File lib/diakonos/functions/buffers.rb, line 165 def open_file( filename = nil, meta = {} ) read_only = !!meta[ 'read_only' ] force_revert = meta[ 'revert' ] || ASK_REVERT if meta[ 'cursor' ] last_row = meta[ 'cursor' ][ 'row' ] last_col = meta[ 'cursor' ][ 'col' ] end if meta[ 'display' ] top_line = meta[ 'display' ][ 'top_line' ] left_column = meta[ 'display' ][ 'left_column' ] end do_open = true buffer = nil if filename filename, last_row_ = ::Diakonos.parse_filename_and_line_number( filename ) last_row = last_row_ || last_row if filename =~ /\(unnamed buffer (\d+)\)/ existing_buffer = @buffers.find { |b| b.object_id == $1.to_i } filename = nil do_open = false else existing_buffer = @buffers.find { |b| b.name == filename } end if filename if existing_buffer do_open = force_revert || ( filename =~ /\.diakonos/ ) switch_to existing_buffer, do_display: false if ! do_open && existing_buffer.file_different? show_buffer_file_diff( existing_buffer ) do choice = get_choice( "Load on-disk version of #{existing_buffer.nice_name}?", [ CHOICE_YES, CHOICE_NO ] ) case choice when CHOICE_YES do_open = true when CHOICE_NO do_open = false end end end end if FileTest.exist?( filename ) # Don't try to open non-files (i.e. directories, pipes, sockets, etc.) do_open &&= FileTest.file?( filename ) end end end if do_open # Is file readable? # Does the "file" utility exist? if( filename && @settings[ 'use_magic_file' ] && FileTest.exist?( "/usr/bin/file" ) && FileTest.exist?( filename ) && /\blisting\.txt\b/ !~ filename ) file_type = `/usr/bin/file -L #{filename}` if file_type !~ /text/ && file_type !~ /empty$/ choice = get_choice( "#{filename} does not appear to be readable. Try to open it anyway?", [ CHOICE_YES, CHOICE_NO ], CHOICE_NO ) case choice when CHOICE_NO do_open = false end end end if do_open buffer = Buffer.new( 'filepath' => filename, 'read_only' => read_only, 'display' => { 'top_line' => top_line, 'left_column' => left_column, }, 'cursor' => { 'row' => last_row, 'col' => last_col, } ) if existing_buffer @buffers[ @buffers.index( existing_buffer ) ] = buffer else if @settings['open_as_first_buffer'] @buffers.unshift buffer else @buffers << buffer end end run_hook_procs( :after_open, buffer ) save_session if switch_to( buffer, do_display: false ) if last_row buffer.cursor_to last_row, last_col || 0, Buffer::DONT_DISPLAY end display_buffer buffer end end elsif existing_buffer if switch_to( existing_buffer, do_display: false ) if last_row existing_buffer.cursor_to last_row, last_col || 0, Buffer::DONT_DISPLAY end display_buffer existing_buffer end end buffer || existing_buffer end
Prompts the user for a file to open, then opens it with open_file
. @see open_file
# File lib/diakonos/functions/buffers.rb, line 290 def open_file_ask prefill = '' if buffer_current if buffer_current.current_line =~ %r#(/\w+)+/\w+\.\w+# prefill = $& elsif buffer_current.name prefill = File.expand_path( File.dirname( buffer_current.name ) ) + "/" end end if @settings[ 'fuzzy_file_find' ] prefill = '' finder = FuzzyFileFinder.new( directories: @session.dir, ceiling: @settings['fuzzy_file_find.max_files'] || 8192, ignores: @fuzzy_ignores, recursive: @settings['fuzzy_file_find.recursive'] ) finder_block = lambda { |input| break if input =~ %r{^/} matches = finder.find(input).sort_by { |m| m[:path] } with_list_file do |list| list.puts matches.map { |m| m[:path] } end open_list_buffer } end file = get_user_input( "Filename: ", history: @rlh_files, initial_text: prefill, &finder_block ) if file && ! file.empty? open_file file update_status_line update_context_line end end
Opens all files within a directory whose contents match a regular expression. @param regexp [String]
The regular expression used to match against. If nil, the user is prompted for a value.
@param search_root [String]
The directory under which to recursively search for matches. If nil, the user is prompted for a value.
# File lib/diakonos/functions/buffers.rb, line 343 def open_matching_files( regexp = nil, search_root = nil ) regexp ||= get_user_input( "Regexp: ", history: @rlh_search ) return if regexp.nil? if buffer_current.current_line =~ %r{\w*/[/\w.]+} prefill = $& else prefill = File.expand_path( File.dirname( buffer_current.name ) ) + "/" end search_root ||= get_user_input( "Search within: ", history: @rlh_files, initial_text: prefill ) return if search_root.nil? files = `egrep -rl '#{regexp.gsub( /'/, "'\\\\''" )}' #{search_root}/*`.split( /\n/ ) if files.any? if files.size > 5 choice = get_choice( "Open #{files.size} files?", [ CHOICE_YES, CHOICE_NO ] ) return if choice == CHOICE_NO end files.each do |f| open_file f end find regexp, direction: :down, case_sensitive: true end end
# File lib/diakonos/functions/text-manipulation.rb, line 130 def operate_on_each_line( ruby_code = get_user_input( 'Ruby code: ', history: @rlh_general, initial_text: 'line.' ) ) if ruby_code lines = buffer_current.selected_text if lines && ! lines.empty? if lines[ -1 ].empty? lines.pop popped = true end new_lines = eval( "lines.collect { |line| #{ruby_code} }" ) if popped new_lines << '' end buffer_current.paste new_lines end end end
# File lib/diakonos/functions/text-manipulation.rb, line 107 def operate_on_lines( ruby_code = get_user_input( 'Ruby code: ', history: @rlh_general, initial_text: 'lines.collect { |l| l }' ) ) if ruby_code lines = buffer_current.selected_text if lines && ! lines.empty? if lines[ -1 ].empty? lines.pop popped = true end new_lines = eval( ruby_code ) if popped new_lines << '' end buffer_current.paste new_lines end end end
# File lib/diakonos/functions/text-manipulation.rb, line 92 def operate_on_string( ruby_code = get_user_input( 'Ruby code: ', history: @rlh_general, initial_text: 'str.' ) ) if ruby_code str = buffer_current.selected_string if str && ! str.empty? buffer_current.paste eval( ruby_code ) end end end
Pitches the current buffer’s view one screenful down.
# File lib/diakonos/functions/cursor.rb, line 226 def page_down if buffer_current.pitch_view( main_window_height, Buffer::DO_PITCH_CURSOR ) == 0 buffer_current.cursor_to_eof end update_status_line update_context_line end
Pitches the current buffer’s view one screenful up.
# File lib/diakonos/functions/cursor.rb, line 235 def page_up if buffer_current.pitch_view( -main_window_height, Buffer::DO_PITCH_CURSOR ) == 0 cursor_bof end update_status_line update_context_line end
# File lib/diakonos/functions/indentation.rb, line 35 def parsed_indent if( buffer_current.changing_selection ) @do_display = false mark = buffer_current.selection_mark (mark.start_row..mark.end_row).each do |row| buffer_current.parsed_indent row: row, do_display: false end @do_display = true display_buffer buffer_current else buffer_current.parsed_indent end update_status_line update_context_line end
Pastes the current clipboard item at the current cursor position.
# File lib/diakonos/functions/clipboard.rb, line 43 def paste buffer_current.paste @clipboard.clip end
Executes a command in a shell, captures the results, and pastes them in the current buffer at the current cursor location. Substitutes Diakonos
shell variables. Interaction with Diakonos
is not possible while the shell is running. For asynchronous shelling, use spawn
.
@param [String] command_
The shell command to execute
@see sub_shell_variables
@see execute
@see shell
@see spawn
# File lib/diakonos/functions/shell.rb, line 200 def paste_shell_result( command_ = nil ) command = command_ || get_user_input( "Command: ", history: @rlh_shell ) return if command.nil? command = sub_shell_variables( command ) Curses::close_screen begin buffer_current.paste( `#{command} 2<&1`.split( /\n/, -1 ) ) rescue Exception => e debug_log e.message debug_log e.backtrace.join( "\n\t" ) show_exception e end Curses::init_screen refresh_all end
# File lib/diakonos/functions.rb, line 201 def play_macro( name = nil ) macro, input_history = @macros[ name ] if input_history @macro_input_history = input_history.deep_clone if macro @playing_macro = true macro.each do |command| eval command end @playing_macro = false @macro_input_history = nil end end end
# File lib/diakonos/functions/tags.rb, line 52 def pop_tag tag = @tag_stack.pop if tag if ! switch_to( @buffers.find { |b| b.name == tag[ 0 ] } ) open_file tag[ 0 ] end buffer_current.cursor_to( tag[ 1 ], tag[ 2 ], Buffer::DO_DISPLAY ) else set_iline "Tag stack empty." end end
# File lib/diakonos/functions.rb, line 221 def print_keychain @capturing_keychain = true set_iline "Type any chain of keystrokes or key chords, then press Enter..." end
# File lib/diakonos/functions.rb, line 216 def print_mapped_function @capturing_mapping = true set_iline "Type any chain of keystrokes or key chords, or press Enter to stop." end
Quits Diakonos
(gracefully).
# File lib/diakonos/functions.rb, line 227 def quit @quitting = true to_all = nil save_session @buffers.each do |buffer| next if ! buffer.modified? switch_to buffer closure_choice = close_buffer( buffer, to_all: to_all ) case closure_choice when CHOICE_CANCEL @quitting = false break when CHOICE_YES_TO_ALL, CHOICE_NO_TO_ALL to_all = closure_choice end end end
# File lib/diakonos/functions/readline.rb, line 4 def readline_abort @readline.abort end
# File lib/diakonos/functions/readline.rb, line 8 def readline_accept @readline.accept current_list_item end
# File lib/diakonos/functions/readline.rb, line 12 def readline_backspace @readline.backspace end
# File lib/diakonos/functions/readline.rb, line 16 def readline_complete_input @readline.complete_input end
# File lib/diakonos/functions/readline.rb, line 28 def readline_cursor_bol @readline.cursor_bol end
# File lib/diakonos/functions/readline.rb, line 48 def readline_cursor_down if showing_list? if list_item_selected? next_list_item end @readline.set_input select_list_item else @readline.history_down end @readline.cursor_write_input end
# File lib/diakonos/functions/readline.rb, line 32 def readline_cursor_eol @readline.cursor_eol end
# File lib/diakonos/functions/readline.rb, line 20 def readline_cursor_left @readline.cursor_left end
# File lib/diakonos/functions/readline.rb, line 24 def readline_cursor_right @readline.cursor_right end
# File lib/diakonos/functions/readline.rb, line 36 def readline_cursor_up if showing_list? if list_item_selected? previous_list_item end @readline.set_input select_list_item else @readline.history_up end @readline.cursor_write_input end
# File lib/diakonos/functions/readline.rb, line 60 def readline_delete @readline.delete end
# File lib/diakonos/functions/readline.rb, line 64 def readline_delete_line @readline.delete_line end
# File lib/diakonos/functions/readline.rb, line 68 def readline_delete_word @readline.delete_word end
# File lib/diakonos/functions/readline.rb, line 72 def readline_grep_context_decrease decrease_grep_context @readline.call_block end
# File lib/diakonos/functions/readline.rb, line 77 def readline_grep_context_increase increase_grep_context @readline.call_block end
# File lib/diakonos/functions/readline.rb, line 82 def readline_page_down page_down @readline.list_sync select_list_item end
# File lib/diakonos/functions/readline.rb, line 87 def readline_page_up page_up @readline.list_sync select_list_item end
# File lib/diakonos/functions/bookmarking.rb, line 43 def remove_named_bookmark( name_ = nil ) if name_.nil? name = get_user_input "Bookmark name: " else name = name_ end if name bookmark = @bookmarks.delete name set_iline "Removed bookmark #{bookmark.to_s}." end end
Unselects any current selection (stops selecting).
# File lib/diakonos/functions/selection.rb, line 26 def remove_selection buffer_current.remove_selection update_status_line end
Places a buffer at a new position in the array of Buffers after shifting down (index+1) all existing Buffers from that position onwards. @param to [Integer] The new 1-based position of the buffer to move @param from [Integer] The original 1-based position of the buffer to move. Default: current buffer
# File lib/diakonos/functions/buffers.rb, line 372 def renumber_buffer( to, from = nil ) if to < 1 raise "Invalid buffer index: #{to.inspect}" end if from && from < 1 raise "Invalid buffer index: #{from.inspect}" end from ||= buffer_to_number( buffer_current ) from_ = from - 1 to_ = to - 1 b = @buffers[from_] @buffers.delete_at from_ @buffers.insert( to_, b ) @buffers.compact! update_status_line end
# File lib/diakonos/functions.rb, line 245 def repeat_last eval @functions_last[ -1 ] if ! @functions_last.empty? end
If the prompt is non-nil, ask the user yes or no question first.
# File lib/diakonos/functions/buffers.rb, line 392 def revert( prompt = nil ) do_revert = true if prompt show_buffer_file_diff do choice = get_choice( prompt, [ CHOICE_YES, CHOICE_NO ] ) case choice when CHOICE_NO do_revert = false end end end if do_revert open_file( buffer_current.name, 'read_only' => false, 'revert' => FORCE_REVERT, 'cursor' => { 'row' => buffer_current.last_row, 'col' => buffer_current.last_col } ) end end
Saves a buffer, then runs the :after_save hook on it. @param [Buffer] buffer
The buffer to save. If nil, defaults to the current buffer.
# File lib/diakonos/functions/buffers.rb, line 424 def save_file( buffer = buffer_current ) buffer.save run_hook_procs( :after_save, buffer ) end
# File lib/diakonos/functions/buffers.rb, line 429 def save_file_as if buffer_current && buffer_current.name path = File.expand_path( File.dirname( buffer_current.name ) ) + "/" file = get_user_input( "Filename: ", history: @rlh_files, initial_text: path ) else file = get_user_input( "Filename: ", history: @rlh_files ) end if file old_name = buffer_current.name if buffer_current.save( file, PROMPT_OVERWRITE ) save_session end end end
Scrolls the current buffer’s view down, as determined by the view.scroll_amount setting.
# File lib/diakonos/functions/cursor.rb, line 245 def scroll_down buffer_current.pitch_view( @settings[ "view.scroll_amount" ] || 1 ) update_status_line update_context_line end
Scrolls the current buffer’s view up, as determined by the view.scroll_amount setting.
# File lib/diakonos/functions/cursor.rb, line 253 def scroll_up if @settings[ "view.scroll_amount" ] buffer_current.pitch_view( -@settings[ "view.scroll_amount" ] ) else buffer_current.pitch_view( -1 ) end update_status_line update_context_line end
Immediately moves the cursor to the next match of a regular expression. The user is not prompted for any value. @param [String] regexp_source
The regular expression to search for.
@param [Symbol] direction
The direction to search; :down (default) or :up.
# File lib/diakonos/functions/search.rb, line 157 def seek( regexp_source, direction = :down ) if regexp_source regexp = Regexp.new( regexp_source ) buffer_current.seek( regexp, direction ) end end
Selects the entire buffer contents.
# File lib/diakonos/functions/selection.rb, line 32 def select_all buffer_current.select_all end
Selects text between two regexps.
# File lib/diakonos/functions/selection.rb, line 37 def select_block( beginning = nil, ending = nil, including_ending = true ) if beginning.nil? input = get_user_input( "Start at regexp: " ) if input beginning = Regexp.new input end end if beginning && ending.nil? input = get_user_input( "End before regexp: " ) if input ending = Regexp.new input end end if beginning && ending buffer_current.select( beginning, ending, including_ending ) end end
Selects the current line.
# File lib/diakonos/functions/selection.rb, line 75 def select_line buffer_current.select_current_line update_status_line end
Selects the word at the current cursor position. If the cursor is not on a word character, the first word following the cursor is selected.
# File lib/diakonos/functions/selection.rb, line 89 def select_word buffer_current.select_word end
# File lib/diakonos/functions/selection.rb, line 93 def select_word_another buffer_current.select_word_another end
Selects the code block which wraps the current cursor position. Execute multiple times in succession to select increasingly outer code blocks.
# File lib/diakonos/functions/selection.rb, line 82 def select_wrapping_block buffer_current.select_wrapping_block update_status_line end
Changes selection mode to block mode (rectangular selection).
# File lib/diakonos/functions/selection.rb, line 56 def selection_mode_block buffer_current.selection_mode_block update_status_line end
Changes selection mode to normal mode (flow selection).
# File lib/diakonos/functions/selection.rb, line 62 def selection_mode_normal buffer_current.selection_mode_normal update_status_line end
Sets the type (language) of the current buffer. @param [String] type_
The type to set the current buffer to. If nil, the user is prompted for a value.
# File lib/diakonos/functions/buffers.rb, line 448 def set_buffer_type( type_ = nil ) type = type_ || get_user_input( "Content type: " ) if type if buffer_current.set_type( type ) update_status_line update_context_line end end end
If read_only is nil, the read_only state of the current buffer is toggled. Otherwise, the read_only state of the current buffer is set to read_only.
# File lib/diakonos/functions/buffers.rb, line 461 def set_read_only( read_only = nil ) if read_only buffer_current.read_only = read_only else buffer_current.read_only = ( ! buffer_current.read_only ) end update_status_line end
# File lib/diakonos/functions/sessions.rb, line 42 def set_session_dir path = get_user_input( "Session directory: ", history: @rlh_files, initial_text: @session.dir, do_complete: DONT_COMPLETE, on_dirs: :accept_dirs ) if path @session.dir = File.expand_path( path ) save_session set_iline "Session dir changed to: #{@session.dir}" else set_iline "(Session dir is: #{@session.dir})" end end
Executes a command in a shell, captures the results, and displays them (if any) in a new buffer. Substitutes Diakonos
shell variables. Interaction with Diakonos
is not possible while the shell is running. For asynchronous shelling, use spawn
. The shell function does not allow interaction with applications run in the shell. Use execute
for interactivity.
@param [String] command_
The shell command to execute
@param [String] result_filename
The name of the temporary file to write the shell results to
@see sub_shell_variables
@see execute
@see spawn
@see paste_shell_result
# File lib/diakonos/functions/shell.rb, line 93 def shell( command_ = nil, result_filename = 'shell-result.txt' ) command = command_ || get_user_input( "Command: ", history: @rlh_shell ) return if command.nil? command = sub_shell_variables( command ) completed = false result_file = "#{@diakonos_home}/#{result_filename}" File.open( result_file , "w" ) do |f| Curses::close_screen stdin, stdout, stderr = Open3.popen3( command ) t1 = Thread.new do stdout.each_line do |line| f.puts line end end t2 = Thread.new do stderr.each_line do |line| f.puts line end end catch :stop do loop do begin Timeout::timeout( 5 ) do t1.join t2.join Curses::init_screen refresh_all completed = true throw :stop end rescue Timeout::Error => e choice = get_choice( "Keep waiting for shell results?", [ CHOICE_YES, CHOICE_NO ], CHOICE_YES ) if choice != CHOICE_YES t1.terminate t2.terminate throw :stop end end end end end if File.size?( result_file ) open_file result_file set_iline "#{completed ? '' : '(interrupted) '}Results for: #{command}" else set_iline "Empty result for: #{command}" end end
Opens a new buffer showing a list of all internal clipboard items. Only for use when no external clipboard is used.
# File lib/diakonos/functions/clipboard.rb, line 49 def show_clips clip_filename = @diakonos_home + "/clips.txt" File.open( clip_filename, "w" ) do |f| case @settings[ 'clipboard.external' ] when 'klipper' f.puts 'Access Klipper directly (tray icon) to get at all clips.' when 'xclip' f.puts 'xclip does not keep a history of clips.' when 'osx' f.puts 'The OSX clipboard does not keep a history of clips.' else @clipboard.each do |clip| f.puts clip f.puts "---------------------------" end end end open_file clip_filename end
# File lib/diakonos/functions/search.rb, line 164 def show_number_of_matches_found( num_replacements = nil ) return if buffer_current.num_matches_found.nil? num_found = buffer_current.num_matches_found if num_found != 1 plural = 'es' end if num_replacements set_iline_if_empty "#{num_replacements} out of #{num_found} match#{plural} replaced" else set_iline_if_empty "#{num_found} match#{plural} found" end end
Executes a command in a shell, captures the results, and pastes them in the current buffer at the current cursor location. Substitutes Diakonos
shell variables. The shell is executed in a separate thread, so interaction with Diakonos
is possible during execution.
@param [String] command_
The shell command to execute
@see sub_shell_variables
@see execute
@see shell
@see paste_shell_result
# File lib/diakonos/functions/shell.rb, line 233 def spawn( command_ = nil ) command = command_ || get_user_input( "Command: ", history: @rlh_shell ) return if command.nil? command = sub_shell_variables( command ) Thread.new do if system( command ) set_iline "Return code #{$?} from '#{command}'" else set_iline "Error code #{$?} executing '#{command}'" end end end
Substitutes Diakonos
shell variables in a String
.
-
$f: The current buffer’s filename
-
$d: The current buffer’s directory
-
$F: A space-separated list of all buffer filenames
-
$i: A string acquired from the user with a prompt
-
$c: The current clipboard text
-
$s: The currently selected text
@param [String] string
The string containing variables to substitute
@return [String]
A new String with values substituted for all variables
# File lib/diakonos/functions/shell.rb, line 24 def sub_shell_variables( string ) return if string.nil? retval = string.dup # Current buffer filename retval.gsub!( /\$f/, ( $1 || "" ) + File.expand_path( buffer_current.name || "" ) ) # Current buffer dir retval.gsub!( /\$d/, ( $1 || "" ) + File.dirname( File.expand_path( buffer_current.name || '' ) ) ) # space-separated list of all buffer filenames name_array = Array.new @buffers.each do |b| name_array.push b.name end retval.gsub!( /\$F/, ( $1 || "" ) + ( name_array.join(' ') || "" ) ) # Get user input, sub it in if retval =~ /\$i/ user_input = get_user_input( "Argument: ", history: @rlh_shell, initial_text: buffer_current.selected_string ) retval.gsub!( /\$i/, user_input ) end # Current clipboard text if retval =~ /\$[ck]/ clip_filename = @diakonos_home + "/clip.txt" File.open( clip_filename, "w" ) do |clipfile| if @clipboard.clip clipfile.puts( @clipboard.clip.join( "\n" ) ) end end retval.gsub!( /\$[ck]/, clip_filename ) end # Currently selected text if retval =~ /\$s/ text_filename = @diakonos_home + "/selected.txt" File.open( text_filename, "w" ) do |textfile| selected_text = buffer_current.selected_text if selected_text textfile.puts( selected_text.join( "\n" ) ) end end retval.gsub!( /\$s/, text_filename ) end retval end
# File lib/diakonos/functions/text-manipulation.rb, line 153 def surround_line( envelope = nil ) buffer_current.set_selection_current_line surround_selection envelope end
# File lib/diakonos/functions/text-manipulation.rb, line 158 def surround_paragraph( envelope = nil ) ( first, _ ), ( last, length ) = buffer_current.paragraph_under_cursor_pos buffer_current.set_selection( first, 0, last, length+1 ) surround_selection envelope end
# File lib/diakonos/functions/text-manipulation.rb, line 164 def surround_selection( parenthesis = nil ) if ! buffer_current.selecting? set_iline "Nothing selected." return end parenthesis ||= get_user_input( "Surround with: " ) if parenthesis text = buffer_current.surround( buffer_current.selected_text, parenthesis ) if text buffer_current.paste text end end end
# File lib/diakonos/functions/text-manipulation.rb, line 179 def surround_word( envelope = nil ) ( start_row, start_col ), ( end_row, end_col ) = buffer_current.word_under_cursor_pos if start_row && start_col && end_row && end_col buffer_current.set_selection( start_row, start_col, end_row, end_col ) surround_selection envelope end end
Send the Diakonos
job to background, as if with Ctrl-Z
# File lib/diakonos/functions.rb, line 250 def suspend Curses::close_screen Process.kill( "SIGSTOP", $PID ) Curses::init_screen refresh_all end
# File lib/diakonos/functions/buffers.rb, line 470 def switch_to_buffer_number( buffer_number_ ) buffer_number = buffer_number_.to_i return if buffer_number < 1 if @buffer_number_last && buffer_number == buffer_to_number(buffer_current) buffer_number = @buffer_number_last end @buffer_number_last = buffer_to_number(buffer_current) switch_to @buffers[ buffer_number - 1 ] end
# File lib/diakonos/functions/buffers.rb, line 480 def switch_to_next_buffer switch_to_buffer_number( buffer_to_number( buffer_current ) + 1 ) end
# File lib/diakonos/functions/buffers.rb, line 484 def switch_to_previous_buffer switch_to_buffer_number( buffer_to_number( buffer_current ) - 1 ) end
# File lib/diakonos/functions/bookmarking.rb, line 56 def toggle_bookmark buffer_current.toggle_bookmark end
Starts or stops macro recording.
# File lib/diakonos/functions.rb, line 258 def toggle_macro_recording( name = nil ) if @macro_history stop_recording_macro else start_recording_macro name end end
If currently selecting, stops selecting. If not currently selecting, begins selecting.
# File lib/diakonos/functions/selection.rb, line 69 def toggle_selection buffer_current.toggle_selection update_status_line end
# File lib/diakonos/functions/sessions.rb, line 59 def toggle_session_setting( key_ = nil, do_redraw = DONT_REDRAW ) key = key_ || get_user_input( "Setting: " ) return if key.nil? value = nil if @session.settings[ key ].class == TrueClass || @session.settings[ key ].class == FalseClass value = ! @session.settings[ key ] elsif @settings[ key ].class == TrueClass || @settings[ key ].class == FalseClass value = ! @settings[ key ] end if value != nil # explicitly true or false @session.settings[ key ] = value merge_session_settings redraw if do_redraw set_iline "#{key} = #{value}" end end
# File lib/diakonos/functions/text-manipulation.rb, line 187 def uncomment buffer_current.uncomment end
Undoes the latest change made to the current buffer, or reopens the file that was just closed.
# File lib/diakonos/functions.rb, line 268 def undo( buffer = buffer_current ) if @functions_last[-1] == 'close_buffer' open_file( @buffer_closed.name, 'cursor' => { 'row' => @buffer_closed.last_row, 'col' => @buffer_closed.last_col, }, 'display' => { 'top_line' => @buffer_closed.top_line, 'left_col' => @buffer_closed.left_column, } ) else buffer.undo end end
# File lib/diakonos/functions/indentation.rb, line 51 def unindent if( buffer_current.changing_selection ) @do_display = false mark = buffer_current.selection_mark if mark.end_col > 0 end_row = mark.end_row else end_row = mark.end_row - 1 end (mark.start_row..end_row).each do |row| buffer_current.unindent row, Buffer::DONT_DISPLAY end @do_display = true display_buffer buffer_current else buffer_current.unindent end end
Redoes the latest change undone on the current buffer.
# File lib/diakonos/functions.rb, line 287 def unundo( buffer = buffer_current ) buffer.unundo end
# File lib/diakonos/functions/text-manipulation.rb, line 191 def wrap_paragraph buffer_current.wrap_paragraph end