Class: Selecta

Inherits:
Object show all
Defined in:
lib/selecta.rb

Defined Under Namespace

Classes: Abort

Constant Summary collapse

VERSION =
[0, 0, 6]

Instance Method Summary collapse

Instance Method Details

#handle_control_character(search, key) ⇒ Object

On each keystroke, generate a new search object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/selecta.rb', line 127

def handle_control_character(search, key)
  case key

  when KEY_CTRL_N then search.down
  when KEY_CTRL_P then search.up

  when KEY_CTRL_U then search.clear_query
  when KEY_CTRL_W then search.delete_word
  when KEY_CTRL_H, KEY_DELETE then search.backspace

  when ?\r, KEY_CTRL_J, KEY_CTRL_M then search.done

  when KEY_CTRL_C then raise Abort

  else search
  end
end

#handle_keys(search, tty) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/selecta.rb', line 103

def handle_keys(search, tty)
  new_query_chars = ""

  # Read through all of the buffered input characters. Process control
  # characters immediately. Save any query characters to be processed
  # together at the end, since there's no reason to process intermediate
  # results when there are more characters already buffered.
  tty.get_available_input.chars.each do |char|
    is_query_char = !!(char =~ /[[:print:]]/)
    if is_query_char
      new_query_chars << char
    else
      search = handle_control_character(search, char)
    end
  end

  if new_query_chars.empty?
    search
  else
    search.append_search_string(new_query_chars)
  end
end

#main_api(keys:, values: keys, options: {}) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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/selecta.rb', line 35

def main_api(keys:, values: keys, options: {})
  unless keys.size == values.size
    $stderr.puts("Keys and values must be arrays of equals size!")
    exit(1)
  end
  # We have to parse options before setting up the screen or trying to read
  # the input in case the user did '-h', an invalid option, etc. and we need
  # to terminate.
  options = Configuration.parse_options(options)
  input_lines = keys

  search = Screen.with_screen do |screen, tty|
    begin
      config = Configuration.from_inputs(input_lines, options, screen.height)
      run_in_screen(config, screen, tty)
    ensure
      config.visible_choices.times { screen.newline }
      screen.cursor_up(config.height - 1)
      screen.write(Text[""])
      screen.cursor_up(1)
    end
  end

  unless search.selection == Search::NoSelection
    values[keys.index(search.selection)]
  end
rescue Screen::NotATTY
  $stderr.puts(
    "Can't get a working TTY. Selecta requires an ANSI-compatible terminal.")
  exit(1)
rescue Abort
  # We were aborted via ^C.
  #
  # If we didn't mess with the TTY configuration at all, then ^C would send
  # SIGINT to the entire process group. That would terminate both Selecta and
  # anything piped into or out of it. Because Selecta puts the terminal in
  # raw mode, that doesn't happen; instead, we detect the ^C as normal input
  # and raise Abort, which leads here.
  #
  # To make pipelines involving Selecta behave as people expect, we send
  # SIGINT to our own process group, which should exactly match what termios
  # would do to us if the terminal weren't in raw mode. "Should!" <- Remove
  # those scare quotes if ten years pass without this breaking!
  #
  # The SIGINT will cause Ruby to raise Interrupt, so we also have to handle
  # that here.
  begin
    Process.kill("INT", -Process.getpgrp)
  rescue Interrupt
    exit(1)
  end
end

#run_in_screen(config, screen, tty) ⇒ Object



88
89
90
91
92
# File 'lib/selecta.rb', line 88

def run_in_screen(config, screen, tty)
  search = Search.from_config(config)
  search = ui_event_loop(search, screen, tty)
  search
end

#ui_event_loop(search, screen, tty) ⇒ Object

Use the search and screen to process user actions until they quit.



95
96
97
98
99
100
101
# File 'lib/selecta.rb', line 95

def ui_event_loop(search, screen, tty)
  while not search.done?
    Renderer.render!(search, screen)
    search = handle_keys(search, tty)
  end
  search
end