Class: Fatty::ShellSession
- Inherits:
-
OutputSession
- Object
- Session
- OutputSession
- Fatty::ShellSession
- Defined in:
- lib/fatty/session/shell_session.rb
Instance Attribute Summary collapse
-
#field ⇒ Object
readonly
Returns the value of attribute field.
-
#history ⇒ Object
readonly
Returns the value of attribute history.
Attributes inherited from OutputSession
#output, #pager, #pager_field, #viewport
Attributes inherited from Session
#counter, #keymap, #terminal, #views
Instance Method Summary collapse
-
#action_env(event:) ⇒ Object
Actions.
- #apply_completion(candidate, range: nil) ⇒ Object
- #apply_completion_prefix(prefix) ⇒ Object
-
#completion_candidates ⇒ Object
Completion.
- #completion_prefix ⇒ Object
- #completion_prefix_range ⇒ Object
-
#init(terminal:) ⇒ Object
Framework and Session Hooks.
-
#initialize(prompt: "sh> ", on_accept: nil, completion_proc: nil, history_ctx: nil, history_path: :default) ⇒ ShellSession
constructor
A new instance of ShellSession.
- #keymap_contexts ⇒ Object
- #longest_common_prefix(strings) ⇒ Object
- #pager_status_viewport(screen) ⇒ Object
-
#persist! ⇒ Object
Save any state we want saved on quit, error, etc.
-
#submit_line ⇒ Object
Perform the on_accept action if defined, but catch a few special commands for quiting and clearing.
-
#tick ⇒ Object
Called by Terminal#go on every loop iteration.
- #update_key(ev) ⇒ Object
- #view(screen:, renderer:) ⇒ Object
Methods inherited from OutputSession
#append_output, #follow_output!, #page_output_from_bottom!, #page_output_from_top!, #pager_active?, #pager_status_prompt, #pager_viewport, #reset_for_command!, #reset_output!, #reset_pager!, #resize_output!
Methods inherited from Session
#add_view, #close, #handle_resize, #inspect, #resolve_action, #update
Methods included from Actionable
Constructor Details
#initialize(prompt: "sh> ", on_accept: nil, completion_proc: nil, history_ctx: nil, history_path: :default) ⇒ ShellSession
Returns a new instance of ShellSession.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/fatty/session/shell_session.rb', line 11 def initialize(prompt: "sh> ", on_accept: nil, completion_proc: nil, history_ctx: nil, history_path: :default) super( keymap: Keymaps.emacs, views: [ Fatty::OutputView.new(z: 0), Fatty::InputView.new(z: 10), Fatty::CursorView.new(z: 100), ] ) @history = Fatty::History.for_path(history_path) @field = Fatty::InputField.new( prompt: prompt, history: @history, completion_proc: completion_proc, history_kind: :command, history_ctx: history_ctx, ) @on_accept = on_accept @completion_proc = completion_proc end |
Instance Attribute Details
#field ⇒ Object (readonly)
Returns the value of attribute field.
9 10 11 |
# File 'lib/fatty/session/shell_session.rb', line 9 def field @field end |
#history ⇒ Object (readonly)
Returns the value of attribute history.
9 10 11 |
# File 'lib/fatty/session/shell_session.rb', line 9 def history @history end |
Instance Method Details
#action_env(event:) ⇒ Object
Actions
115 116 117 118 119 120 121 122 123 124 |
# File 'lib/fatty/session/shell_session.rb', line 115 def action_env(event:) Fatty::ActionEnvironment.new( session: self, counter: counter, event: event, buffer: @field.buffer, field: @field, pager: pager, ) end |
#apply_completion(candidate, range: nil) ⇒ Object
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/fatty/session/shell_session.rb', line 384 def apply_completion(candidate, range: nil) candidate = candidate.to_s return [] if candidate.empty? buffer = @field.buffer target = range || buffer.completion_replace_range old_text = buffer.text.dup old_end = target.end append_space = !candidate.match?(/\s\z/) && (old_end >= old_text.length || old_text[old_end]&.match?(/\s/)) inserted = append_space ? "#{candidate} " : candidate buffer.replace_range(target, inserted) [] end |
#apply_completion_prefix(prefix) ⇒ Object
374 375 376 377 378 379 380 381 382 |
# File 'lib/fatty/session/shell_session.rb', line 374 def apply_completion_prefix(prefix) text = prefix.to_s commands = [] unless text.empty? buffer = @field.buffer buffer.replace_range(completion_prefix_range, text) end commands end |
#completion_candidates ⇒ Object
Completion
331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/fatty/session/shell_session.rb', line 331 def completion_candidates path_candidates = @field.path_completion_candidates return path_candidates if path_candidates.any? return [] unless @completion_proc prefix = completion_prefix Array(@completion_proc.call(@field.buffer)) .compact .map(&:to_s) .reject(&:empty?) .select { |s| s.start_with?(prefix) } .uniq end |
#completion_prefix ⇒ Object
346 347 348 |
# File 'lib/fatty/session/shell_session.rb', line 346 def completion_prefix @field.buffer.completion_prefix end |
#completion_prefix_range ⇒ Object
350 351 352 353 354 355 356 |
# File 'lib/fatty/session/shell_session.rb', line 350 def completion_prefix_range buffer = @field.buffer prefix = completion_prefix finish = buffer.cursor start = finish - prefix.length start...finish end |
#init(terminal:) ⇒ Object
Framework and Session Hooks
37 38 39 40 41 |
# File 'lib/fatty/session/shell_session.rb', line 37 def init(terminal:) super resize_output! [] end |
#keymap_contexts ⇒ Object
43 44 45 |
# File 'lib/fatty/session/shell_session.rb', line 43 def keymap_contexts pager_active? ? [:paging, :terminal] : [:input, :text, :terminal] end |
#longest_common_prefix(strings) ⇒ Object
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/fatty/session/shell_session.rb', line 358 def longest_common_prefix(strings) result = "" if strings.any? result = strings.first.to_s.dup strings.drop(1).each do |s| other = s.to_s i = 0 max = [result.length, other.length].min i += 1 while i < max && result[i] == other[i] result = result[0...i] break if result.empty? end end result end |
#pager_status_viewport(screen) ⇒ Object
83 84 85 86 87 |
# File 'lib/fatty/session/shell_session.rb', line 83 def (screen) vp = .dup vp.height = [screen.output_rect.rows - 1, 1].max vp end |
#persist! ⇒ Object
Save any state we want saved on quit, error, etc.
90 91 92 93 94 95 96 97 |
# File 'lib/fatty/session/shell_session.rb', line 90 def persist! return unless @history.respond_to?(:save!) Fatty.debug("ShellSession#persist!: saving history", tag: :history) @history.save! rescue => e Fatty.error("ShellSession#persist!: failed to save history: #{e.class}: #{e.}", tag: :history) end |
#submit_line ⇒ Object
Perform the on_accept action if defined, but catch a few special commands for quiting and clearing.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/fatty/session/shell_session.rb', line 133 def submit_line line = @field.accept_line.to_s.strip return [] if line.empty? Fatty.info("ShellSession: accept_line: #{line}") case line when "exit", "quit" [[:terminal, :quit]] when "clear" reset_output! [[:send, :alert, :clear, {}]] else reset_for_command! anchor = output.lines.length pager.begin_command!(anchor: anchor) commands = if @on_accept @on_accept.call(line, accept_env) else run_default_command(line) end normalize_accept_commands(commands) end rescue Errno::ENOENT [[:send, :alert, :show, { level: :error, message: "Command not found (#{line})" }]] end |
#tick ⇒ Object
Called by Terminal#go on every loop iteration. Returns true if any visible state changed (dirty).
101 102 103 104 105 106 107 108 109 |
# File 'lib/fatty/session/shell_session.rb', line 101 def tick dirty = false # Animated autoscroll (e.g. after M-s in paging mode). if pager.autoscroll? step = [(.height * 3) / 4, 1].max dirty ||= pager.autoscroll_step?(max_lines: step) end dirty end |
#update_key(ev) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/fatty/session/shell_session.rb', line 47 def update_key(ev) return [] unless ev.is_a?(Fatty::KeyEvent) key_str = "key=#{ev} raw=#{ev.raw}" Fatty.debug("ShellSession.update_key: #{key_str}", tag: :session) case ev.key when :resize [[:terminal, :handle_resize]] when :enter, :return # safety: if somehow not bound, still accept submit_line else [alert_cmd(:warn, "Unbound key: #{ev} (edit config in 'keybindings.yml' to bind)", ev: ev)] end end |
#view(screen:, renderer:) ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/fatty/session/shell_session.rb', line 63 def view(screen:, renderer:) if pager_active? ::Curses.curs_set(0) = (screen) highlights = pager.search_visible_highlights(viewport: ) renderer.render_output(output, viewport: , highlights: highlights) renderer.render_pager_field( pager_field, row: screen.output_rect.rows - 1, role: :pager_status, ) else ::Curses.curs_set(1) renderer.render_output(output, viewport: , highlights: nil) renderer.render_input_field(field) renderer.restore_cursor(field) end end |