JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
ui: html-encode white text too
[watch-my-terminal.git] / client.coffee
1 $ ->
2         timeout = (ms, f) -> setTimeout(f, ms)
3         term = null
4         palette = [
5                 # normal colours
6                 '2e3436',
7                 'cc0000',
8                 '4e9a06',
9                 'c4a000',
10                 '3465a4',
11                 '75507b',
12                 '06989a',
13                 'd3d7cf',
14
15                 # brighter versions (for bold, and 16-color sequences)
16                 '555753',
17                 'ef2929',
18                 '8ae234',
19                 'fce94f',
20                 '729fcf',
21                 'ad7fa8',
22                 '34e2e2',
23                 'eeeeec',
24
25                 # 256 colors
26                 '000000', '00005f', '000087', '0000af', '0000d7', '0000ff', '005f00', '005f5f',
27                 '005f87', '005faf', '005fd7', '005fff', '008700', '00875f', '008787', '0087af',
28                 '0087d7', '0087ff', '00af00', '00af5f', '00af87', '00afaf', '00afd7', '00afff',
29                 '00d700', '00d75f', '00d787', '00d7af', '00d7d7', '00d7ff', '00ff00', '00ff5f',
30                 '00ff87', '00ffaf', '00ffd7', '00ffff', '5f0000', '5f005f', '5f0087', '5f00af',
31                 '5f00d7', '5f00ff', '5f5f00', '5f5f5f', '5f5f87', '5f5faf', '5f5fd7', '5f5fff',
32                 '5f8700', '5f875f', '5f8787', '5f87af', '5f87d7', '5f87ff', '5faf00', '5faf5f',
33                 '5faf87', '5fafaf', '5fafd7', '5fafff', '5fd700', '5fd75f', '5fd787', '5fd7af',
34                 '5fd7d7', '5fd7ff', '5fff00', '5fff5f', '5fff87', '5fffaf', '5fffd7', '5fffff',
35                 '870000', '87005f', '870087', '8700af', '8700d7', '8700ff', '875f00', '875f5f',
36                 '875f87', '875faf', '875fd7', '875fff', '878700', '87875f', '878787', '8787af',
37                 '8787d7', '8787ff', '87af00', '87af5f', '87af87', '87afaf', '87afd7', '87afff',
38                 '87d700', '87d75f', '87d787', '87d7af', '87d7d7', '87d7ff', '87ff00', '87ff5f',
39                 '87ff87', '87ffaf', '87ffd7', '87ffff', 'af0000', 'af005f', 'af0087', 'af00af',
40                 'af00d7', 'af00ff', 'af5f00', 'af5f5f', 'af5f87', 'af5faf', 'af5fd7', 'af5fff',
41                 'af8700', 'af875f', 'af8787', 'af87af', 'af87d7', 'af87ff', 'afaf00', 'afaf5f',
42                 'afaf87', 'afafaf', 'afafd7', 'afafff', 'afd700', 'afd75f', 'afd787', 'afd7af',
43                 'afd7d7', 'afd7ff', 'afff00', 'afff5f', 'afff87', 'afffaf', 'afffd7', 'afffff',
44                 'd70000', 'd7005f', 'd70087', 'd700af', 'd700d7', 'd700ff', 'd75f00', 'd75f5f',
45                 'd75f87', 'd75faf', 'd75fd7', 'd75fff', 'd78700', 'd7875f', 'd78787', 'd787af',
46                 'd787d7', 'd787ff', 'd7af00', 'd7af5f', 'd7af87', 'd7afaf', 'd7afd7', 'd7afff',
47                 'd7d700', 'd7d75f', 'd7d787', 'd7d7af', 'd7d7d7', 'd7d7ff', 'd7ff00', 'd7ff5f',
48                 'd7ff87', 'd7ffaf', 'd7ffd7', 'd7ffff', 'ff0000', 'ff005f', 'ff0087', 'ff00af',
49                 'ff00d7', 'ff00ff', 'ff5f00', 'ff5f5f', 'ff5f87', 'ff5faf', 'ff5fd7', 'ff5fff',
50                 'ff8700', 'ff875f', 'ff8787', 'ff87af', 'ff87d7', 'ff87ff', 'ffaf00', 'ffaf5f',
51                 'ffaf87', 'ffafaf', 'ffafd7', 'ffafff', 'ffd700', 'ffd75f', 'ffd787', 'ffd7af',
52                 'ffd7d7', 'ffd7ff', 'ffff00', 'ffff5f', 'ffff87', 'ffffaf', 'ffffd7', 'ffffff',
53                 '080808', '121212', '1c1c1c', '262626', '303030', '3a3a3a', '444444', '4e4e4e',
54                 '585858', '626262', '6c6c6c', '767676', '808080', '8a8a8a', '949494', '9e9e9e',
55                 'a8a8a8', 'b2b2b2', 'bcbcbc', 'c6c6c6', 'd0d0d0', 'dadada', 'e4e4e4', 'eeeeee'
56         ]
57
58         $body = $('body')
59         $body.css backgroundColor: "##{palette[0]}", color: "##{palette[7]}"
60
61         socket = io.connect('/')
62
63         color_to_css = (i) ->
64                 # handle inverse bit
65                 if i & 0x080000
66                         index = ((i >> 8) & 0xff)
67                 else
68                         index = (i & 0xff)
69
70                 # lighten the basic 8 colors when they're bold
71                 if ((i & 0x10000) and index < 8)
72                         index += 8
73                 return 'color: #' + palette[index] + '; '
74
75         bg_color_to_css = (i) ->
76                 # xor the inverse bit, to get color_to_css to use the bg color
77                 return 'background-' + color_to_css(i ^ 0x080000)
78
79         stylize = (txt, style) ->
80                 return '' if txt.length is 0
81                 return $('<span>').text txt if style is 0x000007
82                 css = ''
83                 css += 'font-weight: bold; ' if style & 0x010000
84                 css += 'text-decoration: underline; ' if style & 0x020000
85                 css += 'font-style: italic; ' if style & 0x200000 # italic
86                 css += 'opacity: 0; ' if style & 0x100000 # invisible
87                 css += color_to_css(style) if ((style & 0x0800ff) isnt 0x07)
88                 css += bg_color_to_css(style) if (style & 0x08ff00)
89                 return $('<span style="'+css+'"></span>').text(txt)
90
91         redraw_wait = false
92         redraw_again = false
93         redraw_now = ->
94                 $body.children().remove()
95                 # cursor can be just off the right side, but we draw it on the last column in that case
96                 if term.x >= term.width
97                         cursor_x = term.width - 1
98                 else
99                         cursor_x = term.x
100                 # invert the cursor TODO: make it blink
101                 if term.cursor_visible
102                         term.attributes[term.y][cursor_x] ^= 0x080000
103                 for i in [0...term.text.length]
104                         div = $('<div>')
105                         txt = ''
106                         a = 0x000007
107                         for j in [0...term.text[i].length]
108                                 if (term.attributes[i][j] isnt a)
109                                         if (txt.length)
110                                                 div.append(stylize(txt, a))
111                                                 txt = ''
112                                         a = term.attributes[i][j]
113                                 txt += term.text[i][j]
114                         if txt.length
115                                 div.append(stylize(txt, a))
116                         $body.append(div)
117                 if term.cursor_visible
118                         term.attributes[term.y][cursor_x] ^= 0x080000
119
120         # limit to 50fps
121         redraw = ->
122                 if (redraw_wait)
123                         redraw_again = true
124                 else
125                         redraw_now()
126                         redraw_wait = true
127                         redraw_again = false
128                         timeout 20, ->
129                                 redraw_wait = false
130                                 if (redraw_again)
131                                         redraw_again = false
132                                         redraw()
133
134         update = (data) ->
135                 if (term)
136                         term.update(data)
137                         redraw()
138
139         socket.on 'data', (data) ->
140                 update(data)
141
142         socket.on 'init', (v) ->
143                 term = terminal.new(v.width, v.height)
144                 update v.text