1 async = require 'async'
6 constructor: (width, height) ->
13 @a = 0 # cursor attributes
17 resize: (width, height) ->
18 # FIXME: write a version that retains some of the data
30 # pass data from stdout
32 return unless data?.length > 0
33 if @partial.length > 0
34 data = @partial + data
36 parts = data.split(/\x1b\[/)
38 if -1 is @escape_sequence_length parts[parts.length - 1]
39 @partial = parts.pop()
41 for i in [0...parts.length]
45 @update_sequence_then_text parts[i]
48 clear_rest_of_line: ->
49 for i in [@x...@width]
51 @attributes[@y][i] = @a
58 # move (newly cleared) top line to the bottom
61 tmp = @attributes.shift()
63 # slide cursor up with rest of text
72 # str has no escape sequences
74 return unless str.length > 0
78 @update_text " ".substr(@x % 8)
83 when '\x08' # backspace
87 # should this set the attribute too?
88 when '\x0a', '\x0b' # lf, vertical tab (same thing)
92 @attributes[@y][@x] = @a
98 set_attribute_bits: (mask, value) ->
99 @a = (@a & ~mask) | value
101 csi_m: default: "0", go: ->
105 @set_attribute_bits 0xffffff, 0
107 @set_attribute_bits 0x100, 1
109 @set_attribute_bits 0x200, 1
111 @set_attribute_bits 0x400, 1
113 @set_attribute_bits 0x800, 1
115 when '22' # not bold... according to a page
116 @set_attribute_bits 0x100, 0
117 when '21' # ... though this would make more sense for "not bold"
118 @set_attribute_bits 0x100, 0
119 when '24' # not underline
120 @set_attribute_bits 0x200, 0
121 when '25' # not blink
122 @set_attribute_bits 0x400, 0
123 when '28' # not invisible
124 @set_attribute_bits 0x800, 0
127 @set_attribute_bits 0xff, 0
129 @set_attribute_bits 0xff, 0xe0
131 @set_attribute_bits 0xff, 0x1c
132 when '33' # fg yellow
133 @set_attribute_bits 0xff, 0xfc
135 @set_attribute_bits 0xff, 0x02
136 when '35' # fg magenta
137 @set_attribute_bits 0xff, 0xe2
139 @set_attribute_bits 0xff, 0x1f
140 when '37', '39' # fg white (39 is default)
141 @set_attribute_bits 0xff, 0xff
144 @set_attribute_bits 0xff00, 0
146 @set_attribute_bits 0xff00, 0xe000
148 @set_attribute_bits 0xff00, 0x1c00
149 when '43' # bg yellow
150 @set_attribute_bits 0xff00, 0xfc00
152 @set_attribute_bits 0xff00, 0x0200
153 when '45' # bg magenta
154 @set_attribute_bits 0xff00, 0xe200
156 @set_attribute_bits 0xff00, 0x1f00
157 when '47', '49' # bg white (49 is default)
158 @set_attribute_bits 0xff00, 0xff
161 # if we don't recognize the style, go back to default
162 @set_attribute_bits 0xffffff, 0
165 # str is the whole escape sequence (minus the esc[ prefix)
166 update_sequence: (str) ->
167 command = @["csi_#{str.substr str.length - 1}"]
168 return unless command?
169 args = str.substr(0, str.length - 1).split ';'
170 for i in [0...args.length]
172 args[i] = command.default
173 command.go.call this, args...
175 update_sequence_then_text: (str) ->
176 len = @escape_sequence_length str
178 console.log "couldn't find escape sequence here: #{str.substr 0, 25}"
179 @update_text "ESC[" + str
181 @update_sequence str.substr 0, len
182 @update_text str.substr len
184 escape_sequence_length: (str) ->
185 parts = str.match(/^[0-9;?]{0,25}./)
186 return -1 unless parts?
187 return parts[0].length
189 exports.new = (width, height) ->
190 return new Terminal width, height