diff --git a/butterfly/static/coffees/main.coffee b/butterfly/static/coffees/main.coffee
index c3c75ff..db33981 100644
--- a/butterfly/static/coffees/main.coffee
+++ b/butterfly/static/coffees/main.coffee
@@ -15,65 +15,786 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+worker = new Worker('/static/javascripts/worker.js')
+
+worker.addEventListener 'message', (e) ->
+ switch e.data.cmd
+ when 'refresh'
+ frontterm.refresh e.data.lines, e.data.start, e.data.end
+
cols = rows = null
quit = false
$ = document.querySelectorAll.bind(document)
send = (data) ->
- ws.send 'S' + data
+ worker.postMessage
+ cmd: 'data'
+ data: data
ctl = (type, args...) ->
params = args.join(',')
if type == 'Resize'
- ws.send 'R' + params
+ worker.postMessage 'R' + params
+ # ws.send 'R' + params
-ws_url = 'ws://' + document.location.host + '/ws' + location.pathname
-ws = new WebSocket ws_url
-
-ws.addEventListener 'open', ->
- console.log "WebSocket open", arguments
- ws.send 'R' + term.cols + ',' + term.rows
- if location.hash
- setTimeout ->
- ws.send 'S' + location.hash.slice(1) + '\n'
- , 100
-
-ws.addEventListener 'error', ->
- console.log "WebSocket error", arguments
-
-ws.addEventListener 'message', (e) ->
- setTimeout ->
- term.write e.data
- , 1
-
-ws.addEventListener 'close', ->
- console.log "WebSocket closed", arguments
- quit = true
- open('','_self').close()
-
-
-term = new Terminal $('#wrapper')[0], send, ctl
addEventListener 'beforeunload', ->
if not quit
'This will exit the terminal session'
-bench = (n=100000000) ->
- rnd = ''
- while rnd.length < n
- rnd += Math.random().toString(36).substring(2)
-
- t0 = (new Date()).getTime()
- term.write rnd
- console.log "#{n} chars in #{(new Date()).getTime() - t0} ms"
+cancel = (ev) ->
+ ev.preventDefault() if ev.preventDefault
+ ev.stopPropagation() if ev.stopPropagation
+ ev.cancelBubble = true
+ false
-cbench = (n=100000000) ->
- rnd = ''
- while rnd.length < n
- rnd += "\x1b[#{30 + parseInt(Math.random() * 20)}m"
- rnd += Math.random().toString(36).substring(2)
+class FrontTerminal
+ constructor: (@parent) ->
+ # Global elements
+ @context = @parent.ownerDocument.defaultView
+ @document = @parent.ownerDocument
+ @body = @document.getElementsByTagName('body')[0]
- t0 = (new Date()).getTime()
- term.write rnd
- console.log "#{n} chars + colors in #{(new Date()).getTime() - t0} ms"
+ # Main terminal element
+ @element = @document.createElement('div')
+ @element.className = 'terminal focus'
+ @element.style.outline = 'none'
+ @element.setAttribute 'tabindex', 0
+
+ @parent.appendChild(@element)
+
+ # Adding one line to compute char size
+ div = @document.createElement('div')
+ div.className = 'line'
+ @element.appendChild(div)
+ @children = [div]
+
+ @compute_char_size()
+ div.style.height = @char_size.height + 'px'
+ term_size = @parent.getBoundingClientRect()
+ @cols = Math.floor(term_size.width / @char_size.width) - 1 # ?
+ @rows = Math.floor(term_size.height / @char_size.height)
+
+ i = @rows - 1
+ while i--
+ div = @document.createElement('div')
+ div.style.height = @char_size.height + 'px'
+ div.className = 'line'
+ @element.appendChild(div)
+ @children.push(div)
+
+ @visualBell = 100
+ @cursorHidden = false
+ @queue = ''
+
+ # stream
+ @defAttr = (0 << 18) | (257 << 9) | (256 << 0)
+ @skipNextKey = null
+ @cursorState = 0
+
+ # Draw screen
+ # @refresh 0, @rows - 1
+
+ @focus()
+
+ @startBlink()
+ addEventListener 'keydown', @keyDown.bind(@)
+ addEventListener 'keypress', @keyPress.bind(@)
+ addEventListener 'focus', @focus.bind(@)
+ addEventListener 'blur', @blur.bind(@)
+ addEventListener 'paste', @paste.bind(@)
+ addEventListener 'resize', @resize.bind(@)
+
+ # Horrible Firefox paste workaround
+ if typeof InstallTrigger isnt "undefined"
+ @element.contentEditable = 'true'
+ @element.addEventListener "mouseup", (ev) =>
+ sel = getSelection().getRangeAt(0)
+ if sel.startOffset is sel.endOffset
+ getSelection().removeAllRanges()
+
+ @initmouse()
+
+ compute_char_size: ->
+ test_span = document.createElement('span')
+ test_span.textContent = '0123456789'
+ @children[0].appendChild(test_span)
+ @char_size =
+ width: test_span.getBoundingClientRect().width / 10
+ height: @children[0].getBoundingClientRect().height
+ @children[0].removeChild(test_span)
+
+ focus: ->
+ @send('\x1b[I') if @sendFocus
+ @showCursor()
+ @element.classList.add('focus')
+ @element.classList.remove('blur')
+
+ blur: ->
+ @cursorState = 1
+ # @refresh(@y, @y)
+ @send('\x1b[O') if @sendFocus
+ @element.classList.add('blur')
+ @element.classList.remove('focus')
+
+ paste: (ev) ->
+ if ev.clipboardData
+ @send ev.clipboardData.getData('text/plain')
+ else if @context.clipboardData
+ @send @context.clipboardData.getData('Text')
+ cancel(ev)
+
+ # XTerm mouse events
+ # http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
+ # To better understand these
+ # the xterm code is very helpful:
+ # Relevant files:
+ # button.c, charproc.c, misc.c
+ # Relevant functions in xterm/button.c:
+ # BtnCode, EmitButtonCode, EditorButton, SendMousePosition
+ initmouse: ->
+ pressed = 32
+
+ # mouseup, mousedown, mousewheel
+ # left click: ^[[M 3<^[[M#3<
+ # mousewheel up: ^[[M`3>
+ sendButton = (ev) =>
+ # get the xterm-style button
+ button = getButton(ev)
+
+ # get mouse coordinates
+ pos = getCoords(ev)
+ return unless pos
+ sendEvent button, pos
+ switch ev.type
+ when "mousedown"
+ pressed = button
+
+ when "mouseup"
+ # keep it at the left
+ # button, just in case.
+ pressed = 32
+
+ # motion example of a left click:
+ # ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
+ sendMove = (ev) =>
+ button = pressed
+ pos = getCoords(ev)
+ return unless pos
+
+ # buttons marked as motions
+ # are incremented by 32
+ button += 32
+ sendEvent button, pos
+
+ # encode button and
+ # position to characters
+ encode = (data, ch) =>
+ unless @utfMouse
+ return data.push(0) if ch is 255
+ ch = 127 if ch > 127
+ data.push ch
+ else
+ return data.push(0) if ch is 2047
+ if ch < 127
+ data.push ch
+ else
+ ch = 2047 if ch > 2047
+ data.push 0xC0 | (ch >> 6)
+ data.push 0x80 | (ch & 0x3F)
+
+
+ # send a mouse event:
+ # regular/utf8: ^[[M Cb Cx Cy
+ # urxvt: ^[[ Cb ; Cx ; Cy M
+ # sgr: ^[[ Cb ; Cx ; Cy M/m
+ # vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
+ # locator: CSI P e ; P b ; P r ; P c ; P p & w
+ sendEvent = (button, pos) =>
+
+ if @urxvtMouse
+ pos.x -= 32
+ pos.y -= 32
+ pos.x++
+ pos.y++
+ @send "\x1b[" + button + ";" + pos.x + ";" + pos.y + "M"
+ return
+
+ if @sgrMouse
+ pos.x -= 32
+ pos.y -= 32
+ @send "\x1b[<" + (if (button & 3) is 3 then button & ~3 else button) + ";" + pos.x + ";" + pos.y + (if (button & 3) is 3 then "m" else "M")
+ return
+
+ data = []
+ encode data, button
+ encode data, pos.x
+ encode data, pos.y
+ @send "\x1b[M" + String.fromCharCode.apply(String, data)
+
+ getButton = (ev) =>
+ # two low bits:
+ # 0 = left
+ # 1 = middle
+ # 2 = right
+ # 3 = release
+ # wheel up/down:
+ # 1, and 2 - with 64 added
+ switch ev.type
+ when "mousedown"
+ button = if ev.button? then +ev.button else (if ev.which? then ev.which - 1 else null)
+ when "mouseup"
+ button = 3
+ when "wheel"
+ button = if ev.deltaY < 0 then 64 else 65
+
+ # next three bits are the modifiers:
+ # 4 = shift, 8 = meta, 16 = control
+ shift = if ev.shiftKey then 4 else 0
+ meta = if ev.metaKey then 8 else 0
+ ctrl = if ev.ctrlKey then 16 else 0
+ mod = shift | meta | ctrl
+
+ # no mods
+ if @vt200Mouse
+ # ctrl only
+ mod &= ctrl
+ else
+ mod = 0 unless @normalMouse
+
+ # increment to SP
+ (32 + (mod << 2)) + button
+
+ # mouse coordinates measured in cols/rows
+ getCoords = (ev) =>
+ x = ev.pageX
+ y = ev.pageY
+
+ # should probably check offsetParent
+ # but this is more portable
+ el = @element
+ while el and el isnt @document.documentElement
+ x -= el.offsetLeft
+ y -= el.offsetTop
+ el = if "offsetParent" of el then el.offsetParent else el.parentNode
+
+ # convert to cols/rows
+ w = @element.clientWidth
+ h = @element.clientHeight
+ x = Math.ceil((x / w) * @cols)
+ y = Math.ceil((y / h) * @rows)
+
+ # be sure to avoid sending
+ # bad positions to the program
+ x = 0 if x < 0
+ x = @cols if x > @cols
+ y = 0 if y < 0
+ y = @rows if y > @rows
+
+ # xterm sends raw bytes and
+ # starts at 32 (SP) for each.
+ x += 32
+ y += 32
+
+ x: x
+ y: y
+ type: ev.type
+
+ addEventListener "mousedown", (ev) =>
+ return unless @mouseEvents
+
+ # send the button
+ sendButton ev
+
+ # fix for odd bug
+ #if (@vt200Mouse && !@normalMouse) {
+ if @vt200Mouse
+ sendButton
+ __proto__: ev
+ type: "mouseup"
+
+ return cancel(ev)
+
+ addEventListener "mousemove", sendMove.bind(this) if @normalMouse
+
+ # x10 compatibility mode can't send button releases
+ unless @x10Mouse
+ addEventListener "mouseup", up = (ev) =>
+ sendButton ev
+ removeEventListener "mousemove", sendMove if @normalMouse
+ removeEventListener "mouseup", up
+ cancel ev
+ cancel ev
+
+ addEventListener "wheel", (ev) =>
+ if @mouseEvents
+ return if @x10Mouse
+ sendButton ev
+ else
+ return if @applicationKeypad
+ @scrollDisp if ev.deltaY > 0 then 5 else -5
+ cancel ev
+
+
+ refresh: (lines, start, end) ->
+ if end - start >= @rows / 3
+ parent = @element.parentNode
+ parent?.removeChild @element
+
+ width = @cols
+ y = start
+
+ if end >= lines.length
+ end = lines.length - 1
+
+ while y <= end
+ row = y
+ line = lines[row]
+ out = ""
+
+ if y is @y and (@ydisp is @ybase or @selectMode) and not @cursorHidden
+ x = @x
+ else
+ x = -Infinity
+
+ attr = @defAttr
+ i = 0
+ while i < width
+ data = line[i][0]
+ ch = line[i][1]
+ if data isnt attr
+ out += "" if attr isnt @defAttr
+ if data isnt @defAttr
+ classes = []
+ out += "> 9) & 0x1ff
+ flags = data >> 18
+
+ # bold
+ classes.push "bold" if flags & 1
+ # underline
+ classes.push "underline" if flags & 2
+ # blink
+ classes.push "blink" if flags & 4
+ # inverse
+ classes.push "reverse-video" if flags & 8
+ # invisible
+ classes.push "invisible" if flags & 16
+
+ fg += 8 if flags & 1 and fg < 8
+ classes.push "bg-color-" + bg
+ classes.push "fg-color-" + fg
+
+ out += "class=\""
+ out += classes.join(" ")
+ out += "\">"
+ out += "" if i is x
+
+ # This is a temporary dirty hack for raw html insertion
+ if ch.length > 1
+ out += ch
+ else
+ switch ch
+ when "&"
+ out += "&"
+ when "<"
+ out += "<"
+ when ">"
+ out += ">"
+ else
+ if ch <= " "
+ out += " "
+ else
+ i++ if "\uff00" < ch < "\uffef"
+ out += ch
+ out += "" if i is x
+ attr = data
+ i++
+ out += "" if attr isnt @defAttr
+ @children[y].innerHTML = out
+ y++
+
+ parent?.appendChild @element
+
+
+ _cursorBlink: ->
+ @cursorState ^= 1
+ cursor = @element.querySelector(".cursor")
+ return unless cursor
+ if cursor.classList.contains("reverse-video")
+ cursor.classList.remove "reverse-video"
+ else
+ cursor.classList.add "reverse-video"
+
+
+ showCursor: ->
+ return
+ # unless @cursorState
+ # @cursorState = 1
+ # @refresh @y, @y
+
+
+ startBlink: ->
+ return unless @cursorBlink
+ @_blinker = => @_cursorBlink()
+ @_blink = setInterval(@_blinker, 500)
+
+
+ refreshBlink: ->
+ return unless @cursorBlink
+ clearInterval @_blink
+ @_blink = setInterval(@_blinker, 500)
+
+
+ scrollDisp: (disp) ->
+ @ydisp += disp
+ if @ydisp > @ybase
+ @ydisp = @ybase
+
+ else
+ @ydisp = 0 if @ydisp < 0
+
+ # @refresh 0, @rows - 1
+
+ keyDown: (ev) ->
+ # Key Resources:
+ # https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
+ # Don't handle modifiers alone
+ return true if ev.keyCode > 15 and ev.keyCode < 19
+
+ # Handle shift insert and ctrl insert copy/paste usefull for typematrix keyboard
+ return true if (ev.shiftKey or ev.ctrlKey) and ev.keyCode is 45
+
+ # Alt-z works as an escape to relay the following keys to the browser.
+ # usefull to trigger browser shortcuts, i.e.: Alt+Z F5 to reload
+ # May be redundant with keyPrefix
+ if ev.altKey and ev.keyCode is 90 and not @skipNextKey
+ @skipNextKey = true
+ @element.classList.add('skip')
+ return cancel(ev)
+
+ if @skipNextKey
+ @skipNextKey = false
+ @element.classList.remove('skip')
+ return true
+
+ switch ev.keyCode
+ # backspace
+ when 8
+ key = if ev.altKey then "\x1b" else ""
+ if ev.shiftKey
+ key += "\x08" # ^H
+ break
+ key += "\x7f" # ^?
+
+ # tab
+ when 9
+ if ev.shiftKey
+ key = "\x1b[Z"
+ break
+ key = "\t"
+
+ # return/enter
+ when 13
+ key = "\r"
+
+ # escape
+ when 27
+ key = "\x1b"
+
+ # left-arrow
+ when 37
+ if @applicationCursor
+ key = "\x1bOD" # SS3 as ^[O for 7-bit
+ #key = '\x8fD'; // SS3 as 0x8f for 8-bit
+ break
+ return true if ev.shiftKey
+ key = "\x1b[D"
+
+ # right-arrow
+ when 39
+ if @applicationCursor
+ key = "\x1bOC"
+ break
+ return true if ev.shiftKey
+ key = "\x1b[C"
+
+ # up-arrow
+ when 38
+ if @applicationCursor
+ key = "\x1bOA"
+ break
+ if ev.ctrlKey
+ @scrollDisp -1
+ return cancel(ev)
+ else if ev.shiftKey
+ return true
+ else
+ key = "\x1b[A"
+
+ # down-arrow
+ when 40
+ if @applicationCursor
+ key = "\x1bOB"
+ break
+ if ev.ctrlKey
+ @scrollDisp 1
+ return cancel(ev)
+ else if ev.shiftKey
+ return true
+ else
+ key = "\x1b[B"
+
+ # delete
+ when 46
+ key = "\x1b[3~"
+
+ # insert
+ when 45
+ key = "\x1b[2~"
+
+ # home
+ when 36
+ if @applicationKeypad
+ key = "\x1bOH"
+ break
+ key = "\x1bOH"
+
+ # end
+ when 35
+ if @applicationKeypad
+ key = "\x1bOF"
+ break
+ key = "\x1bOF"
+
+ # page up
+ when 33
+ if ev.shiftKey
+ @scrollDisp -(@rows - 1)
+ return cancel(ev)
+ else
+ key = "\x1b[5~"
+
+ # page down
+ when 34
+ if ev.shiftKey
+ @scrollDisp @rows - 1
+ return cancel(ev)
+ else
+ key = "\x1b[6~"
+
+ # F1
+ when 112
+ key = "\x1bOP"
+
+ # F2
+ when 113
+ key = "\x1bOQ"
+
+ # F3
+ when 114
+ key = "\x1bOR"
+
+ # F4
+ when 115
+ key = "\x1bOS"
+
+ # F5
+ when 116
+ key = "\x1b[15~"
+
+ # F6
+ when 117
+ key = "\x1b[17~"
+
+ # F7
+ when 118
+ key = "\x1b[18~"
+
+ # F8
+ when 119
+ key = "\x1b[19~"
+
+ # F9
+ when 120
+ key = "\x1b[20~"
+
+ # F10
+ when 121
+ key = "\x1b[21~"
+
+ # F11
+ when 122
+ key = "\x1b[23~"
+
+ # F12
+ when 123
+ key = "\x1b[24~"
+
+ else
+ # a-z and space
+ if ev.ctrlKey
+ if ev.keyCode >= 65 and ev.keyCode <= 90
+
+ # Ctrl-A
+ if @screenKeys
+ if not @prefixMode and not @selectMode and ev.keyCode is 65
+ @enterPrefix()
+ return cancel(ev)
+
+ # Ctrl-V
+ if @prefixMode and ev.keyCode is 86
+ @leavePrefix()
+ return
+
+ # Ctrl-C
+ if (@prefixMode or @selectMode) and ev.keyCode is 67
+ if @visualMode
+ setTimeout (=>
+ @leaveVisual()
+ return
+ ), 1
+ return
+ key = String.fromCharCode(ev.keyCode - 64)
+ else if ev.keyCode is 32
+
+ # NUL
+ key = String.fromCharCode(0)
+ else if ev.keyCode >= 51 and ev.keyCode <= 55
+
+ # escape, file sep, group sep, record sep, unit sep
+ key = String.fromCharCode(ev.keyCode - 51 + 27)
+ else if ev.keyCode is 56
+
+ # delete
+ key = String.fromCharCode(127)
+ else if ev.keyCode is 219
+
+ # ^[ - escape
+ key = String.fromCharCode(27)
+
+ # ^] - group sep
+ else
+ key = String.fromCharCode(29) if ev.keyCode is 221
+
+ else if ev.altKey
+ if ev.keyCode >= 65 and ev.keyCode <= 90
+ key = "\x1b" + String.fromCharCode(ev.keyCode + 32)
+ else if ev.keyCode is 192
+ key = "\x1b`"
+ else
+ key = "\x1b" + (ev.keyCode - 48) if ev.keyCode >= 48 and ev.keyCode <= 57
+
+ if ev.keyCode >= 37 and ev.keyCode <= 40
+ if ev.ctrlKey
+ key = key.slice(0, -1) + "1;5" + key.slice(-1)
+ else if ev.altKey
+ key = key.slice(0, -1) + "1;3" + key.slice(-1)
+ else key = key.slice(0, -1) + "1;4" + key.slice(-1) if ev.shiftKey
+
+ return true unless key
+
+ if @prefixMode
+ @leavePrefix()
+ return cancel(ev)
+
+ if @selectMode
+ @keySelect ev, key
+ return cancel(ev)
+
+ @showCursor()
+ @handler(key)
+ cancel ev
+
+ keyPress: (ev) ->
+ if @skipNextKey is false
+ @skipNextKey = null
+ return true
+
+ cancel ev
+
+ if ev.charCode
+ key = ev.charCode
+ else unless ev.which?
+ key = ev.keyCode
+ else if ev.which isnt 0 and ev.charCode isnt 0
+ key = ev.which
+ else
+ return false
+
+ return false if not key or ev.ctrlKey or ev.altKey or ev.metaKey
+ key = String.fromCharCode(key)
+
+ @showCursor()
+ @handler key
+ false
+
+ handler: (data) ->
+ worker.postMessage
+ cmd: 'data',
+ data: data
+
+ send: (data) ->
+ unless @queue
+ setTimeout (=>
+ @handler @queue
+ @queue = ""
+ return
+ ), 1
+
+ @queue += data
+
+ bell: ->
+ return unless @visualBell
+ @element.classList.add "bell"
+ setTimeout (=>
+ @element.classList.remove "bell"
+ ), @visualBell
+
+ resize: ->
+ old_cols = @cols
+ old_rows = @rows
+ term_size = @parent.getBoundingClientRect()
+ @cols = Math.floor(term_size.width / @char_size.width) - 1 # ?
+ @rows = Math.floor(term_size.height / @char_size.height)
+ if old_cols == @cols and old_rows == @rows
+ return
+
+ @ctl 'Resize', @cols, @rows
+
+ # resize rows
+ j = old_rows
+ if j < @rows
+ el = @element
+ while j++ < @rows
+ if @children.length < @rows
+ line = @document.createElement("div")
+ line.className = 'line'
+ line.style.height = @char_size.height + 'px'
+ el.appendChild line
+ @children.push line
+ else if j > @rows
+ while j-- > @rows
+ if @children.length > @rows
+ el = @children.pop()
+ continue unless el
+ el.parentNode.removeChild el
+
+
+ get_html_height_in_lines: (html) ->
+ temp_node = document.createElement("div")
+ temp_node.innerHTML = html
+ @element.appendChild temp_node
+ html_height = temp_node.getBoundingClientRect().height
+ @element.removeChild temp_node
+ Math.ceil(html_height / @char_size.height)
+
+
+frontterm = new FrontTerminal $('#wrapper')[0], send, ctl
+worker.postMessage
+ cmd: 'init'
+ cols: frontterm.cols
+ rows: frontterm.rows
+ wsurl: 'ws://' + document.location.host + '/ws' + location.pathname
diff --git a/butterfly/static/coffees/worker.coffee b/butterfly/static/coffees/worker.coffee
new file mode 100644
index 0000000..10e9096
--- /dev/null
+++ b/butterfly/static/coffees/worker.coffee
@@ -0,0 +1,2303 @@
+
+ws = null
+backterm = null
+
+self.addEventListener 'message', (e) ->
+ switch e.data.cmd
+ when 'init'
+ backterm = new BackTerminal(e.data.cols, e.data.rows)
+ ws = new WebSocket e.data.wsurl
+ ws.addEventListener 'open', ->
+ console.log "WebSocket open", arguments
+ ws.send 'R' + e.data.cols + ',' + e.data.rows
+ # ws.send 'R' + term.cols + ',' + term.rows
+ # if location.hash
+ # setTimeout ->
+ # ws.send 'S' + location.hash.slice(1) + '\n'
+ # , 100
+
+ ws.addEventListener 'error', ->
+ console.log "WebSocket error", arguments
+
+ ws.addEventListener 'message', (e) ->
+ backterm.write e.data
+ # setTimeout ->
+ # term.write e.data
+ # , 1
+
+ ws.addEventListener 'close', ->
+ console.log "WebSocket closed", arguments
+ # quit = true
+ # open('','_self').close()
+ when 'data'
+ ws.send 'S' + e.data.data
+
+s = 0
+State =
+ normal: s++
+ escaped: s++
+ csi: s++
+ osc: s++
+ charset: s++
+ dcs: s++
+ ignore: s++
+
+
+class BackTerminal
+ constructor: (@cols, @rows) ->
+ @scrollback = 100000
+ @visualBell = 100
+ @convertEol = false
+ @termName = 'xterm'
+ @cursorBlink = true
+ @screenKeys = false
+ @cursorState = 0
+ @reset_vars()
+
+
+ reset_vars: ->
+ @ybase = 0
+ @ydisp = 0
+ @x = 0
+ @y = 0
+ @state = State.normal
+ @scrollTop = 0
+ @scrollBottom = @rows - 1
+
+ # modes
+ @applicationKeypad = false
+ @applicationCursor = false
+ @originMode = false
+ @wraparoundMode = false
+ @normal = null
+
+ # charset
+ @charset = null
+ @gcharset = null
+ @glevel = 0
+ @charsets = [null]
+
+ # stream
+ @defAttr = (0 << 18) | (257 << 9) | (256 << 0)
+ @curAttr = @defAttr
+ @params = []
+ @currentParam = 0
+ @prefix = ""
+ @lines = []
+ i = @rows
+ @lines.push @blankLine() while i--
+ @setupStops()
+
+ eraseAttr: ->
+ (@defAttr & ~0x1ff) | (@curAttr & 0x1ff)
+
+ scroll: ->
+ if ++@ybase is @scrollback
+ @ybase = @ybase / 2 | 0
+ @lines = @lines.slice(-(@ybase + @rows) + 1)
+
+ @ydisp = @ybase
+
+ # last line
+ row = @ybase + @rows - 1
+
+ # subtract the bottom scroll region
+ row -= @rows - 1 - @scrollBottom
+ if row is @lines.length
+ # potential optimization:
+ # pushing is faster than splicing
+ # when they amount to the same
+ # behavior.
+ @lines.push @blankLine()
+ else
+ # add our new line
+ @lines.splice row, 0, @blankLine()
+
+ if @scrollTop isnt 0
+ if @ybase isnt 0
+ @ybase--
+ @ydisp = @ybase
+ @lines.splice @ybase + @scrollTop, 1
+
+ @updateRange @scrollTop
+ @updateRange @scrollBottom
+
+ scrollDisp: (disp) ->
+ @ydisp += disp
+ if @ydisp > @ybase
+ @ydisp = @ybase
+
+ else
+ @ydisp = 0 if @ydisp < 0
+
+ @refresh 0, @rows - 1
+
+ refresh: (start, end) ->
+ self.postMessage
+ cmd: 'refresh'
+ lines: @lines.slice(@ydisp, @ydisp + @rows)
+ start: start
+ end: end
+
+ write: (data) ->
+ @refreshStart = @y
+ @refreshEnd = @y
+
+ if @ybase isnt @ydisp
+ @ydisp = @ybase
+ @maxRange()
+
+ i = 0
+ l = data.length
+ while i < l
+ ch = data[i]
+ switch @state
+ when State.normal
+ switch ch
+
+ # '\a'
+ when "\x07"
+ @bell()
+
+ # '\n', '\v', '\f'
+ when "\n", "\x0b", "\x0c"
+ @x = 0 if @convertEol
+
+ @y++
+ if @y > @scrollBottom
+ @y--
+ @scroll()
+
+ # '\r'
+ when "\r"
+ @x = 0
+
+ # '\b'
+ when "\b"
+ @x-- if @x > 0
+
+ # '\t'
+ when "\t"
+ @x = @nextStop()
+
+ # shift out
+ when "\x0e"
+ @setgLevel 1
+
+ # shift in
+ when "\x0f"
+ @setgLevel 0
+
+ # '\e'
+ when "\x1b"
+ @state = State.escaped
+
+ else
+ # ' '
+ if ch >= " "
+ ch = @charset[ch] if @charset?[ch]
+ if @x >= @cols
+ @x = 0
+ @y++
+ if @y > @scrollBottom
+ @y--
+ @scroll()
+ @lines[@y + @ybase][@x] = [@curAttr, ch]
+ @x++
+ @updateRange @y
+ if "\uff00" < ch < "\uffef"
+ j = @y + @ybase
+ if @cols < 2 or @x >= @cols
+ @lines[j][@x - 1] = [@curAttr, " "]
+ break
+
+ @lines[j][@x] = [@curAttr, " "]
+ @x++
+
+ when State.escaped
+ switch ch
+ # ESC [ Control Sequence Introducer ( CSI is 0x9b).
+ when "["
+ @params = []
+ @currentParam = 0
+ @state = State.csi
+
+ # ESC ] Operating System Command ( OSC is 0x9d).
+ when "]"
+ @params = []
+ @currentParam = 0
+ @state = State.osc
+
+ # ESC P Device Control String ( DCS is 0x90).
+ when "P"
+ @params = []
+ @currentParam = 0
+ @state = State.dcs
+
+ # ESC _ Application Program Command ( APC is 0x9f).
+ when "_"
+ @state = State.ignore
+
+ # ESC ^ Privacy Message ( PM is 0x9e).
+ when "^"
+ @state = State.ignore
+
+ # ESC c Full Reset (RIS).
+ when "c"
+ @reset()
+
+ # ESC E Next Line ( NEL is 0x85).
+ when "E"
+ @x = 0
+ @index()
+
+ # ESC D Index ( IND is 0x84).
+ when "D"
+ @index()
+
+ # ESC M Reverse Index ( RI is 0x8d).
+ when "M"
+ @reverseIndex()
+
+ # ESC % Select default/utf-8 character set.
+ # @ = default, G = utf-8
+ when "%"
+ @setgLevel 0
+ @setgCharset 0, BackTerminal::charsets.US
+ @state = State.normal
+ i++
+
+ # ESC (,),*,+,-,. Designate G0-G2 Character Set.
+ # <-- this seems to get all the attention
+ when "(", ")" , "*" , "+" , "-" , "."
+ switch ch
+ when "("
+ @gcharset = 0
+ when ")", "-"
+ @gcharset = 1
+ when "*", "."
+ @gcharset = 2
+ when "+"
+ @gcharset = 3
+ @state = State.charset
+
+ # Designate G3 Character Set (VT300).
+ # A = ISO Latin-1 Supplemental.
+ # Not implemented.
+ when "/"
+ @gcharset = 3
+ @state = State.charset
+ i--
+
+ # ESC n
+ # Invoke the G2 Character Set as GL (LS2).
+ when "n"
+ @setgLevel 2
+
+ # ESC o
+ # Invoke the G3 Character Set as GL (LS3).
+ when "o"
+ @setgLevel 3
+
+ # ESC |
+ # Invoke the G3 Character Set as GR (LS3R).
+ when "|"
+ @setgLevel 3
+
+ # ESC }
+ # Invoke the G2 Character Set as GR (LS2R).
+ when "}"
+ @setgLevel 2
+
+ # ESC ~
+ # Invoke the G1 Character Set as GR (LS1R).
+ when "~"
+ @setgLevel 1
+
+ # ESC 7 Save Cursor (DECSC).
+ when "7"
+ @saveCursor()
+ @state = State.normal
+
+ # ESC 8 Restore Cursor (DECRC).
+ when "8"
+ @restoreCursor()
+ @state = State.normal
+
+ # ESC # 3 DEC line height/width
+ when "#"
+ @state = State.normal
+ i++
+
+ # ESC H Tab Set (HTS is 0x88).
+ when "H"
+ @tabSet()
+
+ # ESC = Application Keypad (DECPAM).
+ when "="
+ @applicationKeypad = true
+ @state = State.normal
+
+ # ESC > Normal Keypad (DECPNM).
+ when ">"
+ @applicationKeypad = false
+ @state = State.normal
+ else
+ @state = State.normal
+ console.log "Unknown ESC control:", ch
+
+ when State.charset
+ switch ch
+ when "0" # DEC Special Character and Line Drawing Set.
+ cs = BackTerminal::charsets.SCLD
+ when "A" # UK
+ cs = BackTerminal::charsets.UK
+ when "B" # United States (USASCII).
+ cs = BackTerminal::charsets.US
+ when "4" # Dutch
+ cs = BackTerminal::charsets.Dutch
+ # Finnish
+ when "C", "5"
+ cs = BackTerminal::charsets.Finnish
+ when "R" # French
+ cs = BackTerminal::charsets.French
+ when "Q" # FrenchCanadian
+ cs = BackTerminal::charsets.FrenchCanadian
+ when "K" # German
+ cs = BackTerminal::charsets.German
+ when "Y" # Italian
+ cs = BackTerminal::charsets.Italian
+ # NorwegianDanish
+ when "E", "6"
+ cs = BackTerminal::charsets.NorwegianDanish
+ when "Z" # Spanish
+ cs = BackTerminal::charsets.Spanish
+ # Swedish
+ when "H", "7"
+ cs = BackTerminal::charsets.Swedish
+ when "=" # Swiss
+ cs = BackTerminal::charsets.Swiss
+ when "/" # ISOLatin (actually /A)
+ cs = BackTerminal::charsets.ISOLatin
+ i++
+ else # Default
+ cs = BackTerminal::charsets.US
+ @setgCharset @gcharset, cs
+ @gcharset = null
+ @state = State.normal
+
+ when State.osc
+ # OSC Ps ; Pt ST
+ # OSC Ps ; Pt BEL
+ # Set Text Parameters.
+ if ch is "\x1b" or ch is "\x07"
+ i++ if ch is "\x1b"
+ @params.push @currentParam
+ switch @params[0]
+ when 0, 1 , 2
+ if @params[1]
+ @title = @params[1] + " - ƸӜƷ butterfly"
+ @handleTitle @title
+
+ when 99
+ # Custom escape to produce raw html
+ html = "
" + @params[1] + "
"
+ @lines[@y + @ybase][@x] = [
+ @curAttr
+ html
+ ]
+ line = 0
+
+ while line < @get_html_height_in_lines(html) - 1
+ @y++
+ if @y > @scrollBottom
+ @y--
+ @scroll()
+ line++
+ @updateRange @y
+
+ # reset colors
+ @params = []
+ @currentParam = 0
+ @state = State.normal
+ else
+ unless @params.length
+ if ch >= "0" and ch <= "9"
+ @currentParam = @currentParam * 10 + ch.charCodeAt(0) - 48
+ else if ch is ";"
+ @params.push @currentParam
+ @currentParam = ""
+ else
+ @currentParam += ch
+
+ when State.csi
+ # '?', '>', '!'
+ if ch is "?" or ch is ">" or ch is "!"
+ @prefix = ch
+ break
+
+ # 0 - 9
+ if ch >= "0" and ch <= "9"
+ @currentParam = @currentParam * 10 + ch.charCodeAt(0) - 48
+ break
+
+ # '$', '"', ' ', '\''
+ if ch is "$" or ch is "\"" or ch is " " or ch is "'"
+ break
+ @params.push @currentParam
+ @currentParam = 0
+
+ # ';'
+ break if ch is ";"
+ @state = State.normal
+ switch ch
+ # CSI Ps A
+ # Cursor Up Ps Times (default = 1) (CUU).
+ when "A"
+ @cursorUp @params
+
+ # CSI Ps B
+ # Cursor Down Ps Times (default = 1) (CUD).
+ when "B"
+ @cursorDown @params
+
+ # CSI Ps C
+ # Cursor Forward Ps Times (default = 1) (CUF).
+ when "C"
+ @cursorForward @params
+
+ # CSI Ps D
+ # Cursor Backward Ps Times (default = 1) (CUB).
+ when "D"
+ @cursorBackward @params
+
+ # CSI Ps ; Ps H
+ # Cursor Position [row;column] (default = [1,1]) (CUP).
+ when "H"
+ @cursorPos @params
+
+ # CSI Ps J Erase in Display (ED).
+ when "J"
+ @eraseInDisplay @params
+
+ # CSI Ps K Erase in Line (EL).
+ when "K"
+ @eraseInLine @params
+
+ # CSI Pm m Character Attributes (SGR).
+ when "m"
+ @charAttributes @params unless @prefix
+
+ # CSI Ps n Device Status Report (DSR).
+ when "n"
+ @deviceStatus @params unless @prefix
+
+ # CSI Ps @
+ # Insert Ps (Blank) Character(s) (default = 1) (ICH).
+ when "@"
+ @insertChars @params
+
+ # CSI Ps E
+ # Cursor Next Line Ps Times (default = 1) (CNL).
+ when "E"
+ @cursorNextLine @params
+
+ # CSI Ps F
+ # Cursor Preceding Line Ps Times (default = 1) (CNL).
+ when "F"
+ @cursorPrecedingLine @params
+
+ # CSI Ps G
+ # Cursor Character Absolute [column] (default = [row,1]) (CHA).
+ when "G"
+ @cursorCharAbsolute @params
+
+ # CSI Ps L
+ # Insert Ps Line(s) (default = 1) (IL).
+ when "L"
+ @insertLines @params
+
+ # CSI Ps M
+ # Delete Ps Line(s) (default = 1) (DL).
+ when "M"
+ @deleteLines @params
+
+ # CSI Ps P
+ # Delete Ps Character(s) (default = 1) (DCH).
+ when "P"
+ @deleteChars @params
+
+ # CSI Ps X
+ # Erase Ps Character(s) (default = 1) (ECH).
+ when "X"
+ @eraseChars @params
+
+ # CSI Pm ` Character Position Absolute
+ # [column] (default = [row,1]) (HPA).
+ when "`"
+ @charPosAbsolute @params
+
+ # 141 61 a * HPR -
+ # Horizontal Position Relative
+ when "a"
+ @HPositionRelative @params
+
+ # CSI P s c
+ # Send Device Attributes (Primary DA).
+ # CSI > P s c
+ # Send Device Attributes (Secondary DA)
+ when "c"
+ @sendDeviceAttributes @params
+
+ # CSI Pm d
+ # Line Position Absolute [row] (default = [1,column]) (VPA).
+ when "d"
+ @linePosAbsolute @params
+
+ # 145 65 e * VPR - Vertical Position Relative
+ when "e"
+ @VPositionRelative @params
+
+ # CSI Ps ; Ps f
+ # Horizontal and Vertical Position [row;column] (default =
+ # [1,1]) (HVP).
+ when "f"
+ @HVPosition @params
+
+ # CSI Pm h Set Mode (SM).
+ # CSI ? Pm h - mouse escape codes, cursor escape codes
+ when "h"
+ @setMode @params
+
+ # CSI Pm l Reset Mode (RM).
+ # CSI ? Pm l
+ when "l"
+ @resetMode @params
+
+ # CSI Ps ; Ps r
+ # Set Scrolling Region [top;bottom] (default = full size of win-
+ # dow) (DECSTBM).
+ # CSI ? Pm r
+ when "r"
+ @setScrollRegion @params
+
+ # CSI s
+ # Save cursor (ANSI.SYS).
+ when "s"
+ @saveCursor @params
+
+ # CSI u
+ # Restore cursor (ANSI.SYS).
+ when "u"
+ @restoreCursor @params
+
+ # CSI Ps I
+ # Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
+ when "I"
+ @cursorForwardTab @params
+
+ # CSI Ps S Scroll up Ps lines (default = 1) (SU).
+ when "S"
+ @scrollUp @params
+
+ # CSI Ps T Scroll down Ps lines (default = 1) (SD).
+ # CSI Ps ; Ps ; Ps ; Ps ; Ps T
+ # CSI > Ps; Ps T
+ when "T"
+ @scrollDown @params if @params.length < 2 and not @prefix
+
+ # CSI Ps Z
+ # Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
+ when "Z"
+ @cursorBackwardTab @params
+
+ # CSI Ps b Repeat the preceding graphic character Ps times (REP).
+ when "b"
+ @repeatPrecedingCharacter @params
+
+ # CSI Ps g Tab Clear (TBC).
+ when "g"
+ @tabClear @params
+
+ # CSI > Ps p Set pointer mode.
+ # CSI ! p Soft terminal reset (DECSTR).
+ # CSI Ps$ p
+ # Request ANSI mode (DECRQM).
+ # CSI ? Ps$ p
+ # Request DEC private mode (DECRQM).
+ # CSI Ps ; Ps " p
+ when "p"
+ if @prefix is '!'
+ @softReset @params
+
+ else
+ @error "Unknown CSI code: %s.", ch
+ @prefix = ""
+
+ when State.dcs
+ if ch is "\x1b" or ch is "\x07"
+ i++ if ch is "\x1b"
+ switch @prefix
+ # User-Defined Keys (DECUDK).
+ when ""
+ break
+
+ # Request Status String (DECRQSS).
+ # test: echo -e '\eP$q"p\e\\'
+ when "$q"
+ pt = @currentParam
+ valid = false
+ switch pt
+
+ # DECSCA
+ when "\"q"
+ pt = "0\"q"
+
+ # DECSCL
+ when "\"p"
+ pt = "61\"p"
+
+ # DECSTBM
+ when "r"
+ pt = "" + (@scrollTop + 1) + ";" + (@scrollBottom + 1) + "r"
+
+ # SGR
+ when "m"
+ pt = "0m"
+
+ else
+ @error "Unknown DCS Pt: %s.", pt
+ pt = ""
+
+ @send "\x1bP" + +valid + "$r" + pt + "\x1b\\"
+
+ when "+q"
+ pt = @currentParam
+ valid = false
+ @send "\x1bP" + +valid + "+r" + pt + "\x1b\\"
+
+ else
+ @error "Unknown DCS prefix: %s.", @prefix
+
+ @currentParam = 0
+ @prefix = ""
+ @state = State.normal
+
+ else unless @currentParam
+ if not @prefix and ch isnt "$" and ch isnt "+"
+ @currentParam = ch
+ else if @prefix.length is 2
+ @currentParam = ch
+ else
+ @prefix += ch
+ else
+ @currentParam += ch
+
+ when State.ignore
+ # For PM and APC.
+ if ch is "\x1b" or ch is "\x07"
+ i++ if ch is "\x1b"
+ @state = State.normal
+ i++
+ @updateRange @y
+ @refresh @refreshStart, @refreshEnd
+
+ writeln: (data) ->
+ @write "#{data}\r\n"
+
+ setgLevel: (g) ->
+ @glevel = g
+ @charset = @charsets[g]
+
+ setgCharset: (g, charset) ->
+ @charsets[g] = charset
+ @charset = charset if @glevel is g
+
+ resize: (cols, rows) ->
+ @cols = cols
+ @rows = rows
+ # resize cols
+ if old_cols < @cols
+ # does xterm use the default attr?
+ ch = [@defAttr, " "]
+ i = @lines.length
+ while i--
+ @lines[i].push ch while @lines[i].length < @cols
+ else if old_cols > @cols
+ i = @lines.length
+ while i--
+ @lines[i].pop() while @lines[i].length > @cols
+
+ @setupStops old_cols
+
+ # resize rows
+ j = old_rows
+ if j < @rows
+ while j++ < @rows
+ @lines.push @blankLine() if @lines.length < @rows + @ybase
+ else if j > @rows
+ while j-- > @rows
+ @lines.pop() if @lines.length > @rows + @ybase
+
+ # make sure the cursor stays on screen
+ @y = @rows - 1 if @y >= @rows
+ @x = @cols - 1 if @x >= @cols
+
+ @scrollTop = 0
+ @scrollBottom = @rows - 1
+
+ # TODO
+ # @refresh 0, @rows - 1
+
+ # it's a real nightmare trying
+ # to resize the original
+ # screen buffer. just set it
+ # to null for now.
+ @normal = null
+
+ updateRange: (y) ->
+ @refreshStart = y if y < @refreshStart
+ @refreshEnd = y if y > @refreshEnd
+
+ maxRange: ->
+ @refreshStart = 0
+ @refreshEnd = @rows - 1
+
+ setupStops: (i) ->
+ if i?
+ i = @prevStop(i) unless @tabs[i]
+ else
+ @tabs = {}
+ i = 0
+ while i < @cols
+ @tabs[i] = true
+ i += 8
+
+ prevStop: (x) ->
+ x = @x unless x?
+ while not @tabs[--x] and x > 0
+ 1
+
+ if x >= @cols then @cols - 1 else (if x < 0 then 0 else x)
+
+ nextStop: (x) ->
+ x = @x unless x?
+ while not @tabs[++x] and x < @cols
+ 1
+
+ if x >= @cols then @cols - 1 else (if x < 0 then 0 else x)
+
+ eraseRight: (x, y) ->
+ line = @lines[@ybase + y]
+ # xterm
+ ch = [@eraseAttr(), " "]
+
+ while x < @cols
+ line[x] = ch
+ x++
+ @updateRange y
+
+ eraseLeft: (x, y) ->
+ line = @lines[@ybase + y]
+ # xterm
+ ch = [@eraseAttr(), " "]
+ x++
+ line[x] = ch while x--
+ @updateRange y
+
+ eraseLine: (y) ->
+ @eraseRight 0, y
+
+ blankLine: (cur) ->
+ attr = (if cur then @eraseAttr() else @defAttr)
+ ch = [attr, " "]
+ line = []
+ i = 0
+ while i < @cols
+ line[i] = ch
+ i++
+ line
+
+ ch: (cur) ->
+ if cur then [@eraseAttr(), " "] else [@defAttr, " "]
+
+ isterm: (term) ->
+ "#{@termName}".indexOf(term) is 0
+
+ handler: (data) ->
+ @out data
+
+ handleTitle: (title) ->
+ # document.title = title
+
+ ## ESC ##
+
+ # ESC D Index (IND is 0x84).
+ index: ->
+ @y++
+ if @y > @scrollBottom
+ @y--
+ @scroll()
+ @state = State.normal
+
+ # ESC M Reverse Index (RI is 0x8d).
+ reverseIndex: ->
+ @y--
+ if @y < @scrollTop
+ @y++
+
+ # possibly move the code below to term.reverseScroll();
+ # test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
+ # blankLine(true) is xterm/linux behavior
+ @lines.splice @y + @ybase, 0, @blankLine(true)
+ j = @rows - 1 - @scrollBottom
+ @lines.splice @rows - 1 + @ybase - j + 1, 1
+
+ # @maxRange();
+ @updateRange @scrollTop
+ @updateRange @scrollBottom
+ @state = State.normal
+
+
+ # ESC c Full Reset (RIS).
+ reset: ->
+ @reset_vars()
+ @refresh 0, @rows - 1
+
+ # ESC H Tab Set (HTS is 0x88).
+ tabSet: ->
+ @tabs[@x] = true
+ @state = State.normal
+
+
+ ## CSI ##
+
+ # CSI Ps A
+ # Cursor Up Ps Times (default = 1) (CUU).
+ cursorUp: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @y -= param
+ @y = 0 if @y < 0
+
+ # CSI Ps B
+ # Cursor Down Ps Times (default = 1) (CUD).
+ cursorDown: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @y += param
+ @y = @rows - 1 if @y >= @rows
+
+ # CSI Ps C
+ # Cursor Forward Ps Times (default = 1) (CUF).
+ cursorForward: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @x += param
+ @x = @cols - 1 if @x >= @cols
+
+ # CSI Ps D
+ # Cursor Backward Ps Times (default = 1) (CUB).
+ cursorBackward: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @x -= param
+ @x = 0 if @x < 0
+
+ # CSI Ps ; Ps H
+ # Cursor Position [row;column] (default = [1,1]) (CUP).
+ cursorPos: (params) ->
+ row = params[0] - 1
+ if params.length >= 2
+ col = params[1] - 1
+ else
+ col = 0
+
+ if row < 0
+ row = 0
+ else
+ row = @rows - 1 if row >= @rows
+
+ if col < 0
+ col = 0
+ else
+ col = @cols - 1 if col >= @cols
+
+ @x = col
+ @y = row
+
+
+ # CSI Ps J Erase in Display (ED).
+ # Ps = 0 -> Erase Below (default).
+ # Ps = 1 -> Erase Above.
+ # Ps = 2 -> Erase All.
+ # Ps = 3 -> Erase Saved Lines (xterm).
+ # CSI ? Ps J
+ # Erase in Display (DECSED).
+ # Ps = 0 -> Selective Erase Below (default).
+ # Ps = 1 -> Selective Erase Above.
+ # Ps = 2 -> Selective Erase All.
+ eraseInDisplay: (params) ->
+ switch params[0]
+ when 0
+ @eraseRight @x, @y
+ j = @y + 1
+ while j < @rows
+ @eraseLine j
+ j++
+ when 1
+ @eraseLeft @x, @y
+ j = @y
+ @eraseLine j while j--
+ when 2
+ j = @rows
+ @eraseLine j while j--
+
+
+ # CSI Ps K Erase in Line (EL).
+ # Ps = 0 -> Erase to Right (default).
+ # Ps = 1 -> Erase to Left.
+ # Ps = 2 -> Erase All.
+ # CSI ? Ps K
+ # Erase in Line (DECSEL).
+ # Ps = 0 -> Selective Erase to Right (default).
+ # Ps = 1 -> Selective Erase to Left.
+ # Ps = 2 -> Selective Erase All.
+ eraseInLine: (params) ->
+ switch params[0]
+ when 0
+ @eraseRight @x, @y
+ when 1
+ @eraseLeft @x, @y
+ when 2
+ @eraseLine @y
+
+
+ # CSI Pm m Character Attributes (SGR).
+ # Ps = 0 -> Normal (default).
+ # Ps = 1 -> Bold.
+ # Ps = 4 -> Underlined.
+ # Ps = 5 -> Blink (appears as Bold).
+ # Ps = 7 -> Inverse.
+ # Ps = 8 -> Invisible, i.e., hidden (VT300).
+ # Ps = 2 2 -> Normal (neither bold nor faint).
+ # Ps = 2 4 -> Not underlined.
+ # Ps = 2 5 -> Steady (not blinking).
+ # Ps = 2 7 -> Positive (not inverse).
+ # Ps = 2 8 -> Visible, i.e., not hidden (VT300).
+ # Ps = 3 0 -> Set foreground color to Black.
+ # Ps = 3 1 -> Set foreground color to Red.
+ # Ps = 3 2 -> Set foreground color to Green.
+ # Ps = 3 3 -> Set foreground color to Yellow.
+ # Ps = 3 4 -> Set foreground color to Blue.
+ # Ps = 3 5 -> Set foreground color to Magenta.
+ # Ps = 3 6 -> Set foreground color to Cyan.
+ # Ps = 3 7 -> Set foreground color to White.
+ # Ps = 3 9 -> Set foreground color to default (original).
+ # Ps = 4 0 -> Set background color to Black.
+ # Ps = 4 1 -> Set background color to Red.
+ # Ps = 4 2 -> Set background color to Green.
+ # Ps = 4 3 -> Set background color to Yellow.
+ # Ps = 4 4 -> Set background color to Blue.
+ # Ps = 4 5 -> Set background color to Magenta.
+ # Ps = 4 6 -> Set background color to Cyan.
+ # Ps = 4 7 -> Set background color to White.
+ # Ps = 4 9 -> Set background color to default (original).
+
+ # If 16-color support is compiled, the following apply. Assume
+ # that xterm's resources are set so that the ISO color codes are
+ # the first 8 of a set of 16. Then the aixterm colors are the
+ # bright versions of the ISO colors:
+ # Ps = 9 0 -> Set foreground color to Black.
+ # Ps = 9 1 -> Set foreground color to Red.
+ # Ps = 9 2 -> Set foreground color to Green.
+ # Ps = 9 3 -> Set foreground color to Yellow.
+ # Ps = 9 4 -> Set foreground color to Blue.
+ # Ps = 9 5 -> Set foreground color to Magenta.
+ # Ps = 9 6 -> Set foreground color to Cyan.
+ # Ps = 9 7 -> Set foreground color to White.
+ # Ps = 1 0 0 -> Set background color to Black.
+ # Ps = 1 0 1 -> Set background color to Red.
+ # Ps = 1 0 2 -> Set background color to Green.
+ # Ps = 1 0 3 -> Set background color to Yellow.
+ # Ps = 1 0 4 -> Set background color to Blue.
+ # Ps = 1 0 5 -> Set background color to Magenta.
+ # Ps = 1 0 6 -> Set background color to Cyan.
+ # Ps = 1 0 7 -> Set background color to White.
+
+ # If xterm is compiled with the 16-color support disabled, it
+ # supports the following, from rxvt:
+ # Ps = 1 0 0 -> Set foreground and background color to
+ # default.
+
+ # If 88- or 256-color support is compiled, the following apply.
+ # Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
+ # Ps.
+ # Ps = 4 8 ; 5 ; Ps -> Set background color to the second
+ # Ps.
+ charAttributes: (params) ->
+ # Optimize a single SGR0.
+ if params.length is 1 and params[0] is 0
+ @curAttr = @defAttr
+ return
+ flags = @curAttr >> 18
+
+ fg = (@curAttr >> 9) & 0x1ff
+ bg = @curAttr & 0x1ff
+
+ l = params.length
+ i = 0
+ while i < l
+ p = params[i]
+ if p >= 30 and p <= 37
+ # fg color 8
+ fg = p - 30
+ else if p >= 40 and p <= 47
+ # bg color 8
+ bg = p - 40
+ else if p >= 90 and p <= 97
+ # fg color 16
+ p += 8
+ fg = p - 90
+ else if p >= 100 and p <= 107
+ # bg color 16
+ p += 8
+ bg = p - 100
+ else if p is 0
+ # default
+ flags = @defAttr >> 18
+ fg = (@defAttr >> 9) & 0x1ff
+ bg = @defAttr & 0x1ff
+
+ # flags = 0;
+ # fg = 0x1ff;
+ # bg = 0x1ff;
+ else if p is 1
+ # bold text
+ flags |= 1
+ else if p is 4
+ # underlined text
+ flags |= 2
+ else if p is 5
+ # blink
+ flags |= 4
+ else if p is 7
+ # inverse and positive
+ # test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
+ flags |= 8
+ else if p is 8
+ # invisible
+ flags |= 16
+ else if p is 22
+ # not bold
+ flags &= ~1
+ else if p is 24
+ # not underlined
+ flags &= ~2
+ else if p is 25
+ # not blink
+ flags &= ~4
+ else if p is 27
+ # not inverse
+ flags &= ~8
+ else if p is 28
+ # not invisible
+ flags &= ~16
+ else if p is 39
+ # reset fg
+ fg = (@defAttr >> 9) & 0x1ff
+ else if p is 49
+ # reset bg
+ bg = @defAttr & 0x1ff
+ else if p is 38
+ if params[i + 1] is 2
+ # fg color 2^24
+ i += 2
+ fg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff
+ i += 2
+ else if params[i + 1] is 5
+ # fg color 256
+ i += 2
+ fg = params[i] & 0xff
+ else if p is 48
+ if params[i + 1] is 2
+ # bg color 2^24
+ i += 2
+ bg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff
+ i += 2
+ else if params[i + 1] is 5
+ # bg color 256
+ i += 2
+ bg = params[i] & 0xff
+ else if p is 100
+ # reset fg/bg
+ fg = (@defAttr >> 9) & 0x1ff
+ bg = @defAttr & 0x1ff
+ else
+ @error "Unknown SGR attribute: %d.", p
+ i++
+ @curAttr = (flags << 18) | (fg << 9) | bg
+
+
+ # CSI Ps n Device Status Report (DSR).
+ # Ps = 5 -> Status Report. Result (``OK'') is
+ # CSI 0 n
+ # Ps = 6 -> Report Cursor Position (CPR) [row;column].
+ # Result is
+ # CSI r ; c R
+ # CSI ? Ps n
+ # Device Status Report (DSR, DEC-specific).
+ # Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
+ # ? r ; c R (assumes page is zero).
+ # Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
+ # or CSI ? 1 1 n (not ready).
+ # Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
+ # or CSI ? 2 1 n (locked).
+ # Ps = 2 6 -> Report Keyboard status as
+ # CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
+ # The last two parameters apply to VT400 & up, and denote key-
+ # board ready and LK01 respectively.
+ # Ps = 5 3 -> Report Locator status as
+ # CSI ? 5 3 n Locator available, if compiled-in, or
+ # CSI ? 5 0 n No Locator, if not.
+ deviceStatus: (params) ->
+ unless @prefix
+ switch params[0]
+ when 5
+ # status report
+ @send "\x1b[0n"
+ when 6
+ # cursor position
+ @send "\x1b[" + (@y + 1) + ";" + (@x + 1) + "R"
+ else if @prefix is "?"
+ # modern xterm doesnt seem to
+ # respond to any of these except ?6, 6, and 5
+ if params[0] is 6
+ # cursor position
+ @send "\x1b[?" + (@y + 1) + ";" + (@x + 1) + "R"
+
+
+ ## Additions ##
+
+ # CSI Ps @
+ # Insert Ps (Blank) Character(s) (default = 1) (ICH).
+ insertChars: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ row = @y + @ybase
+ j = @x
+ # xterm
+ ch = [@eraseAttr(), " "]
+ while param-- and j < @cols
+ @lines[row].splice j++, 0, ch
+ @lines[row].pop()
+
+
+ # CSI Ps E
+ # Cursor Next Line Ps Times (default = 1) (CNL).
+ # same as CSI Ps B ?
+ cursorNextLine: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @y += param
+ @y = @rows - 1 if @y >= @rows
+ @x = 0
+
+
+ # CSI Ps F
+ # Cursor Preceding Line Ps Times (default = 1) (CNL).
+ # reuse CSI Ps A ?
+ cursorPrecedingLine: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @y -= param
+ @y = 0 if @y < 0
+ @x = 0
+
+
+ # CSI Ps G
+ # Cursor Character Absolute [column] (default = [row,1]) (CHA).
+ cursorCharAbsolute: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @x = param - 1
+
+ # CSI Ps L
+ # Insert Ps Line(s) (default = 1) (IL).
+ insertLines: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ row = @y + @ybase
+ j = @rows - 1 - @scrollBottom
+ j = @rows - 1 + @ybase - j + 1
+ while param--
+ # test: echo -e '\e[44m\e[1L\e[0m'
+ # blankLine(true) - xterm/linux behavior
+ @lines.splice row, 0, @blankLine(true)
+ @lines.splice j, 1
+
+ @updateRange @y
+ @updateRange @scrollBottom
+
+
+ # CSI Ps M
+ # Delete Ps Line(s) (default = 1) (DL).
+ deleteLines: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ row = @y + @ybase
+ j = @rows - 1 - @scrollBottom
+ j = @rows - 1 + @ybase - j
+ while param--
+ # test: echo -e '\e[44m\e[1M\e[0m'
+ # blankLine(true) - xterm/linux behavior
+ @lines.splice j + 1, 0, @blankLine(true)
+ @lines.splice row, 1
+
+ @updateRange @y
+ @updateRange @scrollBottom
+
+
+ # CSI Ps P
+ # Delete Ps Character(s) (default = 1) (DCH).
+ deleteChars: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ row = @y + @ybase
+ # xterm
+ ch = [@eraseAttr(), " "]
+ while param--
+ @lines[row].splice @x, 1
+ @lines[row].push ch
+
+
+ # CSI Ps X
+ # Erase Ps Character(s) (default = 1) (ECH).
+ eraseChars: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ row = @y + @ybase
+ j = @x
+ # xterm
+ ch = [@eraseAttr(), " "]
+ @lines[row][j++] = ch while param-- and j < @cols
+
+
+ # CSI Pm ` Character Position Absolute
+ # [column] (default = [row,1]) (HPA).
+ charPosAbsolute: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @x = param - 1
+ @x = @cols - 1 if @x >= @cols
+
+
+ # 141 61 a * HPR -
+ # Horizontal Position Relative
+ # reuse CSI Ps C ?
+ HPositionRelative: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @x += param
+ @x = @cols - 1 if @x >= @cols
+
+
+ # CSI Ps c Send Device Attributes (Primary DA).
+ # Ps = 0 or omitted -> request attributes from terminal. The
+ # response depends on the decTerminalID resource setting.
+ # -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'')
+ # -> CSI ? 1 ; 0 c (``VT101 with No Options'')
+ # -> CSI ? 6 c (``VT102'')
+ # -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'')
+ # The VT100-style response parameters do not mean anything by
+ # themselves. VT220 parameters do, telling the host what fea-
+ # tures the terminal supports:
+ # Ps = 1 -> 132-columns.
+ # Ps = 2 -> Printer.
+ # Ps = 6 -> Selective erase.
+ # Ps = 8 -> User-defined keys.
+ # Ps = 9 -> National replacement character sets.
+ # Ps = 1 5 -> Technical characters.
+ # Ps = 2 2 -> ANSI color, e.g., VT525.
+ # Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode).
+ # CSI > Ps c
+ # Send Device Attributes (Secondary DA).
+ # Ps = 0 or omitted -> request the terminal's identification
+ # code. The response depends on the decTerminalID resource set-
+ # ting. It should apply only to VT220 and up, but xterm extends
+ # this to VT100.
+ # -> CSI > Pp ; Pv ; Pc c
+ # where Pp denotes the terminal type
+ # Pp = 0 -> ``VT100''.
+ # Pp = 1 -> ``VT220''.
+ # and Pv is the firmware version (for xterm, this was originally
+ # the XFree86 patch number, starting with 95). In a DEC termi-
+ # nal, Pc indicates the ROM cartridge registration number and is
+ # always zero.
+ # More information:
+ # xterm/charproc.c - line 2012, for more information.
+ # vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
+ sendDeviceAttributes: (params) ->
+ return if params[0] > 0
+ unless @prefix
+ if @isterm("xterm") or @isterm("rxvt-unicode") or @isterm("screen")
+ @send "\x1b[?1;2c"
+ else @send "\x1b[?6c" if @isterm("linux")
+
+ else if @prefix is ">"
+ # xterm and urxvt
+ # seem to spit this
+ # out around ~370 times (?).
+ if @isterm("xterm")
+ @send "\x1b[>0;276;0c"
+ else if @isterm("rxvt-unicode")
+ @send "\x1b[>85;95;0c"
+ else if @isterm("linux")
+ # not supported by linux console.
+ # linux console echoes parameters.
+ @send params[0] + "c"
+ else @send "\x1b[>83;40003;0c" if @isterm("screen")
+
+
+ # CSI Pm d
+ # Line Position Absolute [row] (default = [1,column]) (VPA).
+ linePosAbsolute: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @y = param - 1
+ @y = @rows - 1 if @y >= @rows
+
+
+ # 145 65 e * VPR - Vertical Position Relative
+ # reuse CSI Ps B ?
+ VPositionRelative: (params) ->
+ param = params[0]
+ param = 1 if param < 1
+ @y += param
+ @y = @rows - 1 if @y >= @rows
+
+
+ # CSI Ps ; Ps f
+ # Horizontal and Vertical Position [row;column] (default =
+ # [1,1]) (HVP).
+ HVPosition: (params) ->
+ params[0] = 1 if params[0] < 1
+ params[1] = 1 if params[1] < 1
+ @y = params[0] - 1
+ @y = @rows - 1 if @y >= @rows
+ @x = params[1] - 1
+ @x = @cols - 1 if @x >= @cols
+
+
+ # CSI Pm h Set Mode (SM).
+ # Ps = 2 -> Keyboard Action Mode (AM).
+ # Ps = 4 -> Insert Mode (IRM).
+ # Ps = 1 2 -> Send/receive (SRM).
+ # Ps = 2 0 -> Automatic Newline (LNM).
+ # CSI ? Pm h
+ # DEC Private Mode Set (DECSET).
+ # Ps = 1 -> Application Cursor Keys (DECCKM).
+ # Ps = 2 -> Designate USASCII for character sets G0-G3
+ # (DECANM), and set VT100 mode.
+ # Ps = 3 -> 132 Column Mode (DECCOLM).
+ # Ps = 4 -> Smooth (Slow) Scroll (DECSCLM).
+ # Ps = 5 -> Reverse Video (DECSCNM).
+ # Ps = 6 -> Origin Mode (DECOM).
+ # Ps = 7 -> Wraparound Mode (DECAWM).
+ # Ps = 8 -> Auto-repeat Keys (DECARM).
+ # Ps = 9 -> Send Mouse X & Y on button press. See the sec-
+ # tion Mouse Tracking.
+ # Ps = 1 0 -> Show toolbar (rxvt).
+ # Ps = 1 2 -> Start Blinking Cursor (att610).
+ # Ps = 1 8 -> Print form feed (DECPFF).
+ # Ps = 1 9 -> Set print extent to full screen (DECPEX).
+ # Ps = 2 5 -> Show Cursor (DECTCEM).
+ # Ps = 3 0 -> Show scrollbar (rxvt).
+ # Ps = 3 5 -> Enable font-shifting functions (rxvt).
+ # Ps = 3 8 -> Enter Tektronix Mode (DECTEK).
+ # Ps = 4 0 -> Allow 80 -> 132 Mode.
+ # Ps = 4 1 -> more(1) fix (see curses resource).
+ # Ps = 4 2 -> Enable Nation Replacement Character sets (DECN-
+ # RCM).
+ # Ps = 4 4 -> Turn On Margin Bell.
+ # Ps = 4 5 -> Reverse-wraparound Mode.
+ # Ps = 4 6 -> Start Logging. This is normally disabled by a
+ # compile-time option.
+ # Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis-
+ # abled by the titeInhibit resource).
+ # Ps = 6 6 -> Application keypad (DECNKM).
+ # Ps = 6 7 -> Backarrow key sends backspace (DECBKM).
+ # Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
+ # release. See the section Mouse Tracking.
+ # Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
+ # Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
+ # Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
+ # Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
+ # Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
+ # Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt).
+ # Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt).
+ # Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
+ # (enables the eightBitInput resource).
+ # Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
+ # Lock keys. (This enables the numLock resource).
+ # Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
+ # enables the metaSendsEscape resource).
+ # Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
+ # key.
+ # Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This
+ # enables the altSendsEscape resource).
+ # Ps = 1 0 4 0 -> Keep selection even if not highlighted.
+ # (This enables the keepSelection resource).
+ # Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables
+ # the selectToClipboard resource).
+ # Ps = 1 0 4 2 -> Enable Urgency window manager hint when
+ # Control-G is received. (This enables the bellIsUrgent
+ # resource).
+ # Ps = 1 0 4 3 -> Enable raising of the window when Control-G
+ # is received. (enables the popOnBell resource).
+ # Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be
+ # disabled by the titeInhibit resource).
+ # Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis-
+ # abled by the titeInhibit resource).
+ # Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate
+ # Screen Buffer, clearing it first. (This may be disabled by
+ # the titeInhibit resource). This combines the effects of the 1
+ # 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based
+ # applications rather than the 4 7 mode.
+ # Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
+ # Ps = 1 0 5 1 -> Set Sun function-key mode.
+ # Ps = 1 0 5 2 -> Set HP function-key mode.
+ # Ps = 1 0 5 3 -> Set SCO function-key mode.
+ # Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6).
+ # Ps = 1 0 6 1 -> Set VT220 keyboard emulation.
+ # Ps = 2 0 0 4 -> Set bracketed paste mode.
+ # Modes:
+ # http://vt100.net/docs/vt220-rm/chapter4.html
+ setMode: (params) ->
+ if typeof params is "object"
+ l = params.length
+ i = 0
+ while i < l
+ @setMode params[i]
+ i++
+ return
+ if @prefix is "?"
+ switch params
+ when 1
+ @applicationCursor = true
+ when 2
+ @setgCharset 0, BackTerminal::charsets.US
+ @setgCharset 1, BackTerminal::charsets.US
+ @setgCharset 2, BackTerminal::charsets.US
+ @setgCharset 3, BackTerminal::charsets.US
+ # set VT100 mode here
+ when 3 # 132 col mode
+ @savedCols = @cols
+ @resize 132, @rows
+ when 6
+ @originMode = true
+ when 7
+ @wraparoundMode = true
+ when 66
+ @applicationKeypad = true
+ # X10 Mouse
+ # no release, no motion, no wheel, no modifiers.
+ when 9, 1000, 1002, 1003 # any event mouse
+ # any event - sends motion events,
+ # even if there is no button held down.
+ @x10Mouse = params is 9
+ @vt200Mouse = params is 1000
+ @normalMouse = params > 1000
+ @mouseEvents = true
+ @element.style.cursor = "default"
+ when 1004 # send focusin/focusout events
+ # focusin: ^[[I
+ # focusout: ^[[O
+ @sendFocus = true
+ when 1005 # utf8 ext mode mouse
+ @utfMouse = true
+ # for wide terminals
+ # simply encodes large values as utf8 characters
+ when 1006 # sgr ext mode mouse
+ @sgrMouse = true
+ # for wide terminals
+ # does not add 32 to fields
+ # press: ^[[ Keyboard Action Mode (AM).
+ # Ps = 4 -> Replace Mode (IRM).
+ # Ps = 1 2 -> Send/receive (SRM).
+ # Ps = 2 0 -> Normal Linefeed (LNM).
+ # CSI ? Pm l
+ # DEC Private Mode Reset (DECRST).
+ # Ps = 1 -> Normal Cursor Keys (DECCKM).
+ # Ps = 2 -> Designate VT52 mode (DECANM).
+ # Ps = 3 -> 80 Column Mode (DECCOLM).
+ # Ps = 4 -> Jump (Fast) Scroll (DECSCLM).
+ # Ps = 5 -> Normal Video (DECSCNM).
+ # Ps = 6 -> Normal Cursor Mode (DECOM).
+ # Ps = 7 -> No Wraparound Mode (DECAWM).
+ # Ps = 8 -> No Auto-repeat Keys (DECARM).
+ # Ps = 9 -> Don't send Mouse X & Y on button press.
+ # Ps = 1 0 -> Hide toolbar (rxvt).
+ # Ps = 1 2 -> Stop Blinking Cursor (att610).
+ # Ps = 1 8 -> Don't print form feed (DECPFF).
+ # Ps = 1 9 -> Limit print to scrolling region (DECPEX).
+ # Ps = 2 5 -> Hide Cursor (DECTCEM).
+ # Ps = 3 0 -> Don't show scrollbar (rxvt).
+ # Ps = 3 5 -> Disable font-shifting functions (rxvt).
+ # Ps = 4 0 -> Disallow 80 -> 132 Mode.
+ # Ps = 4 1 -> No more(1) fix (see curses resource).
+ # Ps = 4 2 -> Disable Nation Replacement Character sets (DEC-
+ # NRCM).
+ # Ps = 4 4 -> Turn Off Margin Bell.
+ # Ps = 4 5 -> No Reverse-wraparound Mode.
+ # Ps = 4 6 -> Stop Logging. (This is normally disabled by a
+ # compile-time option).
+ # Ps = 4 7 -> Use Normal Screen Buffer.
+ # Ps = 6 6 -> Numeric keypad (DECNKM).
+ # Ps = 6 7 -> Backarrow key sends delete (DECBKM).
+ # Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
+ # release. See the section Mouse Tracking.
+ # Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
+ # Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
+ # Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
+ # Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
+ # Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
+ # Ps = 1 0 1 0 -> Don't scroll to bottom on tty output
+ # (rxvt).
+ # Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt).
+ # Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
+ # the eightBitInput resource).
+ # Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
+ # Lock keys. (This disables the numLock resource).
+ # Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
+ # (This disables the metaSendsEscape resource).
+ # Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
+ # Delete key.
+ # Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key.
+ # (This disables the altSendsEscape resource).
+ # Ps = 1 0 4 0 -> Do not keep selection when not highlighted.
+ # (This disables the keepSelection resource).
+ # Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables
+ # the selectToClipboard resource).
+ # Ps = 1 0 4 2 -> Disable Urgency window manager hint when
+ # Control-G is received. (This disables the bellIsUrgent
+ # resource).
+ # Ps = 1 0 4 3 -> Disable raising of the window when Control-
+ # G is received. (This disables the popOnBell resource).
+ # Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen
+ # first if in the Alternate Screen. (This may be disabled by
+ # the titeInhibit resource).
+ # Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be
+ # disabled by the titeInhibit resource).
+ # Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor
+ # as in DECRC. (This may be disabled by the titeInhibit
+ # resource). This combines the effects of the 1 0 4 7 and 1 0
+ # 4 8 modes. Use this with terminfo-based applications rather
+ # than the 4 7 mode.
+ # Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode.
+ # Ps = 1 0 5 1 -> Reset Sun function-key mode.
+ # Ps = 1 0 5 2 -> Reset HP function-key mode.
+ # Ps = 1 0 5 3 -> Reset SCO function-key mode.
+ # Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6).
+ # Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style.
+ # Ps = 2 0 0 4 -> Reset bracketed paste mode.
+ resetMode: (params) ->
+ if typeof params is "object"
+ l = params.length
+ i = 0
+ while i < l
+ @resetMode params[i]
+ i++
+ return
+
+ if @prefix is "?"
+ switch params
+ when 1
+ @applicationCursor = false
+ when 3
+ @resize @savedCols, @rows if @cols is 132 and @savedCols
+ delete @savedCols
+ when 6
+ @originMode = false
+ when 7
+ @wraparoundMode = false
+ when 66
+ @applicationKeypad = false
+ when 9, 1000, 1002 , 1003 # any event mouse
+ @x10Mouse = false
+ @vt200Mouse = false
+ @normalMouse = false
+ @mouseEvents = false
+ @element.style.cursor = ""
+ when 1004 # send focusin/focusout events
+ @sendFocus = false
+ when 1005 # utf8 ext mode mouse
+ @utfMouse = false
+ when 1006 # sgr ext mode mouse
+ @sgrMouse = false
+ when 1015 # urxvt ext mode mouse
+ @urxvtMouse = false
+ when 25 # hide cursor
+ @cursorHidden = true
+ when 1049, 47, 1047 # normal screen buffer - clearing it first
+ if @normal
+ @lines = @normal.lines
+ @ybase = @normal.ybase
+ @ydisp = @normal.ydisp
+ @x = @normal.x
+ @y = @normal.y
+ @scrollTop = @normal.scrollTop
+ @scrollBottom = @normal.scrollBottom
+ @tabs = @normal.tabs
+ @normal = null
+ @refresh 0, @rows - 1
+ @showCursor()
+
+
+ # CSI Ps ; Ps r
+ # Set Scrolling Region [top;bottom] (default = full size of win-
+ # dow) (DECSTBM).
+ # CSI ? Pm r
+ setScrollRegion: (params) ->
+ return if @prefix
+ @scrollTop = (params[0] or 1) - 1
+ @scrollBottom = (params[1] or @rows) - 1
+ @x = 0
+ @y = 0
+
+
+ # CSI s
+ # Save cursor (ANSI.SYS).
+ saveCursor: (params) ->
+ @savedX = @x
+ @savedY = @y
+
+
+ # CSI u
+ # Restore cursor (ANSI.SYS).
+ restoreCursor: (params) ->
+ @x = @savedX or 0
+ @y = @savedY or 0
+
+ ## Lesser Used ##
+
+ # CSI Ps I
+ # Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
+ cursorForwardTab: (params) ->
+ param = params[0] or 1
+ @x = @nextStop() while param--
+
+
+ # CSI Ps S Scroll up Ps lines (default = 1) (SU).
+ scrollUp: (params) ->
+ param = params[0] or 1
+ while param--
+ @lines.splice @ybase + @scrollTop, 1
+ @lines.splice @ybase + @scrollBottom, 0, @blankLine()
+
+ @updateRange @scrollTop
+ @updateRange @scrollBottom
+
+
+ # CSI Ps T Scroll down Ps lines (default = 1) (SD).
+ scrollDown: (params) ->
+ param = params[0] or 1
+ while param--
+ @lines.splice @ybase + @scrollBottom, 1
+ @lines.splice @ybase + @scrollTop, 0, @blankLine()
+
+ @updateRange @scrollTop
+ @updateRange @scrollBottom
+
+
+ # CSI Ps ; Ps ; Ps ; Ps ; Ps T
+ # Initiate highlight mouse tracking. Parameters are
+ # [func;startx;starty;firstrow;lastrow]. See the section Mouse
+ # Tracking.
+ initMouseTracking: (params) ->
+
+ # Relevant: DECSET 1001
+
+ # CSI > Ps; Ps T
+ # Reset one or more features of the title modes to the default
+ # value. Normally, "reset" disables the feature. It is possi-
+ # ble to disable the ability to reset features by compiling a
+ # different default for the title modes into xterm.
+ # Ps = 0 -> Do not set window/icon labels using hexadecimal.
+ # Ps = 1 -> Do not query window/icon labels using hexadeci-
+ # mal.
+ # Ps = 2 -> Do not set window/icon labels using UTF-8.
+ # Ps = 3 -> Do not query window/icon labels using UTF-8.
+ # (See discussion of "Title Modes").
+ resetTitleModes: (params) ->
+
+
+ # CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
+ cursorBackwardTab: (params) ->
+ param = params[0] or 1
+ @x = @prevStop() while param--
+
+
+ # CSI Ps b Repeat the preceding graphic character Ps times (REP).
+ repeatPrecedingCharacter: (params) ->
+ param = params[0] or 1
+ line = @lines[@ybase + @y]
+ ch = line[@x - 1] or [@defAttr, " "]
+ line[@x++] = ch while param--
+
+
+ # CSI Ps g Tab Clear (TBC).
+ # Ps = 0 -> Clear Current Column (default).
+ # Ps = 3 -> Clear All.
+ # Potentially:
+ # Ps = 2 -> Clear Stops on Line.
+ # http://vt100.net/annarbor/aaa-ug/section6.html
+ tabClear: (params) ->
+ param = params[0]
+ if param <= 0
+ delete @tabs[@x]
+ else
+ @tabs = {} if param is 3
+
+ # CSI Pm i Media Copy (MC).
+ # Ps = 0 -> Print screen (default).
+ # Ps = 4 -> Turn off printer controller mode.
+ # Ps = 5 -> Turn on printer controller mode.
+ # CSI ? Pm i
+ # Media Copy (MC, DEC-specific).
+ # Ps = 1 -> Print line containing cursor.
+ # Ps = 4 -> Turn off autoprint mode.
+ # Ps = 5 -> Turn on autoprint mode.
+ # Ps = 1 0 -> Print composed display, ignores DECPEX.
+ # Ps = 1 1 -> Print all pages.
+ mediaCopy: (params) ->
+
+
+ # CSI > Ps; Ps m
+ # Set or reset resource-values used by xterm to decide whether
+ # to construct escape sequences holding information about the
+ # modifiers pressed with a given key. The first parameter iden-
+ # tifies the resource to set/reset. The second parameter is the
+ # value to assign to the resource. If the second parameter is
+ # omitted, the resource is reset to its initial value.
+ # Ps = 1 -> modifyCursorKeys.
+ # Ps = 2 -> modifyFunctionKeys.
+ # Ps = 4 -> modifyOtherKeys.
+ # If no parameters are given, all resources are reset to their
+ # initial values.
+ setResources: (params) ->
+
+
+ # CSI > Ps n
+ # Disable modifiers which may be enabled via the CSI > Ps; Ps m
+ # sequence. This corresponds to a resource value of "-1", which
+ # cannot be set with the other sequence. The parameter identi-
+ # fies the resource to be disabled:
+ # Ps = 1 -> modifyCursorKeys.
+ # Ps = 2 -> modifyFunctionKeys.
+ # Ps = 4 -> modifyOtherKeys.
+ # If the parameter is omitted, modifyFunctionKeys is disabled.
+ # When modifyFunctionKeys is disabled, xterm uses the modifier
+ # keys to make an extended sequence of functions rather than
+ # adding a parameter to each function key to denote the modi-
+ # fiers.
+ disableModifiers: (params) ->
+
+
+ # CSI > Ps p
+ # Set resource value pointerMode. This is used by xterm to
+ # decide whether to hide the pointer cursor as the user types.
+ # Valid values for the parameter:
+ # Ps = 0 -> never hide the pointer.
+ # Ps = 1 -> hide if the mouse tracking mode is not enabled.
+ # Ps = 2 -> always hide the pointer. If no parameter is
+ # given, xterm uses the default, which is 1 .
+ setPointerMode: (params) ->
+
+
+ # CSI ! p Soft terminal reset (DECSTR).
+ # http://vt100.net/docs/vt220-rm/table4-10.html
+ softReset: (params) ->
+ @cursorHidden = false
+ @insertMode = false
+ @originMode = false
+ @wraparoundMode = false # autowrap
+ @applicationKeypad = false # ?
+ @applicationCursor = false
+ @scrollTop = 0
+ @scrollBottom = @rows - 1
+ @curAttr = @defAttr
+ @x = @y = 0 # ?
+ @charset = null
+ @glevel = 0 # ??
+ @charsets = [null] # ??
+
+
+ # CSI Ps$ p
+ # Request ANSI mode (DECRQM). For VT300 and up, reply is
+ # CSI Ps; Pm$ y
+ # where Ps is the mode number as in RM, and Pm is the mode
+ # value:
+ # 0 - not recognized
+ # 1 - set
+ # 2 - reset
+ # 3 - permanently set
+ # 4 - permanently reset
+ requestAnsiMode: (params) ->
+
+
+ # CSI ? Ps$ p
+ # Request DEC private mode (DECRQM). For VT300 and up, reply is
+ # CSI ? Ps; Pm$ p
+ # where Ps is the mode number as in DECSET, Pm is the mode value
+ # as in the ANSI DECRQM.
+ requestPrivateMode: (params) ->
+
+
+ # CSI Ps ; Ps " p
+ # Set conformance level (DECSCL). Valid values for the first
+ # parameter:
+ # Ps = 6 1 -> VT100.
+ # Ps = 6 2 -> VT200.
+ # Ps = 6 3 -> VT300.
+ # Valid values for the second parameter:
+ # Ps = 0 -> 8-bit controls.
+ # Ps = 1 -> 7-bit controls (always set for VT100).
+ # Ps = 2 -> 8-bit controls.
+ setConformanceLevel: (params) ->
+
+
+ # CSI Ps q Load LEDs (DECLL).
+ # Ps = 0 -> Clear all LEDS (default).
+ # Ps = 1 -> Light Num Lock.
+ # Ps = 2 -> Light Caps Lock.
+ # Ps = 3 -> Light Scroll Lock.
+ # Ps = 2 1 -> Extinguish Num Lock.
+ # Ps = 2 2 -> Extinguish Caps Lock.
+ # Ps = 2 3 -> Extinguish Scroll Lock.
+ loadLEDs: (params) ->
+
+
+ # CSI Ps SP q
+ # Set cursor style (DECSCUSR, VT520).
+ # Ps = 0 -> blinking block.
+ # Ps = 1 -> blinking block (default).
+ # Ps = 2 -> steady block.
+ # Ps = 3 -> blinking underline.
+ # Ps = 4 -> steady underline.
+ setCursorStyle: (params) ->
+
+
+ # CSI Ps " q
+ # Select character protection attribute (DECSCA). Valid values
+ # for the parameter:
+ # Ps = 0 -> DECSED and DECSEL can erase (default).
+ # Ps = 1 -> DECSED and DECSEL cannot erase.
+ # Ps = 2 -> DECSED and DECSEL can erase.
+ setCharProtectionAttr: (params) ->
+
+
+ # CSI ? Pm r
+ # Restore DEC Private Mode Values. The value of Ps previously
+ # saved is restored. Ps values are the same as for DECSET.
+ restorePrivateValues: (params) ->
+
+
+ # CSI Pt; Pl; Pb; Pr; Ps$ r
+ # Change Attributes in Rectangular Area (DECCARA), VT400 and up.
+ # Pt; Pl; Pb; Pr denotes the rectangle.
+ # Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
+ # NOTE: xterm doesn't enable this code by default.
+ setAttrInRectangle: (params) ->
+ t = params[0]
+ l = params[1]
+ b = params[2]
+ r = params[3]
+ attr = params[4]
+ while t < b + 1
+ line = @lines[@ybase + t]
+ i = l
+ while i < r
+ line[i] = [attr, line[i][1]]
+ i++
+ t++
+
+ @updateRange params[0]
+ @updateRange params[2]
+
+
+ # CSI ? Pm s
+ # Save DEC Private Mode Values. Ps values are the same as for
+ # DECSET.
+ savePrivateValues: (params) ->
+
+
+ # CSI Ps ; Ps ; Ps t
+ # Window manipulation (from dtterm, as well as extensions).
+ # These controls may be disabled using the allowWindowOps
+ # resource. Valid values for the first (and any additional
+ # parameters) are:
+ # Ps = 1 -> De-iconify window.
+ # Ps = 2 -> Iconify window.
+ # Ps = 3 ; x ; y -> Move window to [x, y].
+ # Ps = 4 ; height ; width -> Resize the xterm window to
+ # height and width in pixels.
+ # Ps = 5 -> Raise the xterm window to the front of the stack-
+ # ing order.
+ # Ps = 6 -> Lower the xterm window to the bottom of the
+ # stacking order.
+ # Ps = 7 -> Refresh the xterm window.
+ # Ps = 8 ; height ; width -> Resize the text area to
+ # [height;width] in characters.
+ # Ps = 9 ; 0 -> Restore maximized window.
+ # Ps = 9 ; 1 -> Maximize window (i.e., resize to screen
+ # size).
+ # Ps = 1 0 ; 0 -> Undo full-screen mode.
+ # Ps = 1 0 ; 1 -> Change to full-screen.
+ # Ps = 1 1 -> Report xterm window state. If the xterm window
+ # is open (non-iconified), it returns CSI 1 t . If the xterm
+ # window is iconified, it returns CSI 2 t .
+ # Ps = 1 3 -> Report xterm window position. Result is CSI 3
+ # ; x ; y t
+ # Ps = 1 4 -> Report xterm window in pixels. Result is CSI
+ # 4 ; height ; width t
+ # Ps = 1 8 -> Report the size of the text area in characters.
+ # Result is CSI 8 ; height ; width t
+ # Ps = 1 9 -> Report the size of the screen in characters.
+ # Result is CSI 9 ; height ; width t
+ # Ps = 2 0 -> Report xterm window's icon label. Result is
+ # OSC L label ST
+ # Ps = 2 1 -> Report xterm window's title. Result is OSC l
+ # label ST
+ # Ps = 2 2 ; 0 -> Save xterm icon and window title on
+ # stack.
+ # Ps = 2 2 ; 1 -> Save xterm icon title on stack.
+ # Ps = 2 2 ; 2 -> Save xterm window title on stack.
+ # Ps = 2 3 ; 0 -> Restore xterm icon and window title from
+ # stack.
+ # Ps = 2 3 ; 1 -> Restore xterm icon title from stack.
+ # Ps = 2 3 ; 2 -> Restore xterm window title from stack.
+ # Ps >= 2 4 -> Resize to Ps lines (DECSLPP).
+ manipulateWindow: (params) ->
+
+
+ # CSI Pt; Pl; Pb; Pr; Ps$ t
+ # Reverse Attributes in Rectangular Area (DECRARA), VT400 and
+ # up.
+ # Pt; Pl; Pb; Pr denotes the rectangle.
+ # Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7.
+ # NOTE: xterm doesn't enable this code by default.
+ reverseAttrInRectangle: (params) ->
+
+
+ # CSI > Ps; Ps t
+ # Set one or more features of the title modes. Each parameter
+ # enables a single feature.
+ # Ps = 0 -> Set window/icon labels using hexadecimal.
+ # Ps = 1 -> Query window/icon labels using hexadecimal.
+ # Ps = 2 -> Set window/icon labels using UTF-8.
+ # Ps = 3 -> Query window/icon labels using UTF-8. (See dis-
+ # cussion of "Title Modes")
+ setTitleModeFeature: (params) ->
+
+
+ # CSI Ps SP t
+ # Set warning-bell volume (DECSWBV, VT520).
+ # Ps = 0 or 1 -> off.
+ # Ps = 2 , 3 or 4 -> low.
+ # Ps = 5 , 6 , 7 , or 8 -> high.
+ setWarningBellVolume: (params) ->
+
+
+ # CSI Ps SP u
+ # Set margin-bell volume (DECSMBV, VT520).
+ # Ps = 1 -> off.
+ # Ps = 2 , 3 or 4 -> low.
+ # Ps = 0 , 5 , 6 , 7 , or 8 -> high.
+ setMarginBellVolume: (params) ->
+
+
+ # CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
+ # Copy Rectangular Area (DECCRA, VT400 and up).
+ # Pt; Pl; Pb; Pr denotes the rectangle.
+ # Pp denotes the source page.
+ # Pt; Pl denotes the target location.
+ # Pp denotes the target page.
+ # NOTE: xterm doesn't enable this code by default.
+ copyRectangle: (params) ->
+
+
+ # CSI Pt ; Pl ; Pb ; Pr ' w
+ # Enable Filter Rectangle (DECEFR), VT420 and up.
+ # Parameters are [top;left;bottom;right].
+ # Defines the coordinates of a filter rectangle and activates
+ # it. Anytime the locator is detected outside of the filter
+ # rectangle, an outside rectangle event is generated and the
+ # rectangle is disabled. Filter rectangles are always treated
+ # as "one-shot" events. Any parameters that are omitted default
+ # to the current locator position. If all parameters are omit-
+ # ted, any locator motion will be reported. DECELR always can-
+ # cels any prevous rectangle definition.
+ enableFilterRectangle: (params) ->
+
+
+ # CSI Ps x Request Terminal Parameters (DECREQTPARM).
+ # if Ps is a "0" (default) or "1", and xterm is emulating VT100,
+ # the control sequence elicits a response of the same form whose
+ # parameters describe the terminal:
+ # Ps -> the given Ps incremented by 2.
+ # Pn = 1 <- no parity.
+ # Pn = 1 <- eight bits.
+ # Pn = 1 <- 2 8 transmit 38.4k baud.
+ # Pn = 1 <- 2 8 receive 38.4k baud.
+ # Pn = 1 <- clock multiplier.
+ # Pn = 0 <- STP flags.
+ requestParameters: (params) ->
+
+
+ # CSI Ps x Select Attribute Change Extent (DECSACE).
+ # Ps = 0 -> from start to end position, wrapped.
+ # Ps = 1 -> from start to end position, wrapped.
+ # Ps = 2 -> rectangle (exact).
+ selectChangeExtent: (params) ->
+
+
+ # CSI Pc; Pt; Pl; Pb; Pr$ x
+ # Fill Rectangular Area (DECFRA), VT420 and up.
+ # Pc is the character to use.
+ # Pt; Pl; Pb; Pr denotes the rectangle.
+ # NOTE: xterm doesn't enable this code by default.
+ fillRectangle: (params) ->
+ ch = params[0]
+ t = params[1]
+ l = params[2]
+ b = params[3]
+ r = params[4]
+ while t < b + 1
+ line = @lines[@ybase + t]
+ i = l
+ while i < r
+ line[i] = [line[i][0], String.fromCharCode(ch)]
+ i++
+ t++
+
+ @updateRange params[1]
+ @updateRange params[3]
+
+
+ # CSI Ps ; Pu ' z
+ # Enable Locator Reporting (DECELR).
+ # Valid values for the first parameter:
+ # Ps = 0 -> Locator disabled (default).
+ # Ps = 1 -> Locator enabled.
+ # Ps = 2 -> Locator enabled for one report, then disabled.
+ # The second parameter specifies the coordinate unit for locator
+ # reports.
+ # Valid values for the second parameter:
+ # Pu = 0 <- or omitted -> default to character cells.
+ # Pu = 1 <- device physical pixels.
+ # Pu = 2 <- character cells.
+ enableLocatorReporting: (params) ->
+ val = params[0] > 0
+
+
+ # CSI Pt; Pl; Pb; Pr$ z
+ # Erase Rectangular Area (DECERA), VT400 and up.
+ # Pt; Pl; Pb; Pr denotes the rectangle.
+ # NOTE: xterm doesn't enable this code by default.
+ eraseRectangle: (params) ->
+ t = params[0]
+ l = params[1]
+ b = params[2]
+ r = params[3]
+ ch = [@eraseAttr(), " "]
+ while t < b + 1
+ line = @lines[@ybase + t]
+ i = l
+ while i < r
+ line[i] = ch
+ i++
+ t++
+
+ @updateRange params[0]
+ @updateRange params[2]
+
+
+ # CSI Pm ' {
+ # Select Locator Events (DECSLE).
+ # Valid values for the first (and any additional parameters)
+ # are:
+ # Ps = 0 -> only respond to explicit host requests (DECRQLP).
+ # (This is default). It also cancels any filter
+ # rectangle.
+ # Ps = 1 -> report button down transitions.
+ # Ps = 2 -> do not report button down transitions.
+ # Ps = 3 -> report button up transitions.
+ # Ps = 4 -> do not report button up transitions.
+ setLocatorEvents: (params) ->
+
+
+ # CSI Pt; Pl; Pb; Pr$ {
+ # Selective Erase Rectangular Area (DECSERA), VT400 and up.
+ # Pt; Pl; Pb; Pr denotes the rectangle.
+ selectiveEraseRectangle: (params) ->
+
+
+ # CSI Ps ' |
+ # Request Locator Position (DECRQLP).
+ # Valid values for the parameter are:
+ # Ps = 0 , 1 or omitted -> transmit a single DECLRP locator
+ # report.
+
+ # If Locator Reporting has been enabled by a DECELR, xterm will
+ # respond with a DECLRP Locator Report. This report is also
+ # generated on button up and down events if they have been
+ # enabled with a DECSLE, or when the locator is detected outside
+ # of a filter rectangle, if filter rectangles have been enabled
+ # with a DECEFR.
+
+ # -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
+
+ # Parameters are [event;button;row;column;page].
+ # Valid values for the event:
+ # Pe = 0 -> locator unavailable - no other parameters sent.
+ # Pe = 1 -> request - xterm received a DECRQLP.
+ # Pe = 2 -> left button down.
+ # Pe = 3 -> left button up.
+ # Pe = 4 -> middle button down.
+ # Pe = 5 -> middle button up.
+ # Pe = 6 -> right button down.
+ # Pe = 7 -> right button up.
+ # Pe = 8 -> M4 button down.
+ # Pe = 9 -> M4 button up.
+ # Pe = 1 0 -> locator outside filter rectangle.
+ # ``button'' parameter is a bitmask indicating which buttons are
+ # pressed:
+ # Pb = 0 <- no buttons down.
+ # Pb & 1 <- right button down.
+ # Pb & 2 <- middle button down.
+ # Pb & 4 <- left button down.
+ # Pb & 8 <- M4 button down.
+ # ``row'' and ``column'' parameters are the coordinates of the
+ # locator position in the xterm window, encoded as ASCII deci-
+ # mal.
+ # The ``page'' parameter is not used by xterm, and will be omit-
+ # ted.
+ requestLocatorPosition: (params) ->
+
+
+ # CSI P m SP }
+ # Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
+ # NOTE: xterm doesn't enable this code by default.
+ insertColumns: ->
+ param = params[0]
+ l = @ybase + @rows
+ ch = [@eraseAttr(), " "]
+ while param--
+ i = @ybase
+ while i < l
+ @lines[i].splice @x + 1, 0, ch
+ @lines[i].pop()
+ i++
+ @maxRange()
+
+
+ # CSI P m SP ~
+ # Delete P s Column(s) (default = 1) (DECDC), VT420 and up
+ # NOTE: xterm doesn't enable this code by default.
+ deleteColumns: ->
+ param = params[0]
+ l = @ybase + @rows
+ ch = [@eraseAttr(), " "]
+ while param--
+ i = @ybase
+ while i < l
+ @lines[i].splice @x, 1
+ @lines[i].push ch
+ i++
+ @maxRange()
+
+
+ # DEC Special Character and Line Drawing Set.
+ # http://vt100.net/docs/vt102-ug/table5-13.html
+ # A lot of curses apps use this if they see TERM=xterm.
+ # testing: echo -e '\e(0a\e(B'
+ # The xterm output sometimes seems to conflict with the
+ # reference above. xterm seems in line with the reference
+ # when running vttest however.
+ # The table below now uses xterm's output from vttest.
+ charsets:
+ SCLD:# (0
+ "`": "◆" # '◆'
+ a: "▒" # '▒'
+ b: "\t" # '\t'
+ c: "\f" # '\f'
+ d: "\r" # '\r'
+ e: "\n" # '\n'
+ f: "°" # '°'
+ g: "±" # '±'
+ h: "" # '\u2424' (NL)
+ i: "\x0b" # '\v'
+ j: "┘" # '┘'
+ k: "┐" # '┐'
+ l: "┌" # '┌'
+ m: "└" # '└'
+ n: "┼" # '┼'
+ o: "⎺" # '⎺'
+ p: "⎻" # '⎻'
+ q: "─" # '─'
+ r: "⎼" # '⎼'
+ s: "⎽" # '⎽'
+ t: "├" # '├'
+ u: "┤" # '┤'
+ v: "┴" # '┴'
+ w: "┬" # '┬'
+ x: "│" # '│'
+ y: "≤" # '≤'
+ z: "≥" # '≥'
+ "{": "π" # 'π'
+ "|": "≠" # '≠'
+ "}": "£" # '£'
+ "~": "·" # '·'
+ UK: null # (A
+ US: null # (B (USASCII)
+ Dutch: null # (4
+ Finnish: null # (C or (5
+ French: null # (R
+ FrenchCanadian: null # (Q
+ German: null # (K
+ Italian: null # (Y
+ NorwegianDanish: null # (E or (6
+ Spanish: null # (Z
+ Swedish: null # (H or (7
+ Swiss: null # (=
+ ISOLatin: null # /A
diff --git a/butterfly/static/javascripts/main.js b/butterfly/static/javascripts/main.js
index 0130c11..182dbf5 100644
--- a/butterfly/static/javascripts/main.js
+++ b/butterfly/static/javascripts/main.js
@@ -1,7 +1,144 @@
// Generated by CoffeeScript 1.6.3
-var $, State, Terminal, alt, bench, cancel, cbench, cols, ctl, ctrl, first, quit, rows, s, send, state, term, virtual_input, ws, ws_url,
+var $, FrontTerminal, alt, cancel, cols, ctl, ctrl, first, frontterm, quit, rows, send, state, virtual_input, worker,
__slice = [].slice;
+state = {
+ x: null,
+ y: null
+};
+
+document.addEventListener('keydown', function(e) {
+ var _ref;
+ if (e.shiftKey && ((37 <= (_ref = e.keyCode) && _ref <= 40))) {
+ if (state.y === null) {
+ state.y = term.ybase + term.y;
+ }
+ if (e.keyCode === 38) {
+ state.y--;
+ if (state.y < term.ybase) {
+ state.y = term.ybase;
+ }
+ } else if (e.keyCode === 40) {
+ state.y++;
+ if (state.y > term.ybase + term.y) {
+ state.y = term.ybase + term.y;
+ }
+ }
+ term.emit('data', ' \x0b\x15');
+ if (state.y !== term.ybase + term.y) {
+ term.emit('data', term.grabText(0, term.cols - 1, state.y, state.y).replace('\n', ''));
+ }
+ e.stopPropagation();
+ return false;
+ } else {
+ return state.x = state.y = null;
+ }
+});
+
+if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
+ ctrl = false;
+ alt = false;
+ first = true;
+ virtual_input = document.createElement('input');
+ virtual_input.type = 'password';
+ virtual_input.style.position = 'fixed';
+ virtual_input.style.top = 0;
+ virtual_input.style.left = 0;
+ virtual_input.style.border = 'none';
+ virtual_input.style.outline = 'none';
+ virtual_input.style.opacity = 0;
+ virtual_input.value = '0';
+ document.body.appendChild(virtual_input);
+ virtual_input.addEventListener('blur', function() {
+ var _this = this;
+ return setTimeout((function() {
+ return _this.focus();
+ }), 10);
+ });
+ addEventListener('click', function() {
+ return virtual_input.focus();
+ });
+ addEventListener('touchstart', function(e) {
+ if (e.touches.length === 1) {
+ return ctrl = true;
+ } else if (e.touches.length === 2) {
+ ctrl = false;
+ return alt = true;
+ } else if (e.touches.length === 3) {
+ ctrl = true;
+ return alt = true;
+ }
+ });
+ virtual_input.addEventListener('keydown', function(e) {
+ term.keyDown(e);
+ return true;
+ });
+ virtual_input.addEventListener('input', function(e) {
+ var len;
+ len = this.value.length;
+ if (len === 0) {
+ e.keyCode = 8;
+ term.keyDown(e);
+ this.value = '0';
+ return true;
+ }
+ e.keyCode = this.value.charAt(1).charCodeAt(0);
+ if ((ctrl || alt) && !first) {
+ e.keyCode = this.value.charAt(1).charCodeAt(0);
+ e.ctrlKey = ctrl;
+ e.altKey = alt;
+ if (e.keyCode >= 97 && e.keyCode <= 122) {
+ e.keyCode -= 32;
+ }
+ term.keyDown(e);
+ this.value = '0';
+ ctrl = alt = false;
+ return true;
+ }
+ term.keyPress(e);
+ first = false;
+ this.value = '0';
+ return true;
+ });
+}
+
+worker = new Worker('/static/javascripts/worker.js');
+
+worker.addEventListener('message', function(e) {
+ switch (e.data.cmd) {
+ case 'refresh':
+ return frontterm.refresh(e.data.lines, e.data.start, e.data.end);
+ }
+});
+
+cols = rows = null;
+
+quit = false;
+
+$ = document.querySelectorAll.bind(document);
+
+send = function(data) {
+ return worker.postMessage({
+ cmd: 'data',
+ data: data
+ });
+};
+
+ctl = function() {
+ var args, params, type;
+ type = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ params = args.join(',');
+ if (type === 'Resize') {
+ return worker.postMessage('R' + params);
+ }
+};
+
+addEventListener('beforeunload', function() {
+ if (!quit) {
+ return 'This will exit the terminal session';
+ }
+});
+
cancel = function(ev) {
if (ev.preventDefault) {
ev.preventDefault();
@@ -13,25 +150,11 @@ cancel = function(ev) {
return false;
};
-s = 0;
-
-State = {
- normal: s++,
- escaped: s++,
- csi: s++,
- osc: s++,
- charset: s++,
- dcs: s++,
- ignore: s++
-};
-
-Terminal = (function() {
- function Terminal(parent, out, ctl) {
+FrontTerminal = (function() {
+ function FrontTerminal(parent) {
var div, i, term_size,
_this = this;
this.parent = parent;
- this.out = out;
- this.ctl = ctl != null ? ctl : function() {};
this.context = this.parent.ownerDocument.defaultView;
this.document = this.parent.ownerDocument;
this.body = this.document.getElementsByTagName('body')[0];
@@ -57,15 +180,12 @@ Terminal = (function() {
this.element.appendChild(div);
this.children.push(div);
}
- this.scrollback = 100000;
this.visualBell = 100;
- this.convertEol = false;
- this.termName = 'xterm';
- this.cursorBlink = true;
- this.screenKeys = false;
+ this.cursorHidden = false;
+ this.queue = '';
+ this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
+ this.skipNextKey = null;
this.cursorState = 0;
- this.reset_vars();
- this.refresh(0, this.rows - 1);
this.focus();
this.startBlink();
addEventListener('keydown', this.keyDown.bind(this));
@@ -87,41 +207,7 @@ Terminal = (function() {
this.initmouse();
}
- Terminal.prototype.reset_vars = function() {
- var i;
- this.ybase = 0;
- this.ydisp = 0;
- this.x = 0;
- this.y = 0;
- this.cursorHidden = false;
- this.state = State.normal;
- this.queue = '';
- this.scrollTop = 0;
- this.scrollBottom = this.rows - 1;
- this.applicationKeypad = false;
- this.applicationCursor = false;
- this.originMode = false;
- this.wraparoundMode = false;
- this.normal = null;
- this.charset = null;
- this.gcharset = null;
- this.glevel = 0;
- this.charsets = [null];
- this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
- this.curAttr = this.defAttr;
- this.params = [];
- this.currentParam = 0;
- this.prefix = "";
- this.lines = [];
- i = this.rows;
- while (i--) {
- this.lines.push(this.blankLine());
- }
- this.setupStops();
- return this.skipNextKey = null;
- };
-
- Terminal.prototype.compute_char_size = function() {
+ FrontTerminal.prototype.compute_char_size = function() {
var test_span;
test_span = document.createElement('span');
test_span.textContent = '0123456789';
@@ -133,11 +219,7 @@ Terminal = (function() {
return this.children[0].removeChild(test_span);
};
- Terminal.prototype.eraseAttr = function() {
- return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
- };
-
- Terminal.prototype.focus = function() {
+ FrontTerminal.prototype.focus = function() {
if (this.sendFocus) {
this.send('\x1b[I');
}
@@ -146,9 +228,8 @@ Terminal = (function() {
return this.element.classList.remove('blur');
};
- Terminal.prototype.blur = function() {
+ FrontTerminal.prototype.blur = function() {
this.cursorState = 1;
- this.refresh(this.y, this.y);
if (this.sendFocus) {
this.send('\x1b[O');
}
@@ -156,7 +237,7 @@ Terminal = (function() {
return this.element.classList.remove('focus');
};
- Terminal.prototype.paste = function(ev) {
+ FrontTerminal.prototype.paste = function(ev) {
if (ev.clipboardData) {
this.send(ev.clipboardData.getData('text/plain'));
} else if (this.context.clipboardData) {
@@ -165,7 +246,7 @@ Terminal = (function() {
return cancel(ev);
};
- Terminal.prototype.initmouse = function() {
+ FrontTerminal.prototype.initmouse = function() {
var encode, getButton, getCoords, pressed, sendButton, sendEvent, sendMove,
_this = this;
pressed = 32;
@@ -241,7 +322,7 @@ Terminal = (function() {
return _this.send("\x1b[M" + String.fromCharCode.apply(String, data));
};
getButton = function(ev) {
- var button, ctrl, meta, mod, shift;
+ var button, meta, mod, shift;
switch (ev.type) {
case "mousedown":
button = ev.button != null ? +ev.button : (ev.which != null ? ev.which - 1 : null);
@@ -343,7 +424,7 @@ Terminal = (function() {
});
};
- Terminal.prototype.refresh = function(start, end) {
+ FrontTerminal.prototype.refresh = function(lines, start, end) {
var attr, bg, ch, classes, data, fg, flags, i, line, out, parent, row, width, x, y;
if (end - start >= this.rows / 3) {
parent = this.element.parentNode;
@@ -353,12 +434,12 @@ Terminal = (function() {
}
width = this.cols;
y = start;
- if (end >= this.lines.length) {
- end = this.lines.length - 1;
+ if (end >= lines.length) {
+ end = lines.length - 1;
}
while (y <= end) {
- row = y + this.ydisp;
- line = this.lines[row];
+ row = y;
+ line = lines[row];
out = "";
if (y === this.y && (this.ydisp === this.ybase || this.selectMode) && !this.cursorHidden) {
x = this.x;
@@ -447,7 +528,7 @@ Terminal = (function() {
return parent != null ? parent.appendChild(this.element) : void 0;
};
- Terminal.prototype._cursorBlink = function() {
+ FrontTerminal.prototype._cursorBlink = function() {
var cursor;
this.cursorState ^= 1;
cursor = this.element.querySelector(".cursor");
@@ -461,14 +542,9 @@ Terminal = (function() {
}
};
- Terminal.prototype.showCursor = function() {
- if (!this.cursorState) {
- this.cursorState = 1;
- return this.refresh(this.y, this.y);
- }
- };
+ FrontTerminal.prototype.showCursor = function() {};
- Terminal.prototype.startBlink = function() {
+ FrontTerminal.prototype.startBlink = function() {
var _this = this;
if (!this.cursorBlink) {
return;
@@ -479,7 +555,7 @@ Terminal = (function() {
return this._blink = setInterval(this._blinker, 500);
};
- Terminal.prototype.refreshBlink = function() {
+ FrontTerminal.prototype.refreshBlink = function() {
if (!this.cursorBlink) {
return;
}
@@ -487,543 +563,18 @@ Terminal = (function() {
return this._blink = setInterval(this._blinker, 500);
};
- Terminal.prototype.scroll = function() {
- var row;
- if (++this.ybase === this.scrollback) {
- this.ybase = this.ybase / 2 | 0;
- this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
- }
- this.ydisp = this.ybase;
- row = this.ybase + this.rows - 1;
- row -= this.rows - 1 - this.scrollBottom;
- if (row === this.lines.length) {
- this.lines.push(this.blankLine());
- } else {
- this.lines.splice(row, 0, this.blankLine());
- }
- if (this.scrollTop !== 0) {
- if (this.ybase !== 0) {
- this.ybase--;
- this.ydisp = this.ybase;
- }
- this.lines.splice(this.ybase + this.scrollTop, 1);
- }
- this.updateRange(this.scrollTop);
- return this.updateRange(this.scrollBottom);
- };
-
- Terminal.prototype.scrollDisp = function(disp) {
+ FrontTerminal.prototype.scrollDisp = function(disp) {
this.ydisp += disp;
if (this.ydisp > this.ybase) {
- this.ydisp = this.ybase;
+ return this.ydisp = this.ybase;
} else {
if (this.ydisp < 0) {
- this.ydisp = 0;
+ return this.ydisp = 0;
}
}
- return this.refresh(0, this.rows - 1);
};
- Terminal.prototype.write = function(data) {
- var ch, cs, html, i, j, l, line, pt, valid, _ref;
- this.refreshStart = this.y;
- this.refreshEnd = this.y;
- if (this.ybase !== this.ydisp) {
- this.ydisp = this.ybase;
- this.maxRange();
- }
- i = 0;
- l = data.length;
- while (i < l) {
- ch = data[i];
- switch (this.state) {
- case State.normal:
- switch (ch) {
- case "\x07":
- this.bell();
- break;
- case "\n":
- case "\x0b":
- case "\x0c":
- if (this.convertEol) {
- this.x = 0;
- }
- this.y++;
- if (this.y > this.scrollBottom) {
- this.y--;
- this.scroll();
- }
- break;
- case "\r":
- this.x = 0;
- break;
- case "\b":
- if (this.x > 0) {
- this.x--;
- }
- break;
- case "\t":
- this.x = this.nextStop();
- break;
- case "\x0e":
- this.setgLevel(1);
- break;
- case "\x0f":
- this.setgLevel(0);
- break;
- case "\x1b":
- this.state = State.escaped;
- break;
- default:
- if (ch >= " ") {
- if ((_ref = this.charset) != null ? _ref[ch] : void 0) {
- ch = this.charset[ch];
- }
- if (this.x >= this.cols) {
- this.x = 0;
- this.y++;
- if (this.y > this.scrollBottom) {
- this.y--;
- this.scroll();
- }
- }
- this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch];
- this.x++;
- this.updateRange(this.y);
- if (("\uff00" < ch && ch < "\uffef")) {
- j = this.y + this.ybase;
- if (this.cols < 2 || this.x >= this.cols) {
- this.lines[j][this.x - 1] = [this.curAttr, " "];
- break;
- }
- this.lines[j][this.x] = [this.curAttr, " "];
- this.x++;
- }
- }
- }
- break;
- case State.escaped:
- switch (ch) {
- case "[":
- this.params = [];
- this.currentParam = 0;
- this.state = State.csi;
- break;
- case "]":
- this.params = [];
- this.currentParam = 0;
- this.state = State.osc;
- break;
- case "P":
- this.params = [];
- this.currentParam = 0;
- this.state = State.dcs;
- break;
- case "_":
- this.state = State.ignore;
- break;
- case "^":
- this.state = State.ignore;
- break;
- case "c":
- this.reset();
- break;
- case "E":
- this.x = 0;
- this.index();
- break;
- case "D":
- this.index();
- break;
- case "M":
- this.reverseIndex();
- break;
- case "%":
- this.setgLevel(0);
- this.setgCharset(0, Terminal.prototype.charsets.US);
- this.state = State.normal;
- i++;
- break;
- case "(":
- case ")":
- case "*":
- case "+":
- case "-":
- case ".":
- switch (ch) {
- case "(":
- this.gcharset = 0;
- break;
- case ")":
- case "-":
- this.gcharset = 1;
- break;
- case "*":
- case ".":
- this.gcharset = 2;
- break;
- case "+":
- this.gcharset = 3;
- }
- this.state = State.charset;
- break;
- case "/":
- this.gcharset = 3;
- this.state = State.charset;
- i--;
- break;
- case "n":
- this.setgLevel(2);
- break;
- case "o":
- this.setgLevel(3);
- break;
- case "|":
- this.setgLevel(3);
- break;
- case "}":
- this.setgLevel(2);
- break;
- case "~":
- this.setgLevel(1);
- break;
- case "7":
- this.saveCursor();
- this.state = State.normal;
- break;
- case "8":
- this.restoreCursor();
- this.state = State.normal;
- break;
- case "#":
- this.state = State.normal;
- i++;
- break;
- case "H":
- this.tabSet();
- break;
- case "=":
- this.applicationKeypad = true;
- this.state = State.normal;
- break;
- case ">":
- this.applicationKeypad = false;
- this.state = State.normal;
- break;
- default:
- this.state = State.normal;
- console.log("Unknown ESC control:", ch);
- }
- break;
- case State.charset:
- switch (ch) {
- case "0":
- cs = Terminal.prototype.charsets.SCLD;
- break;
- case "A":
- cs = Terminal.prototype.charsets.UK;
- break;
- case "B":
- cs = Terminal.prototype.charsets.US;
- break;
- case "4":
- cs = Terminal.prototype.charsets.Dutch;
- break;
- case "C":
- case "5":
- cs = Terminal.prototype.charsets.Finnish;
- break;
- case "R":
- cs = Terminal.prototype.charsets.French;
- break;
- case "Q":
- cs = Terminal.prototype.charsets.FrenchCanadian;
- break;
- case "K":
- cs = Terminal.prototype.charsets.German;
- break;
- case "Y":
- cs = Terminal.prototype.charsets.Italian;
- break;
- case "E":
- case "6":
- cs = Terminal.prototype.charsets.NorwegianDanish;
- break;
- case "Z":
- cs = Terminal.prototype.charsets.Spanish;
- break;
- case "H":
- case "7":
- cs = Terminal.prototype.charsets.Swedish;
- break;
- case "=":
- cs = Terminal.prototype.charsets.Swiss;
- break;
- case "/":
- cs = Terminal.prototype.charsets.ISOLatin;
- i++;
- break;
- default:
- cs = Terminal.prototype.charsets.US;
- }
- this.setgCharset(this.gcharset, cs);
- this.gcharset = null;
- this.state = State.normal;
- break;
- case State.osc:
- if (ch === "\x1b" || ch === "\x07") {
- if (ch === "\x1b") {
- i++;
- }
- this.params.push(this.currentParam);
- switch (this.params[0]) {
- case 0:
- case 1:
- case 2:
- if (this.params[1]) {
- this.title = this.params[1] + " - ƸӜƷ butterfly";
- this.handleTitle(this.title);
- }
- break;
- case 99:
- html = "" + this.params[1] + "
";
- this.lines[this.y + this.ybase][this.x] = [this.curAttr, html];
- line = 0;
- while (line < this.get_html_height_in_lines(html) - 1) {
- this.y++;
- if (this.y > this.scrollBottom) {
- this.y--;
- this.scroll();
- }
- line++;
- }
- this.updateRange(this.y);
- }
- this.params = [];
- this.currentParam = 0;
- this.state = State.normal;
- } else {
- if (!this.params.length) {
- if (ch >= "0" && ch <= "9") {
- this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
- } else if (ch === ";") {
- this.params.push(this.currentParam);
- this.currentParam = "";
- }
- } else {
- this.currentParam += ch;
- }
- }
- break;
- case State.csi:
- if (ch === "?" || ch === ">" || ch === "!") {
- this.prefix = ch;
- break;
- }
- if (ch >= "0" && ch <= "9") {
- this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
- break;
- }
- if (ch === "$" || ch === "\"" || ch === " " || ch === "'") {
- break;
- }
- this.params.push(this.currentParam);
- this.currentParam = 0;
- if (ch === ";") {
- break;
- }
- this.state = State.normal;
- switch (ch) {
- case "A":
- this.cursorUp(this.params);
- break;
- case "B":
- this.cursorDown(this.params);
- break;
- case "C":
- this.cursorForward(this.params);
- break;
- case "D":
- this.cursorBackward(this.params);
- break;
- case "H":
- this.cursorPos(this.params);
- break;
- case "J":
- this.eraseInDisplay(this.params);
- break;
- case "K":
- this.eraseInLine(this.params);
- break;
- case "m":
- if (!this.prefix) {
- this.charAttributes(this.params);
- }
- break;
- case "n":
- if (!this.prefix) {
- this.deviceStatus(this.params);
- }
- break;
- case "@":
- this.insertChars(this.params);
- break;
- case "E":
- this.cursorNextLine(this.params);
- break;
- case "F":
- this.cursorPrecedingLine(this.params);
- break;
- case "G":
- this.cursorCharAbsolute(this.params);
- break;
- case "L":
- this.insertLines(this.params);
- break;
- case "M":
- this.deleteLines(this.params);
- break;
- case "P":
- this.deleteChars(this.params);
- break;
- case "X":
- this.eraseChars(this.params);
- break;
- case "`":
- this.charPosAbsolute(this.params);
- break;
- case "a":
- this.HPositionRelative(this.params);
- break;
- case "c":
- this.sendDeviceAttributes(this.params);
- break;
- case "d":
- this.linePosAbsolute(this.params);
- break;
- case "e":
- this.VPositionRelative(this.params);
- break;
- case "f":
- this.HVPosition(this.params);
- break;
- case "h":
- this.setMode(this.params);
- break;
- case "l":
- this.resetMode(this.params);
- break;
- case "r":
- this.setScrollRegion(this.params);
- break;
- case "s":
- this.saveCursor(this.params);
- break;
- case "u":
- this.restoreCursor(this.params);
- break;
- case "I":
- this.cursorForwardTab(this.params);
- break;
- case "S":
- this.scrollUp(this.params);
- break;
- case "T":
- if (this.params.length < 2 && !this.prefix) {
- this.scrollDown(this.params);
- }
- break;
- case "Z":
- this.cursorBackwardTab(this.params);
- break;
- case "b":
- this.repeatPrecedingCharacter(this.params);
- break;
- case "g":
- this.tabClear(this.params);
- break;
- case "p":
- if (this.prefix === '!') {
- this.softReset(this.params);
- }
- break;
- default:
- this.error("Unknown CSI code: %s.", ch);
- }
- this.prefix = "";
- break;
- case State.dcs:
- if (ch === "\x1b" || ch === "\x07") {
- if (ch === "\x1b") {
- i++;
- }
- switch (this.prefix) {
- case "":
- break;
- case "$q":
- pt = this.currentParam;
- valid = false;
- switch (pt) {
- case "\"q":
- pt = "0\"q";
- break;
- case "\"p":
- pt = "61\"p";
- break;
- case "r":
- pt = "" + (this.scrollTop + 1) + ";" + (this.scrollBottom + 1) + "r";
- break;
- case "m":
- pt = "0m";
- break;
- default:
- this.error("Unknown DCS Pt: %s.", pt);
- pt = "";
- }
- this.send("\x1bP" + +valid + "$r" + pt + "\x1b\\");
- break;
- case "+q":
- pt = this.currentParam;
- valid = false;
- this.send("\x1bP" + +valid + "+r" + pt + "\x1b\\");
- break;
- default:
- this.error("Unknown DCS prefix: %s.", this.prefix);
- }
- this.currentParam = 0;
- this.prefix = "";
- this.state = State.normal;
- } else if (!this.currentParam) {
- if (!this.prefix && ch !== "$" && ch !== "+") {
- this.currentParam = ch;
- } else if (this.prefix.length === 2) {
- this.currentParam = ch;
- } else {
- this.prefix += ch;
- }
- } else {
- this.currentParam += ch;
- }
- break;
- case State.ignore:
- if (ch === "\x1b" || ch === "\x07") {
- if (ch === "\x1b") {
- i++;
- }
- this.state = State.normal;
- }
- }
- i++;
- }
- this.updateRange(this.y);
- return this.refresh(this.refreshStart, this.refreshEnd);
- };
-
- Terminal.prototype.writeln = function(data) {
- return this.write("" + data + "\r\n");
- };
-
- Terminal.prototype.keyDown = function(ev) {
+ FrontTerminal.prototype.keyDown = function(ev) {
var key,
_this = this;
if (ev.keyCode > 15 && ev.keyCode < 19) {
@@ -1258,19 +809,7 @@ Terminal = (function() {
return cancel(ev);
};
- Terminal.prototype.setgLevel = function(g) {
- this.glevel = g;
- return this.charset = this.charsets[g];
- };
-
- Terminal.prototype.setgCharset = function(g, charset) {
- this.charsets[g] = charset;
- if (this.glevel === g) {
- return this.charset = charset;
- }
- };
-
- Terminal.prototype.keyPress = function(ev) {
+ FrontTerminal.prototype.keyPress = function(ev) {
var key;
if (this.skipNextKey === false) {
this.skipNextKey = null;
@@ -1295,7 +834,14 @@ Terminal = (function() {
return false;
};
- Terminal.prototype.send = function(data) {
+ FrontTerminal.prototype.handler = function(data) {
+ return worker.postMessage({
+ cmd: 'data',
+ data: data
+ });
+ };
+
+ FrontTerminal.prototype.send = function(data) {
var _this = this;
if (!this.queue) {
setTimeout((function() {
@@ -1306,7 +852,7 @@ Terminal = (function() {
return this.queue += data;
};
- Terminal.prototype.bell = function() {
+ FrontTerminal.prototype.bell = function() {
var _this = this;
if (!this.visualBell) {
return;
@@ -1317,8 +863,8 @@ Terminal = (function() {
}), this.visualBell);
};
- Terminal.prototype.resize = function() {
- var ch, el, i, j, line, old_cols, old_rows, term_size;
+ FrontTerminal.prototype.resize = function() {
+ var el, j, line, old_cols, old_rows, term_size, _results, _results1;
old_cols = this.cols;
old_rows = this.rows;
term_size = this.parent.getBoundingClientRect();
@@ -1328,1033 +874,40 @@ Terminal = (function() {
return;
}
this.ctl('Resize', this.cols, this.rows);
- if (old_cols < this.cols) {
- ch = [this.defAttr, " "];
- i = this.lines.length;
- while (i--) {
- while (this.lines[i].length < this.cols) {
- this.lines[i].push(ch);
- }
- }
- } else if (old_cols > this.cols) {
- i = this.lines.length;
- while (i--) {
- while (this.lines[i].length > this.cols) {
- this.lines[i].pop();
- }
- }
- }
- this.setupStops(old_cols);
j = old_rows;
if (j < this.rows) {
el = this.element;
+ _results = [];
while (j++ < this.rows) {
- if (this.lines.length < this.rows + this.ybase) {
- this.lines.push(this.blankLine());
- }
if (this.children.length < this.rows) {
line = this.document.createElement("div");
line.className = 'line';
line.style.height = this.char_size.height + 'px';
el.appendChild(line);
- this.children.push(line);
+ _results.push(this.children.push(line));
+ } else {
+ _results.push(void 0);
}
}
+ return _results;
} else if (j > this.rows) {
+ _results1 = [];
while (j-- > this.rows) {
- if (this.lines.length > this.rows + this.ybase) {
- this.lines.pop();
- }
if (this.children.length > this.rows) {
el = this.children.pop();
if (!el) {
continue;
}
- el.parentNode.removeChild(el);
+ _results1.push(el.parentNode.removeChild(el));
+ } else {
+ _results1.push(void 0);
}
}
- }
- if (this.y >= this.rows) {
- this.y = this.rows - 1;
- }
- if (this.x >= this.cols) {
- this.x = this.cols - 1;
- }
- this.scrollTop = 0;
- this.scrollBottom = this.rows - 1;
- this.refresh(0, this.rows - 1);
- return this.normal = null;
- };
-
- Terminal.prototype.updateRange = function(y) {
- if (y < this.refreshStart) {
- this.refreshStart = y;
- }
- if (y > this.refreshEnd) {
- return this.refreshEnd = y;
+ return _results1;
}
};
- Terminal.prototype.maxRange = function() {
- this.refreshStart = 0;
- return this.refreshEnd = this.rows - 1;
- };
-
- Terminal.prototype.setupStops = function(i) {
- var _results;
- if (i != null) {
- if (!this.tabs[i]) {
- i = this.prevStop(i);
- }
- } else {
- this.tabs = {};
- i = 0;
- }
- _results = [];
- while (i < this.cols) {
- this.tabs[i] = true;
- _results.push(i += 8);
- }
- return _results;
- };
-
- Terminal.prototype.prevStop = function(x) {
- if (x == null) {
- x = this.x;
- }
- while (!this.tabs[--x] && x > 0) {
- 1;
- }
- if (x >= this.cols) {
- return this.cols - 1;
- } else {
- if (x < 0) {
- return 0;
- } else {
- return x;
- }
- }
- };
-
- Terminal.prototype.nextStop = function(x) {
- if (x == null) {
- x = this.x;
- }
- while (!this.tabs[++x] && x < this.cols) {
- 1;
- }
- if (x >= this.cols) {
- return this.cols - 1;
- } else {
- if (x < 0) {
- return 0;
- } else {
- return x;
- }
- }
- };
-
- Terminal.prototype.eraseRight = function(x, y) {
- var ch, line;
- line = this.lines[this.ybase + y];
- ch = [this.eraseAttr(), " "];
- while (x < this.cols) {
- line[x] = ch;
- x++;
- }
- return this.updateRange(y);
- };
-
- Terminal.prototype.eraseLeft = function(x, y) {
- var ch, line;
- line = this.lines[this.ybase + y];
- ch = [this.eraseAttr(), " "];
- x++;
- while (x--) {
- line[x] = ch;
- }
- return this.updateRange(y);
- };
-
- Terminal.prototype.eraseLine = function(y) {
- return this.eraseRight(0, y);
- };
-
- Terminal.prototype.blankLine = function(cur) {
- var attr, ch, i, line;
- attr = (cur ? this.eraseAttr() : this.defAttr);
- ch = [attr, " "];
- line = [];
- i = 0;
- while (i < this.cols) {
- line[i] = ch;
- i++;
- }
- return line;
- };
-
- Terminal.prototype.ch = function(cur) {
- if (cur) {
- return [this.eraseAttr(), " "];
- } else {
- return [this.defAttr, " "];
- }
- };
-
- Terminal.prototype.isterm = function(term) {
- return ("" + this.termName).indexOf(term) === 0;
- };
-
- Terminal.prototype.handler = function(data) {
- return this.out(data);
- };
-
- Terminal.prototype.handleTitle = function(title) {
- return document.title = title;
- };
-
- Terminal.prototype.index = function() {
- this.y++;
- if (this.y > this.scrollBottom) {
- this.y--;
- this.scroll();
- }
- return this.state = State.normal;
- };
-
- Terminal.prototype.reverseIndex = function() {
- var j;
- this.y--;
- if (this.y < this.scrollTop) {
- this.y++;
- this.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
- j = this.rows - 1 - this.scrollBottom;
- this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
- this.updateRange(this.scrollTop);
- this.updateRange(this.scrollBottom);
- }
- return this.state = State.normal;
- };
-
- Terminal.prototype.reset = function() {
- this.reset_vars();
- return this.refresh(0, this.rows - 1);
- };
-
- Terminal.prototype.tabSet = function() {
- this.tabs[this.x] = true;
- return this.state = State.normal;
- };
-
- Terminal.prototype.cursorUp = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.y -= param;
- if (this.y < 0) {
- return this.y = 0;
- }
- };
-
- Terminal.prototype.cursorDown = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.y += param;
- if (this.y >= this.rows) {
- return this.y = this.rows - 1;
- }
- };
-
- Terminal.prototype.cursorForward = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.x += param;
- if (this.x >= this.cols) {
- return this.x = this.cols - 1;
- }
- };
-
- Terminal.prototype.cursorBackward = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.x -= param;
- if (this.x < 0) {
- return this.x = 0;
- }
- };
-
- Terminal.prototype.cursorPos = function(params) {
- var col, row;
- row = params[0] - 1;
- if (params.length >= 2) {
- col = params[1] - 1;
- } else {
- col = 0;
- }
- if (row < 0) {
- row = 0;
- } else {
- if (row >= this.rows) {
- row = this.rows - 1;
- }
- }
- if (col < 0) {
- col = 0;
- } else {
- if (col >= this.cols) {
- col = this.cols - 1;
- }
- }
- this.x = col;
- return this.y = row;
- };
-
- Terminal.prototype.eraseInDisplay = function(params) {
- var j, _results, _results1, _results2;
- switch (params[0]) {
- case 0:
- this.eraseRight(this.x, this.y);
- j = this.y + 1;
- _results = [];
- while (j < this.rows) {
- this.eraseLine(j);
- _results.push(j++);
- }
- return _results;
- break;
- case 1:
- this.eraseLeft(this.x, this.y);
- j = this.y;
- _results1 = [];
- while (j--) {
- _results1.push(this.eraseLine(j));
- }
- return _results1;
- break;
- case 2:
- j = this.rows;
- _results2 = [];
- while (j--) {
- _results2.push(this.eraseLine(j));
- }
- return _results2;
- }
- };
-
- Terminal.prototype.eraseInLine = function(params) {
- switch (params[0]) {
- case 0:
- return this.eraseRight(this.x, this.y);
- case 1:
- return this.eraseLeft(this.x, this.y);
- case 2:
- return this.eraseLine(this.y);
- }
- };
-
- Terminal.prototype.charAttributes = function(params) {
- var bg, fg, flags, i, l, p;
- if (params.length === 1 && params[0] === 0) {
- this.curAttr = this.defAttr;
- return;
- }
- flags = this.curAttr >> 18;
- fg = (this.curAttr >> 9) & 0x1ff;
- bg = this.curAttr & 0x1ff;
- l = params.length;
- i = 0;
- while (i < l) {
- p = params[i];
- if (p >= 30 && p <= 37) {
- fg = p - 30;
- } else if (p >= 40 && p <= 47) {
- bg = p - 40;
- } else if (p >= 90 && p <= 97) {
- p += 8;
- fg = p - 90;
- } else if (p >= 100 && p <= 107) {
- p += 8;
- bg = p - 100;
- } else if (p === 0) {
- flags = this.defAttr >> 18;
- fg = (this.defAttr >> 9) & 0x1ff;
- bg = this.defAttr & 0x1ff;
- } else if (p === 1) {
- flags |= 1;
- } else if (p === 4) {
- flags |= 2;
- } else if (p === 5) {
- flags |= 4;
- } else if (p === 7) {
- flags |= 8;
- } else if (p === 8) {
- flags |= 16;
- } else if (p === 22) {
- flags &= ~1;
- } else if (p === 24) {
- flags &= ~2;
- } else if (p === 25) {
- flags &= ~4;
- } else if (p === 27) {
- flags &= ~8;
- } else if (p === 28) {
- flags &= ~16;
- } else if (p === 39) {
- fg = (this.defAttr >> 9) & 0x1ff;
- } else if (p === 49) {
- bg = this.defAttr & 0x1ff;
- } else if (p === 38) {
- if (params[i + 1] === 2) {
- i += 2;
- fg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
- i += 2;
- } else if (params[i + 1] === 5) {
- i += 2;
- fg = params[i] & 0xff;
- }
- } else if (p === 48) {
- if (params[i + 1] === 2) {
- i += 2;
- bg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
- i += 2;
- } else if (params[i + 1] === 5) {
- i += 2;
- bg = params[i] & 0xff;
- }
- } else if (p === 100) {
- fg = (this.defAttr >> 9) & 0x1ff;
- bg = this.defAttr & 0x1ff;
- } else {
- this.error("Unknown SGR attribute: %d.", p);
- }
- i++;
- }
- return this.curAttr = (flags << 18) | (fg << 9) | bg;
- };
-
- Terminal.prototype.deviceStatus = function(params) {
- if (!this.prefix) {
- switch (params[0]) {
- case 5:
- return this.send("\x1b[0n");
- case 6:
- return this.send("\x1b[" + (this.y + 1) + ";" + (this.x + 1) + "R");
- }
- } else if (this.prefix === "?") {
- if (params[0] === 6) {
- return this.send("\x1b[?" + (this.y + 1) + ";" + (this.x + 1) + "R");
- }
- }
- };
-
- Terminal.prototype.insertChars = function(params) {
- var ch, j, param, row, _results;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this.y + this.ybase;
- j = this.x;
- ch = [this.eraseAttr(), " "];
- _results = [];
- while (param-- && j < this.cols) {
- this.lines[row].splice(j++, 0, ch);
- _results.push(this.lines[row].pop());
- }
- return _results;
- };
-
- Terminal.prototype.cursorNextLine = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.y += param;
- if (this.y >= this.rows) {
- this.y = this.rows - 1;
- }
- return this.x = 0;
- };
-
- Terminal.prototype.cursorPrecedingLine = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.y -= param;
- if (this.y < 0) {
- this.y = 0;
- }
- return this.x = 0;
- };
-
- Terminal.prototype.cursorCharAbsolute = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- return this.x = param - 1;
- };
-
- Terminal.prototype.insertLines = function(params) {
- var j, param, row;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this.y + this.ybase;
- j = this.rows - 1 - this.scrollBottom;
- j = this.rows - 1 + this.ybase - j + 1;
- while (param--) {
- this.lines.splice(row, 0, this.blankLine(true));
- this.lines.splice(j, 1);
- }
- this.updateRange(this.y);
- return this.updateRange(this.scrollBottom);
- };
-
- Terminal.prototype.deleteLines = function(params) {
- var j, param, row;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this.y + this.ybase;
- j = this.rows - 1 - this.scrollBottom;
- j = this.rows - 1 + this.ybase - j;
- while (param--) {
- this.lines.splice(j + 1, 0, this.blankLine(true));
- this.lines.splice(row, 1);
- }
- this.updateRange(this.y);
- return this.updateRange(this.scrollBottom);
- };
-
- Terminal.prototype.deleteChars = function(params) {
- var ch, param, row, _results;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this.y + this.ybase;
- ch = [this.eraseAttr(), " "];
- _results = [];
- while (param--) {
- this.lines[row].splice(this.x, 1);
- _results.push(this.lines[row].push(ch));
- }
- return _results;
- };
-
- Terminal.prototype.eraseChars = function(params) {
- var ch, j, param, row, _results;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this.y + this.ybase;
- j = this.x;
- ch = [this.eraseAttr(), " "];
- _results = [];
- while (param-- && j < this.cols) {
- _results.push(this.lines[row][j++] = ch);
- }
- return _results;
- };
-
- Terminal.prototype.charPosAbsolute = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.x = param - 1;
- if (this.x >= this.cols) {
- return this.x = this.cols - 1;
- }
- };
-
- Terminal.prototype.HPositionRelative = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.x += param;
- if (this.x >= this.cols) {
- return this.x = this.cols - 1;
- }
- };
-
- Terminal.prototype.sendDeviceAttributes = function(params) {
- if (params[0] > 0) {
- return;
- }
- if (!this.prefix) {
- if (this.isterm("xterm") || this.isterm("rxvt-unicode") || this.isterm("screen")) {
- return this.send("\x1b[?1;2c");
- } else {
- if (this.isterm("linux")) {
- return this.send("\x1b[?6c");
- }
- }
- } else if (this.prefix === ">") {
- if (this.isterm("xterm")) {
- return this.send("\x1b[>0;276;0c");
- } else if (this.isterm("rxvt-unicode")) {
- return this.send("\x1b[>85;95;0c");
- } else if (this.isterm("linux")) {
- return this.send(params[0] + "c");
- } else {
- if (this.isterm("screen")) {
- return this.send("\x1b[>83;40003;0c");
- }
- }
- }
- };
-
- Terminal.prototype.linePosAbsolute = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.y = param - 1;
- if (this.y >= this.rows) {
- return this.y = this.rows - 1;
- }
- };
-
- Terminal.prototype.VPositionRelative = function(params) {
- var param;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- this.y += param;
- if (this.y >= this.rows) {
- return this.y = this.rows - 1;
- }
- };
-
- Terminal.prototype.HVPosition = function(params) {
- if (params[0] < 1) {
- params[0] = 1;
- }
- if (params[1] < 1) {
- params[1] = 1;
- }
- this.y = params[0] - 1;
- if (this.y >= this.rows) {
- this.y = this.rows - 1;
- }
- this.x = params[1] - 1;
- if (this.x >= this.cols) {
- return this.x = this.cols - 1;
- }
- };
-
- Terminal.prototype.setMode = function(params) {
- var i, l, normal;
- if (typeof params === "object") {
- l = params.length;
- i = 0;
- while (i < l) {
- this.setMode(params[i]);
- i++;
- }
- return;
- }
- if (this.prefix === "?") {
- switch (params) {
- case 1:
- return this.applicationCursor = true;
- case 2:
- this.setgCharset(0, Terminal.prototype.charsets.US);
- this.setgCharset(1, Terminal.prototype.charsets.US);
- this.setgCharset(2, Terminal.prototype.charsets.US);
- return this.setgCharset(3, Terminal.prototype.charsets.US);
- case 3:
- this.savedCols = this.cols;
- return this.resize(132, this.rows);
- case 6:
- return this.originMode = true;
- case 7:
- return this.wraparoundMode = true;
- case 66:
- return this.applicationKeypad = true;
- case 9:
- case 1000:
- case 1002:
- case 1003:
- this.x10Mouse = params === 9;
- this.vt200Mouse = params === 1000;
- this.normalMouse = params > 1000;
- this.mouseEvents = true;
- return this.element.style.cursor = "default";
- case 1004:
- return this.sendFocus = true;
- case 1005:
- return this.utfMouse = true;
- case 1006:
- return this.sgrMouse = true;
- case 1015:
- return this.urxvtMouse = true;
- case 25:
- return this.cursorHidden = false;
- case 1049:
- case 47:
- case 1047:
- if (!this.normal) {
- normal = {
- lines: this.lines,
- ybase: this.ybase,
- ydisp: this.ydisp,
- x: this.x,
- y: this.y,
- scrollTop: this.scrollTop,
- scrollBottom: this.scrollBottom,
- tabs: this.tabs
- };
- this.reset();
- this.normal = normal;
- return this.showCursor();
- }
- }
- }
- };
-
- Terminal.prototype.resetMode = function(params) {
- var i, l;
- if (typeof params === "object") {
- l = params.length;
- i = 0;
- while (i < l) {
- this.resetMode(params[i]);
- i++;
- }
- return;
- }
- if (this.prefix === "?") {
- switch (params) {
- case 1:
- return this.applicationCursor = false;
- case 3:
- if (this.cols === 132 && this.savedCols) {
- this.resize(this.savedCols, this.rows);
- }
- return delete this.savedCols;
- case 6:
- return this.originMode = false;
- case 7:
- return this.wraparoundMode = false;
- case 66:
- return this.applicationKeypad = false;
- case 9:
- case 1000:
- case 1002:
- case 1003:
- this.x10Mouse = false;
- this.vt200Mouse = false;
- this.normalMouse = false;
- this.mouseEvents = false;
- return this.element.style.cursor = "";
- case 1004:
- return this.sendFocus = false;
- case 1005:
- return this.utfMouse = false;
- case 1006:
- return this.sgrMouse = false;
- case 1015:
- return this.urxvtMouse = false;
- case 25:
- return this.cursorHidden = true;
- case 1049:
- case 47:
- case 1047:
- if (this.normal) {
- this.lines = this.normal.lines;
- this.ybase = this.normal.ybase;
- this.ydisp = this.normal.ydisp;
- this.x = this.normal.x;
- this.y = this.normal.y;
- this.scrollTop = this.normal.scrollTop;
- this.scrollBottom = this.normal.scrollBottom;
- this.tabs = this.normal.tabs;
- this.normal = null;
- this.refresh(0, this.rows - 1);
- return this.showCursor();
- }
- }
- }
- };
-
- Terminal.prototype.setScrollRegion = function(params) {
- if (this.prefix) {
- return;
- }
- this.scrollTop = (params[0] || 1) - 1;
- this.scrollBottom = (params[1] || this.rows) - 1;
- this.x = 0;
- return this.y = 0;
- };
-
- Terminal.prototype.saveCursor = function(params) {
- this.savedX = this.x;
- return this.savedY = this.y;
- };
-
- Terminal.prototype.restoreCursor = function(params) {
- this.x = this.savedX || 0;
- return this.y = this.savedY || 0;
- };
-
- Terminal.prototype.cursorForwardTab = function(params) {
- var param, _results;
- param = params[0] || 1;
- _results = [];
- while (param--) {
- _results.push(this.x = this.nextStop());
- }
- return _results;
- };
-
- Terminal.prototype.scrollUp = function(params) {
- var param;
- param = params[0] || 1;
- while (param--) {
- this.lines.splice(this.ybase + this.scrollTop, 1);
- this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine());
- }
- this.updateRange(this.scrollTop);
- return this.updateRange(this.scrollBottom);
- };
-
- Terminal.prototype.scrollDown = function(params) {
- var param;
- param = params[0] || 1;
- while (param--) {
- this.lines.splice(this.ybase + this.scrollBottom, 1);
- this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine());
- }
- this.updateRange(this.scrollTop);
- return this.updateRange(this.scrollBottom);
- };
-
- Terminal.prototype.initMouseTracking = function(params) {};
-
- Terminal.prototype.resetTitleModes = function(params) {};
-
- Terminal.prototype.cursorBackwardTab = function(params) {
- var param, _results;
- param = params[0] || 1;
- _results = [];
- while (param--) {
- _results.push(this.x = this.prevStop());
- }
- return _results;
- };
-
- Terminal.prototype.repeatPrecedingCharacter = function(params) {
- var ch, line, param, _results;
- param = params[0] || 1;
- line = this.lines[this.ybase + this.y];
- ch = line[this.x - 1] || [this.defAttr, " "];
- _results = [];
- while (param--) {
- _results.push(line[this.x++] = ch);
- }
- return _results;
- };
-
- Terminal.prototype.tabClear = function(params) {
- var param;
- param = params[0];
- if (param <= 0) {
- return delete this.tabs[this.x];
- } else {
- if (param === 3) {
- return this.tabs = {};
- }
- }
- };
-
- Terminal.prototype.mediaCopy = function(params) {};
-
- Terminal.prototype.setResources = function(params) {};
-
- Terminal.prototype.disableModifiers = function(params) {};
-
- Terminal.prototype.setPointerMode = function(params) {};
-
- Terminal.prototype.softReset = function(params) {
- this.cursorHidden = false;
- this.insertMode = false;
- this.originMode = false;
- this.wraparoundMode = false;
- this.applicationKeypad = false;
- this.applicationCursor = false;
- this.scrollTop = 0;
- this.scrollBottom = this.rows - 1;
- this.curAttr = this.defAttr;
- this.x = this.y = 0;
- this.charset = null;
- this.glevel = 0;
- return this.charsets = [null];
- };
-
- Terminal.prototype.requestAnsiMode = function(params) {};
-
- Terminal.prototype.requestPrivateMode = function(params) {};
-
- Terminal.prototype.setConformanceLevel = function(params) {};
-
- Terminal.prototype.loadLEDs = function(params) {};
-
- Terminal.prototype.setCursorStyle = function(params) {};
-
- Terminal.prototype.setCharProtectionAttr = function(params) {};
-
- Terminal.prototype.restorePrivateValues = function(params) {};
-
- Terminal.prototype.setAttrInRectangle = function(params) {
- var attr, b, i, l, line, r, t;
- t = params[0];
- l = params[1];
- b = params[2];
- r = params[3];
- attr = params[4];
- while (t < b + 1) {
- line = this.lines[this.ybase + t];
- i = l;
- while (i < r) {
- line[i] = [attr, line[i][1]];
- i++;
- }
- t++;
- }
- this.updateRange(params[0]);
- return this.updateRange(params[2]);
- };
-
- Terminal.prototype.savePrivateValues = function(params) {};
-
- Terminal.prototype.manipulateWindow = function(params) {};
-
- Terminal.prototype.reverseAttrInRectangle = function(params) {};
-
- Terminal.prototype.setTitleModeFeature = function(params) {};
-
- Terminal.prototype.setWarningBellVolume = function(params) {};
-
- Terminal.prototype.setMarginBellVolume = function(params) {};
-
- Terminal.prototype.copyRectangle = function(params) {};
-
- Terminal.prototype.enableFilterRectangle = function(params) {};
-
- Terminal.prototype.requestParameters = function(params) {};
-
- Terminal.prototype.selectChangeExtent = function(params) {};
-
- Terminal.prototype.fillRectangle = function(params) {
- var b, ch, i, l, line, r, t;
- ch = params[0];
- t = params[1];
- l = params[2];
- b = params[3];
- r = params[4];
- while (t < b + 1) {
- line = this.lines[this.ybase + t];
- i = l;
- while (i < r) {
- line[i] = [line[i][0], String.fromCharCode(ch)];
- i++;
- }
- t++;
- }
- this.updateRange(params[1]);
- return this.updateRange(params[3]);
- };
-
- Terminal.prototype.enableLocatorReporting = function(params) {
- var val;
- return val = params[0] > 0;
- };
-
- Terminal.prototype.eraseRectangle = function(params) {
- var b, ch, i, l, line, r, t;
- t = params[0];
- l = params[1];
- b = params[2];
- r = params[3];
- ch = [this.eraseAttr(), " "];
- while (t < b + 1) {
- line = this.lines[this.ybase + t];
- i = l;
- while (i < r) {
- line[i] = ch;
- i++;
- }
- t++;
- }
- this.updateRange(params[0]);
- return this.updateRange(params[2]);
- };
-
- Terminal.prototype.setLocatorEvents = function(params) {};
-
- Terminal.prototype.selectiveEraseRectangle = function(params) {};
-
- Terminal.prototype.requestLocatorPosition = function(params) {};
-
- Terminal.prototype.insertColumns = function() {
- var ch, i, l, param;
- param = params[0];
- l = this.ybase + this.rows;
- ch = [this.eraseAttr(), " "];
- while (param--) {
- i = this.ybase;
- while (i < l) {
- this.lines[i].splice(this.x + 1, 0, ch);
- this.lines[i].pop();
- i++;
- }
- }
- return this.maxRange();
- };
-
- Terminal.prototype.deleteColumns = function() {
- var ch, i, l, param;
- param = params[0];
- l = this.ybase + this.rows;
- ch = [this.eraseAttr(), " "];
- while (param--) {
- i = this.ybase;
- while (i < l) {
- this.lines[i].splice(this.x, 1);
- this.lines[i].push(ch);
- i++;
- }
- }
- return this.maxRange();
- };
-
- Terminal.prototype.get_html_height_in_lines = function(html) {
+ FrontTerminal.prototype.get_html_height_in_lines = function(html) {
var html_height, temp_node;
temp_node = document.createElement("div");
temp_node.innerHTML = html;
@@ -2364,241 +917,15 @@ Terminal = (function() {
return Math.ceil(html_height / this.char_size.height);
};
- Terminal.prototype.charsets = {
- SCLD: {
- "`": "◆",
- a: "▒",
- b: "\t",
- c: "\f",
- d: "\r",
- e: "\n",
- f: "°",
- g: "±",
- h: "",
- i: "\x0b",
- j: "┘",
- k: "┐",
- l: "┌",
- m: "└",
- n: "┼",
- o: "⎺",
- p: "⎻",
- q: "─",
- r: "⎼",
- s: "⎽",
- t: "├",
- u: "┤",
- v: "┴",
- w: "┬",
- x: "│",
- y: "≤",
- z: "≥",
- "{": "π",
- "|": "≠",
- "}": "£",
- "~": "·"
- },
- UK: null,
- US: null,
- Dutch: null,
- Finnish: null,
- French: null,
- FrenchCanadian: null,
- German: null,
- Italian: null,
- NorwegianDanish: null,
- Spanish: null,
- Swedish: null,
- Swiss: null,
- ISOLatin: null
- };
-
- return Terminal;
+ return FrontTerminal;
})();
-state = {
- x: null,
- y: null
-};
+frontterm = new FrontTerminal($('#wrapper')[0], send, ctl);
-document.addEventListener('keydown', function(e) {
- var _ref;
- if (e.shiftKey && ((37 <= (_ref = e.keyCode) && _ref <= 40))) {
- if (state.y === null) {
- state.y = term.ybase + term.y;
- }
- if (e.keyCode === 38) {
- state.y--;
- if (state.y < term.ybase) {
- state.y = term.ybase;
- }
- } else if (e.keyCode === 40) {
- state.y++;
- if (state.y > term.ybase + term.y) {
- state.y = term.ybase + term.y;
- }
- }
- term.emit('data', ' \x0b\x15');
- if (state.y !== term.ybase + term.y) {
- term.emit('data', term.grabText(0, term.cols - 1, state.y, state.y).replace('\n', ''));
- }
- e.stopPropagation();
- return false;
- } else {
- return state.x = state.y = null;
- }
+worker.postMessage({
+ cmd: 'init',
+ cols: frontterm.cols,
+ rows: frontterm.rows,
+ wsurl: 'ws://' + document.location.host + '/ws' + location.pathname
});
-
-if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
- ctrl = false;
- alt = false;
- first = true;
- virtual_input = document.createElement('input');
- virtual_input.type = 'password';
- virtual_input.style.position = 'fixed';
- virtual_input.style.top = 0;
- virtual_input.style.left = 0;
- virtual_input.style.border = 'none';
- virtual_input.style.outline = 'none';
- virtual_input.style.opacity = 0;
- virtual_input.value = '0';
- document.body.appendChild(virtual_input);
- virtual_input.addEventListener('blur', function() {
- var _this = this;
- return setTimeout((function() {
- return _this.focus();
- }), 10);
- });
- addEventListener('click', function() {
- return virtual_input.focus();
- });
- addEventListener('touchstart', function(e) {
- if (e.touches.length === 1) {
- return ctrl = true;
- } else if (e.touches.length === 2) {
- ctrl = false;
- return alt = true;
- } else if (e.touches.length === 3) {
- ctrl = true;
- return alt = true;
- }
- });
- virtual_input.addEventListener('keydown', function(e) {
- term.keyDown(e);
- return true;
- });
- virtual_input.addEventListener('input', function(e) {
- var len;
- len = this.value.length;
- if (len === 0) {
- e.keyCode = 8;
- term.keyDown(e);
- this.value = '0';
- return true;
- }
- e.keyCode = this.value.charAt(1).charCodeAt(0);
- if ((ctrl || alt) && !first) {
- e.keyCode = this.value.charAt(1).charCodeAt(0);
- e.ctrlKey = ctrl;
- e.altKey = alt;
- if (e.keyCode >= 97 && e.keyCode <= 122) {
- e.keyCode -= 32;
- }
- term.keyDown(e);
- this.value = '0';
- ctrl = alt = false;
- return true;
- }
- term.keyPress(e);
- first = false;
- this.value = '0';
- return true;
- });
-}
-
-cols = rows = null;
-
-quit = false;
-
-$ = document.querySelectorAll.bind(document);
-
-send = function(data) {
- return ws.send('S' + data);
-};
-
-ctl = function() {
- var args, params, type;
- type = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
- params = args.join(',');
- if (type === 'Resize') {
- return ws.send('R' + params);
- }
-};
-
-ws_url = 'ws://' + document.location.host + '/ws' + location.pathname;
-
-ws = new WebSocket(ws_url);
-
-ws.addEventListener('open', function() {
- console.log("WebSocket open", arguments);
- ws.send('R' + term.cols + ',' + term.rows);
- if (location.hash) {
- return setTimeout(function() {
- return ws.send('S' + location.hash.slice(1) + '\n');
- }, 100);
- }
-});
-
-ws.addEventListener('error', function() {
- return console.log("WebSocket error", arguments);
-});
-
-ws.addEventListener('message', function(e) {
- return setTimeout(function() {
- return term.write(e.data);
- }, 1);
-});
-
-ws.addEventListener('close', function() {
- console.log("WebSocket closed", arguments);
- quit = true;
- return open('', '_self').close();
-});
-
-term = new Terminal($('#wrapper')[0], send, ctl);
-
-addEventListener('beforeunload', function() {
- if (!quit) {
- return 'This will exit the terminal session';
- }
-});
-
-bench = function(n) {
- var rnd, t0;
- if (n == null) {
- n = 100000000;
- }
- rnd = '';
- while (rnd.length < n) {
- rnd += Math.random().toString(36).substring(2);
- }
- t0 = (new Date()).getTime();
- term.write(rnd);
- return console.log("" + n + " chars in " + ((new Date()).getTime() - t0) + " ms");
-};
-
-cbench = function(n) {
- var rnd, t0;
- if (n == null) {
- n = 100000000;
- }
- rnd = '';
- while (rnd.length < n) {
- rnd += "\x1b[" + (30 + parseInt(Math.random() * 20)) + "m";
- rnd += Math.random().toString(36).substring(2);
- }
- t0 = (new Date()).getTime();
- term.write(rnd);
- return console.log("" + n + " chars + colors in " + ((new Date()).getTime() - t0) + " ms");
-};
diff --git a/butterfly/static/javascripts/worker.js b/butterfly/static/javascripts/worker.js
new file mode 100644
index 0000000..f1bc4d6
--- /dev/null
+++ b/butterfly/static/javascripts/worker.js
@@ -0,0 +1,1712 @@
+// Generated by CoffeeScript 1.6.3
+var BackTerminal, State, backterm, s, ws;
+
+ws = null;
+
+backterm = null;
+
+self.addEventListener('message', function(e) {
+ switch (e.data.cmd) {
+ case 'init':
+ backterm = new BackTerminal(e.data.cols, e.data.rows);
+ ws = new WebSocket(e.data.wsurl);
+ ws.addEventListener('open', function() {
+ console.log("WebSocket open", arguments);
+ return ws.send('R' + e.data.cols + ',' + e.data.rows);
+ });
+ ws.addEventListener('error', function() {
+ return console.log("WebSocket error", arguments);
+ });
+ ws.addEventListener('message', function(e) {
+ return backterm.write(e.data);
+ });
+ return ws.addEventListener('close', function() {
+ return console.log("WebSocket closed", arguments);
+ });
+ case 'data':
+ return ws.send('S' + e.data.data);
+ }
+});
+
+s = 0;
+
+State = {
+ normal: s++,
+ escaped: s++,
+ csi: s++,
+ osc: s++,
+ charset: s++,
+ dcs: s++,
+ ignore: s++
+};
+
+BackTerminal = (function() {
+ function BackTerminal(cols, rows) {
+ this.cols = cols;
+ this.rows = rows;
+ this.scrollback = 100000;
+ this.visualBell = 100;
+ this.convertEol = false;
+ this.termName = 'xterm';
+ this.cursorBlink = true;
+ this.screenKeys = false;
+ this.cursorState = 0;
+ this.reset_vars();
+ }
+
+ BackTerminal.prototype.reset_vars = function() {
+ var i;
+ this.ybase = 0;
+ this.ydisp = 0;
+ this.x = 0;
+ this.y = 0;
+ this.state = State.normal;
+ this.scrollTop = 0;
+ this.scrollBottom = this.rows - 1;
+ this.applicationKeypad = false;
+ this.applicationCursor = false;
+ this.originMode = false;
+ this.wraparoundMode = false;
+ this.normal = null;
+ this.charset = null;
+ this.gcharset = null;
+ this.glevel = 0;
+ this.charsets = [null];
+ this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
+ this.curAttr = this.defAttr;
+ this.params = [];
+ this.currentParam = 0;
+ this.prefix = "";
+ this.lines = [];
+ i = this.rows;
+ while (i--) {
+ this.lines.push(this.blankLine());
+ }
+ return this.setupStops();
+ };
+
+ BackTerminal.prototype.eraseAttr = function() {
+ return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
+ };
+
+ BackTerminal.prototype.scroll = function() {
+ var row;
+ if (++this.ybase === this.scrollback) {
+ this.ybase = this.ybase / 2 | 0;
+ this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
+ }
+ this.ydisp = this.ybase;
+ row = this.ybase + this.rows - 1;
+ row -= this.rows - 1 - this.scrollBottom;
+ if (row === this.lines.length) {
+ this.lines.push(this.blankLine());
+ } else {
+ this.lines.splice(row, 0, this.blankLine());
+ }
+ if (this.scrollTop !== 0) {
+ if (this.ybase !== 0) {
+ this.ybase--;
+ this.ydisp = this.ybase;
+ }
+ this.lines.splice(this.ybase + this.scrollTop, 1);
+ }
+ this.updateRange(this.scrollTop);
+ return this.updateRange(this.scrollBottom);
+ };
+
+ BackTerminal.prototype.scrollDisp = function(disp) {
+ this.ydisp += disp;
+ if (this.ydisp > this.ybase) {
+ this.ydisp = this.ybase;
+ } else {
+ if (this.ydisp < 0) {
+ this.ydisp = 0;
+ }
+ }
+ return this.refresh(0, this.rows - 1);
+ };
+
+ BackTerminal.prototype.refresh = function(start, end) {
+ return self.postMessage({
+ cmd: 'refresh',
+ lines: this.lines.slice(this.ydisp, this.ydisp + this.rows),
+ start: start,
+ end: end
+ });
+ };
+
+ BackTerminal.prototype.write = function(data) {
+ var ch, cs, html, i, j, l, line, pt, valid, _ref;
+ this.refreshStart = this.y;
+ this.refreshEnd = this.y;
+ if (this.ybase !== this.ydisp) {
+ this.ydisp = this.ybase;
+ this.maxRange();
+ }
+ i = 0;
+ l = data.length;
+ while (i < l) {
+ ch = data[i];
+ switch (this.state) {
+ case State.normal:
+ switch (ch) {
+ case "\x07":
+ this.bell();
+ break;
+ case "\n":
+ case "\x0b":
+ case "\x0c":
+ if (this.convertEol) {
+ this.x = 0;
+ }
+ this.y++;
+ if (this.y > this.scrollBottom) {
+ this.y--;
+ this.scroll();
+ }
+ break;
+ case "\r":
+ this.x = 0;
+ break;
+ case "\b":
+ if (this.x > 0) {
+ this.x--;
+ }
+ break;
+ case "\t":
+ this.x = this.nextStop();
+ break;
+ case "\x0e":
+ this.setgLevel(1);
+ break;
+ case "\x0f":
+ this.setgLevel(0);
+ break;
+ case "\x1b":
+ this.state = State.escaped;
+ break;
+ default:
+ if (ch >= " ") {
+ if ((_ref = this.charset) != null ? _ref[ch] : void 0) {
+ ch = this.charset[ch];
+ }
+ if (this.x >= this.cols) {
+ this.x = 0;
+ this.y++;
+ if (this.y > this.scrollBottom) {
+ this.y--;
+ this.scroll();
+ }
+ }
+ this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch];
+ this.x++;
+ this.updateRange(this.y);
+ if (("\uff00" < ch && ch < "\uffef")) {
+ j = this.y + this.ybase;
+ if (this.cols < 2 || this.x >= this.cols) {
+ this.lines[j][this.x - 1] = [this.curAttr, " "];
+ break;
+ }
+ this.lines[j][this.x] = [this.curAttr, " "];
+ this.x++;
+ }
+ }
+ }
+ break;
+ case State.escaped:
+ switch (ch) {
+ case "[":
+ this.params = [];
+ this.currentParam = 0;
+ this.state = State.csi;
+ break;
+ case "]":
+ this.params = [];
+ this.currentParam = 0;
+ this.state = State.osc;
+ break;
+ case "P":
+ this.params = [];
+ this.currentParam = 0;
+ this.state = State.dcs;
+ break;
+ case "_":
+ this.state = State.ignore;
+ break;
+ case "^":
+ this.state = State.ignore;
+ break;
+ case "c":
+ this.reset();
+ break;
+ case "E":
+ this.x = 0;
+ this.index();
+ break;
+ case "D":
+ this.index();
+ break;
+ case "M":
+ this.reverseIndex();
+ break;
+ case "%":
+ this.setgLevel(0);
+ this.setgCharset(0, BackTerminal.prototype.charsets.US);
+ this.state = State.normal;
+ i++;
+ break;
+ case "(":
+ case ")":
+ case "*":
+ case "+":
+ case "-":
+ case ".":
+ switch (ch) {
+ case "(":
+ this.gcharset = 0;
+ break;
+ case ")":
+ case "-":
+ this.gcharset = 1;
+ break;
+ case "*":
+ case ".":
+ this.gcharset = 2;
+ break;
+ case "+":
+ this.gcharset = 3;
+ }
+ this.state = State.charset;
+ break;
+ case "/":
+ this.gcharset = 3;
+ this.state = State.charset;
+ i--;
+ break;
+ case "n":
+ this.setgLevel(2);
+ break;
+ case "o":
+ this.setgLevel(3);
+ break;
+ case "|":
+ this.setgLevel(3);
+ break;
+ case "}":
+ this.setgLevel(2);
+ break;
+ case "~":
+ this.setgLevel(1);
+ break;
+ case "7":
+ this.saveCursor();
+ this.state = State.normal;
+ break;
+ case "8":
+ this.restoreCursor();
+ this.state = State.normal;
+ break;
+ case "#":
+ this.state = State.normal;
+ i++;
+ break;
+ case "H":
+ this.tabSet();
+ break;
+ case "=":
+ this.applicationKeypad = true;
+ this.state = State.normal;
+ break;
+ case ">":
+ this.applicationKeypad = false;
+ this.state = State.normal;
+ break;
+ default:
+ this.state = State.normal;
+ console.log("Unknown ESC control:", ch);
+ }
+ break;
+ case State.charset:
+ switch (ch) {
+ case "0":
+ cs = BackTerminal.prototype.charsets.SCLD;
+ break;
+ case "A":
+ cs = BackTerminal.prototype.charsets.UK;
+ break;
+ case "B":
+ cs = BackTerminal.prototype.charsets.US;
+ break;
+ case "4":
+ cs = BackTerminal.prototype.charsets.Dutch;
+ break;
+ case "C":
+ case "5":
+ cs = BackTerminal.prototype.charsets.Finnish;
+ break;
+ case "R":
+ cs = BackTerminal.prototype.charsets.French;
+ break;
+ case "Q":
+ cs = BackTerminal.prototype.charsets.FrenchCanadian;
+ break;
+ case "K":
+ cs = BackTerminal.prototype.charsets.German;
+ break;
+ case "Y":
+ cs = BackTerminal.prototype.charsets.Italian;
+ break;
+ case "E":
+ case "6":
+ cs = BackTerminal.prototype.charsets.NorwegianDanish;
+ break;
+ case "Z":
+ cs = BackTerminal.prototype.charsets.Spanish;
+ break;
+ case "H":
+ case "7":
+ cs = BackTerminal.prototype.charsets.Swedish;
+ break;
+ case "=":
+ cs = BackTerminal.prototype.charsets.Swiss;
+ break;
+ case "/":
+ cs = BackTerminal.prototype.charsets.ISOLatin;
+ i++;
+ break;
+ default:
+ cs = BackTerminal.prototype.charsets.US;
+ }
+ this.setgCharset(this.gcharset, cs);
+ this.gcharset = null;
+ this.state = State.normal;
+ break;
+ case State.osc:
+ if (ch === "\x1b" || ch === "\x07") {
+ if (ch === "\x1b") {
+ i++;
+ }
+ this.params.push(this.currentParam);
+ switch (this.params[0]) {
+ case 0:
+ case 1:
+ case 2:
+ if (this.params[1]) {
+ this.title = this.params[1] + " - ƸӜƷ butterfly";
+ this.handleTitle(this.title);
+ }
+ break;
+ case 99:
+ html = "" + this.params[1] + "
";
+ this.lines[this.y + this.ybase][this.x] = [this.curAttr, html];
+ line = 0;
+ while (line < this.get_html_height_in_lines(html) - 1) {
+ this.y++;
+ if (this.y > this.scrollBottom) {
+ this.y--;
+ this.scroll();
+ }
+ line++;
+ }
+ this.updateRange(this.y);
+ }
+ this.params = [];
+ this.currentParam = 0;
+ this.state = State.normal;
+ } else {
+ if (!this.params.length) {
+ if (ch >= "0" && ch <= "9") {
+ this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
+ } else if (ch === ";") {
+ this.params.push(this.currentParam);
+ this.currentParam = "";
+ }
+ } else {
+ this.currentParam += ch;
+ }
+ }
+ break;
+ case State.csi:
+ if (ch === "?" || ch === ">" || ch === "!") {
+ this.prefix = ch;
+ break;
+ }
+ if (ch >= "0" && ch <= "9") {
+ this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
+ break;
+ }
+ if (ch === "$" || ch === "\"" || ch === " " || ch === "'") {
+ break;
+ }
+ this.params.push(this.currentParam);
+ this.currentParam = 0;
+ if (ch === ";") {
+ break;
+ }
+ this.state = State.normal;
+ switch (ch) {
+ case "A":
+ this.cursorUp(this.params);
+ break;
+ case "B":
+ this.cursorDown(this.params);
+ break;
+ case "C":
+ this.cursorForward(this.params);
+ break;
+ case "D":
+ this.cursorBackward(this.params);
+ break;
+ case "H":
+ this.cursorPos(this.params);
+ break;
+ case "J":
+ this.eraseInDisplay(this.params);
+ break;
+ case "K":
+ this.eraseInLine(this.params);
+ break;
+ case "m":
+ if (!this.prefix) {
+ this.charAttributes(this.params);
+ }
+ break;
+ case "n":
+ if (!this.prefix) {
+ this.deviceStatus(this.params);
+ }
+ break;
+ case "@":
+ this.insertChars(this.params);
+ break;
+ case "E":
+ this.cursorNextLine(this.params);
+ break;
+ case "F":
+ this.cursorPrecedingLine(this.params);
+ break;
+ case "G":
+ this.cursorCharAbsolute(this.params);
+ break;
+ case "L":
+ this.insertLines(this.params);
+ break;
+ case "M":
+ this.deleteLines(this.params);
+ break;
+ case "P":
+ this.deleteChars(this.params);
+ break;
+ case "X":
+ this.eraseChars(this.params);
+ break;
+ case "`":
+ this.charPosAbsolute(this.params);
+ break;
+ case "a":
+ this.HPositionRelative(this.params);
+ break;
+ case "c":
+ this.sendDeviceAttributes(this.params);
+ break;
+ case "d":
+ this.linePosAbsolute(this.params);
+ break;
+ case "e":
+ this.VPositionRelative(this.params);
+ break;
+ case "f":
+ this.HVPosition(this.params);
+ break;
+ case "h":
+ this.setMode(this.params);
+ break;
+ case "l":
+ this.resetMode(this.params);
+ break;
+ case "r":
+ this.setScrollRegion(this.params);
+ break;
+ case "s":
+ this.saveCursor(this.params);
+ break;
+ case "u":
+ this.restoreCursor(this.params);
+ break;
+ case "I":
+ this.cursorForwardTab(this.params);
+ break;
+ case "S":
+ this.scrollUp(this.params);
+ break;
+ case "T":
+ if (this.params.length < 2 && !this.prefix) {
+ this.scrollDown(this.params);
+ }
+ break;
+ case "Z":
+ this.cursorBackwardTab(this.params);
+ break;
+ case "b":
+ this.repeatPrecedingCharacter(this.params);
+ break;
+ case "g":
+ this.tabClear(this.params);
+ break;
+ case "p":
+ if (this.prefix === '!') {
+ this.softReset(this.params);
+ }
+ break;
+ default:
+ this.error("Unknown CSI code: %s.", ch);
+ }
+ this.prefix = "";
+ break;
+ case State.dcs:
+ if (ch === "\x1b" || ch === "\x07") {
+ if (ch === "\x1b") {
+ i++;
+ }
+ switch (this.prefix) {
+ case "":
+ break;
+ case "$q":
+ pt = this.currentParam;
+ valid = false;
+ switch (pt) {
+ case "\"q":
+ pt = "0\"q";
+ break;
+ case "\"p":
+ pt = "61\"p";
+ break;
+ case "r":
+ pt = "" + (this.scrollTop + 1) + ";" + (this.scrollBottom + 1) + "r";
+ break;
+ case "m":
+ pt = "0m";
+ break;
+ default:
+ this.error("Unknown DCS Pt: %s.", pt);
+ pt = "";
+ }
+ this.send("\x1bP" + +valid + "$r" + pt + "\x1b\\");
+ break;
+ case "+q":
+ pt = this.currentParam;
+ valid = false;
+ this.send("\x1bP" + +valid + "+r" + pt + "\x1b\\");
+ break;
+ default:
+ this.error("Unknown DCS prefix: %s.", this.prefix);
+ }
+ this.currentParam = 0;
+ this.prefix = "";
+ this.state = State.normal;
+ } else if (!this.currentParam) {
+ if (!this.prefix && ch !== "$" && ch !== "+") {
+ this.currentParam = ch;
+ } else if (this.prefix.length === 2) {
+ this.currentParam = ch;
+ } else {
+ this.prefix += ch;
+ }
+ } else {
+ this.currentParam += ch;
+ }
+ break;
+ case State.ignore:
+ if (ch === "\x1b" || ch === "\x07") {
+ if (ch === "\x1b") {
+ i++;
+ }
+ this.state = State.normal;
+ }
+ }
+ i++;
+ }
+ this.updateRange(this.y);
+ return this.refresh(this.refreshStart, this.refreshEnd);
+ };
+
+ BackTerminal.prototype.writeln = function(data) {
+ return this.write("" + data + "\r\n");
+ };
+
+ BackTerminal.prototype.setgLevel = function(g) {
+ this.glevel = g;
+ return this.charset = this.charsets[g];
+ };
+
+ BackTerminal.prototype.setgCharset = function(g, charset) {
+ this.charsets[g] = charset;
+ if (this.glevel === g) {
+ return this.charset = charset;
+ }
+ };
+
+ BackTerminal.prototype.resize = function(cols, rows) {
+ var ch, i, j;
+ this.cols = cols;
+ this.rows = rows;
+ if (old_cols < this.cols) {
+ ch = [this.defAttr, " "];
+ i = this.lines.length;
+ while (i--) {
+ while (this.lines[i].length < this.cols) {
+ this.lines[i].push(ch);
+ }
+ }
+ } else if (old_cols > this.cols) {
+ i = this.lines.length;
+ while (i--) {
+ while (this.lines[i].length > this.cols) {
+ this.lines[i].pop();
+ }
+ }
+ }
+ this.setupStops(old_cols);
+ j = old_rows;
+ if (j < this.rows) {
+ while (j++ < this.rows) {
+ if (this.lines.length < this.rows + this.ybase) {
+ this.lines.push(this.blankLine());
+ }
+ }
+ } else if (j > this.rows) {
+ while (j-- > this.rows) {
+ if (this.lines.length > this.rows + this.ybase) {
+ this.lines.pop();
+ }
+ }
+ }
+ if (this.y >= this.rows) {
+ this.y = this.rows - 1;
+ }
+ if (this.x >= this.cols) {
+ this.x = this.cols - 1;
+ }
+ this.scrollTop = 0;
+ this.scrollBottom = this.rows - 1;
+ return this.normal = null;
+ };
+
+ BackTerminal.prototype.updateRange = function(y) {
+ if (y < this.refreshStart) {
+ this.refreshStart = y;
+ }
+ if (y > this.refreshEnd) {
+ return this.refreshEnd = y;
+ }
+ };
+
+ BackTerminal.prototype.maxRange = function() {
+ this.refreshStart = 0;
+ return this.refreshEnd = this.rows - 1;
+ };
+
+ BackTerminal.prototype.setupStops = function(i) {
+ var _results;
+ if (i != null) {
+ if (!this.tabs[i]) {
+ i = this.prevStop(i);
+ }
+ } else {
+ this.tabs = {};
+ i = 0;
+ }
+ _results = [];
+ while (i < this.cols) {
+ this.tabs[i] = true;
+ _results.push(i += 8);
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.prevStop = function(x) {
+ if (x == null) {
+ x = this.x;
+ }
+ while (!this.tabs[--x] && x > 0) {
+ 1;
+ }
+ if (x >= this.cols) {
+ return this.cols - 1;
+ } else {
+ if (x < 0) {
+ return 0;
+ } else {
+ return x;
+ }
+ }
+ };
+
+ BackTerminal.prototype.nextStop = function(x) {
+ if (x == null) {
+ x = this.x;
+ }
+ while (!this.tabs[++x] && x < this.cols) {
+ 1;
+ }
+ if (x >= this.cols) {
+ return this.cols - 1;
+ } else {
+ if (x < 0) {
+ return 0;
+ } else {
+ return x;
+ }
+ }
+ };
+
+ BackTerminal.prototype.eraseRight = function(x, y) {
+ var ch, line;
+ line = this.lines[this.ybase + y];
+ ch = [this.eraseAttr(), " "];
+ while (x < this.cols) {
+ line[x] = ch;
+ x++;
+ }
+ return this.updateRange(y);
+ };
+
+ BackTerminal.prototype.eraseLeft = function(x, y) {
+ var ch, line;
+ line = this.lines[this.ybase + y];
+ ch = [this.eraseAttr(), " "];
+ x++;
+ while (x--) {
+ line[x] = ch;
+ }
+ return this.updateRange(y);
+ };
+
+ BackTerminal.prototype.eraseLine = function(y) {
+ return this.eraseRight(0, y);
+ };
+
+ BackTerminal.prototype.blankLine = function(cur) {
+ var attr, ch, i, line;
+ attr = (cur ? this.eraseAttr() : this.defAttr);
+ ch = [attr, " "];
+ line = [];
+ i = 0;
+ while (i < this.cols) {
+ line[i] = ch;
+ i++;
+ }
+ return line;
+ };
+
+ BackTerminal.prototype.ch = function(cur) {
+ if (cur) {
+ return [this.eraseAttr(), " "];
+ } else {
+ return [this.defAttr, " "];
+ }
+ };
+
+ BackTerminal.prototype.isterm = function(term) {
+ return ("" + this.termName).indexOf(term) === 0;
+ };
+
+ BackTerminal.prototype.handler = function(data) {
+ return this.out(data);
+ };
+
+ BackTerminal.prototype.handleTitle = function(title) {};
+
+ BackTerminal.prototype.index = function() {
+ this.y++;
+ if (this.y > this.scrollBottom) {
+ this.y--;
+ this.scroll();
+ }
+ return this.state = State.normal;
+ };
+
+ BackTerminal.prototype.reverseIndex = function() {
+ var j;
+ this.y--;
+ if (this.y < this.scrollTop) {
+ this.y++;
+ this.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
+ j = this.rows - 1 - this.scrollBottom;
+ this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
+ this.updateRange(this.scrollTop);
+ this.updateRange(this.scrollBottom);
+ }
+ return this.state = State.normal;
+ };
+
+ BackTerminal.prototype.reset = function() {
+ this.reset_vars();
+ return this.refresh(0, this.rows - 1);
+ };
+
+ BackTerminal.prototype.tabSet = function() {
+ this.tabs[this.x] = true;
+ return this.state = State.normal;
+ };
+
+ BackTerminal.prototype.cursorUp = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.y -= param;
+ if (this.y < 0) {
+ return this.y = 0;
+ }
+ };
+
+ BackTerminal.prototype.cursorDown = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.y += param;
+ if (this.y >= this.rows) {
+ return this.y = this.rows - 1;
+ }
+ };
+
+ BackTerminal.prototype.cursorForward = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.x += param;
+ if (this.x >= this.cols) {
+ return this.x = this.cols - 1;
+ }
+ };
+
+ BackTerminal.prototype.cursorBackward = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.x -= param;
+ if (this.x < 0) {
+ return this.x = 0;
+ }
+ };
+
+ BackTerminal.prototype.cursorPos = function(params) {
+ var col, row;
+ row = params[0] - 1;
+ if (params.length >= 2) {
+ col = params[1] - 1;
+ } else {
+ col = 0;
+ }
+ if (row < 0) {
+ row = 0;
+ } else {
+ if (row >= this.rows) {
+ row = this.rows - 1;
+ }
+ }
+ if (col < 0) {
+ col = 0;
+ } else {
+ if (col >= this.cols) {
+ col = this.cols - 1;
+ }
+ }
+ this.x = col;
+ return this.y = row;
+ };
+
+ BackTerminal.prototype.eraseInDisplay = function(params) {
+ var j, _results, _results1, _results2;
+ switch (params[0]) {
+ case 0:
+ this.eraseRight(this.x, this.y);
+ j = this.y + 1;
+ _results = [];
+ while (j < this.rows) {
+ this.eraseLine(j);
+ _results.push(j++);
+ }
+ return _results;
+ break;
+ case 1:
+ this.eraseLeft(this.x, this.y);
+ j = this.y;
+ _results1 = [];
+ while (j--) {
+ _results1.push(this.eraseLine(j));
+ }
+ return _results1;
+ break;
+ case 2:
+ j = this.rows;
+ _results2 = [];
+ while (j--) {
+ _results2.push(this.eraseLine(j));
+ }
+ return _results2;
+ }
+ };
+
+ BackTerminal.prototype.eraseInLine = function(params) {
+ switch (params[0]) {
+ case 0:
+ return this.eraseRight(this.x, this.y);
+ case 1:
+ return this.eraseLeft(this.x, this.y);
+ case 2:
+ return this.eraseLine(this.y);
+ }
+ };
+
+ BackTerminal.prototype.charAttributes = function(params) {
+ var bg, fg, flags, i, l, p;
+ if (params.length === 1 && params[0] === 0) {
+ this.curAttr = this.defAttr;
+ return;
+ }
+ flags = this.curAttr >> 18;
+ fg = (this.curAttr >> 9) & 0x1ff;
+ bg = this.curAttr & 0x1ff;
+ l = params.length;
+ i = 0;
+ while (i < l) {
+ p = params[i];
+ if (p >= 30 && p <= 37) {
+ fg = p - 30;
+ } else if (p >= 40 && p <= 47) {
+ bg = p - 40;
+ } else if (p >= 90 && p <= 97) {
+ p += 8;
+ fg = p - 90;
+ } else if (p >= 100 && p <= 107) {
+ p += 8;
+ bg = p - 100;
+ } else if (p === 0) {
+ flags = this.defAttr >> 18;
+ fg = (this.defAttr >> 9) & 0x1ff;
+ bg = this.defAttr & 0x1ff;
+ } else if (p === 1) {
+ flags |= 1;
+ } else if (p === 4) {
+ flags |= 2;
+ } else if (p === 5) {
+ flags |= 4;
+ } else if (p === 7) {
+ flags |= 8;
+ } else if (p === 8) {
+ flags |= 16;
+ } else if (p === 22) {
+ flags &= ~1;
+ } else if (p === 24) {
+ flags &= ~2;
+ } else if (p === 25) {
+ flags &= ~4;
+ } else if (p === 27) {
+ flags &= ~8;
+ } else if (p === 28) {
+ flags &= ~16;
+ } else if (p === 39) {
+ fg = (this.defAttr >> 9) & 0x1ff;
+ } else if (p === 49) {
+ bg = this.defAttr & 0x1ff;
+ } else if (p === 38) {
+ if (params[i + 1] === 2) {
+ i += 2;
+ fg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
+ i += 2;
+ } else if (params[i + 1] === 5) {
+ i += 2;
+ fg = params[i] & 0xff;
+ }
+ } else if (p === 48) {
+ if (params[i + 1] === 2) {
+ i += 2;
+ bg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
+ i += 2;
+ } else if (params[i + 1] === 5) {
+ i += 2;
+ bg = params[i] & 0xff;
+ }
+ } else if (p === 100) {
+ fg = (this.defAttr >> 9) & 0x1ff;
+ bg = this.defAttr & 0x1ff;
+ } else {
+ this.error("Unknown SGR attribute: %d.", p);
+ }
+ i++;
+ }
+ return this.curAttr = (flags << 18) | (fg << 9) | bg;
+ };
+
+ BackTerminal.prototype.deviceStatus = function(params) {
+ if (!this.prefix) {
+ switch (params[0]) {
+ case 5:
+ return this.send("\x1b[0n");
+ case 6:
+ return this.send("\x1b[" + (this.y + 1) + ";" + (this.x + 1) + "R");
+ }
+ } else if (this.prefix === "?") {
+ if (params[0] === 6) {
+ return this.send("\x1b[?" + (this.y + 1) + ";" + (this.x + 1) + "R");
+ }
+ }
+ };
+
+ BackTerminal.prototype.insertChars = function(params) {
+ var ch, j, param, row, _results;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ row = this.y + this.ybase;
+ j = this.x;
+ ch = [this.eraseAttr(), " "];
+ _results = [];
+ while (param-- && j < this.cols) {
+ this.lines[row].splice(j++, 0, ch);
+ _results.push(this.lines[row].pop());
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.cursorNextLine = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.y += param;
+ if (this.y >= this.rows) {
+ this.y = this.rows - 1;
+ }
+ return this.x = 0;
+ };
+
+ BackTerminal.prototype.cursorPrecedingLine = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.y -= param;
+ if (this.y < 0) {
+ this.y = 0;
+ }
+ return this.x = 0;
+ };
+
+ BackTerminal.prototype.cursorCharAbsolute = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ return this.x = param - 1;
+ };
+
+ BackTerminal.prototype.insertLines = function(params) {
+ var j, param, row;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ row = this.y + this.ybase;
+ j = this.rows - 1 - this.scrollBottom;
+ j = this.rows - 1 + this.ybase - j + 1;
+ while (param--) {
+ this.lines.splice(row, 0, this.blankLine(true));
+ this.lines.splice(j, 1);
+ }
+ this.updateRange(this.y);
+ return this.updateRange(this.scrollBottom);
+ };
+
+ BackTerminal.prototype.deleteLines = function(params) {
+ var j, param, row;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ row = this.y + this.ybase;
+ j = this.rows - 1 - this.scrollBottom;
+ j = this.rows - 1 + this.ybase - j;
+ while (param--) {
+ this.lines.splice(j + 1, 0, this.blankLine(true));
+ this.lines.splice(row, 1);
+ }
+ this.updateRange(this.y);
+ return this.updateRange(this.scrollBottom);
+ };
+
+ BackTerminal.prototype.deleteChars = function(params) {
+ var ch, param, row, _results;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ row = this.y + this.ybase;
+ ch = [this.eraseAttr(), " "];
+ _results = [];
+ while (param--) {
+ this.lines[row].splice(this.x, 1);
+ _results.push(this.lines[row].push(ch));
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.eraseChars = function(params) {
+ var ch, j, param, row, _results;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ row = this.y + this.ybase;
+ j = this.x;
+ ch = [this.eraseAttr(), " "];
+ _results = [];
+ while (param-- && j < this.cols) {
+ _results.push(this.lines[row][j++] = ch);
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.charPosAbsolute = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.x = param - 1;
+ if (this.x >= this.cols) {
+ return this.x = this.cols - 1;
+ }
+ };
+
+ BackTerminal.prototype.HPositionRelative = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.x += param;
+ if (this.x >= this.cols) {
+ return this.x = this.cols - 1;
+ }
+ };
+
+ BackTerminal.prototype.sendDeviceAttributes = function(params) {
+ if (params[0] > 0) {
+ return;
+ }
+ if (!this.prefix) {
+ if (this.isterm("xterm") || this.isterm("rxvt-unicode") || this.isterm("screen")) {
+ return this.send("\x1b[?1;2c");
+ } else {
+ if (this.isterm("linux")) {
+ return this.send("\x1b[?6c");
+ }
+ }
+ } else if (this.prefix === ">") {
+ if (this.isterm("xterm")) {
+ return this.send("\x1b[>0;276;0c");
+ } else if (this.isterm("rxvt-unicode")) {
+ return this.send("\x1b[>85;95;0c");
+ } else if (this.isterm("linux")) {
+ return this.send(params[0] + "c");
+ } else {
+ if (this.isterm("screen")) {
+ return this.send("\x1b[>83;40003;0c");
+ }
+ }
+ }
+ };
+
+ BackTerminal.prototype.linePosAbsolute = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.y = param - 1;
+ if (this.y >= this.rows) {
+ return this.y = this.rows - 1;
+ }
+ };
+
+ BackTerminal.prototype.VPositionRelative = function(params) {
+ var param;
+ param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this.y += param;
+ if (this.y >= this.rows) {
+ return this.y = this.rows - 1;
+ }
+ };
+
+ BackTerminal.prototype.HVPosition = function(params) {
+ if (params[0] < 1) {
+ params[0] = 1;
+ }
+ if (params[1] < 1) {
+ params[1] = 1;
+ }
+ this.y = params[0] - 1;
+ if (this.y >= this.rows) {
+ this.y = this.rows - 1;
+ }
+ this.x = params[1] - 1;
+ if (this.x >= this.cols) {
+ return this.x = this.cols - 1;
+ }
+ };
+
+ BackTerminal.prototype.setMode = function(params) {
+ var i, l, normal;
+ if (typeof params === "object") {
+ l = params.length;
+ i = 0;
+ while (i < l) {
+ this.setMode(params[i]);
+ i++;
+ }
+ return;
+ }
+ if (this.prefix === "?") {
+ switch (params) {
+ case 1:
+ return this.applicationCursor = true;
+ case 2:
+ this.setgCharset(0, BackTerminal.prototype.charsets.US);
+ this.setgCharset(1, BackTerminal.prototype.charsets.US);
+ this.setgCharset(2, BackTerminal.prototype.charsets.US);
+ return this.setgCharset(3, BackTerminal.prototype.charsets.US);
+ case 3:
+ this.savedCols = this.cols;
+ return this.resize(132, this.rows);
+ case 6:
+ return this.originMode = true;
+ case 7:
+ return this.wraparoundMode = true;
+ case 66:
+ return this.applicationKeypad = true;
+ case 9:
+ case 1000:
+ case 1002:
+ case 1003:
+ this.x10Mouse = params === 9;
+ this.vt200Mouse = params === 1000;
+ this.normalMouse = params > 1000;
+ this.mouseEvents = true;
+ return this.element.style.cursor = "default";
+ case 1004:
+ return this.sendFocus = true;
+ case 1005:
+ return this.utfMouse = true;
+ case 1006:
+ return this.sgrMouse = true;
+ case 1015:
+ return this.urxvtMouse = true;
+ case 25:
+ return this.cursorHidden = false;
+ case 1049:
+ case 47:
+ case 1047:
+ if (!this.normal) {
+ normal = {
+ lines: this.lines,
+ ybase: this.ybase,
+ ydisp: this.ydisp,
+ x: this.x,
+ y: this.y,
+ scrollTop: this.scrollTop,
+ scrollBottom: this.scrollBottom,
+ tabs: this.tabs
+ };
+ this.reset();
+ this.normal = normal;
+ return this.showCursor();
+ }
+ }
+ }
+ };
+
+ BackTerminal.prototype.resetMode = function(params) {
+ var i, l;
+ if (typeof params === "object") {
+ l = params.length;
+ i = 0;
+ while (i < l) {
+ this.resetMode(params[i]);
+ i++;
+ }
+ return;
+ }
+ if (this.prefix === "?") {
+ switch (params) {
+ case 1:
+ return this.applicationCursor = false;
+ case 3:
+ if (this.cols === 132 && this.savedCols) {
+ this.resize(this.savedCols, this.rows);
+ }
+ return delete this.savedCols;
+ case 6:
+ return this.originMode = false;
+ case 7:
+ return this.wraparoundMode = false;
+ case 66:
+ return this.applicationKeypad = false;
+ case 9:
+ case 1000:
+ case 1002:
+ case 1003:
+ this.x10Mouse = false;
+ this.vt200Mouse = false;
+ this.normalMouse = false;
+ this.mouseEvents = false;
+ return this.element.style.cursor = "";
+ case 1004:
+ return this.sendFocus = false;
+ case 1005:
+ return this.utfMouse = false;
+ case 1006:
+ return this.sgrMouse = false;
+ case 1015:
+ return this.urxvtMouse = false;
+ case 25:
+ return this.cursorHidden = true;
+ case 1049:
+ case 47:
+ case 1047:
+ if (this.normal) {
+ this.lines = this.normal.lines;
+ this.ybase = this.normal.ybase;
+ this.ydisp = this.normal.ydisp;
+ this.x = this.normal.x;
+ this.y = this.normal.y;
+ this.scrollTop = this.normal.scrollTop;
+ this.scrollBottom = this.normal.scrollBottom;
+ this.tabs = this.normal.tabs;
+ this.normal = null;
+ this.refresh(0, this.rows - 1);
+ return this.showCursor();
+ }
+ }
+ }
+ };
+
+ BackTerminal.prototype.setScrollRegion = function(params) {
+ if (this.prefix) {
+ return;
+ }
+ this.scrollTop = (params[0] || 1) - 1;
+ this.scrollBottom = (params[1] || this.rows) - 1;
+ this.x = 0;
+ return this.y = 0;
+ };
+
+ BackTerminal.prototype.saveCursor = function(params) {
+ this.savedX = this.x;
+ return this.savedY = this.y;
+ };
+
+ BackTerminal.prototype.restoreCursor = function(params) {
+ this.x = this.savedX || 0;
+ return this.y = this.savedY || 0;
+ };
+
+ BackTerminal.prototype.cursorForwardTab = function(params) {
+ var param, _results;
+ param = params[0] || 1;
+ _results = [];
+ while (param--) {
+ _results.push(this.x = this.nextStop());
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.scrollUp = function(params) {
+ var param;
+ param = params[0] || 1;
+ while (param--) {
+ this.lines.splice(this.ybase + this.scrollTop, 1);
+ this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine());
+ }
+ this.updateRange(this.scrollTop);
+ return this.updateRange(this.scrollBottom);
+ };
+
+ BackTerminal.prototype.scrollDown = function(params) {
+ var param;
+ param = params[0] || 1;
+ while (param--) {
+ this.lines.splice(this.ybase + this.scrollBottom, 1);
+ this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine());
+ }
+ this.updateRange(this.scrollTop);
+ return this.updateRange(this.scrollBottom);
+ };
+
+ BackTerminal.prototype.initMouseTracking = function(params) {};
+
+ BackTerminal.prototype.resetTitleModes = function(params) {};
+
+ BackTerminal.prototype.cursorBackwardTab = function(params) {
+ var param, _results;
+ param = params[0] || 1;
+ _results = [];
+ while (param--) {
+ _results.push(this.x = this.prevStop());
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.repeatPrecedingCharacter = function(params) {
+ var ch, line, param, _results;
+ param = params[0] || 1;
+ line = this.lines[this.ybase + this.y];
+ ch = line[this.x - 1] || [this.defAttr, " "];
+ _results = [];
+ while (param--) {
+ _results.push(line[this.x++] = ch);
+ }
+ return _results;
+ };
+
+ BackTerminal.prototype.tabClear = function(params) {
+ var param;
+ param = params[0];
+ if (param <= 0) {
+ return delete this.tabs[this.x];
+ } else {
+ if (param === 3) {
+ return this.tabs = {};
+ }
+ }
+ };
+
+ BackTerminal.prototype.mediaCopy = function(params) {};
+
+ BackTerminal.prototype.setResources = function(params) {};
+
+ BackTerminal.prototype.disableModifiers = function(params) {};
+
+ BackTerminal.prototype.setPointerMode = function(params) {};
+
+ BackTerminal.prototype.softReset = function(params) {
+ this.cursorHidden = false;
+ this.insertMode = false;
+ this.originMode = false;
+ this.wraparoundMode = false;
+ this.applicationKeypad = false;
+ this.applicationCursor = false;
+ this.scrollTop = 0;
+ this.scrollBottom = this.rows - 1;
+ this.curAttr = this.defAttr;
+ this.x = this.y = 0;
+ this.charset = null;
+ this.glevel = 0;
+ return this.charsets = [null];
+ };
+
+ BackTerminal.prototype.requestAnsiMode = function(params) {};
+
+ BackTerminal.prototype.requestPrivateMode = function(params) {};
+
+ BackTerminal.prototype.setConformanceLevel = function(params) {};
+
+ BackTerminal.prototype.loadLEDs = function(params) {};
+
+ BackTerminal.prototype.setCursorStyle = function(params) {};
+
+ BackTerminal.prototype.setCharProtectionAttr = function(params) {};
+
+ BackTerminal.prototype.restorePrivateValues = function(params) {};
+
+ BackTerminal.prototype.setAttrInRectangle = function(params) {
+ var attr, b, i, l, line, r, t;
+ t = params[0];
+ l = params[1];
+ b = params[2];
+ r = params[3];
+ attr = params[4];
+ while (t < b + 1) {
+ line = this.lines[this.ybase + t];
+ i = l;
+ while (i < r) {
+ line[i] = [attr, line[i][1]];
+ i++;
+ }
+ t++;
+ }
+ this.updateRange(params[0]);
+ return this.updateRange(params[2]);
+ };
+
+ BackTerminal.prototype.savePrivateValues = function(params) {};
+
+ BackTerminal.prototype.manipulateWindow = function(params) {};
+
+ BackTerminal.prototype.reverseAttrInRectangle = function(params) {};
+
+ BackTerminal.prototype.setTitleModeFeature = function(params) {};
+
+ BackTerminal.prototype.setWarningBellVolume = function(params) {};
+
+ BackTerminal.prototype.setMarginBellVolume = function(params) {};
+
+ BackTerminal.prototype.copyRectangle = function(params) {};
+
+ BackTerminal.prototype.enableFilterRectangle = function(params) {};
+
+ BackTerminal.prototype.requestParameters = function(params) {};
+
+ BackTerminal.prototype.selectChangeExtent = function(params) {};
+
+ BackTerminal.prototype.fillRectangle = function(params) {
+ var b, ch, i, l, line, r, t;
+ ch = params[0];
+ t = params[1];
+ l = params[2];
+ b = params[3];
+ r = params[4];
+ while (t < b + 1) {
+ line = this.lines[this.ybase + t];
+ i = l;
+ while (i < r) {
+ line[i] = [line[i][0], String.fromCharCode(ch)];
+ i++;
+ }
+ t++;
+ }
+ this.updateRange(params[1]);
+ return this.updateRange(params[3]);
+ };
+
+ BackTerminal.prototype.enableLocatorReporting = function(params) {
+ var val;
+ return val = params[0] > 0;
+ };
+
+ BackTerminal.prototype.eraseRectangle = function(params) {
+ var b, ch, i, l, line, r, t;
+ t = params[0];
+ l = params[1];
+ b = params[2];
+ r = params[3];
+ ch = [this.eraseAttr(), " "];
+ while (t < b + 1) {
+ line = this.lines[this.ybase + t];
+ i = l;
+ while (i < r) {
+ line[i] = ch;
+ i++;
+ }
+ t++;
+ }
+ this.updateRange(params[0]);
+ return this.updateRange(params[2]);
+ };
+
+ BackTerminal.prototype.setLocatorEvents = function(params) {};
+
+ BackTerminal.prototype.selectiveEraseRectangle = function(params) {};
+
+ BackTerminal.prototype.requestLocatorPosition = function(params) {};
+
+ BackTerminal.prototype.insertColumns = function() {
+ var ch, i, l, param;
+ param = params[0];
+ l = this.ybase + this.rows;
+ ch = [this.eraseAttr(), " "];
+ while (param--) {
+ i = this.ybase;
+ while (i < l) {
+ this.lines[i].splice(this.x + 1, 0, ch);
+ this.lines[i].pop();
+ i++;
+ }
+ }
+ return this.maxRange();
+ };
+
+ BackTerminal.prototype.deleteColumns = function() {
+ var ch, i, l, param;
+ param = params[0];
+ l = this.ybase + this.rows;
+ ch = [this.eraseAttr(), " "];
+ while (param--) {
+ i = this.ybase;
+ while (i < l) {
+ this.lines[i].splice(this.x, 1);
+ this.lines[i].push(ch);
+ i++;
+ }
+ }
+ return this.maxRange();
+ };
+
+ BackTerminal.prototype.charsets = {
+ SCLD: {
+ "`": "◆",
+ a: "▒",
+ b: "\t",
+ c: "\f",
+ d: "\r",
+ e: "\n",
+ f: "°",
+ g: "±",
+ h: "",
+ i: "\x0b",
+ j: "┘",
+ k: "┐",
+ l: "┌",
+ m: "└",
+ n: "┼",
+ o: "⎺",
+ p: "⎻",
+ q: "─",
+ r: "⎼",
+ s: "⎽",
+ t: "├",
+ u: "┤",
+ v: "┴",
+ w: "┬",
+ x: "│",
+ y: "≤",
+ z: "≥",
+ "{": "π",
+ "|": "≠",
+ "}": "£",
+ "~": "·"
+ },
+ UK: null,
+ US: null,
+ Dutch: null,
+ Finnish: null,
+ French: null,
+ FrenchCanadian: null,
+ German: null,
+ Italian: null,
+ NorwegianDanish: null,
+ Spanish: null,
+ Swedish: null,
+ Swiss: null,
+ ISOLatin: null
+ };
+
+ return BackTerminal;
+
+})();
diff --git a/dev.py b/dev.py
index c47f43a..188ecbf 100755
--- a/dev.py
+++ b/dev.py
@@ -8,7 +8,7 @@ import shlex
commands = [
'coffee -wcb -j butterfly/static/javascripts/main.js ' +
- 'butterfly/static/coffees/term.coffee ' +
+ # 'butterfly/static/coffees/term.coffee ' +
'butterfly/static/coffees/backsel.coffee ' +
'butterfly/static/coffees/virtual_input.coffee ' +
'butterfly/static/coffees/main.coffee ',