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)

Defined Under Namespace

Classes: Environment

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:

  • @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.

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

Yields:

  • (_self)

Yield Parameters:



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/rawline/editor.rb', line 131

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

  @env_stack = [Environment.new(terminal: terminal)]

  @word_break_characters = " \t\n\"'@><=;|&{()}"
  @mode = :insert

  @completion_proc = filename_completion_proc

  @match_hidden_files = false
  set_default_keys
  @add_history = false
  push_keyboard_input_processor self
  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_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.



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

def event_loop
  @event_loop
end

#focused_input_boxObject

TODO: dom traversal for lookup rather than assignment



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

def focused_input_box
  @focused_input_box
end

#historyObject

Returns the value of attribute history.



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

def history
  @history
end

#inputObject (readonly)

Returns the value of attribute input.



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

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.



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

def keyboard_input_processors
  @keyboard_input_processors
end

#lineObject

Returns the value of attribute line.



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

def line
  @line
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
87
88
# 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
  )

  KeyBindings.default_terminal = terminal

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

Instance Method Details

#add_to_history(allow_empty: false) ⇒ Object

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



789
790
791
792
793
794
# File 'lib/rawline/editor.rb', line 789

def add_to_history(allow_empty: false)
  if @add_history && (allow_empty || !@line.text.empty?)
    Treefell['editor'].puts "add_to_history text=#{@line.text}"
    history << @line.text.dup
  end
end

#add_to_line_history(allow_empty: false) ⇒ Object

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



779
780
781
782
783
784
# File 'lib/rawline/editor.rb', line 779

def add_to_line_history(allow_empty: false)
  if allow_empty || !@line.text.empty?
    Treefell['editor'].puts "add_to_line_history text=#{@line.text}"
    @line.history << @line.text.dup
  end
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.



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

def bind(key, &block)
  keys.bind(key, &block)
end

#check_for_keyboard_inputObject

INPUT



246
247
248
249
250
251
252
# File 'lib/rawline/editor.rb', line 246

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

#clear_historyObject

Clear the editor history.



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

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.



394
395
396
397
398
399
# File 'lib/rawline/editor.rb', line 394

def clear_line
  Treefell['editor'].puts "clear_line"
  add_to_line_history
  @line_editor.clear_line
  history.clear_position
end

#clear_screenObject



401
402
403
404
405
# File 'lib/rawline/editor.rb', line 401

def clear_screen
  Treefell['editor'].puts "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.



595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
# File 'lib/rawline/editor.rb', line 595

def complete
  focused_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
    },
    completion_selected: -> (completion) {
      completion_selected(completion)
    },
    done: -> (*leftover_bytes){
      completion_done
      leftover_bytes = leftover_bytes.flatten
      pop_keyboard_input_processor
      if leftover_bytes.any?
        keyboard_input_processor.read_bytes(leftover_bytes)
      end
      focused_input_box.cursor_on
    },
    keys: terminal.keys
  )
  push_keyboard_input_processor(completer)
  completer.read_bytes(@char)
end

#completion_classObject



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

def completion_class ; @env_stack.first.completion_class ; end

#completion_doneObject



661
662
663
664
665
666
667
668
# File 'lib/rawline/editor.rb', line 661

def completion_done
  if @on_word_complete_done
    Treefell['editor'].puts "word-completion-done calling on_word_complete_done callback"
    @on_word_complete_done.call
  else
    Treefell['editor'].puts 'word-completion-done no on_word_complete_done callback to call'
  end
end

#completion_found(completion:, possible_completions:) ⇒ Object



625
626
627
628
629
630
631
632
633
634
# File 'lib/rawline/editor.rb', line 625

def completion_found(completion:, possible_completions:)
  Treefell['editor'].puts "word-completion-found: #{completion.inspect} possible_completions: #{possible_completions.inspect}"
  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

  completion_selected(completion)
end

#completion_not_foundObject



648
649
650
651
652
653
654
655
656
657
658
659
# File 'lib/rawline/editor.rb', line 648

def completion_not_found
  Treefell['editor'].puts 'word-completion-not-found'
  if @on_word_complete_no_match
    word = @line.word[:text]
    sub_word = @line.text[@line.word[:start]..@line.position-1] || ""
    payload = { sub_word: sub_word, word: word }
    Treefell['editor'].puts "word-completion-not-found calling callback with payload: #{payload.inspect}"
    @on_word_complete_no_match.call(name: "word-completion-no-match", payload: payload)
  else
    Treefell['editor'].puts 'word-completion-not-found no on_word_complete_no_match callback to call'
  end
end

#completion_selected(completion) ⇒ Object



636
637
638
639
640
641
642
643
644
645
646
# File 'lib/rawline/editor.rb', line 636

def completion_selected(completion)
  Treefell['editor'].puts "word-completion-selected #{completion.inspect}"
  move_to_position @line.word[:end]
  delete_n_characters(@line.word[:end] - @line.word[:start], true)
  write completion.to_s

  if @on_word_completion_selected
    Treefell['editor'].puts "word-completion-selected callback called with #{completioni}"
    @on_word_completion_selected.call(name: "word-completion-selected", payload: { completion: completion })
  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.



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

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, position: 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 write. This method is called automatically by process_character.



359
360
361
# File 'lib/rawline/editor.rb', line 359

def default_action
  insert(@char)
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.



435
436
437
438
439
440
441
# File 'lib/rawline/editor.rb', line 435

def delete_character(no_line_history=false)
  Treefell['editor'].puts "delete_character"
  if @line_editor.delete_character
    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.



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

def delete_left_character(no_line_history=false)
  Treefell['editor'].puts "delete_left_character"
  if @line_editor.delete_left_character
    add_to_line_history unless no_line_history
    history.clear_position
  end
end

#delete_n_characters(number_of_characters_to_delete, no_line_history = false) ⇒ Object



421
422
423
424
425
426
427
# File 'lib/rawline/editor.rb', line 421

def delete_n_characters(number_of_characters_to_delete, no_line_history=false)
  Treefell['editor'].puts "delete_n_characters n=#{number_of_characters_to_delete}"
  if @line_editor.delete_n_characters(number_of_characters_to_delete)
    add_to_line_history unless no_line_history
    history.clear_position
  end
end

#envObject



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

def env ; @env_stack.last ; end

#escape(string) ⇒ Object



945
946
947
# File 'lib/rawline/editor.rb', line 945

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

#eventsObject

Returns the Editor’s event loop.



236
237
238
# File 'lib/rawline/editor.rb', line 236

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.



694
695
696
697
698
699
700
701
702
703
704
705
706
# File 'lib/rawline/editor.rb', line 694

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

#focus_input_box(box) ⇒ Object



820
821
822
823
# File 'lib/rawline/editor.rb', line 820

def focus_input_box(box)
  @dom.focus_input_box(box)
  @renderer.render_cursor
end

#highlight_text_up_to(text, position) ⇒ Object



443
444
445
446
# File 'lib/rawline/editor.rb', line 443

def highlight_text_up_to(text, position)
  Treefell['editor'].puts "highlight_text_up_to text=#{text} position=#{position}"
  @line_editor.highlight_text_up_to(text, position)
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.



759
760
761
762
# File 'lib/rawline/editor.rb', line 759

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.



769
770
771
772
# File 'lib/rawline/editor.rb', line 769

def history_forward
  generic_history_forward(history)
  add_to_line_history
end

#insert(string, add_to_line_history: true) ⇒ Object

Inserts a string at the current line position, shifting characters to right if necessary.



452
453
454
455
456
457
# File 'lib/rawline/editor.rb', line 452

def insert(string, add_to_line_history: true)
  Treefell['editor'].puts "insert string=#{string} add_to_line_history=#{add_to_line_history}"
  if @line_editor.insert(string)
    self.add_to_line_history if add_to_line_history
  end
end

#key_bound?Boolean

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

Returns:

  • (Boolean)


342
343
344
# File 'lib/rawline/editor.rb', line 342

def key_bound?
  keys.bound?(@char)
end

#keyboard_input_processorObject



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

def keyboard_input_processor ; env.keyboard_input_processors.last ; end

#keysObject



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

def keys ; @env_stack.first.keys ; end

#kill_forwardObject



459
460
461
462
463
464
465
# File 'lib/rawline/editor.rb', line 459

def kill_forward
  Treefell['editor'].puts "kill_forward"
  @line_editor.kill_forward.tap do
    add_to_line_history(allow_empty: true)
    history.clear_position
  end
end

#library_versionObject

Return the current RawLine version



174
175
176
# File 'lib/rawline/editor.rb', line 174

def library_version
  "RawLine v#{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.



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

def move_left
  Treefell['editor'].puts "move_left"
  @line_editor.move_left
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.



502
503
504
505
# File 'lib/rawline/editor.rb', line 502

def move_right
  Treefell['editor'].puts "move_right"
  @line_editor.move_right
end

#move_to_beginning_of_inputObject



507
508
509
510
# File 'lib/rawline/editor.rb', line 507

def move_to_beginning_of_input
  Treefell['editor'].puts "move_to_beginning_of_input"
  @line_editor.move_to_beginning_of_input
end

#move_to_end_of_inputObject



512
513
514
515
# File 'lib/rawline/editor.rb', line 512

def move_to_end_of_input
  Treefell['editor'].puts "move_to_end_of_input"
  @line_editor.move_to_end_of_input
end

#move_to_position(pos) ⇒ Object

Move the cursor to pos.



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

def move_to_position(pos)
  Treefell['editor'].puts "move_to_position 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_editor.position = pos
end

#new_envObject



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

def new_env ; Environment.new ; end

#newlineObject

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



374
375
376
377
# File 'lib/rawline/editor.rb', line 374

def newline
  add_to_history
			history.clear_position
end

#on_read_line(&blk) ⇒ Object



379
380
381
# File 'lib/rawline/editor.rb', line 379

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

#on_word_complete(&blk) ⇒ Object



670
671
672
673
# File 'lib/rawline/editor.rb', line 670

def on_word_complete(&blk)
  Treefell['editor'].puts "setting on_word_complete callback"
  @on_word_complete = blk
end

#on_word_complete_done(&blk) ⇒ Object



680
681
682
683
# File 'lib/rawline/editor.rb', line 680

def on_word_complete_done(&blk)
  Treefell['editor'].puts "setting on_word_complete_done callback"
  @on_word_complete_done = blk
end

#on_word_complete_no_match(&blk) ⇒ Object



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

def on_word_complete_no_match(&blk)
  Treefell['editor'].puts "setting on_word_complete_no_match callback"
  @on_word_complete_no_match = blk
end

#on_word_completion_selected(&blk) ⇒ Object



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

def on_word_completion_selected(&blk)
  Treefell['editor'].puts "setting on_word_completion_selected callback"
  @on_word_completion_selected = blk
end

#overwrite_line(new_line, position: nil, highlight_up_to: nil) ⇒ Object

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



541
542
543
544
545
546
# File 'lib/rawline/editor.rb', line 541

def overwrite_line(new_line, position: nil, highlight_up_to: nil)
  Treefell['editor'].puts "overwrite_line new_line=#{new_line} position=#{position} highlight_up_to=#{highlight_up_to}"
  if @line_editor.overwrite_line(new_line, position: position, highlight_up_to: highlight_up_to)
    @event_loop.add_event name: "render", source: focused_input_box
  end
end

#parse_key_code_sequences(bytes) ⇒ Object

Parse a key or key sequence into the corresponding codes.



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

def parse_key_code_sequences(bytes)
  KeycodeParser.new(@terminal.keys).parse_bytes_into_sequences(bytes)
end

#pop_envObject



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

def pop_env ; @env_stack.pop ; end

#pop_keyboard_input_processorObject



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

def pop_keyboard_input_processor ; env.keyboard_input_processors.pop ; end

#press_keyObject

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



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

def press_key
  keys[@char].call
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



306
307
308
309
310
311
312
# File 'lib/rawline/editor.rb', line 306

def process_character
  if @char.is_a?(Array)
    press_key if key_bound?
  else
    default_action
  end
end

#process_lineObject



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

def process_line
  @event_loop.immediately(name: "process_line", source: self) do
    add_to_history

    @terminal.snapshot_tty_attrs
    @terminal.pseudo_cooked!

    @terminal.move_to_beginning_of_row
    @terminal.puts
  end
  @event_loop.immediately(name: "line_read", source: self, payload: { line: @line.text.without_ansi.dup })
  @event_loop.immediately(name: "prepare_new_line", source: self) do
    history.clear_position
    reset_line
    move_to_beginning_of_input
  end
  @event_loop.immediately(name: "restore_tty_attrs", source: self) { @terminal.restore_tty_attrs }
  @event_loop.immediately(name: "render", source: self, payload: { reset: true })
end

#promptObject



178
179
180
# File 'lib/rawline/editor.rb', line 178

def prompt
  @prompt
end

#prompt=(text) ⇒ Object



182
183
184
185
186
187
# File 'lib/rawline/editor.rb', line 182

def prompt=(text)
  return if @line && @line.prompt == text
  @prompt = Prompt.new(text)
  Treefell['editor'].puts "prompt=#{prompt.inspect}"
  @dom.prompt_box.content = @prompt
end

#push_env(env) ⇒ Object



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

def push_env(env) ; @env_stack.push env ; end

#push_keyboard_input_processor(kip) ⇒ Object



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

def push_keyboard_input_processor(kip) ; env.keyboard_input_processors.push kip ; end

#puts(*args) ⇒ Object

Write to output and then immediately re-render.



573
574
575
576
# File 'lib/rawline/editor.rb', line 573

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

#read_bytes(bytes) ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/rawline/editor.rb', line 254

def read_bytes(bytes)
  return unless bytes.any?

  Treefell['editor'].puts "read_bytes #{bytes.inspect}"
  old_position = @line.position

  key_code_sequences = parse_key_code_sequences(bytes)

  Treefell['editor'].puts "key code sequences: #{key_code_sequences.inspect}"
  begin
    key_code_sequences.each do |sequence|
      @char = sequence
      if @char == @terminal.keys[:enter] || !@char
        Treefell['editor'].puts "processing line: #{@line.text.inspect}"

        @renderer.pause
        process_line
      else
        process_character
        new_position = @line.position
      end
    end
  ensure
    @renderer.unpause
  end
end

#redoObject

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



750
751
752
# File 'lib/rawline/editor.rb', line 750

def redo
  generic_history_forward(@line.history)
end

#redraw_promptObject



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

def redraw_prompt
  Treefell['editor'].puts "redrawing prompt=#{prompt.inspect} reset=true"
  render(reset: true)
end

#reset_lineObject



548
549
550
551
552
# File 'lib/rawline/editor.rb', line 548

def reset_line
  Treefell['editor'].puts "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.



718
719
720
721
722
723
724
725
726
727
# File 'lib/rawline/editor.rb', line 718

def show_history
  pos = @line.position
  text = @line.text
  max_index_width = history.length.to_s.length
  history.each_with_index do |item, i|
    @terminal.puts sprintf("%-#{max_index_width}d %s\n", i+1, item)
  end
  render(reset: true)
  overwrite_line(text, position: pos)
end

#startObject

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



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/rawline/editor.rb', line 210

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

  Signal.trap("SIGWINCH") do
    Treefell['editor'].puts "terminal-resized trap=SIGWINCH"
    @event_loop.add_event name: "terminal-resized", source: self
  end

  @event_registry.subscribe("terminal-resized") do
    width, height = terminal_width, terminal_height
    Treefell['editor'].puts "terminal-resizing width=#{width} height=#{height}"
    @renderer.update_dimensions(width: width, height: 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.



231
232
233
# File 'lib/rawline/editor.rb', line 231

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

#terminal_heightObject



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

def terminal_height ; @terminal.height ; end

#terminal_widthObject



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

def terminal_width ; @terminal.width ; end

#toggle_modeObject

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



557
558
559
560
561
562
# File 'lib/rawline/editor.rb', line 557

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

#unbind(key) ⇒ Object



335
336
337
# File 'lib/rawline/editor.rb', line 335

def unbind(key)
  keys.unbind(key)
end

#undoObject

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



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

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

#write(string, add_to_line_history: true) ⇒ Object

Write a string starting from the cursor position ovewriting any character at the current position if necessary.



471
472
473
474
475
476
# File 'lib/rawline/editor.rb', line 471

def write(string, add_to_line_history: true)
  Treefell['editor'].puts "write string=#{string}"
  if @line_editor.write(string)
    self.add_to_line_history if add_to_line_history
  end
end

#yank_forward(text) ⇒ Object



478
479
480
481
482
483
484
# File 'lib/rawline/editor.rb', line 478

def yank_forward(text)
  Treefell['editor'].puts "yank_forward"
  @line_editor.yank_forward(text).tap do
    add_to_line_history
    history.clear_position
  end
end