scriptty 0.5.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|