X-Git-Url: https://jasonwoof.com/gitweb/?p=watch-my-terminal.git;a=blobdiff_plain;f=terminal.coffee;h=360fb1ad57c8ce3d8ab9771f57b5b93603836e60;hp=94be906e2901c860a112442393aba45cd5297f00;hb=1700d1f6d76490cd696f9072bf28d595a4e484c5;hpb=7be31fd57ea61d523cafa9bbf950a326afd11968 diff --git a/terminal.coffee b/terminal.coffee index 94be906..360fb1a 100644 --- a/terminal.coffee +++ b/terminal.coffee @@ -6,25 +6,26 @@ class Terminal constructor: (width, height) -> @width = 1 @height = 1 - @text = [""] - @attributes = [0] + @text = [] + @attributes = [] @x = 0 @y = 0 + @a = 0 # cursor attributes @partial = '' @resize width, height - @text_callbacks = [] - @sequence_callbacks = [] - on: (evt, callback) -> - @["#{evt}_callbacks"].push callback - resize: (width, height) -> # FIXME: write a version that retains some of the data + @width = width + @height = height @text = [] @attributes = [] - for i in [0...height] - @text[i] = "" - @attributes[i] = new Array(width) + for y in [0...height] + @text[y] = [] + @attributes[y] = [] + for x in [0...width] + @text[y].push ' ' + @attributes[y].push 0 # pass data from stdout update: (data) -> @@ -43,19 +44,133 @@ class Terminal else @update_sequence_then_text parts[i] return + + clear_rest_of_line: -> + for i in [@x...@width] + @text[@y][i] = ' ' + @attributes[@y][i] = @a + + add_new_line: -> + # clear top line + for i in [0...@width] + @text[0][i] = ' ' + @attributes[0][i] = 0 + # move (newly cleared) top line to the bottom + tmp = @text.shift() + @text.push(tmp) + tmp = @attributes.shift() + @attributes.push(tmp) + # slide cursor up with rest of text + @y -= 1 + + wrap_to_next_line: -> + if @y is @height - 1 + @add_new_line() + @y += 1 + @x = 0 # str has no escape sequences update_text: (str) -> return unless str.length > 0 - for c in @text_callbacks - c str - console.log "text: \"#{str}\"" # FIXME + for c in str + switch c + when '\t' # tab + @update_text " ".substr(@x % 8) + when '\x07' # bell + false + when '\x0d' # cr + @x = 0 + when '\x08' # backspace + if @x > 0 + @x -= 1 + @text[@y][@x] = ' ' + # should this set the attribute too? + when '\x0a', '\x0b' # lf, vertical tab (same thing) + @wrap_to_next_line() + else + @text[@y][@x] = c + @attributes[@y][@x] = @a + @x += 1 + if @x is @width + @wrap_to_next_line() + return + + set_attribute_bits: (mask, value) -> + @a = (@a & ~mask) | value + + csi_m: default: "0", go: -> + for i in arguments + switch i + when '0' + @set_attribute_bits 0xffffff, 0 + when '1' # bold + @set_attribute_bits 0x100, 1 + when '4' # underline + @set_attribute_bits 0x200, 1 + when '5' # blink + @set_attribute_bits 0x400, 1 + when '8' # invisible + @set_attribute_bits 0x800, 1 + + when '22' # not bold... according to a page + @set_attribute_bits 0x100, 0 + when '21' # ... though this would make more sense for "not bold" + @set_attribute_bits 0x100, 0 + when '24' # not underline + @set_attribute_bits 0x200, 0 + when '25' # not blink + @set_attribute_bits 0x400, 0 + when '28' # not invisible + @set_attribute_bits 0x800, 0 + + when '30' # fg black + @set_attribute_bits 0xff, 0 + when '31' # fg red + @set_attribute_bits 0xff, 0xe0 + when '32' # fg green + @set_attribute_bits 0xff, 0x1c + when '33' # fg yellow + @set_attribute_bits 0xff, 0xfc + when '34' # fg blue + @set_attribute_bits 0xff, 0x02 + when '35' # fg magenta + @set_attribute_bits 0xff, 0xe2 + when '36' # fg cyan + @set_attribute_bits 0xff, 0x1f + when '37', '39' # fg white (39 is default) + @set_attribute_bits 0xff, 0xff + + when '40' # bg black + @set_attribute_bits 0xff00, 0 + when '41' # bg red + @set_attribute_bits 0xff00, 0xe000 + when '42' # bg green + @set_attribute_bits 0xff00, 0x1c00 + when '43' # bg yellow + @set_attribute_bits 0xff00, 0xfc00 + when '44' # bg blue + @set_attribute_bits 0xff00, 0x0200 + when '45' # bg magenta + @set_attribute_bits 0xff00, 0xe200 + when '46' # bg cyan + @set_attribute_bits 0xff00, 0x1f00 + when '47', '49' # bg white (49 is default) + @set_attribute_bits 0xff00, 0xff + + else + # if we don't recognize the style, go back to default + @set_attribute_bits 0xffffff, 0 + return # str is the whole escape sequence (minus the esc[ prefix) update_sequence: (str) -> - for c in @sequence_callbacks - c str - console.log "sequence: \"#{str}\"" # FIXME + command = @["csi_#{str.substr str.length - 1}"] + return unless command? + args = str.substr(0, str.length - 1).split ';' + for i in [0...args.length] + if args[i] is '' + args[i] = command.default + command.go.call this, args... update_sequence_then_text: (str) -> len = @escape_sequence_length str