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