Class: Coolline
- Inherits:
-
Object
- Object
- Coolline
- Defined in:
- lib/coolline/ansi.rb,
lib/coolline/menu.rb,
lib/coolline/editor.rb,
lib/coolline/handler.rb,
lib/coolline/history.rb,
lib/coolline/version.rb,
lib/coolline/coolline.rb
Defined Under Namespace
Modules: ANSI, Editor Classes: Handler, History, Menu
Constant Summary collapse
- Version =
"0.5.0"
- ConfigDir =
File.join(ENV["HOME"], ".config", "coolline")
- CacheDir =
File.join(ENV["HOME"], ".cache", "coolline")
- ConfigFile =
File.join(ConfigDir, "coolline.rb")
- HistoryFile =
File.join(CacheDir, "history")
- NullFile =
if defined? File::NULL File::NULL else "/dev/null" end
- Settings =
Returns All the defaults settings.
{ :word_boundaries => [" ", "-", "_"], :completion_word_boundaries => [" ", "-", "_"], :handlers => [ Handler.new(/\A(?:\C-h|\x7F)\z/, &:kill_backward_char), Handler.new(?\C-a, &:beginning_of_line), Handler.new(?\C-e, &:end_of_line), Handler.new(?\C-k, &:kill_line), Handler.new(?\C-u, &:kill_beginning_of_line), Handler.new(?\C-f, &:forward_char), Handler.new(?\C-b, &:backward_char), Handler.new(?\C-d, &:kill_current_char_or_leave), Handler.new(?\C-c) { Process.kill(:INT, Process.pid) }, Handler.new(?\C-w, &:kill_backward_word), Handler.new(?\C-t, &:transpose_chars), Handler.new(?\C-n, &:next_history_line), Handler.new(?\C-p, &:previous_history_line), Handler.new(?\C-r, &:interactive_search), Handler.new(?\C-l, &:clear_screen), Handler.new(?\t, &:complete), Handler.new(?\C-a..?\C-z) {}, Handler.new(/\A\e(?:\C-h|\x7F)\z/, &:kill_backward_word), Handler.new("\eb", &:backward_word), Handler.new("\ef", &:forward_word), Handler.new("\e[A", &:previous_history_line), Handler.new("\e[B", &:next_history_line), Handler.new("\e[3~", &:kill_current_char), Handler.new("\e[5~", &:previous_history_line), Handler.new("\e[6~", &:next_history_line), Handler.new("\e[7~", &:beginning_of_line), Handler.new("\e[8~", &:end_of_line), Handler.new("\e[C", &:forward_char), Handler.new("\e[D", &:backward_char), Handler.new("\e[F", &:end_of_line), Handler.new("\e[H", &:beginning_of_line), Handler.new("\eOH", &:beginning_of_line), Handler.new("\eOF", &:end_of_line), Handler.new("\ed", &:kill_forward_word), Handler.new("\et", &:transpose_words), Handler.new("\ec", &:capitalize_word), Handler.new("\eu", &:uppercase_word), Handler.new("\el", &:lowercase_word), Handler.new("\e<", &:first_history_line), Handler.new("\e>", &:last_history_line), Handler.new(/\e.+/) {}, ], :unknown_char_proc => :insert_string.to_proc, :transform_proc => proc { |line| line }, :completion_proc => proc { |cool| [] }, :history_file => HistoryFile, :history_size => 5000, }
Constants included from ANSI
Instance Attribute Summary collapse
-
#completion_proc ⇒ Proc
Proc called to retrieve completions.
-
#completion_word_boundaries ⇒ Array<String, Regexp>
Expressions detected as word boundaries for the purpose of autocompletion.
- #handlers ⇒ Array<Handler>
-
#history ⇒ History
History object.
-
#history_file ⇒ String
Name of the file containing history.
-
#history_size ⇒ Integer
Size of the history.
- #input ⇒ IO
-
#line ⇒ String
Current line.
- #menu ⇒ Menu
- #output ⇒ IO
-
#pos ⇒ Integer
Cursor position.
-
#prompt ⇒ String
Current prompt.
-
#transform_proc ⇒ Proc
Proc called to change the way a line is displayed.
-
#unknown_char_proc ⇒ Proc
Proc called to handle unmatched characters.
-
#word_boundaries ⇒ Array<String, Regexp>
Expressions detected as word boundaries for the purpose of motion commands.
-
#word_boundaries_regexp ⇒ Regexp
readonly
Regular expression to match word boundaries.
Class Method Summary collapse
-
.bind(key) {|cool| ... } ⇒ Object
Binds a key to a block.
-
.load_config ⇒ Object
Loads the config, unless it has already been loaded.
-
.load_config! ⇒ Object
Loads the config, even if it has already been loaded.
-
.readline(*args) ⇒ Object
Perform a quick, one-off readline (equivalent to ‘Coolline.new.readline(…)`).
Instance Method Summary collapse
- #bind(key, &action) ⇒ Object
-
#close ⇒ Object
Closes the History object.
-
#common_beginning(candidates) ⇒ String
The common part between all completion candidates.
-
#complete ⇒ Object
Tries to complete the current word.
-
#completed_word ⇒ String
The string to be completed (useful in the completion proc).
-
#completed_word=(string) ⇒ Object
Sets the word at point, and moves the cursor to after the end of said word.
-
#first_history_line ⇒ Object
Selects the first line of history.
-
#gets ⇒ Object
Reads a line with no prompt.
-
#initialize {|self| ... } ⇒ Coolline
constructor
Creates a new cool line.
-
#interactive_search ⇒ Object
Prompts the user to search for a line.
- #kill_current_char_or_leave ⇒ Object
-
#last_history_line ⇒ Object
Selects the last line of history.
-
#next_history_line ⇒ Object
Selects the next line in history (if any).
-
#previous_history_line ⇒ Object
Selects the previous line in history (if any).
-
#print(*objs) ⇒ Object
Prints objects to the output.
-
#readline(prompt = ">> ", default_line = "") ⇒ Object
Reads a line from the terminal.
- #readline_dumb(prompt) ⇒ Object
- #readline_full(prompt = ">> ", default_line = "") ⇒ Object
-
#render ⇒ Object
Displays the current code on the terminal.
- #word_boundary?(char) ⇒ Boolean
Methods included from Editor
#backward_char, #backward_word, #beginning_of_line, #capitalize_word, #clear_line, #end_of_line, #forward_char, #forward_word, #insert_string, #kill_backward_char, #kill_backward_word, #kill_beginning_of_line, #kill_current_char, #kill_forward_word, #kill_line, #lowercase_word, #non_word_boundary_after, #non_word_boundary_before, #transpose_chars, #transpose_words, #uppercase_word, #word_beginning_after, #word_beginning_before, #word_boundary_after, #word_boundary_before, #word_end_after, #word_end_before
Methods included from ANSI
#ansi_length, #ansi_print, #clear_screen, #erase_line, #go_to, #go_to_col, #go_to_next_line, #go_to_previous_line, #reset_color, #reset_line, #start_with_ansi_code?, #strip_ansi_codes
Constructor Details
#initialize {|self| ... } ⇒ Coolline
Creates a new cool line.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/coolline/coolline.rb', line 122 def initialize self.class.load_config @input = STDIN # must be the actual IO object @output = $stdout self.word_boundaries = Settings[:word_boundaries].dup self.completion_word_boundaries = Settings[:completion_word_boundaries].dup self.handlers = Settings[:handlers].dup self.transform_proc = Settings[:transform_proc] self.unknown_char_proc = Settings[:unknown_char_proc] self.completion_proc = Settings[:completion_proc] self.history_file = Settings[:history_file] self.history_size = Settings[:history_size] yield self if block_given? @history ||= History.new(@history_file, @history_size) @menu = Menu.new(@input, @output) end |
Instance Attribute Details
#completion_proc ⇒ Proc
Returns Proc called to retrieve completions.
171 172 173 |
# File 'lib/coolline/coolline.rb', line 171 def completion_proc @completion_proc end |
#completion_word_boundaries ⇒ Array<String, Regexp>
Returns Expressions detected as word boundaries for the purpose of autocompletion.
162 163 164 |
# File 'lib/coolline/coolline.rb', line 162 def completion_word_boundaries @completion_word_boundaries end |
#handlers ⇒ Array<Handler>
174 175 176 |
# File 'lib/coolline/coolline.rb', line 174 def handlers @handlers end |
#history ⇒ History
Returns History object.
183 184 185 |
# File 'lib/coolline/coolline.rb', line 183 def history @history end |
#history_file ⇒ String
Returns Name of the file containing history.
177 178 179 |
# File 'lib/coolline/coolline.rb', line 177 def history_file @history_file end |
#history_size ⇒ Integer
Returns Size of the history.
180 181 182 |
# File 'lib/coolline/coolline.rb', line 180 def history_size @history_size end |
#input ⇒ IO
146 147 148 |
# File 'lib/coolline/coolline.rb', line 146 def input @input end |
#line ⇒ String
Returns Current line.
186 187 188 |
# File 'lib/coolline/coolline.rb', line 186 def line @line end |
#output ⇒ IO
146 147 148 |
# File 'lib/coolline/coolline.rb', line 146 def output @output end |
#pos ⇒ Integer
Returns Cursor position.
189 190 191 |
# File 'lib/coolline/coolline.rb', line 189 def pos @pos end |
#prompt ⇒ String
Returns Current prompt.
192 193 194 |
# File 'lib/coolline/coolline.rb', line 192 def prompt @prompt end |
#transform_proc ⇒ Proc
Returns Proc called to change the way a line is displayed.
165 166 167 |
# File 'lib/coolline/coolline.rb', line 165 def transform_proc @transform_proc end |
#unknown_char_proc ⇒ Proc
Returns Proc called to handle unmatched characters.
168 169 170 |
# File 'lib/coolline/coolline.rb', line 168 def unknown_char_proc @unknown_char_proc end |
#word_boundaries ⇒ Array<String, Regexp>
Returns Expressions detected as word boundaries for the purpose of motion commands.
150 151 152 |
# File 'lib/coolline/coolline.rb', line 150 def word_boundaries @word_boundaries end |
#word_boundaries_regexp ⇒ Regexp (readonly)
Returns Regular expression to match word boundaries.
153 154 155 |
# File 'lib/coolline/coolline.rb', line 153 def word_boundaries_regexp @word_boundaries_regexp end |
Class Method Details
.bind(key) {|cool| ... } ⇒ Object
Binds a key to a block. This key binding will have precedence over already defined key bindings.
111 112 113 |
# File 'lib/coolline/coolline.rb', line 111 def self.bind(key, &action) Coolline::Settings[:handlers].unshift Coolline::Handler.new(key, &action) end |
.load_config ⇒ Object
Loads the config, unless it has already been loaded
102 103 104 |
# File 'lib/coolline/coolline.rb', line 102 def self.load_config load_config! unless @config_loaded end |
.load_config! ⇒ Object
Loads the config, even if it has already been loaded
93 94 95 96 97 98 99 |
# File 'lib/coolline/coolline.rb', line 93 def self.load_config! if File.exist? ConfigFile load ConfigFile end @config_loaded = true end |
.readline(*args) ⇒ Object
Perform a quick, one-off readline (equivalent to ‘Coolline.new.readline(…)`)
198 199 200 |
# File 'lib/coolline/coolline.rb', line 198 def self.readline(*args) new.readline(*args) end |
Instance Method Details
#bind(key, &action) ⇒ Object
115 116 117 |
# File 'lib/coolline/coolline.rb', line 115 def bind(key, &action) handlers.unshift Coolline::Handler.new(key, &action) end |
#close ⇒ Object
Closes the History object. Should be called when you’re done with a Coolline instance.
310 311 312 |
# File 'lib/coolline/coolline.rb', line 310 def close @history.close end |
#common_beginning(candidates) ⇒ String
Returns The common part between all completion candidates.
419 420 421 422 423 424 425 426 |
# File 'lib/coolline/coolline.rb', line 419 def common_beginning(candidates) candidates.inject do |common, el| i = 0 i += 1 while common[i] == el[i] and i != el.size el[0...i] end end |
#complete ⇒ Object
Tries to complete the current word
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
# File 'lib/coolline/coolline.rb', line 429 def complete old_word_boundaries = word_boundaries self.word_boundaries = completion_word_boundaries return if word_boundary? line[pos - 1] completions = @completion_proc.call(self) if completions.empty? .string = "(No completions found)" else .list = completions self.completed_word = common_beginning(completions) end ensure self.word_boundaries = old_word_boundaries end |
#completed_word ⇒ String
Returns The string to be completed (useful in the completion proc).
406 407 408 |
# File 'lib/coolline/coolline.rb', line 406 def completed_word line[word_beginning_before(pos)...pos] end |
#completed_word=(string) ⇒ Object
Sets the word at point, and moves the cursor to after the end of said word.
411 412 413 414 415 |
# File 'lib/coolline/coolline.rb', line 411 def completed_word=(string) beg = word_beginning_before(pos) line[beg...pos] = string self.pos = beg + string.size end |
#first_history_line ⇒ Object
Selects the first line of history
326 327 328 329 330 331 332 |
# File 'lib/coolline/coolline.rb', line 326 def first_history_line @history.index = 0 @line.replace @history[0] @history_moved = true end_of_line end |
#gets ⇒ Object
Reads a line with no prompt
299 300 301 |
# File 'lib/coolline/coolline.rb', line 299 def gets readline "" end |
#interactive_search ⇒ Object
Prompts the user to search for a line
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/coolline/coolline.rb', line 362 def interactive_search found_index = @history.index # Use another coolline instance for the search! :D Coolline.new { |c| # Remove the search handler (to avoid nesting confusion) c.handlers.delete_if { |h| h.char == "\C-r" } # search line c.transform_proc = proc do pattern = Regexp.new Regexp.escape(c.line) line, found_index = @history.search(pattern, @history.index).first if line "#{c.line}): #{line}" else "#{c.line}): [pattern not found]" end end # Disable history c.history_file = NullFile c.history_size = 0 }.readline("(search:") found_index ||= @history.index @line.replace @history[found_index] @pos = [@line.size, @pos].min @history.index = found_index @history_moved = true end |
#kill_current_char_or_leave ⇒ Object
397 398 399 400 401 402 403 |
# File 'lib/coolline/coolline.rb', line 397 def kill_current_char_or_leave if @line.empty? @should_exit = true else kill_current_char end end |
#last_history_line ⇒ Object
Selects the last line of history
353 354 355 356 357 358 359 |
# File 'lib/coolline/coolline.rb', line 353 def last_history_line @history.index = @history.size - 2 @line.replace @history[@history.index] @history_moved = true end_of_line end |
#next_history_line ⇒ Object
Selects the next line in history (if any).
When on the last line, this method replaces the current line with an empty string.
338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/coolline/coolline.rb', line 338 def next_history_line if @history.index + 2 < @history.size @history.index += 1 @line.replace @history[@history.index + 1] || @history.current else @line.replace @history[-1] @history.index = @history.size - 2 end @history_moved = true end_of_line end |
#previous_history_line ⇒ Object
Selects the previous line in history (if any)
315 316 317 318 319 320 321 322 323 |
# File 'lib/coolline/coolline.rb', line 315 def previous_history_line if @history.index >= 0 @line.replace @history[@history.index] @history.index -= 1 end @history_moved = true end_of_line end |
#print(*objs) ⇒ Object
Prints objects to the output.
304 305 306 |
# File 'lib/coolline/coolline.rb', line 304 def print(*objs) @output.print(*objs) end |
#readline(prompt = ">> ", default_line = "") ⇒ Object
Reads a line from the terminal
204 205 206 207 208 209 210 |
# File 'lib/coolline/coolline.rb', line 204 def readline(prompt = ">> ", default_line = "") if @input.tty? readline_full(prompt, default_line) else readline_dumb(prompt) end end |
#readline_dumb(prompt) ⇒ Object
212 213 214 215 216 217 218 219 |
# File 'lib/coolline/coolline.rb', line 212 def readline_dumb(prompt) print prompt line = @input.gets self.line = line ? line.chomp : "" print transform(line), "\n" line.chomp if line end |
#readline_full(prompt = ">> ", default_line = "") ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/coolline/coolline.rb', line 221 def readline_full(prompt = ">> ", default_line = "") @prompt = prompt @history.delete_empty @accumulator = nil @history_moved = false @should_exit = false self.line = default_line render @history.index = @history.size - 1 @history << @line @input.raw do |raw_stdin| until (char = raw_stdin.getc) == "\r" @menu.erase handle(char) return if @should_exit if @history_moved @history_moved = false end render end end @menu.erase print "\n" @history[-1] = @line if @history.size != 0 @history.index = @history.size @history.save_line @line end |
#render ⇒ Object
Displays the current code on the terminal
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/coolline/coolline.rb', line 265 def render return unless @input.tty? width = @input.winsize[1] prompt_size = ansi_length(@prompt) line = transform(@line) stripped_line_width = ansi_length(line) line += " " * [width - stripped_line_width - prompt_size, 0].max reset_line width_before = UnicodeUtils.display_width @line[0..@pos] width_before += 1 if @pos >= @line.length if ansi_length(@prompt + line) <= width print @prompt + line else print @prompt left_width = width - prompt_size start_index = [width_before - left_width, 0].max end_index = start_index + left_width ansi_print(line, start_index, end_index) end @menu.display go_to_col [prompt_size + width_before, width]. min end |
#word_boundary?(char) ⇒ Boolean
447 448 449 |
# File 'lib/coolline/coolline.rb', line 447 def word_boundary?(char) char =~ word_boundaries_regexp end |