Browse files

Added a menu to display temporary information below the current line

  • Loading branch information...
1 parent a65160a commit 8e506e57126029bfffef00894c75446691fd9a12 @Mon-Ouie committed Oct 2, 2012
Showing with 102 additions and 5 deletions.
  1. +1 −0 lib/coolline.rb
  2. +12 −4 lib/coolline/coolline.rb
  3. +88 −0 lib/coolline/menu.rb
  4. +1 −1 repl.rb
View
1 lib/coolline.rb
@@ -1,6 +1,7 @@
require 'coolline/handler'
require 'coolline/history'
require 'coolline/editor'
+require 'coolline/menu'
require 'coolline/coolline'
View
16 lib/coolline/coolline.rb
@@ -127,6 +127,8 @@ def initialize
yield self if block_given?
@history ||= History.new(@history_file, @history_size)
+
+ @menu = Menu.new(@input, @output)
end
# @return [IO]
@@ -173,6 +175,9 @@ def word_boundaries=(array)
# @return [String] Current prompt
attr_accessor :prompt
+ # @return [Menu]
+ attr_accessor :menu
+
# Reads a line from the terminal
# @param [String] prompt Characters to print before each line
def readline(prompt = ">> ")
@@ -195,6 +200,8 @@ def readline(prompt = ">> ")
@history << @line
until (char = @input.getch) == "\r"
+ @menu.erase
+
handle(char)
return if @should_exit
@@ -205,6 +212,8 @@ def readline(prompt = ">> ")
render
end
+ @menu.erase
+
print "\n"
@history[-1] = @line if @history.size != 0
@@ -254,11 +263,10 @@ def render
break if i >= end_index
end
end
-
- if @pos < left_width + 1
- print "\e[#{prompt_size + @pos + 1}G"
- end
end
+
+ @menu.display
+ print "\e[#{[prompt_size + @pos + 1, width].min}G"
end
# Reads a line with no prompt
View
88 lib/coolline/menu.rb
@@ -0,0 +1,88 @@
+class Coolline
+ # A menu allows to display some information on a rectangle below the cursor.
+ #
+ # It displays a string or a list of strings until the user presses another
+ # key.
+ class Menu
+ def initialize(input, output)
+ @input = input
+ @output = output
+
+ @string = ""
+
+ @last_line_count = 0
+ end
+
+ # Renders the menu below the current line.
+ #
+ # This will ensure not to draw to much, so that the line currently being
+ # edited will always stay visible.
+ #
+ # Once the menu is drawn, the cursor returns to the correct line.
+ def display
+ # An empty string shouldn't be treated like a 1-line string.
+ return if @string.empty?
+
+ height, width = @input.winsize
+
+ lines = @string.lines.to_a
+
+ lines[0, height - 1].each do |line|
+ @output.print "\n\r"
+ @output.print line[0, width].chomp
+ end
+
+ go_to_line([0, height - lines.size].max)
+ reset_color
+
+ @last_line_count = [height - 1, lines.size].min
+ end
+
+ # Erases anything that had been written by the menu.
+ #
+ # This allows to hide the menu once it is no longer relevant.
+ #
+ # Notice it can only work by knowing how many lines the menu drew on the
+ # screen last time it was called, and assuming the terminal size didn't
+ # change.
+ def erase
+ return if @last_line_count.zero?
+
+ self.string = ""
+
+ @last_line_count.times do
+ go_to_next_line
+ erase_line
+ end
+
+ go_to_line(@output.winsize[0] - @last_line_count)
+
+ @last_line_count = 0
+
+ reset_color
+ end
+
+ # Resets the current ansi color codes.
+ def reset_color
+ print "\e[0m"
+ end
+
+ # Erases the current line.
+ def erase_line
+ @output.print "\e[0K"
+ end
+
+ # Moves to the beginning of the next line.
+ def go_to_next_line
+ @output.print "\e[E"
+ end
+
+ # Moves to the cursor to the beginning of the given (1-indexed) line.
+ def go_to_line(id)
+ @output.print "\e[#{id};1H"
+ end
+
+ # @return [String] Information to be displayed
+ attr_accessor :string
+ end
+end
View
2 repl.rb
@@ -5,7 +5,7 @@
require 'pp'
Coolline.bind "\C-z" do |c|
- puts c.object_id
+ c.menu.string = "Coolline object id: #{c.object_id}"
end
cool = Coolline.new do |c|

0 comments on commit 8e506e5

Please sign in to comment.