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: ->
104 while fixed[0] is '0'
105 fixed = fixed.substr 1
108 @set_attribute_bits 0xffffff, 0
110 @set_attribute_bits 0x10000, 0x10000
112 @set_attribute_bits 0x20000, 0x20000
114 @set_attribute_bits 0x40000, 0x40000
116 @set_attribute_bits 0x80000, 0x80000
118 when '22' # not bold... according to a page
119 @set_attribute_bits 0x10000, 0
120 when '21' # ... though this would make more sense for "not bold"
121 @set_attribute_bits 0x10000, 0
122 when '24' # not underline
123 @set_attribute_bits 0x20000, 0
124 when '25' # not blink
125 @set_attribute_bits 0x40000, 0
126 when '28' # not invisible
127 @set_attribute_bits 0x80000, 0
130 @set_attribute_bits 0xff, 0x00
132 @set_attribute_bits 0xff, 0x01
134 @set_attribute_bits 0xff, 0x02
135 when '33' # fg yellow
136 @set_attribute_bits 0xff, 0x03
138 @set_attribute_bits 0xff, 0x04
139 when '35' # fg magenta
140 @set_attribute_bits 0xff, 0x05
142 @set_attribute_bits 0xff, 0x06
143 when '37', '39' # fg white (39 is default)
144 @set_attribute_bits 0xff, 0x07
147 @set_attribute_bits 0xff00, 0x0000
149 @set_attribute_bits 0xff00, 0x0100
151 @set_attribute_bits 0xff00, 0x0200
152 when '43' # bg yellow
153 @set_attribute_bits 0xff00, 0x0300
155 @set_attribute_bits 0xff00, 0x0400
156 when '45' # bg magenta
157 @set_attribute_bits 0xff00, 0x0500
159 @set_attribute_bits 0xff00, 0x0600
161 @set_attribute_bits 0xff00, 0x0700
162 when '49' # bg default
163 @set_attribute_bits 0xff00, 0x0000
166 # if we don't recognize the style, go back to default
167 @set_attribute_bits 0xffffff, 0
170 # str is the whole escape sequence (minus the esc[ prefix)
171 update_sequence: (str) ->
172 command = @["csi_#{str.substr str.length - 1}"]
173 return unless command?
174 args = str.substr(0, str.length - 1).split ';'
175 for i in [0...args.length]
177 args[i] = command.default
178 command.go.call this, args...
180 update_sequence_then_text: (str) ->
181 len = @escape_sequence_length str
183 console.log "couldn't find escape sequence here: #{str.substr 0, 25}"
184 @update_text "ESC[" + str
186 @update_sequence str.substr 0, len
187 @update_text str.substr len
189 escape_sequence_length: (str) ->
190 parts = str.match(/^[0-9;?]{0,25}./)
191 return -1 unless parts?
192 return parts[0].length
194 exports.new = (width, height) ->
195 return new Terminal width, height