mini_term 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Test mapped sequences coming from the keyboard.
4
+ #
5
+
6
+ require_relative '../lib/mini_term'
7
+
8
+ MiniTerm.open
9
+ no_map = false
10
+ $mini_term_exit_info = {}
11
+
12
+ # Process any arguments.
13
+ ARGV.each do |arg|
14
+ if arg == '--no-map'
15
+ no_map = true
16
+ else
17
+ path = File.absolute_path(arg)
18
+ puts "Requiring '#{path}'"
19
+ require path
20
+ end
21
+ end
22
+
23
+ puts
24
+
25
+ # Load the sample Windows mapping.
26
+ unless MiniTerm.map_types.include?(:windows)
27
+ MiniTerm.add_map(:windows) do |map|
28
+
29
+ unless no_map
30
+
31
+ # Make local copies of the prefixes for brevity.
32
+ x00 = MiniTerm::PREFIX_00
33
+ xe0 = MiniTerm::PREFIX_E0
34
+
35
+ map[" ".."~"] = :insert_text
36
+
37
+ #Left Arrows
38
+ map[x00+"K"] = :go_left
39
+ map[xe0+"K"] = :go_left
40
+
41
+ map[x00+"s"] = :word_left
42
+ map[xe0+"s"] = :word_left
43
+
44
+ #Right Arrows
45
+ map[x00+"M"] = :go_right
46
+ map[xe0+"M"] = :go_right
47
+
48
+ map[x00+"t"] = :word_right
49
+ map[xe0+"t"] = :word_right
50
+
51
+ #Up Arrows
52
+ map[x00+"H"] = :previous_history
53
+ map[xe0+"H"] = :previous_history
54
+
55
+ #Down Arrows
56
+ map[x00+"P"] = :next_history
57
+ map[xe0+"P"] = :next_history
58
+
59
+ #The Home keys
60
+ map[x00+"G"] = :go_home
61
+ map[xe0+"G"] = :go_home
62
+
63
+ #The End keys
64
+ map[x00+"O"] = :go_end
65
+ map[xe0+"O"] = :go_end
66
+
67
+ #The Backspace key
68
+ map["\x08"] = :delete_left
69
+
70
+ #The Delete keys
71
+ map["\x7F"] = :delete_right
72
+ map[x00+"S"] = :delete_right
73
+ map[xe0+"S"] = :delete_right
74
+
75
+ #Auto-completion.
76
+ map["\t"] = :auto_complete
77
+
78
+ #The Enter key
79
+ map["\x0D"] = :enter
80
+
81
+ #The Escape key
82
+ map["\e"] = :cancel
83
+ end
84
+
85
+ #End of Input
86
+ map["\x1A"] = :end_of_input
87
+
88
+ $mini_term_exit_info[:windows] = [:end_of_input, "Ctrl+z"]
89
+ end
90
+ end
91
+
92
+ # Load the sample ANSI mapping.
93
+ unless MiniTerm.map_types.include?(:ansi)
94
+ MiniTerm.add_map(:ansi) do |map|
95
+
96
+ unless no_map
97
+ map[" ".."~"] = :insert_text
98
+
99
+ #Left Arrows
100
+ map["\e[D"] = :go_left
101
+ map["\eOD"] = :go_left
102
+ map["\x02"] = :go_left
103
+
104
+ map["\e[1;5D"] = :word_left
105
+ map["\eb"] = :word_left
106
+
107
+ #Right Arrows
108
+ map["\e[C"] = :go_right
109
+ map["\eOC"] = :go_right
110
+ map["\x06"] = :go_right
111
+
112
+ map["\e[1;5C"] = :word_right
113
+ map["\ef"] = :word_right
114
+
115
+ #Up Arrows
116
+ map["\e[A"] = :previous_history
117
+ map["\eOA"] = :previous_history
118
+ map["\x12"] = :previous_history
119
+
120
+ #Down Arrows
121
+ map["\e[B"] = :next_history
122
+ map["\eOB"] = :next_history
123
+
124
+ #The Home keys
125
+ map["\e[H"] = :go_home
126
+ map["\eOH"] = :go_home
127
+ map["\x01"] = :go_home
128
+
129
+ #The End keys
130
+ map["\e[F"] = :go_end
131
+ map["\eOF"] = :go_end
132
+ map["\x05"] = :go_end
133
+
134
+ #The Backspace key
135
+ map["\x7F"] = :delete_left
136
+ map["\x08"] = :delete_left
137
+ map["\x15"] = :delete_all_left
138
+
139
+ #The Delete keys
140
+ map["\x1F"] = :delete_right
141
+ map["\e[3~"] = :delete_right
142
+ map["\x0B"] = :delete_all_right
143
+
144
+ #Auto-completion.
145
+ map["\t"] = :auto_complete
146
+
147
+ #The Enter key
148
+ map["\x0D"] = :enter
149
+
150
+ #The Cancel key
151
+ map["\f"] = :cancel
152
+ end
153
+
154
+ #End of Input
155
+ map["\ez"] = :end_of_input
156
+
157
+ $mini_term_exit_info[:ansi] = [:end_of_input, "Alt+z"]
158
+ end
159
+ end
160
+
161
+ exit_action, exit_desc = $mini_term_exit_info[MiniTerm::TERM_TYPE]
162
+ puts "Testing Mapped Keyboard input. Press #{exit_desc} to quit."
163
+
164
+ puts "Current maps = #{MiniTerm.map_types.inspect}"
165
+ puts "Current term type = #{MiniTerm::TERM_TYPE.inspect}"
166
+ puts
167
+
168
+ loop do
169
+ mapped = MiniTerm.get_mapped_char
170
+ puts "action = #{mapped[0].inspect}, text = #{mapped[1].chars.inspect}"
171
+ break if mapped[0] == exit_action
172
+ end
173
+
174
+ MiniTerm.close
175
+ puts
176
+ puts
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # It's snowing!
4
+ #
5
+
6
+ require_relative '../lib/mini_term'
7
+
8
+ begin
9
+ MiniTerm.open
10
+
11
+ if ARGV[0]
12
+ start = ARGV[0].hex
13
+
14
+ if ARGV[1]
15
+ finish = ARGV[1].hex
16
+ snow_flakes = (start..finish).map {|c| c.chr(Encoding::UTF_8)}
17
+ else
18
+ snow_flakes = [start.chr(Encoding::UTF_8)]
19
+ end
20
+
21
+ else
22
+ snow_flakes = ["*"]
23
+ end
24
+
25
+ gen = Random.new
26
+
27
+ y_limit, x_limit = MiniTerm.term_info
28
+
29
+ loop do
30
+ x = gen.rand(x_limit)
31
+ y = gen.rand(y_limit)
32
+
33
+ if (x < (x_limit-1)) || (y < (y_limit-1))
34
+ MiniTerm.set_posn(row: y, column: x)
35
+ snow_flakes.shuffle!
36
+ MiniTerm.print(snow_flakes[0])
37
+ end
38
+
39
+ x = gen.rand(x_limit)
40
+ y = gen.rand(y_limit)
41
+
42
+ if (x < (x_limit-1)) || (y < (y_limit-1))
43
+ MiniTerm.set_posn(row: y, column: x)
44
+ MiniTerm.print(" ")
45
+ end
46
+
47
+ break if MiniTerm.raw(&:has_raw_char?)
48
+ end
49
+
50
+ ensure
51
+ MiniTerm.getch
52
+ MiniTerm.clear_screen
53
+ MiniTerm.close
54
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Sample the first 65536 code points.
4
+ #
5
+
6
+ # Compute the range of code points to be displayed.
7
+ last_code, first_code = ARGV.map(&:hex).reverse
8
+ first_code ||= 32
9
+ last_code ||= 65536
10
+ last_code = 65536 if last_code > 65536
11
+
12
+ puts "Code points in the range: #{"%X"%first_code}...#{"%X"%last_code}"
13
+
14
+ # Compute the 64 element lines to be displayed.
15
+ first_line = first_code/64
16
+ last_line = (last_code+63)/64
17
+
18
+ # Display the code points.
19
+ (first_line...last_line).each do |line|
20
+ print "%4X " % (line*64)
21
+
22
+ 8.times do |bundle|
23
+ print ' '
24
+ start = line*64 + bundle*8
25
+ finish = start+8
26
+
27
+ (start...finish).each do |code|
28
+ if code.between?(first_code, last_code) && code >= 32
29
+ begin
30
+ print code.chr(Encoding::UTF_8)
31
+ rescue RangeError
32
+ print 'E'
33
+ end
34
+ else
35
+ print ' '
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ puts
42
+ end
data/exe/raw_key_test ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Test raw byte sequences coming from the keyboard.
4
+ #
5
+
6
+ require_relative '../lib/mini_term'
7
+
8
+ puts "Testing Raw Keyboard input. Press Q to quit."
9
+ MiniTerm.open(pass_ctrl_s: true, pass_ctrl_c: true)
10
+ key = nil
11
+
12
+ MiniTerm.raw do |i|
13
+ until key == "Q"
14
+ key = MiniTerm.get_raw_char
15
+ print "[" + "%02X" % key.bytes[0] + "]"
16
+ end
17
+ end
18
+
19
+ MiniTerm.close
20
+ puts
21
+ puts
data/irbt.rb ADDED
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+ # An IRB + mini_term test session.
3
+
4
+ require 'irb'
5
+
6
+ puts "Starting an IRB console with mini_term loaded."
7
+
8
+ if ARGV[0] == 'local'
9
+ require_relative 'lib/mini_term'
10
+ puts "mini_term loaded locally: #{MiniTerm::VERSION}"
11
+
12
+ ARGV.shift
13
+ else
14
+ require 'mini_term'
15
+ puts "mini_term loaded from gem: #{MiniTerm::VERSION}"
16
+ end
17
+
18
+ IRB.start
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+
3
+ # MiniTerm needs to put text on the screen! (ANSI Specific Code)
4
+ module MiniTerm
5
+
6
+ # Put some text onto the screen.
7
+ def self.print(text)
8
+ STDOUT.print(text)
9
+ self
10
+ end
11
+
12
+ # Sound a beep
13
+ def self.beep
14
+ STDERR.write(BELL)
15
+ STDERR.flush
16
+ self
17
+ end
18
+
19
+ # Clear the screen and home the cursor
20
+ def self.clear_screen
21
+ STDOUT.print("\e[f\e[2J")
22
+ self
23
+ end
24
+
25
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+
3
+ # Get input from the user in raw mode. (ANSI Specific Code)
4
+ module MiniTerm
5
+
6
+ # Is there a character waiting?
7
+ def self.has_raw_char?
8
+ raw { STDIN.ready? }
9
+ end
10
+
11
+ #Get a uncooked character keystroke.
12
+ def self.get_raw_char
13
+ fail MiniTermNotRaw, "Not in raw mode." unless raw?
14
+ STDIN.getch
15
+ end
16
+
17
+ private
18
+
19
+ # Get user input uncooked, with no echo or buffering.
20
+ def self.begin_raw_input
21
+ @raw_input = true
22
+ STDIN.raw!
23
+ end
24
+
25
+ # Done with raw mode for now.
26
+ def self.end_raw_input
27
+ STDIN.cooked!
28
+ @raw_input = false
29
+ end
30
+
31
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ # Give MiniTerm control of the cursor position. (ANSI Specific Code)
4
+ module MiniTerm
5
+
6
+ # Set the row (optional) and column of the cursor.
7
+ def self.set_posn(row: nil, column:)
8
+ if row
9
+ STDOUT.print("\e[#{row};#{column}f")
10
+ else
11
+ STDOUT.print("\e#{column}G")
12
+ end
13
+
14
+ self
15
+ end
16
+
17
+ end
@@ -0,0 +1,11 @@
1
+ # coding: utf-8
2
+
3
+ # Get size info about the console window. (ANSI Specific Code)
4
+ module MiniTerm
5
+
6
+ # Get term_info [rows, cols]
7
+ def self.term_info
8
+ IO.console.winsize
9
+ end
10
+
11
+ end
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+
3
+ require 'io/console'
4
+ require 'io/wait'
5
+
6
+ require_relative 'ansi/term_info'
7
+ require_relative 'ansi/set_posn'
8
+ require_relative 'ansi/raw_input'
9
+ require_relative 'ansi/output'
10
+
11
+ module MiniTerm
12
+
13
+ # What options are supported in this ANSI mode?
14
+ VALID_OPTIONS = [:quiet, :strict].freeze
15
+
16
+ end
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+
3
+ # Common control character definitions. (Common Code)
4
+ module MiniTerm
5
+
6
+ BELL = "\x07"
7
+ LINE_FEED = "\x0A"
8
+ CARRIAGE_RETURN = "\x0D"
9
+ ESCAPE = "\x1B"
10
+
11
+ # These are mostly used in Windows maps.
12
+ PREFIX_00 = 0x00.chr
13
+ PREFIX_E0 = 0xE0.chr
14
+
15
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+
3
+ # Get input from the user in mapped mode. (Common Code)
4
+ module MiniTerm
5
+
6
+ # The different keyboard maps available.
7
+ @maps = Hash.new do |_h, key|
8
+ fail MiniTermNoMap, "No mapping for term type #{key.inspect}."
9
+ end
10
+
11
+ # What terminal types are mapped?
12
+ def self.map_types
13
+ @maps.keys
14
+ end
15
+
16
+ # Add a terminal mapping.
17
+ def self.add_map(type, &defn_block)
18
+ @maps[type] = Mapper.new(&defn_block)
19
+ end
20
+
21
+ # Get a mapped character. Note: The block is for testing only.
22
+ def self.get_mapped_char(&block)
23
+ mapper = @maps[MiniTerm::TERM_TYPE]
24
+ proc = block_given? ? block : Proc.new { get_raw_char }
25
+ raw { mapper.get_mapped_char(&proc) }
26
+ end
27
+
28
+ end
@@ -0,0 +1,58 @@
1
+ # coding: utf-8
2
+
3
+ # A input text mapper. (Common Code)
4
+ module MiniTerm
5
+
6
+ # Translate raw input to mapped commands.
7
+ class Mapper
8
+
9
+ #Set up the keystroke mapper.
10
+ def initialize
11
+ @map = Hash.new {|_h, key| [:unmapped, key]}
12
+ yield self
13
+ end
14
+
15
+ #Add a map entry
16
+ def []=(indexes, value)
17
+ indexes = [indexes] unless indexes.is_a?(Range)
18
+
19
+ indexes.each do |index|
20
+ process_non_terminals(index)
21
+
22
+ if @map.has_key?(index)
23
+ fail MiniTermKME, "Duplicate entry #{index.inspect}"
24
+ end
25
+
26
+ @map[index] = [value, index]
27
+ end
28
+ end
29
+
30
+ #Handle the preamble characters in the command sequence.
31
+ def process_non_terminals(index)
32
+ seq = ""
33
+
34
+ index.chop.chars.each do |char|
35
+ seq << char
36
+
37
+ if @map.has_key?(seq) && @map[seq]
38
+ fail MiniTermKME, "Ambiguous entry #{index.inspect}"
39
+ end
40
+
41
+ @map[seq] = false
42
+ end
43
+ end
44
+
45
+ #Get a mapped input sequence.
46
+ def get_mapped_char
47
+ key_seq, key_cmd = "", nil
48
+
49
+ begin
50
+ key_seq << yield
51
+ key_cmd = @map[key_seq]
52
+ end until key_cmd
53
+
54
+ key_cmd
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+
3
+ # Get input from the user in raw mode. (Common Code)
4
+ module MiniTerm
5
+
6
+ # Is input raw or cooked?
7
+ @raw_input = false
8
+
9
+ # Is raw mode in effect?
10
+ def self.raw?
11
+ @raw_input
12
+ end
13
+
14
+ # Execute the block with input in raw mode.
15
+ def self.raw
16
+ begin_raw_input unless (already_raw = raw?)
17
+ yield(self)
18
+ ensure
19
+ end_raw_input unless already_raw
20
+ end
21
+
22
+ # Flush the keyboard buffer.
23
+ def self.flush
24
+ raw do |input|
25
+ while input.has_raw_char?
26
+ input.get_raw_char
27
+ end
28
+ end
29
+
30
+ self
31
+ end
32
+
33
+ end
@@ -0,0 +1,54 @@
1
+ # coding: utf-8
2
+
3
+ # Common Terminal Info. (Common Code)
4
+ module MiniTerm
5
+
6
+ @options = nil
7
+ @term_open = false
8
+
9
+ def self.open(options = {})
10
+ @term_open = true
11
+ @options = options
12
+ validate_options
13
+ end
14
+
15
+ def self.close
16
+ end_raw_input if raw?
17
+ @term_open = false
18
+ @options = nil
19
+ end
20
+
21
+ # Is the mini_term open just now?
22
+ def self.term_open?
23
+ @term_open
24
+ end
25
+
26
+ # Make sure that mini_term is closed on exit.
27
+ at_exit do
28
+ if MiniTerm.term_open?
29
+ puts "Force MiniTerm.close" unless @options[:quiet]
30
+ MiniTerm.close
31
+ end
32
+ end
33
+
34
+ # What is the terminal width in characters?
35
+ def self.width
36
+ term_info[1]
37
+ end
38
+
39
+ # What is the terminal height in rows?
40
+ def self.height
41
+ term_info[0]
42
+ end
43
+
44
+ private
45
+
46
+ def self.validate_options
47
+ return if (bad = @options.keys - VALID_OPTIONS).empty?
48
+
49
+ msg = "MiniTerm.open, Invalid options: #{bad.join(", ")}"
50
+ puts msg unless @options[:quiet]
51
+ fail MiniTermStrict, msg if @options[:strict]
52
+ end
53
+
54
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ # The abstract base exception for mini term.
4
+ class MiniTermError < StandardError; end
5
+
6
+ # The exception raised when something is really messed up.
7
+ class MiniTermWTF < MiniTermError; end
8
+
9
+ # The exception raised due to strictness.
10
+ class MiniTermStrict < MiniTermError; end
11
+
12
+ # The exception raised when no keyboard mapping is found.
13
+ class MiniTermNoMap < MiniTermError; end
14
+
15
+ # The exception raised when the keyboard mapping is invalid.
16
+ class MiniTermKME < MiniTermError; end
17
+
18
+ # The exception raised when raw mode is mandatory.
19
+ class MiniTermNotRaw < MiniTermError; end
@@ -0,0 +1,8 @@
1
+ # coding: utf-8
2
+
3
+ # A simple, portable terminal interface object.
4
+ module MiniTerm
5
+ VERSION = "0.1.0".freeze
6
+
7
+ DESCRIPTION = "mini_term: A portable encapsulation of the console terminal.".freeze
8
+ end