Class: RawLine::Editor

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
HighLine::SystemExtensions
Defined in:
lib/rawline/editor.rb,
lib/rawline/editor.rb

Overview

The Editor class defines methods to:

  • Read characters from STDIN or any type of input

  • Write characters to STDOUT or any type of output

  • Bind keys to specific actions

  • Perform line-related operations like moving, navigating through history, etc.

Note that the following default key bindings are provided:

  • TAB: word completion defined via completion_proc

  • LEFT/RIGHT ARROWS: cursor movement (left/right)

  • UP/DOWN ARROWS: history navigation

  • DEL: Delete character under cursor

  • BACKSPACE: Delete character before cursor

  • INSERT: Toggle insert/replace mode (default: insert)

  • CTRL+K: Clear the whole line

  • CTRL+Z: undo (unless already registered by the OS)

  • CTRL+Y: redo (unless already registered by the OS)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dom:, input:, renderer:, terminal:) {|_self| ... } ⇒ Editor

Create an instance of RawLine::Editor which can be used to read from input and perform line-editing operations. This method takes an optional block used to override the following instance attributes:

  • @history_size - the size of the editor history buffer (30).

  • @line_history_size - the size of the editor line history buffer (50).

  • @keys - the keys (arrays of character codes) bound to specific actions.

  • @word_break_characters - a regex used for word separation, default inclues: “ tn"\‘`@$><=;|&{(”

  • @mode - The editor’s character insertion mode (:insert).

  • @completion_proc - a Proc object used to perform word completion.

  • @completion_append_string - a string to append to completed words (”).

  • @terminal - a RawLine::Terminal containing character key codes.

Yields:

  • (_self)

Yield Parameters:



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/rawline/editor.rb', line 102

def initialize(dom:, input:, renderer:, terminal:)
  @dom = dom
  @input = input
  @renderer = renderer
  @terminal = terminal

  @history_size = 30
  @line_history_size = 50
  @keys = {}
  @word_break_characters = " \t\n\"'@\$><=;|&{("
  @mode = :insert
  @completion_class = Completer
  @completion_proc = filename_completion_proc
  @completion_append_string = ''
  @match_hidden_files = false
  set_default_keys
  @add_history = false
  @highlight_history_matching_text = true
  @history = HistoryBuffer.new(@history_size) do |h|
    h.duplicates = false;
    h.exclude = lambda { |item| item.strip == "" }
  end
  @keyboard_input_processors = [self]
  # @allow_prompt_updates = true
  yield self if block_given?
  update_word_separator
  @char = nil

  initialize_events
  initialize_line
end

Instance Attribute Details

#charObject

Returns the value of attribute char.



44
45
46
# File 'lib/rawline/editor.rb', line 44

def char
  @char
end

#completion_append_stringObject

Returns the value of attribute completion_append_string.



46
47
48
# File 'lib/rawline/editor.rb', line 46

def completion_append_string
  @completion_append_string
end

#completion_classObject

Returns the value of attribute completion_class.



46
47
48
# File 'lib/rawline/editor.rb', line 46

def completion_class
  @completion_class
end

#completion_procObject

Returns the value of attribute completion_proc.



46
47
48
# File 'lib/rawline/editor.rb', line 46

def completion_proc
  @completion_proc
end

#content_boxObject

TODO: dom traversal for lookup rather than assignment



52
53
54
# File 'lib/rawline/editor.rb', line 52

def content_box
  @content_box
end

#domObject

Returns the value of attribute dom.



49
50
51
# File 'lib/rawline/editor.rb', line 49

def dom
  @dom
end

#event_loopObject (readonly)

Returns the value of attribute event_loop.



134
135
136
# File 'lib/rawline/editor.rb', line 134

def event_loop
  @event_loop
end

#highlight_history_matching_textObject

Returns the value of attribute highlight_history_matching_text.



44
45
46
# File 'lib/rawline/editor.rb', line 44

def highlight_history_matching_text
  @highlight_history_matching_text
end

#historyObject

Returns the value of attribute history.



46
47
48
# File 'lib/rawline/editor.rb', line 46

def history
  @history
end

#history_sizeObject

Returns the value of attribute history_size.



44
45
46
# File 'lib/rawline/editor.rb', line 44

def history_size
  @history_size
end

#inputObject (readonly)

Returns the value of attribute input.



134
135
136
# File 'lib/rawline/editor.rb', line 134

def input
  @input
end

#input_boxObject

TODO: dom traversal for lookup rather than assignment



52
53
54
# File 'lib/rawline/editor.rb', line 52

def input_box
  @input_box
end

#keyboard_input_processorsObject (readonly)

Returns the value of attribute keyboard_input_processors.



135
136
137
# File 'lib/rawline/editor.rb', line 135

def keyboard_input_processors
  @keyboard_input_processors
end

#keysObject

Returns the value of attribute keys.



45
46
47
# File 'lib/rawline/editor.rb', line 45

def keys
  @keys
end

#lineObject

Returns the value of attribute line.



46
47
48
# File 'lib/rawline/editor.rb', line 46

def line
  @line
end

#line_history_sizeObject

Returns the value of attribute line_history_size.



44
45
46
# File 'lib/rawline/editor.rb', line 44

def line_history_size
  @line_history_size
end

#match_hidden_filesObject

Returns the value of attribute match_hidden_files.



47
48
49
# File 'lib/rawline/editor.rb', line 47

def match_hidden_files
  @match_hidden_files
end

#modeObject

Returns the value of attribute mode.



45
46
47
# File 'lib/rawline/editor.rb', line 45

def mode
  @mode
end

#prompt_boxObject

TODO: dom traversal for lookup rather than assignment



52
53
54
# File 'lib/rawline/editor.rb', line 52

def prompt_box
  @prompt_box
end

#terminalObject

Returns the value of attribute terminal.



45
46
47
# File 'lib/rawline/editor.rb', line 45

def terminal
  @terminal
end

#word_break_charactersObject

Returns the value of attribute word_break_characters.



48
49
50
# File 'lib/rawline/editor.rb', line 48

def word_break_characters
  @word_break_characters
end

Class Method Details

.create(dom: nil, &blk) ⇒ Object



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

def self.create(dom: nil, &blk)
  terminal = nil

  input = STDIN
  output = STDOUT

  case RUBY_PLATFORM
  when /mswin/i then
    terminal = WindowsTerminal.new(input, output)
    if RawLine.win32console? then
      win32_io = Win32::Console::ANSI::IO.new
    end
  else
    terminal = VT220Terminal.new(input, output)
  end

  dom ||= DomTree.new

  renderer = RawLine::Renderer.new(
    dom: dom,
    output: terminal.output,
    width: terminal.width,
    height: terminal.height
  )

  new(
    dom: dom,
    input: NonBlockingInput.new(input),
    renderer: renderer,
    terminal: terminal,
    &blk
  )
end

Instance Method Details

#add_to_historyObject

Add the current line (@line.text) to the editor history.



793
794
795
# File 'lib/rawline/editor.rb', line 793

def add_to_history
  @history << @line.text.dup if @add_history && @line.text != ""
end

#add_to_line_historyObject

Add the current line (@line.text) to the line history, to allow undo/redo operations.



786
787
788
# File 'lib/rawline/editor.rb', line 786

def add_to_line_history
  @line.history << @line.text.dup unless @line.text == ""
end

#bind(key, &block) ⇒ Object

Bind a key to an action specified via block. key can be:

  • A Symbol identifying a character or character sequence defined for the current terminal

  • A Fixnum identifying a character defined for the current terminal

  • An Array identifying a character or character sequence defined for the current terminal

  • A String identifying a character or character sequence, even if it is not defined for the current terminal

  • An Hash identifying a character or character sequence, even if it is not defined for the current terminal

If key is a hash, then:

  • It must contain only one key/value pair

  • The key identifies the name of the character or character sequence

  • The value identifies the code(s) corresponding to the character or character sequence

  • The value can be a Fixnum, a String or an Array.



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/rawline/editor.rb', line 280

def bind(key, &block)
  case key.class.to_s
  when 'Symbol' then
    raise BindingException, "Unknown key or key sequence '#{key.to_s}' (#{key.class.to_s})" unless @terminal.keys[key]
    @keys[@terminal.keys[key]] = block
  when 'Array' then
    raise BindingException, "Unknown key or key sequence '#{key.join(", ")}' (#{key.class.to_s})" unless @terminal.keys.has_value? key
    @keys[key] = block
  when 'Fixnum' then
    raise BindingException, "Unknown key or key sequence '#{key.to_s}' (#{key.class.to_s})" unless @terminal.keys.has_value? [key]
    @keys[[key]] = block
  when 'String' then
    if key.length == 1 then
      @keys[[key.ord]] = block
    else
      bind_hash({:"#{key}" => key}, block)
    end
  when 'Hash' then
    raise BindingException, "Cannot bind more than one key or key sequence at once" unless key.values.length == 1
    bind_hash(key, block)
  else
    raise BindingException, "Unable to bind '#{key.to_s}' (#{key.class.to_s})"
  end
  @terminal.update
end

#check_for_keyboard_inputObject

INPUT



206
207
208
209
210
211
212
# File 'lib/rawline/editor.rb', line 206

def check_for_keyboard_input
  bytes = @input.read
  if bytes.any?
    @keyboard_input_processors.last.read_bytes(bytes)
  end
  @event_loop.add_event name: 'check_for_keyboard_input', source: self
end

#clear_historyObject

Clear the editor history.



739
740
741
# File 'lib/rawline/editor.rb', line 739

def clear_history
  @history.empty
end

#clear_lineObject

Clear the current line, i.e. @line.text and @line.position. This action is bound to ctrl+k by default.



385
386
387
388
389
390
391
# File 'lib/rawline/editor.rb', line 385

def clear_line
  add_to_line_history
  @line.text = ""
  @line.position = 0
  @dom.input_box.position = @line.position
  @history.clear_position
end

#clear_screenObject



393
394
395
396
# File 'lib/rawline/editor.rb', line 393

def clear_screen
  @terminal.clear_screen
  render(reset: true)
end

#completeObject

Complete the current word according to what returned by @completion_proc. Characters can be appended to the completed word via @completion_append_character and word separators can be defined via @word_separator.

This action is bound to the tab key by default, so the first match is displayed the first time the user presses tab, and all the possible messages will be displayed (cyclically) when tab is pressed again.



636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
# File 'lib/rawline/editor.rb', line 636

def complete
  @dom.input_box.cursor_off
  completer = @completion_class.new(
    char: @char,
    line: @line,
    completion: @completion_proc,
    completion_found: -> (completion:, possible_completions:) {
      completion_found(completion: completion, possible_completions: possible_completions)
    },
    completion_not_found: -> {
      completion_not_found
    },
    done: -> (*leftover_bytes){
      completion_done
      leftover_bytes = leftover_bytes.flatten
      @keyboard_input_processors.pop
      if leftover_bytes.any?
        @keyboard_input_processors.last.read_bytes(leftover_bytes)
      end
      @dom.input_box.cursor_on
    },
    keys: terminal.keys
  )
  @keyboard_input_processors.push(completer)
  completer.read_bytes(@char)
end

#completion_doneObject



683
684
685
686
687
# File 'lib/rawline/editor.rb', line 683

def completion_done
  if @on_word_complete_done
    @on_word_complete_done.call
  end
end

#completion_found(completion:, possible_completions:) ⇒ Object



663
664
665
666
667
668
669
670
671
672
673
# File 'lib/rawline/editor.rb', line 663

def completion_found(completion:, possible_completions:)
  if @on_word_complete
    word = @line.word[:text]
    sub_word = @line.text[@line.word[:start]..@line.position-1] || ""
    @on_word_complete.call(name: "word-completion", payload: { sub_word: sub_word, word: word, completion: completion, possible_completions: possible_completions })
  end

  move_to_position @line.word[:end]
  delete_n_characters(@line.word[:end] - @line.word[:start], true)
  write completion.to_s + @completion_append_string.to_s
end

#completion_not_foundObject



675
676
677
678
679
680
681
# File 'lib/rawline/editor.rb', line 675

def completion_not_found
  if @on_word_complete_no_match
    word = @line.word[:text]
    sub_word = @line.text[@line.word[:start]..@line.position-1] || ""
    @on_word_complete_no_match.call(name: "word-completion-no-match", payload: { sub_word: sub_word, word: word })
  end
end

#debug_lineObject

Print debug information about the current line. Note that after the message is displayed, the line text and position will be restored.



807
808
809
810
811
812
813
814
815
816
817
818
819
# File 'lib/rawline/editor.rb', line 807

def debug_line
  pos = @line.position
  text = @line.text
  word = @line.word
  # terminal.puts
  # terminal.puts "Text: [#{text}]"
  # terminal.puts "Length: #{@line.length}"
  # terminal.puts "Position: #{pos}"
  # terminal.puts "Character at Position: [#{text[pos].chr}] (#{text[pos]})" unless pos >= @line.length
  # terminal.puts "Current Word: [#{word[:text]}] (#{word[:start]} -- #{word[:end]})"
  clear_line
  overwrite_line(text, pos)
end

#default_actionObject

Execute the default action for the last character read via read. By default it prints the character to the screen via print_character. This method is called automatically by process_character.



349
350
351
352
# File 'lib/rawline/editor.rb', line 349

def default_action
  @dom.input_box.content += @char.chr
  print_character
end

#delete_character(no_line_history = false) ⇒ Object

Delete the character under the cursor. If no_line_hisytory is set to true, the deletion won’t be recorded in the line history. This action is bound to the delete key by default.



428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/rawline/editor.rb', line 428

def delete_character(no_line_history=false)
  unless @line.position > @line.eol
    # save characters to shift
    chars = (@line.eol?) ? ' ' : select_characters_from_cursor(1)
    #remove character from line
    @line[@line.position] = ''
    @dom.input_box.content = @line.text
    @dom.input_box.position = @line.position
    add_to_line_history unless no_line_history
    @history.clear_position
  end
end

#delete_left_character(no_line_history = false) ⇒ Object

Delete the character at the left of the cursor. If no_line_hisytory is set to true, the deletion won’t be recorded in the line history. This action is bound to the backspace key by default.



404
405
406
407
408
# File 'lib/rawline/editor.rb', line 404

def delete_left_character(no_line_history=false)
  if move_left then
    delete_character(no_line_history)
  end
end

#delete_n_characters(number_of_characters_to_delete, no_line_history = false) ⇒ Object



410
411
412
413
414
415
416
417
418
419
420
# File 'lib/rawline/editor.rb', line 410

def delete_n_characters(number_of_characters_to_delete, no_line_history=false)
  number_of_characters_to_delete.times do |n|
    @line[@line.position] = ''
    @line.left
  end

  @dom.input_box.position = @line.position
  @dom.input_box.content = @line.text
  add_to_line_history unless no_line_history
  @history.clear_position
end

#escape(string) ⇒ Object



979
980
981
# File 'lib/rawline/editor.rb', line 979

def escape(string)
  string.each_byte { |c| @win32_io.putc c }
end

#eventsObject

Returns the Editor’s event loop.



196
197
198
# File 'lib/rawline/editor.rb', line 196

def events
  @event_loop
end

#filename_completion_procObject

Complete file and directory names. Hidden files and directories are matched only if @match_hidden_files is true.



705
706
707
708
709
710
711
712
713
714
715
716
717
# File 'lib/rawline/editor.rb', line 705

def filename_completion_proc
  lambda do |word, _|
    dirs = @line.text.split('/')
      path = @line.text.match(/^\/|[a-zA-Z]:\//) ? "/" : Dir.pwd+"/"
    if dirs.length == 0 then # starting directory
      dir = path
    else
      dirs.delete(dirs.last) unless File.directory?(path+dirs.join('/'))
      dir = path+dirs.join('/')
    end
    Dir.entries(dir).select { |e| (e =~ /^\./ && @match_hidden_files && word == '') || (e =~ /^#{word}/ && e !~ /^\./) }
  end
end

#highlight_text_up_to(text, position) ⇒ Object



441
442
443
# File 'lib/rawline/editor.rb', line 441

def highlight_text_up_to(text, position)
  ANSIString.new("\e[1m#{text[0...position]}\e[0m#{text[position..-1]}")
end

#history_backObject

Load the previous entry of the editor in place of the current line (@line.text). This action is bound to the up arrow key by default.



766
767
768
769
# File 'lib/rawline/editor.rb', line 766

def history_back
  generic_history_back(@history)
  add_to_line_history
end

#history_forwardObject

Load the next entry of the editor history in place of the current line (@line.text). This action is bound to down arrow key by default.



776
777
778
779
# File 'lib/rawline/editor.rb', line 776

def history_forward
  generic_history_forward(@history)
  add_to_line_history
end

#key_bound?Boolean

Return true if the last character read via read is bound to an action.

Returns:

  • (Boolean)


332
333
334
# File 'lib/rawline/editor.rb', line 332

def key_bound?
  @keys[@char] ? true : false
end

#kill_forwardObject



445
446
447
448
449
450
451
452
# File 'lib/rawline/editor.rb', line 445

def kill_forward
  killed_text = @line.text[@line.position..-1]
  @line.text[@line.position..-1] = ANSIString.new("")
  @dom.input_box.content = line.text
  @dom.input_box.position = @line.position
  @history.clear_position
  killed_text
end

#library_versionObject

Return the current RawLine version



140
141
142
# File 'lib/rawline/editor.rb', line 140

def library_version
  "RawLine v#{RawLine.rawline_version}"
end

#move_leftObject

Move the cursor left (if possible) by printing a backspace, updating @line.position accordingly. This action is bound to the left arrow key by default.



467
468
469
470
471
472
473
474
# File 'lib/rawline/editor.rb', line 467

def move_left
  unless @line.bol? then
    @line.left
    @dom.input_box.position = @line.position
    return true
  end
  false
end

#move_rightObject

Move the cursor right (if possible) by re-printing the character at the right of the cursor, if any, and updating @line.position accordingly. This action is bound to the right arrow key by default.



482
483
484
485
486
487
488
489
# File 'lib/rawline/editor.rb', line 482

def move_right
  unless @line.position > @line.eol then
    @line.right
    @dom.input_box.position = @line.position
    return true
  end
  false
end

#move_to_beginning_of_inputObject



491
492
493
494
# File 'lib/rawline/editor.rb', line 491

def move_to_beginning_of_input
  @line.position = @line.bol
  @dom.input_box.position = @line.position
end

#move_to_end_of_inputObject



496
497
498
499
# File 'lib/rawline/editor.rb', line 496

def move_to_end_of_input
  @line.position = @line.length
  @dom.input_box.position = @line.position
end

#move_to_end_of_lineObject



520
521
522
523
524
525
526
527
528
529
530
# File 'lib/rawline/editor.rb', line 520

def move_to_end_of_line
  rows_to_move_down = number_of_terminal_rows - current_terminal_row
  # rows_to_move_down.times { @output.print @terminal.term_info.control_string("cud1") }
  # @terminal.move_down_n_rows rows_to_move_down
  @line.position = @line.length
  @dom.input_box.position = @line.position

  column = (@line.prompt.length + @line.position) % terminal_width
  # @output.print @terminal.term_info.control_string("hpa", column)
  # @terminal.move_to_column((@line.prompt.length + @line.position) % terminal_width)
end

#move_to_position(pos) ⇒ Object

Move the cursor to pos.



504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/rawline/editor.rb', line 504

def move_to_position(pos)
  rows_to_move = current_terminal_row - terminal_row_for_line_position(pos)
  if rows_to_move > 0
    # rows_to_move.times { @output.print @terminal.term_info.control_string("cuu1") }
    # @terminal.move_up_n_rows(rows_to_move)
  else
    # rows_to_move.abs.times { @output.print @terminal.term_info.control_string("cud1") }
    # @terminal.move_down_n_rows(rows_to_move.abs)
  end
  column = (@line.prompt.length + pos) % terminal_width
  # @output.print @terminal.term_info.control_string("hpa", column)
  # @terminal.move_to_column((@line.prompt.length + pos) % terminal_width)
  @line.position = pos
  @dom.input_box.position = @line.position
end

#newlineObject

Adds @line.text to the editor history. This action is bound to the enter key by default.



365
366
367
368
# File 'lib/rawline/editor.rb', line 365

def newline
  add_to_history
			@history.clear_position
end

#on_read_line(&blk) ⇒ Object



370
371
372
# File 'lib/rawline/editor.rb', line 370

def on_read_line(&blk)
  @event_registry.subscribe :line_read, &blk
end

#on_word_complete(&blk) ⇒ Object



689
690
691
# File 'lib/rawline/editor.rb', line 689

def on_word_complete(&blk)
  @on_word_complete = blk
end

#on_word_complete_done(&blk) ⇒ Object



697
698
699
# File 'lib/rawline/editor.rb', line 697

def on_word_complete_done(&blk)
  @on_word_complete_done = blk
end

#on_word_complete_no_match(&blk) ⇒ Object



693
694
695
# File 'lib/rawline/editor.rb', line 693

def on_word_complete_no_match(&blk)
  @on_word_complete_no_match = blk
end

#overwrite_line(new_line, position = nil, options = {}) ⇒ Object

Overwrite the current line (@line.text) with new_line, and optionally reset the cursor position to position.



537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# File 'lib/rawline/editor.rb', line 537

def overwrite_line(new_line, position=nil, options={})
  text = @line.text
  @highlighting = false

  if options[:highlight_up_to]
    @highlighting = true
    new_line = highlight_text_up_to(new_line, options[:highlight_up_to])
  end

  @ignore_position_change = true
  @line.position = position || new_line.length
  @line.text = new_line
  @dom.input_box.content = @line.text
  @dom.input_box.position = @line.position
  @event_loop.add_event name: "render", source: @dom.input_box
end

#parse_key_codes(bytes) ⇒ Object

Parse a key or key sequence into the corresponding codes.



357
358
359
# File 'lib/rawline/editor.rb', line 357

def parse_key_codes(bytes)
  KeycodeParser.new(@terminal.keys).parse_bytes(bytes)
end

#press_keyObject

Call the action bound to the last character read via read. This method is called automatically by process_character.



340
341
342
# File 'lib/rawline/editor.rb', line 340

def press_key
  @keys[@char].call
end

Write a character to output at cursor position, shifting characters as appropriate. If no_line_history is set to true, the updated won’t be saved in the history of the current line.



581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/rawline/editor.rb', line 581

def print_character(char=@char, no_line_history = false)
  if @line.position < @line.length then
    chars = select_characters_from_cursor if @mode == :insert
    @line.text[@line.position] = (@mode == :insert) ? "#{char.chr}#{@line.text[@line.position]}" : "#{char.chr}"
    @line.right
    @dom.input_box.position = @line.position
    # if @mode == :insert then
    #   chars.length.times { @line.left } # move cursor back
    # end
  else
    @line.right
    @line << char
  end
  @dom.input_box.content = @line.text
  @dom.input_box.position = @line.position
  add_to_line_history unless no_line_history
end

#process_characterObject

Process a character. If the key corresponding to the inputted character is bound to an action, call press_key, otherwise call default_action. This method is called automatically by read



254
255
256
257
258
259
260
261
# File 'lib/rawline/editor.rb', line 254

def process_character
  case @char.class.to_s
  when 'Fixnum' then
    default_action
  when 'Array'
    press_key if key_bound?
  end
end

#process_lineObject



235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/rawline/editor.rb', line 235

def process_line
  @event_loop.add_event(name: "process_line", source: self) do
    @terminal.snapshot_tty_attrs
    @terminal.pseudo_cooked!

    move_to_beginning_of_input
    @terminal.puts
  end

  @event_loop.add_event name: "line_read", source: self, payload: { line: @line.text.without_ansi.dup }
  @event_loop.add_event(name: "restore_tty_attrs", source: self) { @terminal.restore_tty_attrs }
  @event_loop.add_event name: "render", source: self, payload: { reset: true }
end

#promptObject



144
145
146
# File 'lib/rawline/editor.rb', line 144

def prompt
  @prompt
end

#prompt=(text) ⇒ Object



148
149
150
151
152
# File 'lib/rawline/editor.rb', line 148

def prompt=(text)
  return if @line && @line.prompt == text
  @prompt = Prompt.new(text)
  @dom.prompt_box.content = @prompt
end

#puts(*args) ⇒ Object

Write to output and then immediately re-render.



602
603
604
605
# File 'lib/rawline/editor.rb', line 602

def puts(*args)
  @terminal.puts(*args)
  render(reset: true)
end

#read_bytes(bytes) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/rawline/editor.rb', line 214

def read_bytes(bytes)
  return unless bytes.any?
  old_position = @line.position
  key_codes = parse_key_codes(bytes)
  key_codes.each do |key_code|
    @char = key_code
    process_character

    new_position = @line.position

    if !@ignore_position_change && new_position != old_position
      @matching_text = @line.text[0...@line.position]
    end

    @ignore_position_change = false
    if @char == @terminal.keys[:enter] || !@char
      process_line
    end
  end
end

#redoObject

Redo a previously-undone modification to the current line (@line.text). This action is bound to ctrl+y by default.



757
758
759
# File 'lib/rawline/editor.rb', line 757

def redo
  generic_history_forward(@line.history)
end

#redraw_promptObject



154
155
156
# File 'lib/rawline/editor.rb', line 154

def redraw_prompt
  render(reset: true)
end

#reset_lineObject



554
555
556
557
# File 'lib/rawline/editor.rb', line 554

def reset_line
  initialize_line
  render(reset: true)
end

#show_historyObject

Print the content of the editor history. Note that after the message is displayed, the line text and position will be restored.



729
730
731
732
733
734
# File 'lib/rawline/editor.rb', line 729

def show_history
  pos = @line.position
  text = @line.text
  @history.each {|l| puts "- [#{l}]"}
  overwrite_line(text, pos)
end

#startObject

Starts the editor event loop. Must be called before the editor can be interacted with.



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/rawline/editor.rb', line 173

def start
  @terminal.raw!
  at_exit { @terminal.cooked! }

  Signal.trap("SIGWINCH") do
    @event_loop.add_event name: "terminal-resized", source: self
  end

  @event_registry.subscribe("terminal-resized") do
    @renderer.update_dimensions(width: terminal_width, height: terminal_height)
    @event_loop.add_event name: "render", source: self
  end

  @event_loop.add_event name: "render", source: self
  @event_loop.start
end

#subscribe(*args, &blk) ⇒ Object

Subscribes to an event with the given block as a callback.



191
192
193
# File 'lib/rawline/editor.rb', line 191

def subscribe(*args, &blk)
  @event_registry.subscribe(*args, &blk)
end

#terminal_heightObject



159
# File 'lib/rawline/editor.rb', line 159

def terminal_height ; @terminal.height ; end

#terminal_widthObject



158
# File 'lib/rawline/editor.rb', line 158

def terminal_width ; @terminal.width ; end

#toggle_modeObject

Toggle the editor @mode to :replace or :insert (default).



562
563
564
565
566
567
# File 'lib/rawline/editor.rb', line 562

def toggle_mode
  case @mode
  when :insert then @mode = :replace
  when :replace then @mode = :insert
  end
end

#unbind(key) ⇒ Object



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/rawline/editor.rb', line 306

def unbind(key)
  block = case key.class.to_s
    when 'Symbol' then
      @keys.delete @terminal.keys[key]
    when 'Array' then
      @keys.delete @keys[key]
    when 'Fixnum' then
      @keys.delete[[key]]
    when 'String' then
      if key.length == 1 then
        @keys.delete([key.ord])
      else
        raise NotImplementedError, "This is no implemented yet. It needs to return the previously bound block"
        bind_hash({:"#{key}" => key}, block)
      end
    when 'Hash' then
      raise BindingException, "Cannot bind more than one key or key sequence at once" unless key.values.length == 1
      bind_hash(key, -> { })
    end
  @terminal.update
  block
end

#undoObject

Undo the last modification to the current line (@line.text). This action is bound to ctrl+z by default.



747
748
749
750
# File 'lib/rawline/editor.rb', line 747

def undo
  generic_history_back(@line.history) if @line.history.position == nil
  generic_history_back(@line.history)
end

#write(string) ⇒ Object

Write a string starting from the cursor position.



610
611
612
613
614
615
616
617
# File 'lib/rawline/editor.rb', line 610

def write(string)
  @line.text[@line.position] = string
  string.length.times { @line.right }
  @dom.input_box.position = @line.position
  @dom.input_box.content = @line.text

  add_to_line_history
end

#yank_forward(text) ⇒ Object



454
455
456
457
458
459
460
# File 'lib/rawline/editor.rb', line 454

def yank_forward(text)
  @line.text[line.position] = text
  @line.position = line.position + text.length
  @dom.input_box.content = line.text
  @dom.input_box.position = @line.position
  @history.clear_position
end