A HighLine object is a “high-level line oriented” shell over an input and an output stream. HighLine simplifies common console interaction, effectively replacing puts() and gets(). User code can simply specify the question to ask and any details about user interaction, then leave the rest of the work to HighLine. When HighLine.ask() returns, you’ll have the answer you requested, even if HighLine had to ask many times, validate results, perform range checking, convert types, etc.
color_scheme.rb
Created by Jeremy Hinegardner on 2007-01-24 Copyright 2007. All rights reserved
This is Free Software. See LICENSE and COPYING for details
simulate.rb
Created by Andy Rossmeissl on 2012-04-29. Copyright 2005 Gray Productions. All rights reserved. This is Free Software. See LICENSE and COPYING for details.
adapted from gist.github.com/194554
Extensions for class String
HighLine::String is a subclass of String with convenience methods added for colorization.
Available convenience methods include:
* 'color' method e.g. highline_string.color(:bright_blue, :underline) * colors e.g. highline_string.magenta * RGB colors e.g. highline_string.rgb_ff6000 or highline_string.rgb(255,96,0) * background colors e.g. highline_string.on_magenta * RGB background colors e.g. highline_string.on_rgb_ff6000 or highline_string.on_rgb(255,96,0) * styles e.g. highline_string.underline
Additionally, convenience methods can be chained, for instance the following are equivalent:
highline_string.bright_blue.blink.underline highline_string.color(:bright_blue, :blink, :underline) HighLine.color(highline_string, :bright_blue, :blink, :underline)
For those less squeamish about possible conflicts, the same convenience methods can be added to the builtin String class, as follows:
require 'highline' Highline.colorize_strings
color_scheme.rb
Created by Richard LeBer on 2011-06-27. Copyright 2011. All rights reserved
This is Free Software. See LICENSE and COPYING for details
The version of the installed library.
Embed in a String to clear all previous ANSI sequences. This MUST be done before the program exits!
for example bold black. Bold without a color displays the system-defined bold color (e.g. red on Mac iTerm)
These RGB colors are approximate; see en.wikipedia.org/wiki/ANSI_escape_code
On Mac OSX Terminal, white is actually gray
Alias for WHITE, since WHITE is actually a light gray on Macs
On Mac OSX Terminal, this is black foreground, or bright white background. Also used as base for RGB colors, if available
# File lib/highline/string_extensions.rb, line 27 27: def self.String(s) 28: HighLine::String.new(s) 29: end
# File lib/highline/style.rb, line 12 12: def self.Style(*args) 13: args = args.compact.flatten 14: if args.size==1 15: arg = args.first 16: if arg.is_a?(Style) 17: Style.list[arg.name] || Style.index(arg) 18: elsif arg.is_a?(::String) && arg =~ /^\e\[/ # arg is a code 19: if styles = Style.code_index[arg] 20: styles.first 21: else 22: Style.new(:code=>arg) 23: end 24: elsif style = Style.list[arg] 25: style 26: elsif HighLine.color_scheme && HighLine.color_scheme[arg] 27: HighLine.color_scheme[arg] 28: elsif arg.is_a?(Hash) 29: Style.new(arg) 30: elsif arg.to_s.downcase =~ /^rgb_([a-f0-9]{6})$/ 31: Style.rgb($1) 32: elsif arg.to_s.downcase =~ /^on_rgb_([a-f0-9]{6})$/ 33: Style.rgb($1).on 34: else 35: raise NameError, "#{arg.inspect} is not a defined Style" 36: end 37: else 38: name = args 39: Style.list[name] || Style.new(:list=>args) 40: end 41: end
This method provides easy access to ANSI color sequences, without the user needing to remember to CLEAR at the end of each sequence. Just pass the string to color, followed by a list of colors you would like it to be affected by. The colors can be HighLine class constants, or symbols (:blue for BLUE, for example). A CLEAR will automatically be embedded to the end of the returned String.
This method returns the original string unchanged if HighLine::use_color? is false.
# File lib/highline.rb, line 377 377: def self.color( string, *colors ) 378: return string unless self.use_color? 379: Style(*colors).color(string) 380: end
In case you just want the color code, without the embedding and the CLEAR
# File lib/highline.rb, line 383 383: def self.color_code(*colors) 384: Style(*colors).code 385: end
Returns the current color scheme.
# File lib/highline.rb, line 82 82: def self.color_scheme 83: @@color_scheme 84: end
Pass ColorScheme to setting to turn set a HighLine color scheme.
# File lib/highline.rb, line 77 77: def self.color_scheme=( setting ) 78: @@color_scheme = setting 79: end
# File lib/highline/string_extensions.rb, line 128 128: def self.colorize_strings 129: ::String.send(:include, StringExtensions) 130: end
For RGB colors:
# File lib/highline.rb, line 150 150: def self.const_missing(name) 151: if name.to_s =~ /^(ON_)?(RGB_)([A-F0-9]{6})(_STYLE)?$/ # RGB color 152: on = $1 153: suffix = $4 154: if suffix 155: code_name = $1.to_s + $2 + $3 156: else 157: code_name = name.to_s 158: end 159: style_name = code_name + '_STYLE' 160: style = Style.rgb($3) 161: style = style.on if on 162: const_set(style_name, style) 163: const_set(code_name, style.code) 164: if suffix 165: style 166: else 167: style.code 168: end 169: else 170: raise NameError, "Bad color or uninitialized constant #{name}" 171: end 172: end
Create an instance of HighLine, connected to the streams input and output.
# File lib/highline.rb, line 178 178: def initialize( input = $stdin, output = $stdout, 179: wrap_at = nil, page_at = nil ) 180: @input = input 181: @output = output 182: if JRUBY 183: require 'java' 184: java_import 'java.io.OutputStreamWriter' 185: java_import 'java.nio.channels.Channels' 186: java_import 'jline.ConsoleReader' 187: java_import 'jline.Terminal' 188: 189: @java_input = Channels.newInputStream($stdin.to_channel) 190: @java_output = OutputStreamWriter.new(Channels.newOutputStream($stdout.to_channel)) 191: @java_terminal = Terminal.getTerminal 192: @java_console = ConsoleReader.new(@java_input, @java_output) 193: @java_console.setUseHistory(false) 194: @java_console.setBellEnabled(true) 195: @java_console.setUsePagination(false) 196: end 197: 198: self.wrap_at = wrap_at 199: self.page_at = page_at 200: 201: @question = nil 202: @answer = nil 203: @menu = nil 204: @header = nil 205: @prompt = nil 206: @gather = nil 207: @answers = nil 208: @key = nil 209: end
For checking if the current version of HighLine supports RGB colors Usage: HighLine.supports_rgb_color? rescue false # rescue for compatibility with older versions Note: color usage also depends on HighLine.use_color being set
# File lib/highline.rb, line 56 56: def self.supports_rgb_color? 57: true 58: end
Pass false to setting to turn off HighLine’s EOF tracking.
# File lib/highline.rb, line 64 64: def self.track_eof=( setting ) 65: @@track_eof = setting 66: end
Returns true if HighLine is currently tracking EOF for input.
# File lib/highline.rb, line 69 69: def self.track_eof? 70: @@track_eof 71: end
Remove color codes from a string
# File lib/highline.rb, line 398 398: def self.uncolor(string) 399: Style.uncolor(string) 400: end
Pass false to setting to turn off HighLine’s color escapes.
# File lib/highline.rb, line 44 44: def self.use_color=( setting ) 45: @@use_color = setting 46: end
Returns true if HighLine is currently using color escapes.
# File lib/highline.rb, line 49 49: def self.use_color? 50: @@use_color 51: end
Returns true if HighLine is currently using a color scheme.
# File lib/highline.rb, line 87 87: def self.using_color_scheme? 88: not @@color_scheme.nil? 89: end
A shortcut to HighLine.ask() a question that only accepts “yes” or “no” answers (“y” and “n” are allowed) and returns true or false (true for “yes”). If provided a true value, character will cause HighLine to fetch a single character response. A block can be provided to further configure the question as in HighLine.ask()
Raises EOFError if input is exhausted.
# File lib/highline.rb, line 227 227: def agree( yes_or_no_question, character = nil ) 228: ask(yes_or_no_question, lambda { |yn| yn.downcase[0] == yy}) do |q| 229: q.validate = /\Ay(?:es)?|no?\Z/ 230: q.responses[:not_valid] = 'Please enter "yes" or "no".' 231: q.responses[:ask_on_error] = :question 232: q.character = character 233: 234: yield q if block_given? 235: end 236: end
This method is the primary interface for user input. Just provide a question to ask the user, the answer_type you want returned, and optionally a code block setting up details of how you want the question handled. See HighLine.say() for details on the format of question, and HighLine::Question for more information about answer_type and what’s valid in the code block.
If @question is set before ask() is called, parameters are ignored and that object (must be a HighLine::Question) is used to drive the process instead.
Raises EOFError if input is exhausted.
# File lib/highline.rb, line 252 252: def ask( question, answer_type = String, &details ) # :yields: question 253: @question ||= Question.new(question, answer_type, &details) 254: 255: return gather if @question.gather 256: 257: # readline() needs to handle it's own output, but readline only supports 258: # full line reading. Therefore if @question.echo is anything but true, 259: # the prompt will not be issued. And we have to account for that now. 260: say(@question) unless (@question.readline and @question.echo == true) 261: begin 262: @answer = @question.answer_or_default(get_response) 263: unless @question.valid_answer?(@answer) 264: explain_error(:not_valid) 265: raise QuestionError 266: end 267: 268: @answer = @question.convert(@answer) 269: 270: if @question.in_range?(@answer) 271: if @question.confirm 272: # need to add a layer of scope to ask a question inside a 273: # question, without destroying instance data 274: context_change = self.class.new(@input, @output, @wrap_at, @page_at) 275: if @question.confirm == true 276: confirm_question = "Are you sure? " 277: else 278: # evaluate ERb under initial scope, so it will have 279: # access to @question and @answer 280: template = ERB.new(@question.confirm, nil, "%") 281: confirm_question = template.result(binding) 282: end 283: unless context_change.agree(confirm_question) 284: explain_error(nil) 285: raise QuestionError 286: end 287: end 288: 289: @answer 290: else 291: explain_error(:not_in_range) 292: raise QuestionError 293: end 294: rescue QuestionError 295: retry 296: rescue ArgumentError, NameError => error 297: raise if error.is_a?(NoMethodError) 298: if error.message =~ /ambiguous/ 299: # the assumption here is that OptionParser::Completion#complete 300: # (used for ambiguity resolution) throws exceptions containing 301: # the word 'ambiguous' whenever resolution fails 302: explain_error(:ambiguous_completion) 303: else 304: explain_error(:invalid_type) 305: end 306: retry 307: rescue Question::NoAutoCompleteMatch 308: explain_error(:no_completion) 309: retry 310: ensure 311: @question = nil # Reset Question object. 312: end 313: end
This method is HighLine’s menu handler. For simple usage, you can just pass all the menu items you wish to display. At that point, choose() will build and display a menu, walk the user through selection, and return their choice amoung the provided items. You might use this in a case statement for quick and dirty menus.
However, choose() is capable of much more. If provided, a block will be passed a HighLine::Menu object to configure. Using this method, you can customize all the details of menu handling from index display, to building a complete shell-like menuing system. See HighLine::Menu for all the methods it responds to.
Raises EOFError if input is exhausted.
# File lib/highline.rb, line 330 330: def choose( *items, &details ) 331: @menu = @question = Menu.new(&details) 332: @menu.choices(*items) unless items.empty? 333: 334: # Set _answer_type_ so we can double as the Question for ask(). 335: @menu.answer_type = if @menu.shell 336: lambda do |command| # shell-style selection 337: first_word = command.to_s.split.first || "" 338: 339: options = @menu.options 340: options.extend(OptionParser::Completion) 341: answer = options.complete(first_word) 342: 343: if answer.nil? 344: raise Question::NoAutoCompleteMatch 345: end 346: 347: [answer.last, command.sub(/^\s*#{first_word}\s*/, "")] 348: end 349: else 350: @menu.options # normal menu selection, by index or name 351: end 352: 353: # Provide hooks for ERb layouts. 354: @header = @menu.header 355: @prompt = @menu.prompt 356: 357: if @menu.shell 358: selected = ask("Ignored", @menu.answer_type) 359: @menu.select(self, *selected) 360: else 361: selected = ask("Ignored", @menu.answer_type) 362: @menu.select(self, selected) 363: end 364: end
Works as an instance method, same as the class method
# File lib/highline.rb, line 393 393: def color(*args) 394: self.class.color(*args) 395: end
Works as an instance method, same as the class method
# File lib/highline.rb, line 388 388: def color_code(*colors) 389: self.class.color_code(*colors) 390: end
This method is a utility for quickly and easily laying out lists. It can be accessed within ERb replacements of any text that will be sent to the user.
The only required parameter is items, which should be the Array of items to list. A specified mode controls how that list is formed and option has different effects, depending on the mode. Recognized modes are:
:columns_across | items will be placed in columns, flowing from left to right. If given, option is the number of columns to be used. When absent, columns will be determined based on wrap_at or a default of 80 characters. |
:columns_down | Identical to :columns_across, save flow goes down. |
:uneven_columns_across | Like :columns_across but each column is sized independently. |
:uneven_columns_down | Like :columns_down but each column is sized independently. |
:inline | All items are placed on a single line. The last two items are separated by option or a default of “ or “. All other items are separated by “, “. |
:rows | The default mode. Each of the items is placed on it’s own line. The option parameter is ignored in this mode. |
Each member of the items Array is passed through ERb and thus can contain their own expansions. Color escape expansions do not contribute to the final field width.
# File lib/highline.rb, line 440 440: def list( items, mode = :rows, option = nil ) 441: items = items.to_ary.map do |item| 442: ERB.new(item, nil, "%").result(binding) 443: end 444: 445: if items.empty? 446: "" 447: else 448: case mode 449: when :inline 450: option = " or " if option.nil? 451: 452: if items.size == 1 453: items.first 454: else 455: items[0..2].join(", ") + "#{option}#{items.last}" 456: end 457: when :columns_across, :columns_down 458: max_length = actual_length( 459: items.max { |a, b| actual_length(a) <=> actual_length(b) } 460: ) 461: 462: if option.nil? 463: limit = @wrap_at || 80 464: option = (limit + 2) / (max_length + 2) 465: end 466: 467: items = items.map do |item| 468: pad = max_length + (item.to_s.length - actual_length(item)) 469: "%-#{pad}s" % item 470: end 471: row_count = (items.size / option.to_f).ceil 472: 473: if mode == :columns_across 474: rows = Array.new(row_count) { Array.new } 475: items.each_with_index do |item, index| 476: rows[index / option] << item 477: end 478: 479: rows.map { |row| row.join(" ") + "\n" }.join 480: else 481: columns = Array.new(option) { Array.new } 482: items.each_with_index do |item, index| 483: columns[index / row_count] << item 484: end 485: 486: list = "" 487: columns.first.size.times do |index| 488: list << columns.map { |column| column[index] }. 489: compact.join(" ") + "\n" 490: end 491: list 492: end 493: when :uneven_columns_across 494: if option.nil? 495: limit = @wrap_at || 80 496: items.size.downto(1) do |column_count| 497: row_count = (items.size / column_count.to_f).ceil 498: rows = Array.new(row_count) { Array.new } 499: items.each_with_index do |item, index| 500: rows[index / column_count] << item 501: end 502: 503: widths = Array.new(column_count, 0) 504: rows.each do |row| 505: row.each_with_index do |field, column| 506: size = actual_length(field) 507: widths[column] = size if size > widths[column] 508: end 509: end 510: 511: if column_count == 1 or 512: widths.inject(0) { |sum, n| sum + n + 2 } <= limit + 2 513: return rows.map { |row| 514: row.zip(widths).map { |field, i| 515: "%-#{i + (field.to_s.length - actual_length(field))}s" % field 516: }.join(" ") + "\n" 517: }.join 518: end 519: end 520: else 521: row_count = (items.size / option.to_f).ceil 522: rows = Array.new(row_count) { Array.new } 523: items.each_with_index do |item, index| 524: rows[index / option] << item 525: end 526: 527: widths = Array.new(option, 0) 528: rows.each do |row| 529: row.each_with_index do |field, column| 530: size = actual_length(field) 531: widths[column] = size if size > widths[column] 532: end 533: end 534: 535: return rows.map { |row| 536: row.zip(widths).map { |field, i| 537: "%-#{i + (field.to_s.length - actual_length(field))}s" % field 538: }.join(" ") + "\n" 539: }.join 540: end 541: when :uneven_columns_down 542: if option.nil? 543: limit = @wrap_at || 80 544: items.size.downto(1) do |column_count| 545: row_count = (items.size / column_count.to_f).ceil 546: columns = Array.new(column_count) { Array.new } 547: items.each_with_index do |item, index| 548: columns[index / row_count] << item 549: end 550: 551: widths = Array.new(column_count, 0) 552: columns.each_with_index do |column, i| 553: column.each do |field| 554: size = actual_length(field) 555: widths[i] = size if size > widths[i] 556: end 557: end 558: 559: if column_count == 1 or 560: widths.inject(0) { |sum, n| sum + n + 2 } <= limit + 2 561: list = "" 562: columns.first.size.times do |index| 563: list << columns.zip(widths).map { |column, width| 564: field = column[index] 565: "%-#{width + (field.to_s.length - actual_length(field))}s" % 566: field 567: }.compact.join(" ").strip + "\n" 568: end 569: return list 570: end 571: end 572: else 573: row_count = (items.size / option.to_f).ceil 574: columns = Array.new(option) { Array.new } 575: items.each_with_index do |item, index| 576: columns[index / row_count] << item 577: end 578: 579: widths = Array.new(option, 0) 580: columns.each_with_index do |column, i| 581: column.each do |field| 582: size = actual_length(field) 583: widths[i] = size if size > widths[i] 584: end 585: end 586: 587: list = "" 588: columns.first.size.times do |index| 589: list << columns.zip(widths).map { |column, width| 590: field = column[index] 591: "%-#{width + (field.to_s.length - actual_length(field))}s" % field 592: }.compact.join(" ").strip + "\n" 593: end 594: return list 595: end 596: else 597: items.map { |i| "#{i}\n" }.join 598: end 599: end 600: end
Returns the number of columns for the console, or a default it they cannot be determined.
# File lib/highline.rb, line 654 654: def output_cols 655: return 80 unless @output.tty? 656: terminal_size.first 657: rescue 658: return 80 659: end
Returns the number of rows for the console, or a default if they cannot be determined.
# File lib/highline.rb, line 665 665: def output_rows 666: return 24 unless @output.tty? 667: terminal_size.last 668: rescue 669: return 24 670: end
Set to an integer value to cause HighLine to page output lines over the indicated line limit. When nil, the default, no paging occurs. If set to :auto, HighLine will attempt to determing the rows available for the @output or use a sensible default.
# File lib/highline.rb, line 646 646: def page_at=( setting ) 647: @page_at = setting == :auto ? output_rows - 2 : setting 648: end
The basic output method for HighLine objects. If the provided statement ends with a space or tab character, a newline will not be appended (output will be flush()ed). All other cases are passed straight to Kernel.puts().
The statement parameter is processed as an ERb template, supporting embedded Ruby code. The template is evaluated with a binding inside the HighLine instance, providing easy access to the ANSI color constants and the HighLine.color() method.
# File lib/highline.rb, line 612 612: def say( statement ) 613: statement = statement.to_str 614: return unless statement.length > 0 615: 616: template = ERB.new(statement, nil, "%") 617: statement = template.result(binding) 618: 619: statement = wrap(statement) unless @wrap_at.nil? 620: statement = page_print(statement) unless @page_at.nil? 621: 622: if statement[1, 1] == " " or statement[1, 1] == "\t" 623: @output.print(statement) 624: @output.flush 625: else 626: @output.puts(statement) 627: end 628: end
Works as an instance method, same as the class method
# File lib/highline.rb, line 403 403: def uncolor(string) 404: self.class.uncolor(string) 405: end
Set to an integer value to cause HighLine to wrap output lines at the indicated character limit. When nil, the default, no wrapping occurs. If set to :auto, HighLine will attempt to determing the columns available for the @output or use a sensible default.
# File lib/highline.rb, line 636 636: def wrap_at=( setting ) 637: @wrap_at = setting == :auto ? output_cols : setting 638: end
Returns the length of the passed string_with_escapes, minus and color sequence escapes.
# File lib/highline.rb, line 972 972: def actual_length( string_with_escapes ) 973: string_with_escapes.to_s.gsub(/\e\[\d{1,2}m/, "").length 974: end
Ask user if they wish to continue paging output. Allows them to type “q” to cancel the paging process.
# File lib/highline.rb, line 937 937: def continue_paging? 938: command = HighLine.new(@input, @output).ask( 939: "-- press enter/return to continue or q to stop -- " 940: ) { |q| q.character = true } 941: command !~ /\A[qQ]\Z/ # Only continue paging if Q was not hit. 942: end
A helper method for sending the output stream and error and repeat of the question.
# File lib/highline.rb, line 678 678: def explain_error( error ) 679: say(@question.responses[error]) unless error.nil? 680: if @question.responses[:ask_on_error] == :question 681: say(@question) 682: elsif @question.responses[:ask_on_error] 683: say(@question.responses[:ask_on_error]) 684: end 685: end
Collects an Array/Hash full of answers as described in HighLine::Question.gather().
Raises EOFError if input is exhausted.
# File lib/highline.rb, line 693 693: def gather( ) 694: @gather = @question.gather 695: @answers = [ ] 696: original_question = @question 697: 698: @question.gather = false 699: 700: case @gather 701: when Integer 702: @answers << ask(@question) 703: @gather -= 1 704: 705: original_question.question = "" 706: until @gather.zero? 707: @question = original_question 708: @answers << ask(@question) 709: @gather -= 1 710: end 711: when ::String, Regexp 712: @answers << ask(@question) 713: 714: original_question.question = "" 715: until (@gather.is_a?(::String) and @answers.last.to_s == @gather) or 716: (@gather.is_a?(Regexp) and @answers.last.to_s =~ @gather) 717: @question = original_question 718: @answers << ask(@question) 719: end 720: 721: @answers.pop 722: when Hash 723: @answers = { } 724: @gather.keys.sort.each do |key| 725: @question = original_question 726: @key = key 727: @answers[key] = ask(@question) 728: end 729: end 730: 731: @answers 732: end
Read a line of input from the input stream and process whitespace as requested by the Question object.
If Question’s readline property is set, that library will be used to fetch input. WARNING: This ignores the currently set input stream.
Raises EOFError if input is exhausted.
# File lib/highline.rb, line 743 743: def get_line( ) 744: if @question.readline 745: require "readline" # load only if needed 746: 747: # capture say()'s work in a String to feed to readline() 748: old_output = @output 749: @output = StringIO.new 750: say(@question) 751: question = @output.string 752: @output = old_output 753: 754: # prep auto-completion 755: Readline.completion_proc = lambda do |string| 756: @question.selection.grep(/\A#{Regexp.escape(string)}/) 757: end 758: 759: # work-around ugly readline() warnings 760: old_verbose = $VERBOSE 761: $VERBOSE = nil 762: raw_answer = Readline.readline(question, true) 763: if raw_answer.nil? 764: if @@track_eof 765: raise EOFError, "The input stream is exhausted." 766: else 767: raw_answer = String.new # Never return nil 768: end 769: end 770: answer = @question.change_case( 771: @question.remove_whitespace(raw_answer)) 772: $VERBOSE = old_verbose 773: 774: answer 775: else 776: if JRUBY 777: enable_echo_afterwards = @java_terminal.isEchoEnabled 778: @java_terminal.disableEcho 779: begin 780: raw_answer = @java_console.readLine(nil, nil) 781: ensure 782: @java_terminal.enableEcho if enable_echo_afterwards 783: end 784: else 785: raise EOFError, "The input stream is exhausted." if @@track_eof and 786: @input.eof? 787: raw_answer = @input.gets 788: end 789: 790: @question.change_case(@question.remove_whitespace(raw_answer)) 791: end 792: end
Return a line or character of input, as requested for this question. Character input will be returned as a single character String, not an Integer.
This question’s first_answer will be returned instead of input, if set.
Raises EOFError if input is exhausted.
# File lib/highline.rb, line 813 813: def get_response( ) 814: return @question.first_answer if @question.first_answer? 815: 816: stty = (CHARACTER_MODE == "stty") 817: 818: if @question.character.nil? 819: if @question.echo == true and @question.limit.nil? 820: get_line 821: else 822: if JRUBY 823: enable_echo_afterwards = @java_terminal.isEchoEnabled 824: @java_terminal.disableEcho 825: elsif stty 826: raw_no_echo_mode 827: end 828: 829: line = "" 830: backspace_limit = 0 831: begin 832: 833: while character = get_single_character(stty) 834: # honor backspace and delete 835: if character == 127 or character == 8 836: line.slice!(1, 1) 837: backspace_limit -= 1 838: else 839: line << character.chr 840: backspace_limit = line.size 841: end 842: # looking for carriage return (decimal 13) or 843: # newline (decimal 10) in raw input 844: break if character == 13 or character == 10 845: if @question.echo != false 846: if character == 127 or character == 8 847: # only backspace if we have characters on the line to 848: # eliminate, otherwise we'll tromp over the prompt 849: if backspace_limit >= 0 then 850: @output.print("\b#{HighLine.Style(:erase_char).code}") 851: else 852: # do nothing 853: end 854: else 855: if @question.echo == true 856: @output.print(character.chr) 857: else 858: @output.print(@question.echo) 859: end 860: end 861: @output.flush 862: end 863: break if @question.limit and line.size == @question.limit 864: end 865: ensure 866: if JRUBY 867: @java_terminal.enableEcho if enable_echo_afterwards 868: elsif stty 869: restore_mode 870: end 871: end 872: if @question.overwrite 873: @output.print("\r#{HighLine.Style(:erase_line).code}") 874: @output.flush 875: else 876: say("\n") 877: end 878: 879: @question.change_case(@question.remove_whitespace(line)) 880: end 881: else 882: if JRUBY 883: enable_echo_afterwards = @java_terminal.isEchoEnabled 884: @java_terminal.disableEcho 885: end 886: begin 887: if @question.character == :getc 888: response = get_single_character(true).chr 889: else 890: response = get_single_character(stty).chr 891: if @question.overwrite 892: @output.print("\r#{HighLine.Style(:erase_line).code}") 893: @output.flush 894: else 895: echo = if @question.echo == true 896: response 897: elsif @question.echo != false 898: @question.echo 899: else 900: "" 901: end 902: say("#{echo}\n") 903: end 904: end 905: ensure 906: if JRUBY 907: @java_terminal.enableEcho if enable_echo_afterwards 908: end 909: end 910: @question.change_case(response) 911: end 912: end
# File lib/highline.rb, line 794 794: def get_single_character(is_stty) 795: if JRUBY 796: @java_console.readVirtualKey 797: elsif is_stty 798: @input.getbyte 799: else 800: get_character(@input) 801: end 802: end
Page print a series of at most page_at lines for output. After each page is printed, HighLine will pause until the user presses enter/return then display the next page of data.
Note that the final page of output is not printed, but returned instead. This is to support any special handling for the final sequence.
# File lib/highline.rb, line 922 922: def page_print( output ) 923: lines = output.scan(/[^\n]*\n?/) 924: while lines.size > @page_at 925: @output.puts lines.slice!(0...@page_at).join 926: @output.puts 927: # Return last line if user wants to abort paging 928: return (["...\n"] + lines.slice(2,1)).join unless continue_paging? 929: end 930: return lines.join 931: end
Wrap a sequence of lines at wrap_at characters per line. Existing newlines will not be affected by this process, but additional newlines may be added.
# File lib/highline.rb, line 949 949: def wrap( text ) 950: wrapped = [ ] 951: text.each_line do |line| 952: while line =~ /([^\n]{#{@wrap_at + 1},})/ 953: search = $1.dup 954: replace = $1.dup 955: if index = replace.rindex(" ", @wrap_at) 956: replace[index, 1] = "\n" 957: replace.sub!(/\n[ \t]+/, "\n") 958: line.sub!(search, replace) 959: else 960: line[$~.begin(1) + @wrap_at, 0] = "\n" 961: end 962: end 963: wrapped << line 964: end 965: return wrapped.join 966: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.