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.4.4"
- 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 => [" ", "-", "_"], :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.
- #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.
-
#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.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/coolline/coolline.rb', line 120 def initialize self.class.load_config @input = STDIN # must be the actual IO object @output = $stdout self.word_boundaries = Settings[: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.
162 163 164 |
# File 'lib/coolline/coolline.rb', line 162 def completion_proc @completion_proc end |
#handlers ⇒ Array<Handler>
165 166 167 |
# File 'lib/coolline/coolline.rb', line 165 def handlers @handlers end |
#history ⇒ History
Returns History object.
174 175 176 |
# File 'lib/coolline/coolline.rb', line 174 def history @history end |
#history_file ⇒ String
Returns Name of the file containing history.
168 169 170 |
# File 'lib/coolline/coolline.rb', line 168 def history_file @history_file end |
#history_size ⇒ Integer
Returns Size of the history.
171 172 173 |
# File 'lib/coolline/coolline.rb', line 171 def history_size @history_size end |
#input ⇒ IO
142 143 144 |
# File 'lib/coolline/coolline.rb', line 142 def input @input end |
#line ⇒ String
Returns Current line.
177 178 179 |
# File 'lib/coolline/coolline.rb', line 177 def line @line end |
#output ⇒ IO
142 143 144 |
# File 'lib/coolline/coolline.rb', line 142 def output @output end |
#pos ⇒ Integer
Returns Cursor position.
180 181 182 |
# File 'lib/coolline/coolline.rb', line 180 def pos @pos end |
#prompt ⇒ String
Returns Current prompt.
183 184 185 |
# File 'lib/coolline/coolline.rb', line 183 def prompt @prompt end |
#transform_proc ⇒ Proc
Returns Proc called to change the way a line is displayed.
156 157 158 |
# File 'lib/coolline/coolline.rb', line 156 def transform_proc @transform_proc end |
#unknown_char_proc ⇒ Proc
Returns Proc called to handle unmatched characters.
159 160 161 |
# File 'lib/coolline/coolline.rb', line 159 def unknown_char_proc @unknown_char_proc end |
#word_boundaries ⇒ Array<String, Regexp>
Returns Expressions detected as word boundaries.
145 146 147 |
# File 'lib/coolline/coolline.rb', line 145 def word_boundaries @word_boundaries end |
#word_boundaries_regexp ⇒ Regexp (readonly)
Returns Regular expression to match word boundaries.
148 149 150 |
# File 'lib/coolline/coolline.rb', line 148 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.
109 110 111 |
# File 'lib/coolline/coolline.rb', line 109 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
100 101 102 |
# File 'lib/coolline/coolline.rb', line 100 def self.load_config load_config! unless @config_loaded end |
.load_config! ⇒ Object
Loads the config, even if it has already been loaded
91 92 93 94 95 96 97 |
# File 'lib/coolline/coolline.rb', line 91 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(…)`)
189 190 191 |
# File 'lib/coolline/coolline.rb', line 189 def self.readline(*args) new.readline(*args) end |
Instance Method Details
#bind(key, &action) ⇒ Object
113 114 115 |
# File 'lib/coolline/coolline.rb', line 113 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.
297 298 299 |
# File 'lib/coolline/coolline.rb', line 297 def close @history.close end |
#common_beginning(candidates) ⇒ String
Returns The common part between all completion candidates.
406 407 408 409 410 411 412 413 |
# File 'lib/coolline/coolline.rb', line 406 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
416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/coolline/coolline.rb', line 416 def complete 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 end |
#completed_word ⇒ String
Returns The string to be completed (useful in the completion proc).
393 394 395 |
# File 'lib/coolline/coolline.rb', line 393 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.
398 399 400 401 402 |
# File 'lib/coolline/coolline.rb', line 398 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
313 314 315 316 317 318 319 |
# File 'lib/coolline/coolline.rb', line 313 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
286 287 288 |
# File 'lib/coolline/coolline.rb', line 286 def gets readline "" end |
#interactive_search ⇒ Object
Prompts the user to search for a line
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/coolline/coolline.rb', line 349 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
384 385 386 387 388 389 390 |
# File 'lib/coolline/coolline.rb', line 384 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
340 341 342 343 344 345 346 |
# File 'lib/coolline/coolline.rb', line 340 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.
325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/coolline/coolline.rb', line 325 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)
302 303 304 305 306 307 308 309 310 |
# File 'lib/coolline/coolline.rb', line 302 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.
291 292 293 |
# File 'lib/coolline/coolline.rb', line 291 def print(*objs) @output.print(*objs) end |
#readline(prompt = ">> ", default_line = "") ⇒ Object
Reads a line from the terminal
195 196 197 198 199 200 201 |
# File 'lib/coolline/coolline.rb', line 195 def readline(prompt = ">> ", default_line = "") if @input.tty? readline_full(prompt, default_line) else readline_dumb(prompt) end end |
#readline_dumb(prompt) ⇒ Object
203 204 205 206 207 208 209 210 |
# File 'lib/coolline/coolline.rb', line 203 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
212 213 214 215 216 217 218 219 220 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 |
# File 'lib/coolline/coolline.rb', line 212 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
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/coolline/coolline.rb', line 256 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 if ansi_length(@prompt + line) <= width print @prompt + line else print @prompt left_width = width - prompt_size start_index = [@pos - left_width + 1, 0].max end_index = start_index + left_width ansi_print(line, start_index, end_index) end @menu.display go_to_col [prompt_size + @pos + 1, width].min end |
#word_boundary?(char) ⇒ Boolean
429 430 431 |
# File 'lib/coolline/coolline.rb', line 429 def word_boundary?(char) char =~ word_boundaries_regexp end |