diff --git a/lib/reline.rb b/lib/reline.rb index 66375faabd..bf8f9c3f58 100644 --- a/lib/reline.rb +++ b/lib/reline.rb @@ -84,8 +84,29 @@ module Reline @@dig_perfect_match_proc = p end + def self.insert_text(text) + @@line_editor&.insert_text(text) + self + end + + def self.redisplay + @@line_editor&.rerender + end + + def self.line_buffer + @@line_editor&.line + end + + def self.point + @@line_editor ? @@line_editor.byte_pointer : 0 + end + + def self.point=(val) + @@line_editor.byte_pointer = val + end + def self.delete_text(start = nil, length = nil) - raise NotImplementedError + @@line_editor&.delete_text(start, length) end def self.input=(val) @@ -103,6 +124,28 @@ module Reline @@output = val end + def self.vi_editing_mode + @@config.editing_mode = :vi_insert + nil + end + + def self.emacs_editing_mode + @@config.editing_mode = :emacs + nil + end + + def self.vi_editing_mode? + @@config.editing_mode_is?(:vi_insert, :vi_command) + end + + def self.emacs_editing_mode? + @@config.editing_mode_is?(:emacs) + end + + def self.get_screen_size + Reline::IO.get_screen_size + end + def retrieve_completion_block(line, byte_pointer) break_regexp = /[#{Regexp.escape(@@basic_word_break_characters)}]/ before_pointer = line.byteslice(0, byte_pointer) @@ -131,6 +174,7 @@ module Reline Reline::HISTORY << whole_buffer end + @@line_editor.reset_line if @@line_editor.whole_buffer.nil? whole_buffer end @@ -143,6 +187,7 @@ module Reline Reline::HISTORY << line.chomp end + @@line_editor.reset_line if @@line_editor.line.nil? line end @@ -189,7 +234,8 @@ module Reline key_stroke = Reline::KeyStroke.new(config) begin - while c = Reline::IO.getc + loop do + c = Reline::IO.getc key_stroke.input_to!(c)&.then { |inputs| inputs.each { |c| @@line_editor.input_key(c) diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb index ac0a820759..fdfe74a6ee 100644 --- a/lib/reline/key_stroke.rb +++ b/lib/reline/key_stroke.rb @@ -28,6 +28,9 @@ class Reline::KeyStroke end def input_to!(bytes) + if bytes.nil? + return @buffer.push(nil)&.tap { clear } + end @buffer.concat Array(bytes) input_to(@buffer)&.tap { clear } end diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index 21616ddd96..1b60b67923 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -7,6 +7,7 @@ require 'pathname' class Reline::LineEditor # TODO: undo attr_reader :line + attr_reader :byte_pointer attr_accessor :confirm_multiline_termination_proc attr_accessor :completion_proc attr_accessor :pre_input_hook @@ -106,6 +107,10 @@ class Reline::LineEditor @first_prompt = true @searching_prompt = nil @first_char = true + reset_line + end + + def reset_line @cursor = 0 @cursor_max = 0 @byte_pointer = 0 @@ -636,6 +641,63 @@ class Reline::LineEditor end end + 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 + + def delete_text(start = nil, length = nil) + if start.nil? and length.nil? + @line&.clear + @byte_pointer = 0 + @cursor = 0 + @cursor_max = 0 + 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 + + def byte_pointer=(val) + @byte_pointer = val + str = @line.byteslice(0, @byte_pointer) + @cursor = calculate_width(str) + @cursor_max = calculate_width(@line) + end + def whole_buffer temp_lines = @buffer_of_lines.dup temp_lines[@line_index] = @line