scriptty 0.5.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitattributes +1 -0
- data/.gitignore +3 -0
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/README.rdoc +31 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/bin/scriptty-capture +5 -0
- data/bin/scriptty-dump-screens +4 -0
- data/bin/scriptty-replay +5 -0
- data/bin/scriptty-term-test +4 -0
- data/bin/scriptty-transcript-parse +4 -0
- data/examples/captures/xterm-overlong-line-prompt.bin +9 -0
- data/examples/captures/xterm-vim-session.bin +262 -0
- data/examples/demo-capture.rb +19 -0
- data/examples/telnet-nego.rb +55 -0
- data/lib/scriptty/apps/capture_app/console.rb +104 -0
- data/lib/scriptty/apps/capture_app/password_prompt.rb +65 -0
- data/lib/scriptty/apps/capture_app.rb +213 -0
- data/lib/scriptty/apps/dump_screens_app.rb +166 -0
- data/lib/scriptty/apps/replay_app.rb +229 -0
- data/lib/scriptty/apps/term_test_app.rb +124 -0
- data/lib/scriptty/apps/transcript_parse_app.rb +143 -0
- data/lib/scriptty/cursor.rb +39 -0
- data/lib/scriptty/exception.rb +38 -0
- data/lib/scriptty/expect.rb +392 -0
- data/lib/scriptty/multiline_buffer.rb +192 -0
- data/lib/scriptty/net/event_loop.rb +610 -0
- data/lib/scriptty/screen_pattern/generator.rb +398 -0
- data/lib/scriptty/screen_pattern/parser.rb +558 -0
- data/lib/scriptty/screen_pattern.rb +104 -0
- data/lib/scriptty/term/dg410/dg410-client-escapes.txt +37 -0
- data/lib/scriptty/term/dg410/dg410-escapes.txt +82 -0
- data/lib/scriptty/term/dg410/parser.rb +162 -0
- data/lib/scriptty/term/dg410.rb +489 -0
- data/lib/scriptty/term/xterm/xterm-escapes.txt +73 -0
- data/lib/scriptty/term/xterm.rb +661 -0
- data/lib/scriptty/term.rb +40 -0
- data/lib/scriptty/util/fsm/definition_parser.rb +111 -0
- data/lib/scriptty/util/fsm/scriptty_fsm_definition.treetop +189 -0
- data/lib/scriptty/util/fsm.rb +177 -0
- data/lib/scriptty/util/transcript/reader.rb +96 -0
- data/lib/scriptty/util/transcript/writer.rb +111 -0
- data/test/apps/capture_app_test.rb +123 -0
- data/test/apps/transcript_parse_app_test.rb +118 -0
- data/test/cursor_test.rb +51 -0
- data/test/fsm_definition_parser_test.rb +220 -0
- data/test/fsm_test.rb +322 -0
- data/test/multiline_buffer_test.rb +275 -0
- data/test/net/event_loop_test.rb +402 -0
- data/test/screen_pattern/generator_test.rb +408 -0
- data/test/screen_pattern/parser_test/explicit_cursor_pattern.txt +14 -0
- data/test/screen_pattern/parser_test/explicit_fields.txt +22 -0
- data/test/screen_pattern/parser_test/multiple_patterns.txt +42 -0
- data/test/screen_pattern/parser_test/simple_pattern.txt +14 -0
- data/test/screen_pattern/parser_test/truncated_heredoc.txt +12 -0
- data/test/screen_pattern/parser_test/utf16bebom_pattern.bin +0 -0
- data/test/screen_pattern/parser_test/utf16lebom_pattern.bin +0 -0
- data/test/screen_pattern/parser_test/utf8_pattern.bin +14 -0
- data/test/screen_pattern/parser_test/utf8_unix_pattern.bin +14 -0
- data/test/screen_pattern/parser_test/utf8bom_pattern.bin +14 -0
- data/test/screen_pattern/parser_test.rb +266 -0
- data/test/term/dg410/parser_test.rb +139 -0
- data/test/term/xterm_test.rb +327 -0
- data/test/test_helper.rb +3 -0
- data/test/util/transcript/reader_test.rb +131 -0
- data/test/util/transcript/writer_test.rb +126 -0
- data/test.watchr +29 -0
- metadata +175 -0
@@ -0,0 +1,489 @@
|
|
1
|
+
# = DG410 terminal emulation
|
2
|
+
# Copyright (C) 2010 Infonium Inc.
|
3
|
+
#
|
4
|
+
# This file is part of ScripTTY.
|
5
|
+
#
|
6
|
+
# ScripTTY is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# ScripTTY is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
17
|
+
# along with ScripTTY. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
# XXX TODO - deduplicate between this and xterm.rb
|
20
|
+
|
21
|
+
require 'scriptty/multiline_buffer'
|
22
|
+
require 'scriptty/cursor'
|
23
|
+
require 'scriptty/util/fsm'
|
24
|
+
require 'set'
|
25
|
+
|
26
|
+
module ScripTTY # :nodoc:
|
27
|
+
module Term
|
28
|
+
class DG410
|
29
|
+
require 'scriptty/term/dg410/parser' # we want to create the DG410 class here before parser.rb reopens it
|
30
|
+
|
31
|
+
DEFAULT_FLAGS = {
|
32
|
+
:insert_mode => false,
|
33
|
+
:wraparound_mode => false,
|
34
|
+
:roll_mode => true, # scroll up when the cursor moves beyond the bottom
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
# width and height of the display buffer
|
38
|
+
attr_reader :width, :height
|
39
|
+
|
40
|
+
# Return ScripTTY::Term::DG410::Parser
|
41
|
+
def self.parser_class
|
42
|
+
Parser
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(height=24, width=80)
|
46
|
+
@parser = self.class.parser_class.new(:callback => self, :callback_method => :send)
|
47
|
+
|
48
|
+
@height = height
|
49
|
+
@width = width
|
50
|
+
|
51
|
+
@proprietary_escape_callback = nil
|
52
|
+
|
53
|
+
reset_to_initial_state!
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_unknown_sequence(mode=nil, &block)
|
57
|
+
@parser.on_unknown_sequence(mode, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def on_proprietary_escape(mode=nil, &block)
|
61
|
+
if mode == :ignore and !block
|
62
|
+
@proprietary_escape_callback = nil
|
63
|
+
elsif !mode and block
|
64
|
+
@proprietary_escape_callback = block
|
65
|
+
else
|
66
|
+
raise ArgumentError.new("mode and block are mutually exclusive")
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def feed_bytes(bytes)
|
72
|
+
@parser.feed_bytes(bytes)
|
73
|
+
end
|
74
|
+
|
75
|
+
def feed_byte(byte)
|
76
|
+
@parser.feed_byte(byte)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return an array of lines of text representing the state of the terminal.
|
80
|
+
# Used for debugging.
|
81
|
+
def debug_info
|
82
|
+
output = []
|
83
|
+
output << "state:#{@parser.fsm.state.inspect} seq:#{@parser.fsm.input_sequence && @parser.fsm.input_sequence.join.inspect}"
|
84
|
+
output << "scrolling_region: #{@scrolling_region.inspect}"
|
85
|
+
output << "flags: roll:#{@flags[:roll_mode]} wraparound:#{@flags[:wraparound_mode]} insert:#{@flags[:insert_mode]}"
|
86
|
+
output
|
87
|
+
end
|
88
|
+
|
89
|
+
def inspect # :nodoc:
|
90
|
+
# The default inspect method shows way too much information. Simplify it.
|
91
|
+
"#<#{self.class.name}:#{sprintf('0x%0x', object_id)} h=#{@height.inspect} w=#{@width.inspect} cursor=#{cursor_pos.inspect}>"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return an array of strings representing the lines of text on the screen
|
95
|
+
#
|
96
|
+
# NOTE: If passing copy=false, do not modify the return value or the strings inside it.
|
97
|
+
def text(copy=true)
|
98
|
+
if copy
|
99
|
+
@glyphs.content.map{|line| line.dup}
|
100
|
+
else
|
101
|
+
@glyphs.content
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Return the cursor position, as an array of [row, column].
|
106
|
+
#
|
107
|
+
# [0,0] represents the topmost, leftmost position.
|
108
|
+
def cursor_pos
|
109
|
+
[@cursor.row, @cursor.column]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Set the cursor position to [row, column].
|
113
|
+
#
|
114
|
+
# [0,0] represents the topmost, leftmost position.
|
115
|
+
def cursor_pos=(v)
|
116
|
+
@cursor.pos = v
|
117
|
+
end
|
118
|
+
|
119
|
+
# Replace the text on the screen with the specified text.
|
120
|
+
#
|
121
|
+
# NOTE: This is API is very likely to change in the future.
|
122
|
+
def text=(a)
|
123
|
+
@glyphs.clear!
|
124
|
+
@glyphs.replace_at(0, 0, a)
|
125
|
+
a
|
126
|
+
end
|
127
|
+
|
128
|
+
protected
|
129
|
+
|
130
|
+
# Reset to the initial state. Return true.
|
131
|
+
def reset_to_initial_state!
|
132
|
+
@flags = DEFAULT_FLAGS.dup
|
133
|
+
|
134
|
+
# current cursor position
|
135
|
+
@cursor = Cursor.new
|
136
|
+
@cursor.row = @cursor.column = 0
|
137
|
+
@saved_cursor_position = [0,0]
|
138
|
+
|
139
|
+
# Screen buffer
|
140
|
+
@glyphs = MultilineBuffer.new(@height, @width) # the displayable characters (as bytes)
|
141
|
+
@attrs = MultilineBuffer.new(@height, @width) # character attributes (as bytes)
|
142
|
+
|
143
|
+
# Vertical scrolling region. An array of [start_row, end_row]. Defaults to [0, height-1].
|
144
|
+
@scrolling_region = [0, @height-1]
|
145
|
+
true
|
146
|
+
end
|
147
|
+
|
148
|
+
# Replace the character under the cursor with the specified character.
|
149
|
+
#
|
150
|
+
# If curfwd is true, the cursor is also moved forward.
|
151
|
+
#
|
152
|
+
# Returns true.
|
153
|
+
def put_char!(input, curfwd=false)
|
154
|
+
raise TypeError.new("input must be single-character string") unless input.is_a?(String) and input.length == 1
|
155
|
+
@glyphs.replace_at(@cursor.row, @cursor.column, input)
|
156
|
+
@attrs.replace_at(@cursor.row, @cursor.column, " ")
|
157
|
+
cursor_forward! if curfwd
|
158
|
+
true
|
159
|
+
end
|
160
|
+
|
161
|
+
# Move the cursor to the leftmost column in the current row, then return true.
|
162
|
+
def carriage_return!
|
163
|
+
@cursor.column = 0
|
164
|
+
true
|
165
|
+
end
|
166
|
+
|
167
|
+
# Move the cursor down one row and return true.
|
168
|
+
#
|
169
|
+
# If the cursor is on the bottom row of the vertical scrolling region,
|
170
|
+
# the region is scrolled. If bot, but the cursor is on the bottom of
|
171
|
+
# the screen, this command has no effect.
|
172
|
+
def line_feed!
|
173
|
+
if @cursor.row == @scrolling_region[1] # cursor is on the bottom row of the scrolling region
|
174
|
+
if @flags[:roll_enable]
|
175
|
+
scroll_up!
|
176
|
+
else
|
177
|
+
@cursor.row = @scrolling_region[0]
|
178
|
+
end
|
179
|
+
elsif @cursor.row >= @height-1
|
180
|
+
# do nothing
|
181
|
+
else
|
182
|
+
cursor_down!
|
183
|
+
end
|
184
|
+
true
|
185
|
+
end
|
186
|
+
|
187
|
+
# Save the cursor position. Return true.
|
188
|
+
def save_cursor!
|
189
|
+
@saved_cursor_position = [@cursor.row, @cursor.column]
|
190
|
+
true
|
191
|
+
end
|
192
|
+
|
193
|
+
# Restore the saved cursor position. If nothing has been saved, then go to the home position. Return true.
|
194
|
+
def restore_cursor!
|
195
|
+
@cursor.row, @cursor.column = @saved_cursor_position
|
196
|
+
true
|
197
|
+
end
|
198
|
+
|
199
|
+
# Move the cursor down one row and return true.
|
200
|
+
# If the cursor is on the bottom row, return false without moving the cursor.
|
201
|
+
def cursor_down!
|
202
|
+
if @cursor.row >= @height-1
|
203
|
+
false
|
204
|
+
else
|
205
|
+
@cursor.row += 1
|
206
|
+
true
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Move the cursor up one row and return true.
|
211
|
+
# If the cursor is on the top row, return false without moving the cursor.
|
212
|
+
def cursor_up!
|
213
|
+
if @cursor.row <= 0
|
214
|
+
false
|
215
|
+
else
|
216
|
+
@cursor.row -= 1
|
217
|
+
true
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Move the cursor right one column and return true.
|
222
|
+
# If the cursor is on the right-most column, return false without moving the cursor.
|
223
|
+
def cursor_right!
|
224
|
+
if @cursor.column >= @width-1
|
225
|
+
false
|
226
|
+
else
|
227
|
+
@cursor.column += 1
|
228
|
+
true
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Move the cursor to the right. Wrap around if we reach the end of the screen.
|
233
|
+
#
|
234
|
+
# Return true.
|
235
|
+
def cursor_forward!(options={})
|
236
|
+
if @cursor.column >= @width-1
|
237
|
+
line_feed!
|
238
|
+
carriage_return!
|
239
|
+
else
|
240
|
+
cursor_right!
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Move the cursor left one column and return true.
|
245
|
+
# If the cursor is on the left-most column, return false without moving the cursor.
|
246
|
+
def cursor_left!
|
247
|
+
if @cursor.column <= 0
|
248
|
+
false
|
249
|
+
else
|
250
|
+
@cursor.column -= 1
|
251
|
+
true
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
alias cursor_back! cursor_left! # In the future, this might not be an alias
|
256
|
+
|
257
|
+
# Scroll the contents of the screen up by one row and return true.
|
258
|
+
# The position of the cursor does not change.
|
259
|
+
def scroll_up!
|
260
|
+
@glyphs.scroll_up_region(@scrolling_region[0], 0, @scrolling_region[1], @width-1, 1)
|
261
|
+
@attrs.scroll_up_region(@scrolling_region[0], 0, @scrolling_region[1], @width-1, 1)
|
262
|
+
true
|
263
|
+
end
|
264
|
+
|
265
|
+
# Scroll the contents of the screen down by one row and return true.
|
266
|
+
# The position of the cursor does not change.
|
267
|
+
def scroll_down!
|
268
|
+
@glyphs.scroll_down_region(@scrolling_region[0], 0, @scrolling_region[1], @width-1, 1)
|
269
|
+
@attrs.scroll_down_region(@scrolling_region[0], 0, @scrolling_region[1], @width-1, 1)
|
270
|
+
true
|
271
|
+
end
|
272
|
+
|
273
|
+
# Erase, starting with the character under the cursor and extending to the end of the line.
|
274
|
+
# Return true.
|
275
|
+
def erase_to_end_of_line!
|
276
|
+
@glyphs.replace_at(@cursor.row, @cursor.column, " "*(@width-@cursor.column))
|
277
|
+
@attrs.replace_at(@cursor.row, @cursor.column, " "*(@width-@cursor.column))
|
278
|
+
true
|
279
|
+
end
|
280
|
+
|
281
|
+
# Erase, starting with the beginning of the line and extending to the character under the cursor.
|
282
|
+
# Return true.
|
283
|
+
def erase_to_start_of_line!
|
284
|
+
@glyphs.replace_at(@cursor.row, 0, " "*(@cursor.column+1))
|
285
|
+
@attrs.replace_at(@cursor.row, 0, " "*(@cursor.column+1))
|
286
|
+
true
|
287
|
+
end
|
288
|
+
|
289
|
+
# Erase the current (or specified) line. The cursor position is unchanged.
|
290
|
+
# Return true.
|
291
|
+
def erase_line!(row=nil)
|
292
|
+
row = @cursor.row unless row
|
293
|
+
@glyphs.replace_at(row, 0, " "*@width)
|
294
|
+
@attrs.replace_at(row, 0, " "*@width)
|
295
|
+
true
|
296
|
+
end
|
297
|
+
|
298
|
+
# Erase the window. Return true.
|
299
|
+
def erase_window!
|
300
|
+
empty_line = " "*@width
|
301
|
+
@height.times do |row|
|
302
|
+
@glyphs.replace_at(row, 0, empty_line)
|
303
|
+
@attrs.replace_at(row, 0, empty_line)
|
304
|
+
end
|
305
|
+
true
|
306
|
+
end
|
307
|
+
|
308
|
+
# Delete the specified number of lines, starting at the cursor position
|
309
|
+
# extending downwards. The lines below the deleted lines are scrolled up,
|
310
|
+
# and blank lines are inserted below them.
|
311
|
+
# Return true.
|
312
|
+
def delete_lines!(count=1)
|
313
|
+
@glyphs.scroll_up_region(@cursor.row, 0, @height-1, @width-1, count)
|
314
|
+
@attrs.scroll_up_region(@cursor.row, 0, @height-1, @width-1, count)
|
315
|
+
true
|
316
|
+
end
|
317
|
+
|
318
|
+
# Delete the specified number of characters, starting at the cursor position
|
319
|
+
# extending to the end of the line. The characters to the right of the
|
320
|
+
# cursor are scrolled left, and blanks are inserted after them.
|
321
|
+
# Return true.
|
322
|
+
def delete_characters!(count=1)
|
323
|
+
@glyphs.scroll_left_region(@cursor.row, @cursor.column, @cursor.row, @width-1, count)
|
324
|
+
@attrs.scroll_left_region(@cursor.row, @cursor.column, @cursor.row, @width-1, count)
|
325
|
+
true
|
326
|
+
end
|
327
|
+
|
328
|
+
# Insert the specified number of blank characters at the cursor position.
|
329
|
+
# The characters to the right of the cursor are scrolled right, and blanks
|
330
|
+
# are inserted in their place.
|
331
|
+
# Return true.
|
332
|
+
def insert_blank_characters!(count=1)
|
333
|
+
@glyphs.scroll_right_region(@cursor.row, @cursor.column, @cursor.row, @width-1, count)
|
334
|
+
@attrs.scroll_right_region(@cursor.row, @cursor.column, @cursor.row, @width-1, count)
|
335
|
+
true
|
336
|
+
end
|
337
|
+
|
338
|
+
# Insert the specified number of lines characters at the cursor position.
|
339
|
+
# The characters to the below the cursor are scrolled down, and blank
|
340
|
+
# lines are inserted in their place.
|
341
|
+
# Return true.
|
342
|
+
def insert_blank_lines!(count=1)
|
343
|
+
@glyphs.scroll_down_region(@cursor.row, 0, @height-1, @width-1, count)
|
344
|
+
@attrs.scroll_down_region(@cursor.row, 0, @height-1, @width-1, count)
|
345
|
+
true
|
346
|
+
end
|
347
|
+
|
348
|
+
private
|
349
|
+
|
350
|
+
# Set the vertical scrolling region.
|
351
|
+
#
|
352
|
+
# Values will be clipped.
|
353
|
+
def set_scrolling_region!(top, bottom)
|
354
|
+
@scrolling_region[0] = [0, [@height-1, top].min].max
|
355
|
+
@scrolling_region[1] = [0, [@width-1, bottom].min].max
|
356
|
+
nil
|
357
|
+
end
|
358
|
+
|
359
|
+
def error(message) # XXX - This sucks
|
360
|
+
raise ArgumentError.new(message)
|
361
|
+
#puts message # DEBUG FIXME
|
362
|
+
end
|
363
|
+
|
364
|
+
def t_reset(fsm)
|
365
|
+
reset_to_initial_state!
|
366
|
+
end
|
367
|
+
|
368
|
+
# Printable character
|
369
|
+
def t_printable(fsm) # :nodoc:
|
370
|
+
insert_blank_characters! if @flags[:insert_mode] # TODO
|
371
|
+
put_char!(fsm.input)
|
372
|
+
cursor_forward!
|
373
|
+
end
|
374
|
+
|
375
|
+
# Move the cursor to the left margin on the current row.
|
376
|
+
def t_carriage_return(fsm)
|
377
|
+
carriage_return!
|
378
|
+
end
|
379
|
+
|
380
|
+
# Move the cursor to the left margin on the next row.
|
381
|
+
def t_new_line(fsm)
|
382
|
+
carriage_return!
|
383
|
+
line_feed!
|
384
|
+
end
|
385
|
+
|
386
|
+
# Move cursor to the top-left cell of the window.
|
387
|
+
def t_window_home(fsm)
|
388
|
+
@cursor.pos = [0,0]
|
389
|
+
end
|
390
|
+
|
391
|
+
# Erase all characters starting at the cursor and extending to the end of the window.
|
392
|
+
def t_erase_unprotected(fsm)
|
393
|
+
# Erase to the end of the current line
|
394
|
+
erase_to_end_of_line!
|
395
|
+
# Erase subsequent lines to the end of the window.
|
396
|
+
(@cursor.row+1..@height-1).each do |row|
|
397
|
+
erase_line!(row)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
# Erase all characters starting at the cursor and extending to the end of the line.
|
402
|
+
def t_erase_end_of_line(fsm)
|
403
|
+
erase_to_end_of_line!
|
404
|
+
end
|
405
|
+
|
406
|
+
# Move the cursor to the specified position within the window.
|
407
|
+
# <020> <column> <row>
|
408
|
+
def t_write_window_address(fsm)
|
409
|
+
column, row = fsm.input_sequence[1,2].join.unpack("C*")
|
410
|
+
row = @cursor.row if row == 0177 # 0177 == special case: do not change the row
|
411
|
+
column = @cursor.column if column == 0177 # 0177 == special case: do not change the column
|
412
|
+
column = @width-1 if column > @width-1
|
413
|
+
row = @height-1 if row > @height-1
|
414
|
+
@cursor.pos = [row, column]
|
415
|
+
end
|
416
|
+
|
417
|
+
# Erase all characters in the current window, and move the cursor to
|
418
|
+
# the top-left cell of the window.
|
419
|
+
def t_erase_window(fsm)
|
420
|
+
erase_window!
|
421
|
+
@cursor.pos = [0,0]
|
422
|
+
end
|
423
|
+
|
424
|
+
def t_cursor_up(fsm)
|
425
|
+
cursor_up!
|
426
|
+
end
|
427
|
+
|
428
|
+
def t_cursor_down(fsm)
|
429
|
+
cursor_down!
|
430
|
+
end
|
431
|
+
|
432
|
+
def t_cursor_right(fsm)
|
433
|
+
cursor_right!
|
434
|
+
end
|
435
|
+
|
436
|
+
def t_cursor_left(fsm)
|
437
|
+
cursor_left!
|
438
|
+
end
|
439
|
+
|
440
|
+
# ESC ] ... M
|
441
|
+
# XXX - What is this?
|
442
|
+
def t_osc_m(fsm) end # TODO
|
443
|
+
def t_osc_k(fsm) end # TODO
|
444
|
+
|
445
|
+
def t_roll_enable(fsm)
|
446
|
+
@flags[:roll_mode] = true
|
447
|
+
end
|
448
|
+
|
449
|
+
def t_roll_disable(fsm)
|
450
|
+
@flags[:roll_mode] = false
|
451
|
+
end
|
452
|
+
|
453
|
+
def t_print_window(fsm) end # TODO
|
454
|
+
|
455
|
+
def t_bell(fsm) end # TODO
|
456
|
+
|
457
|
+
def t_blink_enable(fsm) end # TODO
|
458
|
+
def t_blink_disable(fsm) end # TODO
|
459
|
+
def t_underscore_on(fsm) end # TODO
|
460
|
+
def t_underscore_off(fsm) end # TODO
|
461
|
+
def t_blink_on(fsm) end # TODO
|
462
|
+
def t_blink_off(fsm) end # TODO
|
463
|
+
def t_reverse_video_on(fsm) end # TODO
|
464
|
+
def t_reverse_video_off(fsm) end # TODO
|
465
|
+
def t_dim_on(fsm) end # TODO
|
466
|
+
def t_dim_off(fsm) end # TODO
|
467
|
+
def t_set_cursor_type(fsm) end # TODO
|
468
|
+
|
469
|
+
def t_telnet_will(fsm) end # TODO
|
470
|
+
def t_telnet_wont(fsm) end # TODO
|
471
|
+
def t_telnet_do(fsm) end # TODO
|
472
|
+
def t_telnet_dont(fsm) end # TODO
|
473
|
+
def t_telnet_subnegotiation(fsm) end # TODO
|
474
|
+
|
475
|
+
# Proprietary escape code
|
476
|
+
# <036> ~ <2-byte-command> <n> <n*bytes>
|
477
|
+
def t_proprietary_escape(fsm)
|
478
|
+
command = fsm.input_sequence[2,2].join
|
479
|
+
payload = fsm.input_sequence[5..-1].join
|
480
|
+
@proprietary_escape_callback.call(command, payload) if @proprietary_escape_callback
|
481
|
+
end
|
482
|
+
|
483
|
+
# Acknowledgement of proprietary escape sequence.
|
484
|
+
# From the server to the client, this is just a single-character ACK
|
485
|
+
def t_proprietary_ack(fsm) end # TODO
|
486
|
+
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Terminal escapes for xterm
|
2
|
+
# See:
|
3
|
+
# - ECMA-48 / ISO/IEC 6429 (formerly ANSI X3.64)
|
4
|
+
# http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
|
5
|
+
# - ECMA-6 7-bit Coded Character Set
|
6
|
+
# http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-006.pdf
|
7
|
+
# - "Xterm Control Sequences"
|
8
|
+
# http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
9
|
+
# - Wikipedia "ANSI Escape Code"
|
10
|
+
# http://en.wikipedia.org/wiki/ANSI_escape_code
|
11
|
+
'\x00' => t_nul
|
12
|
+
'\x07' => t_bell
|
13
|
+
'\x08' => t_bs
|
14
|
+
'\x0a' => t_new_line
|
15
|
+
'\x0d' => t_carriage_return
|
16
|
+
'\e' => {
|
17
|
+
'7' => t_save_cursor # cross reference: ESC [ s
|
18
|
+
'8' => t_restore_cursor # cross reference: ESC [ u
|
19
|
+
'c' => t_reset
|
20
|
+
'H' => t_tab_set
|
21
|
+
'=' => t_application_keypad
|
22
|
+
'>' => t_normal_keypad
|
23
|
+
'[' => t_parse_csi => { # ANSI CSI escape sequence - ESC [ ...
|
24
|
+
'?' => t_parse_csi => { # DEC escape sequences - ESC [ ? ...
|
25
|
+
'h' => t_dec_private_mode_set
|
26
|
+
'l' => t_dec_private_mode_reset
|
27
|
+
}
|
28
|
+
'>' => t_parse_csi => { # ESC [ > ...
|
29
|
+
'c' => t_send_device_attributes_secondary # Secondary DA
|
30
|
+
}
|
31
|
+
'A' => t_cursor_up
|
32
|
+
'B' => t_cursor_down
|
33
|
+
'C' => t_cursor_right
|
34
|
+
'D' => t_cursor_left
|
35
|
+
'H' => t_cursor_position
|
36
|
+
'J' => t_erase_in_display
|
37
|
+
'K' => t_erase_in_line
|
38
|
+
'L' => t_insert_lines
|
39
|
+
'M' => t_delete_lines
|
40
|
+
'P' => t_delete_characters
|
41
|
+
'S' => t_scroll_up
|
42
|
+
'T' => t_scroll_down
|
43
|
+
'c' => t_send_device_attributes_primary # Primary DA
|
44
|
+
'g' => t_tab_clear
|
45
|
+
'h' => t_set_mode
|
46
|
+
'l' => t_reset_mode
|
47
|
+
'm' => t_sgr # "select graphics rendition" - colour, bold, underline, etc.
|
48
|
+
'r' => t_set_scrolling_region
|
49
|
+
's' => t_save_cursor # cross reference: ESC 7
|
50
|
+
'u' => t_restore_cursor # cross reference: ESC 8
|
51
|
+
}
|
52
|
+
']' => t_parse_osc => { # OSC - "Operating system command"
|
53
|
+
'\007' => t_osc_set_text_params
|
54
|
+
}
|
55
|
+
}
|
56
|
+
'\377' => {
|
57
|
+
'\372' => t_parse_telnet_sb => {
|
58
|
+
* => t_telnet_subnegotiation
|
59
|
+
}
|
60
|
+
'\373' => {
|
61
|
+
* => t_telnet_will
|
62
|
+
}
|
63
|
+
'\374' => {
|
64
|
+
* => t_telnet_wont
|
65
|
+
}
|
66
|
+
'\375' => {
|
67
|
+
* => t_telnet_do
|
68
|
+
}
|
69
|
+
'\376' => {
|
70
|
+
* => t_telnet_dont
|
71
|
+
}
|
72
|
+
}
|
73
|
+
[\x20-\x7e] => t_printable
|