Object
# File reline/line_editor.rb, line 639 def add_dialog_proc(name, p, context = nil) dialog = Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context)) if index = @dialogs.find_index { |d| d.name == name } @dialogs[index] = dialog else @dialogs << dialog end end
# File reline/line_editor.rb, line 1893 def byte_pointer=(val) @byte_pointer = val str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) end
# File reline/line_editor.rb, line 1657 def call_completion_proc result = retrieve_completion_block(true) pre, target, post = result result = call_completion_proc_with_checking_args(pre, target, post) Reline.core.instance_variable_set(:@completion_quote_character, nil) result end
# File reline/line_editor.rb, line 1665 def call_completion_proc_with_checking_args(pre, target, post) if @completion_proc and target argnum = @completion_proc.parameters.inject(0) { |result, item| case item.first when :req, :opt result + 1 when :rest break 3 end } case argnum when 1 result = @completion_proc.(target) when 2 result = @completion_proc.(target, pre) when 3..Float::INFINITY result = @completion_proc.(target, pre, post) end end result end
# File reline/line_editor.rb, line 1811 def confirm_multiline_termination temp_buffer = @buffer_of_lines.dup if @previous_line_index and @line_index == (@buffer_of_lines.size - 1) temp_buffer[@previous_line_index] = @line else temp_buffer[@line_index] = @line end @confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n") end
# File reline/line_editor.rb, line 1833 def delete_text(start = nil, length = nil) if start.nil? and length.nil? if @is_multiline if @buffer_of_lines.size == 1 @line&.clear @byte_pointer = 0 @cursor = 0 @cursor_max = 0 elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0 @buffer_of_lines.pop @line_index -= 1 @line = @buffer_of_lines[@line_index] @byte_pointer = 0 @cursor = 0 @cursor_max = calculate_width(@line) elsif @line_index < (@buffer_of_lines.size - 1) @buffer_of_lines.delete_at(@line_index) @line = @buffer_of_lines[@line_index] @byte_pointer = 0 @cursor = 0 @cursor_max = calculate_width(@line) end else @line&.clear @byte_pointer = 0 @cursor = 0 @cursor_max = 0 end elsif not start.nil? and not length.nil? if @line before = @line.byteslice(0, start) after = @line.byteslice(start + length, @line.bytesize) @line = before + after @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) end elsif start.is_a?(Range) range = start first = range.first last = range.last last = @line.bytesize - 1 if last > @line.bytesize last += @line.bytesize if last < 0 first += @line.bytesize if first < 0 range = range.exclude_end? ? first...last : first..last @line = @line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding) @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) else @line = @line.byteslice(0, start) @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) end end
# File reline/line_editor.rb, line 1275 def editing_mode @config.editing_mode end
# File reline/line_editor.rb, line 250 def finalize Signal.trap('INT', @old_trap) begin Signal.trap('TSTP', @old_tstp_trap) rescue ArgumentError end end
# File reline/line_editor.rb, line 1922 def finish @finished = true @rerender_all = true @config.reset end
# File reline/line_editor.rb, line 1918 def finished? @finished end
# File reline/line_editor.rb, line 1582 def input_key(key) @last_key = key @config.reset_oneshot_key_bindings @dialogs.each do |dialog| if key.char.instance_of?(Symbol) and key.char == dialog.name return end end @just_cursor_moving = nil if key.char.nil? if @first_char @line = nil end finish return end old_line = @line.dup @first_char = false completion_occurs = false if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord unless @config.disable_completion result = call_completion_proc if result.is_a?(Array) completion_occurs = true process_insert if @config.autocompletion move_completed_list(result, :down) else complete(result) end end end elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up if not @config.disable_completion and @config.autocompletion result = call_completion_proc if result.is_a?(Array) completion_occurs = true process_insert move_completed_list(result, :up) end end elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char) unless @config.disable_completion result = call_completion_proc if result.is_a?(Array) completion_occurs = true process_insert move_completed_list(result, "\C-p".ord == key.char ? :up : :down) end end elsif Symbol === key.char and respond_to?(key.char, true) process_key(key.char, key.char) else normal_char(key) end unless completion_occurs @completion_state = CompletionState::NORMAL @completion_journey_data = nil end if not @in_pasting and @just_cursor_moving.nil? if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line @just_cursor_moving = true elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line @just_cursor_moving = true else @just_cursor_moving = false end else @just_cursor_moving = false end if @is_multiline and @auto_indent_proc and not simplified_rendering? process_auto_indent end end
# File reline/line_editor.rb, line 1821 def insert_text(text) width = calculate_width(text) if @cursor == @cursor_max @line += text else @line = byteinsert(@line, @byte_pointer, text) end @byte_pointer += text.bytesize @cursor += width @cursor_max += width end
# File reline/line_editor.rb, line 973 def just_move_cursor prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines) move_cursor_up(@started_from) new_first_line_started_from = if @line_index.zero? 0 else calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt) end first_line_diff = new_first_line_started_from - @first_line_started_from new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false) new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1 calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from) @previous_line_index = nil if @rerender_all @line = @buffer_of_lines[@line_index] rerender_all_lines @rerender_all = false true else @line = @buffer_of_lines[@line_index] @first_line_started_from = new_first_line_started_from @started_from = new_started_from @cursor = new_cursor @cursor_max = new_cursor_max @byte_pointer = new_byte_pointer move_cursor_down(first_line_diff + @started_from) Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) false end end
# File reline/line_editor.rb, line 323 def multiline_off @is_multiline = false end
# File reline/line_editor.rb, line 319 def multiline_on @is_multiline = true end
# File reline/line_editor.rb, line 431 def rerender return if @line.nil? if @menu_info scroll_down(@highest_in_all - @first_line_started_from) @rerender_all = true end if @menu_info show_menu @menu_info = nil end prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines) if @cleared clear_screen_buffer(prompt, prompt_list, prompt_width) @cleared = false return end if @is_multiline and finished? and @scroll_partial_screen # Re-output all code higher than the screen when finished. Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen) Reline::IOGate.move_cursor_column(0) @scroll_partial_screen = nil prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines) if @previous_line_index new_lines = whole_lines(index: @previous_line_index, line: @line) else new_lines = whole_lines end modify_lines(new_lines).each_with_index do |line, index| @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n" Reline::IOGate.erase_after_cursor end @output.flush clear_dialog return end new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line)) rendered = false if @add_newline_to_end_of_buffer rerender_added_newline(prompt, prompt_width) @add_newline_to_end_of_buffer = false else if @just_cursor_moving and not @rerender_all rendered = just_move_cursor render_dialog((prompt_width + @cursor) % @screen_size.last) @just_cursor_moving = false return elsif @previous_line_index or new_highest_in_this != @highest_in_this rerender_changed_current_line @previous_line_index = nil rendered = true elsif @rerender_all rerender_all_lines @rerender_all = false rendered = true else end end if @is_multiline if finished? # Always rerender on finish because output_modifier_proc may return a different output. if @previous_line_index new_lines = whole_lines(index: @previous_line_index, line: @line) else new_lines = whole_lines end line = modify_lines(new_lines)[@line_index] clear_dialog prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines) render_partial(prompt, prompt_width, line, @first_line_started_from) move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1) scroll_down(1) Reline::IOGate.move_cursor_column(0) Reline::IOGate.erase_after_cursor else if not rendered and not @in_pasting line = modify_lines(whole_lines)[@line_index] prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines) render_partial(prompt, prompt_width, line, @first_line_started_from) end render_dialog((prompt_width + @cursor) % @screen_size.last) end @buffer_of_lines[@line_index] = @line @rest_height = 0 if @scroll_partial_screen else line = modify_lines(whole_lines)[@line_index] render_partial(prompt, prompt_width, line, 0) if finished? scroll_down(1) Reline::IOGate.move_cursor_column(0) Reline::IOGate.erase_after_cursor end end end
# File reline/line_editor.rb, line 425 def rerender_all @rerender_all = true process_insert(force: true) rerender end
# File reline/line_editor.rb, line 149 def reset(prompt = '', encoding:) @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y @screen_size = Reline::IOGate.get_screen_size @screen_height = @screen_size.first reset_variables(prompt, encoding: encoding) Reline::IOGate.set_winch_handler do @resized = true end if ENV.key?('RELINE_ALT_SCROLLBAR') @full_block = '::' @upper_half_block = "''" @lower_half_block = '..' @block_elem_width = 2 elsif Reline::IOGate.win? @full_block = '█' @upper_half_block = '▀' @lower_half_block = '▄' @block_elem_width = 1 elsif @encoding == Encoding::UTF_8 @full_block = '█' @upper_half_block = '▀' @lower_half_block = '▄' @block_elem_width = Reline::Unicode.calculate_width('█') else @full_block = '::' @upper_half_block = "''" @lower_half_block = '..' @block_elem_width = 2 end end
# File reline/line_editor.rb, line 301 def reset_line @cursor = 0 @cursor_max = 0 @byte_pointer = 0 @buffer_of_lines = [String.new(encoding: @encoding)] @line_index = 0 @previous_line_index = nil @line = @buffer_of_lines[0] @first_line_started_from = 0 @move_up = 0 @started_from = 0 @highest_in_this = 1 @highest_in_all = 1 @line_backup_in_history = nil @multibyte_buffer = String.new(encoding: 'ASCII-8BIT') @check_new_auto_indent = false end
# File reline/line_editor.rb, line 262 def reset_variables(prompt = '', encoding:) @prompt = prompt.gsub("\n", "\\n") @mark_pointer = nil @encoding = encoding @is_multiline = false @finished = false @cleared = false @rerender_all = false @history_pointer = nil @kill_ring ||= Reline::KillRing.new @vi_clipboard = '' @vi_arg = nil @waiting_proc = nil @waiting_operator_proc = nil @waiting_operator_vi_arg = nil @completion_journey_data = nil @completion_state = CompletionState::NORMAL @perfect_matched = nil @menu_info = nil @first_prompt = true @searching_prompt = nil @first_char = true @add_newline_to_end_of_buffer = false @just_cursor_moving = nil @cached_prompt_list = nil @prompt_cache_time = nil @eof = false @continuous_insertion_buffer = String.new(encoding: @encoding) @scroll_partial_screen = nil @prev_mode_string = nil @drop_terminate_spaces = false @in_pasting = false @auto_indent_proc = nil @dialogs = [] @last_key = nil @resized = false reset_line end
# File reline/line_editor.rb, line 180 def resize return unless @resized @resized = false @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y old_screen_size = @screen_size @screen_size = Reline::IOGate.get_screen_size @screen_height = @screen_size.first if old_screen_size.last < @screen_size.last # columns increase @rerender_all = true rerender else back = 0 new_buffer = whole_lines prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer) new_buffer.each_with_index do |line, index| prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc width = prompt_width + calculate_width(line) height = calculate_height_by_width(width) back += height end @highest_in_all = back @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @first_line_started_from = if @line_index.zero? 0 else calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt) end if @prompt_proc prompt = prompt_list[@line_index] prompt_width = calculate_width(prompt, true) end calculate_nearest_cursor @started_from = calculate_height_by_width(prompt_width + @cursor) - 1 Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @rerender_all = true end end
# File reline/line_editor.rb, line 1729 def retrieve_completion_block(set_completion_quote_character = false) if Reline.completer_word_break_characters.empty? word_break_regexp = nil else word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/ end if Reline.completer_quote_characters.empty? quote_characters_regexp = nil else quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/ end before = @line.byteslice(0, @byte_pointer) rest = nil break_pointer = nil quote = nil closing_quote = nil escaped_quote = nil i = 0 while i < @byte_pointer do slice = @line.byteslice(i, @byte_pointer - i) unless slice.valid_encoding? i += 1 next end if quote and slice.start_with?(closing_quote) quote = nil i += 1 rest = nil elsif quote and slice.start_with?(escaped_quote) # skip i += 2 elsif quote_characters_regexp and slice =~ quote_characters_regexp # find new " rest = $' quote = $& closing_quote = /(?!\\)#{Regexp.escape(quote)}/ escaped_quote = /\\#{Regexp.escape(quote)}/ i += 1 break_pointer = i - 1 elsif word_break_regexp and not quote and slice =~ word_break_regexp rest = $' i += 1 before = @line.byteslice(i, @byte_pointer - i) break_pointer = i else i += 1 end end postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer) if rest preposing = @line.byteslice(0, break_pointer) target = rest if set_completion_quote_character and quote Reline.core.instance_variable_set(:@completion_quote_character, quote) if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote insert_text(quote) end end else preposing = '' if break_pointer preposing = @line.byteslice(0, break_pointer) else preposing = '' end target = before end if @is_multiline if @previous_line_index lines = whole_lines(index: @previous_line_index, line: @line) else lines = whole_lines end if @line_index > 0 preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing end if (lines.size - 1) > @line_index postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n") end end [preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)] end
# File reline/line_editor.rb, line 62 def set_pasting_state(in_pasting) @in_pasting = in_pasting end
# File reline/line_editor.rb, line 220 def set_signal_handlers @old_trap = Signal.trap('INT') { clear_dialog if @scroll_partial_screen move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1) else move_cursor_down(@highest_in_all - @line_index - 1) end Reline::IOGate.move_cursor_column(0) scroll_down(1) case @old_trap when 'DEFAULT', 'SYSTEM_DEFAULT' raise Interrupt when 'IGNORE' # Do nothing when 'EXIT' exit else @old_trap.call if @old_trap.respond_to?(:call) end } begin @old_tstp_trap = Signal.trap('TSTP') { Reline::IOGate.ungetc("\C-z".ord) @old_tstp_trap.call if @old_tstp_trap.respond_to?(:call) } rescue ArgumentError end end
# File reline/line_editor.rb, line 66 def simplified_rendering? if finished? false elsif @just_cursor_moving and not @rerender_all true else not @rerender_all and not finished? and @in_pasting end end
# File reline/line_editor.rb, line 1906 def whole_buffer if @buffer_of_lines.size == 1 and @line.nil? nil else if @previous_line_index whole_lines(index: @previous_line_index, line: @line).join("\n") else whole_lines.join("\n") end end end
# File reline/line_editor.rb, line 1900 def whole_lines(index: @line_index, line: @line) temp_lines = @buffer_of_lines.dup temp_lines[index] = line temp_lines end
# File reline/line_editor.rb, line 1467 def wrap_method_call(method_symbol, method_obj, key, with_operator = false) if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil? not_insertion = method_symbol != :ed_insert process_insert(force: not_insertion) end if @vi_arg and argumentable?(method_obj) if with_operator and inclusive?(method_obj) method_obj.(key, arg: @vi_arg, inclusive: true) else method_obj.(key, arg: @vi_arg) end else if with_operator and inclusive?(method_obj) method_obj.(key, inclusive: true) else method_obj.(key) end end end