Class: TTY::Reader Private
- Inherits:
-
Object
- Object
- TTY::Reader
- Includes:
- Wisper::Publisher
- Defined in:
- lib/tty/reader.rb,
lib/tty/reader/line.rb,
lib/tty/reader/mode.rb,
lib/tty/reader/codes.rb,
lib/tty/reader/console.rb,
lib/tty/reader/history.rb,
lib/tty/reader/version.rb,
lib/tty/reader/win_api.rb,
lib/tty/reader/key_event.rb,
lib/tty/reader/win_console.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
A class responsible for reading character input from STDIN
Used internally to provide key and line reading functionality
Defined Under Namespace
Modules: Codes, WinAPI Classes: Console, History, Key, KeyEvent, Line, Mode, WinConsole
Constant Summary collapse
- InputInterrupt =
Raised when the user hits the interrupt key(Control-C)
Class.new(StandardError)
- CARRIAGE_RETURN =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Key codes
13
- NEWLINE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
10
- BACKSPACE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
127
- DELETE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
8
- VERSION =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"0.1.0"
Instance Attribute Summary collapse
- #console ⇒ Object readonly private
- #env ⇒ Object readonly private
- #input ⇒ Object readonly private
- #output ⇒ Object readonly private
- #track_history ⇒ Object (also: #track_history?) readonly private
Instance Method Summary collapse
- #add_to_history(line) ⇒ Object private
-
#get_codes(options = {}, codes = []) ⇒ Array[Integer]
private
Get input code points.
- #history_next ⇒ Object private
- #history_next? ⇒ Boolean private
- #history_previous ⇒ Object private
- #history_previous? ⇒ Boolean private
-
#initialize(input = $stdin, output = $stdout, options = {}) ⇒ Reader
constructor
Initialize a Reader.
-
#inspect ⇒ String
Inspect class name and public attributes.
-
#keyctrl_d ⇒ Object
(also: #keyctrl_z)
private
Capture Ctrl+d and Ctrl+z key events.
-
#read_keypress(options = {}) ⇒ String
(also: #read_char)
Read a keypress including invisible multibyte codes and return a character as a string.
-
#read_line(*args) ⇒ String
Get a single line from STDIN.
-
#read_multiline(prompt = '') {|String| ... } ⇒ Array[String]
(also: #read_lines)
Read multiple lines and return them in an array.
-
#select_console(input) ⇒ Object
private
Select appropriate console.
-
#trigger(event, *args) ⇒ Object
Expose event broadcasting.
-
#unbufferred(&block) ⇒ Object
Get input in unbuffered mode.
Constructor Details
#initialize(input = $stdin, output = $stdout, options = {}) ⇒ Reader
Initialize a Reader
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/tty/reader.rb', line 57 def initialize(input = $stdin, output = $stdout, = {}) @input = input @output = output @interrupt = .fetch(:interrupt) { :error } @env = .fetch(:env) { ENV } @track_history = .fetch(:track_history) { true } @console = select_console(input) @history = History.new do |h| h.duplicates = false h.exclude = proc { |line| line.strip == '' } end @stop = false # gathering input subscribe(self) end |
Instance Attribute Details
#console ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
36 37 38 |
# File 'lib/tty/reader.rb', line 36 def console @console end |
#env ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
31 32 33 |
# File 'lib/tty/reader.rb', line 31 def env @env end |
#input ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
27 28 29 |
# File 'lib/tty/reader.rb', line 27 def input @input end |
#output ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
29 30 31 |
# File 'lib/tty/reader.rb', line 29 def output @output end |
#track_history ⇒ Object (readonly) Also known as: track_history?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
33 34 35 |
# File 'lib/tty/reader.rb', line 33 def track_history @track_history end |
Instance Method Details
#add_to_history(line) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
274 275 276 |
# File 'lib/tty/reader.rb', line 274 def add_to_history(line) @history.push(line) end |
#get_codes(options = {}, codes = []) ⇒ Array[Integer]
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get input code points
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/tty/reader.rb', line 133 def get_codes( = {}, codes = []) opts = { echo: true, raw: false }.merge() char = console.get_char(opts) handle_interrupt if char == console.keys[:ctrl_c] return if char.nil? codes << char.ord condition = proc { |escape| (codes - escape).empty? || (escape - codes).empty? && !(64..126).include?(codes.last) } while console.escape_codes.any?(&condition) get_codes(, codes) end codes end |
#history_next ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
282 283 284 285 |
# File 'lib/tty/reader.rb', line 282 def history_next @history.next @history.get end |
#history_next? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
278 279 280 |
# File 'lib/tty/reader.rb', line 278 def history_next? @history.next? end |
#history_previous ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
291 292 293 294 295 |
# File 'lib/tty/reader.rb', line 291 def history_previous line = @history.get @history.previous line end |
#history_previous? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
287 288 289 |
# File 'lib/tty/reader.rb', line 287 def history_previous? @history.previous? end |
#inspect ⇒ String
Inspect class name and public attributes
301 302 303 |
# File 'lib/tty/reader.rb', line 301 def inspect "#<#{self.class}: @input=#{input}, @output=#{output}>" end |
#keyctrl_d ⇒ Object Also known as: keyctrl_z
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Capture Ctrl+d and Ctrl+z key events
269 270 271 |
# File 'lib/tty/reader.rb', line 269 def keyctrl_d(*) @stop = true end |
#read_keypress(options = {}) ⇒ String Also known as: read_char
Read a keypress including invisible multibyte codes and return a character as a string. Nothing is echoed to the console. This call will block for a single keypress, but will not wait for Enter to be pressed.
115 116 117 118 119 120 121 122 |
# File 'lib/tty/reader.rb', line 115 def read_keypress( = {}) opts = { echo: false, raw: true }.merge() codes = unbufferred { get_codes(opts) } char = codes ? codes.pack('U*') : nil trigger_key_event(char) if char char end |
#read_line(*args) ⇒ String
Get a single line from STDIN. Each key pressed is echoed back to the shell. The input terminates when enter or return key is pressed.
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/tty/reader.rb', line 165 def read_line(*args) = args.last.respond_to?(:to_hash) ? args.pop : {} prompt = args.empty? ? '' : args.pop opts = { echo: true, raw: true }.merge() line = Line.new('') ctrls = console.keys.keys.grep(/ctrl/) clear_line = "\e[2K\e[1G" while (codes = unbufferred { get_codes(opts) }) && (code = codes[0]) char = codes.pack('U*') trigger_key_event(char) if console.keys[:backspace] == char || BACKSPACE == code next if line.start? line.left line.delete elsif console.keys[:delete] == char || DELETE == code line.delete elsif [console.keys[:ctrl_d], console.keys[:ctrl_z]].include?(char) break elsif ctrls.include?(console.keys.key(char)) # skip elsif console.keys[:up] == char next unless history_previous? line.replace(history_previous) elsif console.keys[:down] == char line.replace(history_next? ? history_next : '') elsif console.keys[:left] == char line.left elsif console.keys[:right] == char line.right else if opts[:raw] && code == CARRIAGE_RETURN char = "\n" line.move_to_end end line.insert(char) end if opts[:raw] && opts[:echo] output.print(clear_line) output.print(prompt + line.to_s) if char == "\n" line.move_to_start elsif !line.end? output.print("\e[#{line.size - line.cursor}D") end end break if (code == CARRIAGE_RETURN || code == NEWLINE) if (console.keys[:backspace] == char || BACKSPACE == code) && opts[:echo] if opts[:raw] output.print("\e[1X") unless line.start? else output.print(?\s + (line.start? ? '' : ?\b)) end end end add_to_history(line.to_s.rstrip) if track_history? line.to_s end |
#read_multiline(prompt = '') {|String| ... } ⇒ Array[String] Also known as: read_lines
Read multiple lines and return them in an array. Skip empty lines in the returned lines array. The input gathering is terminated by Ctrl+d or Ctrl+z.
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/tty/reader.rb', line 241 def read_multiline(prompt = '') @stop = false lines = [] loop do line = read_line(prompt) break if !line || line == '' next if line !~ /\S/ && !@stop if block_given? yield(line) unless line.to_s.empty? else lines << line unless line.to_s.empty? end break if @stop end lines end |
#select_console(input) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Select appropriate console
76 77 78 79 80 81 82 |
# File 'lib/tty/reader.rb', line 76 def select_console(input) if windows? && !env['TTY_TEST'] WinConsole.new(input) else Console.new(input) end end |
#trigger(event, *args) ⇒ Object
Expose event broadcasting
262 263 264 |
# File 'lib/tty/reader.rb', line 262 def trigger(event, *args) publish(event, *args) end |
#unbufferred(&block) ⇒ Object
Get input in unbuffered mode.
92 93 94 95 96 97 98 99 |
# File 'lib/tty/reader.rb', line 92 def unbufferred(&block) bufferring = output.sync # Immediately flush output output.sync = true block[] if block_given? ensure output.sync = bufferring end |