terminal 0.2 → 0.3.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile.lock +11 -5
- data/app/assets/stylesheets/terminal.css +256 -0
- data/bin/terminal +1 -0
- data/lib/terminal.rb +3 -4
- data/lib/terminal/engine.rb +4 -0
- data/lib/terminal/preview.rb +34 -3
- data/lib/terminal/renderer.rb +111 -162
- data/lib/terminal/screen.rb +282 -0
- data/lib/terminal/templates/preview.html.erb +46 -89
- data/lib/terminal/version.rb +1 -1
- data/script/benchmark +20 -0
- data/script/buildbox/benchmark.sh +8 -0
- data/script/buildbox/profile_methods.sh +8 -0
- data/script/buildbox/specs.sh +8 -0
- data/script/profile_methods +21 -0
- data/spec/fixtures/curl.sh.raw +1 -1
- data/spec/fixtures/curl.sh.rendered +2 -2
- data/spec/fixtures/homer.sh.rendered +18 -18
- data/spec/fixtures/pikachu.sh.raw +47 -0
- data/spec/fixtures/pikachu.sh.rendered +46 -0
- data/spec/terminal/renderer_spec.rb +129 -22
- data/spec/terminal/screen_spec.rb +77 -0
- data/terminal.gemspec +5 -3
- metadata +50 -10
- data/lib/terminal/color.rb +0 -7
- data/lib/terminal/node.rb +0 -15
- data/lib/terminal/reset.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4b4dd150fe6a6cfcad302893bdd602885b6dffd
|
4
|
+
data.tar.gz: f2caa188722eca09b14e8f404ff96b837b6b9652
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c658ae729a6ef14725497173d11eb8169aaaa0f04387e8a84a32c0461447a805b6d08cbb5b71a1f6fd78292d841ee4b30f0f54f853fbd36aa83f6d4fa8929634
|
7
|
+
data.tar.gz: 35e07c07b55db481be848513ee9838d529e8dfc12e7b5b22d44da79078994284e9f039c4704e788dc965bd0a47e5de5ba012192a9c2298506f0dc7934b562401
|
data/.rspec
ADDED
data/Gemfile.lock
CHANGED
@@ -1,33 +1,39 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
terminal (0.
|
4
|
+
terminal (0.2)
|
5
5
|
escape_utils (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
+
benchmark-ips (2.0.0)
|
10
11
|
diff-lcs (1.2.5)
|
11
12
|
escape_utils (1.0.1)
|
13
|
+
hirb (0.7.2)
|
14
|
+
method_profiler (2.0.1)
|
15
|
+
hirb (>= 0.6.0)
|
12
16
|
rake (10.3.2)
|
13
17
|
rspec (3.0.0)
|
14
18
|
rspec-core (~> 3.0.0)
|
15
19
|
rspec-expectations (~> 3.0.0)
|
16
20
|
rspec-mocks (~> 3.0.0)
|
17
|
-
rspec-core (3.0.
|
21
|
+
rspec-core (3.0.3)
|
18
22
|
rspec-support (~> 3.0.0)
|
19
|
-
rspec-expectations (3.0.
|
23
|
+
rspec-expectations (3.0.3)
|
20
24
|
diff-lcs (>= 1.2.0, < 2.0)
|
21
25
|
rspec-support (~> 3.0.0)
|
22
|
-
rspec-mocks (3.0.
|
26
|
+
rspec-mocks (3.0.3)
|
23
27
|
rspec-support (~> 3.0.0)
|
24
|
-
rspec-support (3.0.
|
28
|
+
rspec-support (3.0.3)
|
25
29
|
|
26
30
|
PLATFORMS
|
27
31
|
ruby
|
28
32
|
|
29
33
|
DEPENDENCIES
|
34
|
+
benchmark-ips
|
30
35
|
bundler (~> 1.6)
|
36
|
+
method_profiler
|
31
37
|
rake
|
32
38
|
rspec
|
33
39
|
terminal!
|
@@ -0,0 +1,256 @@
|
|
1
|
+
.term-fg30 { color: #666; } /* black (but we can't use black, so a diff color) */
|
2
|
+
.term-fg31 { color: #e10c02; } /* red */
|
3
|
+
.term-fg32 { color: #00bd02; } /* green */
|
4
|
+
.term-fg33 { color: #c6c502; } /* yellow */
|
5
|
+
.term-fg34 { color: #8db7e0; } /* blue */
|
6
|
+
.term-fg35 { color: #ceacde; } /* magenta */
|
7
|
+
.term-fg36 { color: #00cdd9; } /* cyan */
|
8
|
+
.term-fg90 { color: #838887; } /* grey */
|
9
|
+
|
10
|
+
/* high intense colors */
|
11
|
+
.term-fgi1 { color: #5ef765; }
|
12
|
+
|
13
|
+
/* background colors */
|
14
|
+
.term-bg42 { background: #99ff5f; }
|
15
|
+
|
16
|
+
/* xterm colors */
|
17
|
+
.term-fgx16 { color: #000000; }
|
18
|
+
.term-fgx17 { color: #00005f; }
|
19
|
+
.term-fgx18 { color: #000087; }
|
20
|
+
.term-fgx19 { color: #0000af; }
|
21
|
+
.term-fgx20 { color: #0000d7; }
|
22
|
+
.term-fgx21 { color: #0000ff; }
|
23
|
+
.term-fgx22 { color: #005f00; }
|
24
|
+
.term-fgx23 { color: #005f5f; }
|
25
|
+
.term-fgx24 { color: #005f87; }
|
26
|
+
.term-fgx25 { color: #005faf; }
|
27
|
+
.term-fgx26 { color: #005fd7; }
|
28
|
+
.term-fgx27 { color: #005fff; }
|
29
|
+
.term-fgx28 { color: #008700; }
|
30
|
+
.term-fgx29 { color: #00875f; }
|
31
|
+
.term-fgx30 { color: #008787; }
|
32
|
+
.term-fgx31 { color: #0087af; }
|
33
|
+
.term-fgx32 { color: #0087d7; }
|
34
|
+
.term-fgx33 { color: #0087ff; }
|
35
|
+
.term-fgx34 { color: #00af00; }
|
36
|
+
.term-fgx35 { color: #00af5f; }
|
37
|
+
.term-fgx36 { color: #00af87; }
|
38
|
+
.term-fgx37 { color: #00afaf; }
|
39
|
+
.term-fgx38 { color: #00afd7; }
|
40
|
+
.term-fgx39 { color: #00afff; }
|
41
|
+
.term-fgx40 { color: #00d700; }
|
42
|
+
.term-fgx41 { color: #00d75f; }
|
43
|
+
.term-fgx42 { color: #00d787; }
|
44
|
+
.term-fgx43 { color: #00d7af; }
|
45
|
+
.term-fgx44 { color: #00d7d7; }
|
46
|
+
.term-fgx45 { color: #00d7ff; }
|
47
|
+
.term-fgx46 { color: #00ff00; }
|
48
|
+
.term-fgx47 { color: #00ff5f; }
|
49
|
+
.term-fgx48 { color: #00ff87; }
|
50
|
+
.term-fgx49 { color: #00ffaf; }
|
51
|
+
.term-fgx50 { color: #00ffd7; }
|
52
|
+
.term-fgx51 { color: #00ffff; }
|
53
|
+
.term-fgx52 { color: #5f0000; }
|
54
|
+
.term-fgx53 { color: #5f005f; }
|
55
|
+
.term-fgx54 { color: #5f0087; }
|
56
|
+
.term-fgx55 { color: #5f00af; }
|
57
|
+
.term-fgx56 { color: #5f00d7; }
|
58
|
+
.term-fgx57 { color: #5f00ff; }
|
59
|
+
.term-fgx58 { color: #5f5f00; }
|
60
|
+
.term-fgx59 { color: #5f5f5f; }
|
61
|
+
.term-fgx60 { color: #5f5f87; }
|
62
|
+
.term-fgx61 { color: #5f5faf; }
|
63
|
+
.term-fgx62 { color: #5f5fd7; }
|
64
|
+
.term-fgx63 { color: #5f5fff; }
|
65
|
+
.term-fgx64 { color: #5f8700; }
|
66
|
+
.term-fgx65 { color: #5f875f; }
|
67
|
+
.term-fgx66 { color: #5f8787; }
|
68
|
+
.term-fgx67 { color: #5f87af; }
|
69
|
+
.term-fgx68 { color: #5f87d7; }
|
70
|
+
.term-fgx69 { color: #5f87ff; }
|
71
|
+
.term-fgx70 { color: #5faf00; }
|
72
|
+
.term-fgx71 { color: #5faf5f; }
|
73
|
+
.term-fgx72 { color: #5faf87; }
|
74
|
+
.term-fgx73 { color: #5fafaf; }
|
75
|
+
.term-fgx74 { color: #5fafd7; }
|
76
|
+
.term-fgx75 { color: #5fafff; }
|
77
|
+
.term-fgx76 { color: #5fd700; }
|
78
|
+
.term-fgx77 { color: #5fd75f; }
|
79
|
+
.term-fgx78 { color: #5fd787; }
|
80
|
+
.term-fgx79 { color: #5fd7af; }
|
81
|
+
.term-fgx80 { color: #5fd7d7; }
|
82
|
+
.term-fgx81 { color: #5fd7ff; }
|
83
|
+
.term-fgx82 { color: #5fff00; }
|
84
|
+
.term-fgx83 { color: #5fff5f; }
|
85
|
+
.term-fgx84 { color: #5fff87; }
|
86
|
+
.term-fgx85 { color: #5fffaf; }
|
87
|
+
.term-fgx86 { color: #5fffd7; }
|
88
|
+
.term-fgx87 { color: #5fffff; }
|
89
|
+
.term-fgx88 { color: #870000; }
|
90
|
+
.term-fgx89 { color: #87005f; }
|
91
|
+
.term-fgx90 { color: #870087; }
|
92
|
+
.term-fgx91 { color: #8700af; }
|
93
|
+
.term-fgx92 { color: #8700d7; }
|
94
|
+
.term-fgx93 { color: #8700ff; }
|
95
|
+
.term-fgx94 { color: #875f00; }
|
96
|
+
.term-fgx95 { color: #875f5f; }
|
97
|
+
.term-fgx96 { color: #875f87; }
|
98
|
+
.term-fgx97 { color: #875faf; }
|
99
|
+
.term-fgx98 { color: #875fd7; }
|
100
|
+
.term-fgx99 { color: #875fff; }
|
101
|
+
.term-fgx100 { color: #878700; }
|
102
|
+
.term-fgx101 { color: #87875f; }
|
103
|
+
.term-fgx102 { color: #878787; }
|
104
|
+
.term-fgx103 { color: #8787af; }
|
105
|
+
.term-fgx104 { color: #8787d7; }
|
106
|
+
.term-fgx105 { color: #8787ff; }
|
107
|
+
.term-fgx106 { color: #87af00; }
|
108
|
+
.term-fgx107 { color: #87af5f; }
|
109
|
+
.term-fgx108 { color: #87af87; }
|
110
|
+
.term-fgx109 { color: #87afaf; }
|
111
|
+
.term-fgx110 { color: #87afd7; }
|
112
|
+
.term-fgx111 { color: #87afff; }
|
113
|
+
.term-fgx112 { color: #87d700; }
|
114
|
+
.term-fgx113 { color: #87d75f; }
|
115
|
+
.term-fgx114 { color: #87d787; }
|
116
|
+
.term-fgx115 { color: #87d7af; }
|
117
|
+
.term-fgx116 { color: #87d7d7; }
|
118
|
+
.term-fgx117 { color: #87d7ff; }
|
119
|
+
.term-fgx118 { color: #87ff00; }
|
120
|
+
.term-fgx119 { color: #87ff5f; }
|
121
|
+
.term-fgx120 { color: #87ff87; }
|
122
|
+
.term-fgx121 { color: #87ffaf; }
|
123
|
+
.term-fgx122 { color: #87ffd7; }
|
124
|
+
.term-fgx123 { color: #87ffff; }
|
125
|
+
.term-fgx124 { color: #af0000; }
|
126
|
+
.term-fgx125 { color: #af005f; }
|
127
|
+
.term-fgx126 { color: #af0087; }
|
128
|
+
.term-fgx127 { color: #af00af; }
|
129
|
+
.term-fgx128 { color: #af00d7; }
|
130
|
+
.term-fgx129 { color: #af00ff; }
|
131
|
+
.term-fgx130 { color: #af5f00; }
|
132
|
+
.term-fgx131 { color: #af5f5f; }
|
133
|
+
.term-fgx132 { color: #af5f87; }
|
134
|
+
.term-fgx133 { color: #af5faf; }
|
135
|
+
.term-fgx134 { color: #af5fd7; }
|
136
|
+
.term-fgx135 { color: #af5fff; }
|
137
|
+
.term-fgx136 { color: #af8700; }
|
138
|
+
.term-fgx137 { color: #af875f; }
|
139
|
+
.term-fgx138 { color: #af8787; }
|
140
|
+
.term-fgx139 { color: #af87af; }
|
141
|
+
.term-fgx140 { color: #af87d7; }
|
142
|
+
.term-fgx141 { color: #af87ff; }
|
143
|
+
.term-fgx142 { color: #afaf00; }
|
144
|
+
.term-fgx143 { color: #afaf5f; }
|
145
|
+
.term-fgx144 { color: #afaf87; }
|
146
|
+
.term-fgx145 { color: #afafaf; }
|
147
|
+
.term-fgx146 { color: #afafd7; }
|
148
|
+
.term-fgx147 { color: #afafff; }
|
149
|
+
.term-fgx148 { color: #afd700; }
|
150
|
+
.term-fgx149 { color: #afd75f; }
|
151
|
+
.term-fgx150 { color: #afd787; }
|
152
|
+
.term-fgx151 { color: #afd7af; }
|
153
|
+
.term-fgx152 { color: #afd7d7; }
|
154
|
+
.term-fgx153 { color: #afd7ff; }
|
155
|
+
.term-fgx154 { color: #afff00; }
|
156
|
+
.term-fgx155 { color: #afff5f; }
|
157
|
+
.term-fgx156 { color: #afff87; }
|
158
|
+
.term-fgx157 { color: #afffaf; }
|
159
|
+
.term-fgx158 { color: #afffd7; }
|
160
|
+
.term-fgx159 { color: #afffff; }
|
161
|
+
.term-fgx160 { color: #d70000; }
|
162
|
+
.term-fgx161 { color: #d7005f; }
|
163
|
+
.term-fgx162 { color: #d70087; }
|
164
|
+
.term-fgx163 { color: #d700af; }
|
165
|
+
.term-fgx164 { color: #d700d7; }
|
166
|
+
.term-fgx165 { color: #d700ff; }
|
167
|
+
.term-fgx166 { color: #d75f00; }
|
168
|
+
.term-fgx167 { color: #d75f5f; }
|
169
|
+
.term-fgx168 { color: #d75f87; }
|
170
|
+
.term-fgx169 { color: #d75faf; }
|
171
|
+
.term-fgx170 { color: #d75fd7; }
|
172
|
+
.term-fgx171 { color: #d75fff; }
|
173
|
+
.term-fgx172 { color: #d78700; }
|
174
|
+
.term-fgx173 { color: #d7875f; }
|
175
|
+
.term-fgx174 { color: #d78787; }
|
176
|
+
.term-fgx175 { color: #d787af; }
|
177
|
+
.term-fgx176 { color: #d787d7; }
|
178
|
+
.term-fgx177 { color: #d787ff; }
|
179
|
+
.term-fgx178 { color: #d7af00; }
|
180
|
+
.term-fgx179 { color: #d7af5f; }
|
181
|
+
.term-fgx180 { color: #d7af87; }
|
182
|
+
.term-fgx181 { color: #d7afaf; }
|
183
|
+
.term-fgx182 { color: #d7afd7; }
|
184
|
+
.term-fgx183 { color: #d7afff; }
|
185
|
+
.term-fgx184 { color: #d7d700; }
|
186
|
+
.term-fgx185 { color: #d7d75f; }
|
187
|
+
.term-fgx186 { color: #d7d787; }
|
188
|
+
.term-fgx187 { color: #d7d7af; }
|
189
|
+
.term-fgx188 { color: #d7d7d7; }
|
190
|
+
.term-fgx189 { color: #d7d7ff; }
|
191
|
+
.term-fgx190 { color: #d7ff00; }
|
192
|
+
.term-fgx191 { color: #d7ff5f; }
|
193
|
+
.term-fgx192 { color: #d7ff87; }
|
194
|
+
.term-fgx193 { color: #d7ffaf; }
|
195
|
+
.term-fgx194 { color: #d7ffd7; }
|
196
|
+
.term-fgx195 { color: #d7ffff; }
|
197
|
+
.term-fgx196 { color: #ff0000; }
|
198
|
+
.term-fgx197 { color: #ff005f; }
|
199
|
+
.term-fgx198 { color: #ff0087; }
|
200
|
+
.term-fgx199 { color: #ff00af; }
|
201
|
+
.term-fgx200 { color: #ff00d7; }
|
202
|
+
.term-fgx201 { color: #ff00ff; }
|
203
|
+
.term-fgx202 { color: #ff5f00; }
|
204
|
+
.term-fgx203 { color: #ff5f5f; }
|
205
|
+
.term-fgx204 { color: #ff5f87; }
|
206
|
+
.term-fgx205 { color: #ff5faf; }
|
207
|
+
.term-fgx206 { color: #ff5fd7; }
|
208
|
+
.term-fgx207 { color: #ff5fff; }
|
209
|
+
.term-fgx208 { color: #ff8700; }
|
210
|
+
.term-fgx209 { color: #ff875f; }
|
211
|
+
.term-fgx210 { color: #ff8787; }
|
212
|
+
.term-fgx211 { color: #ff87af; }
|
213
|
+
.term-fgx212 { color: #ff87d7; }
|
214
|
+
.term-fgx213 { color: #ff87ff; }
|
215
|
+
.term-fgx214 { color: #ffaf00; }
|
216
|
+
.term-fgx215 { color: #ffaf5f; }
|
217
|
+
.term-fgx216 { color: #ffaf87; }
|
218
|
+
.term-fgx217 { color: #ffafaf; }
|
219
|
+
.term-fgx218 { color: #ffafd7; }
|
220
|
+
.term-fgx219 { color: #ffafff; }
|
221
|
+
.term-fgx220 { color: #ffd700; }
|
222
|
+
.term-fgx221 { color: #ffd75f; }
|
223
|
+
.term-fgx222 { color: #ffd787; }
|
224
|
+
.term-fgx223 { color: #ffd7af; }
|
225
|
+
.term-fgx224 { color: #ffd7d7; }
|
226
|
+
.term-fgx225 { color: #ffd7ff; }
|
227
|
+
.term-fgx226 { color: #ffff00; }
|
228
|
+
.term-fgx227 { color: #ffff5f; }
|
229
|
+
.term-fgx228 { color: #ffff87; }
|
230
|
+
.term-fgx229 { color: #ffffaf; }
|
231
|
+
.term-fgx230 { color: #ffffd7; }
|
232
|
+
.term-fgx231 { color: #ffffff; }
|
233
|
+
.term-fgx232 { color: #080808; }
|
234
|
+
.term-fgx233 { color: #121212; }
|
235
|
+
.term-fgx234 { color: #1c1c1c; }
|
236
|
+
.term-fgx235 { color: #262626; }
|
237
|
+
.term-fgx236 { color: #303030; }
|
238
|
+
.term-fgx237 { color: #3a3a3a; }
|
239
|
+
.term-fgx238 { color: #444444; }
|
240
|
+
.term-fgx239 { color: #4e4e4e; }
|
241
|
+
.term-fgx240 { color: #585858; }
|
242
|
+
.term-fgx241 { color: #626262; }
|
243
|
+
.term-fgx242 { color: #6c6c6c; }
|
244
|
+
.term-fgx243 { color: #767676; }
|
245
|
+
.term-fgx244 { color: #808080; }
|
246
|
+
.term-fgx245 { color: #8a8a8a; }
|
247
|
+
.term-fgx246 { color: #949494; }
|
248
|
+
.term-fgx247 { color: #9e9e9e; }
|
249
|
+
.term-fgx248 { color: #a8a8a8; }
|
250
|
+
.term-fgx249 { color: #b2b2b2; }
|
251
|
+
.term-fgx250 { color: #bcbcbc; }
|
252
|
+
.term-fgx251 { color: #c6c6c6; }
|
253
|
+
.term-fgx252 { color: #d0d0d0; }
|
254
|
+
.term-fgx253 { color: #dadada; }
|
255
|
+
.term-fgx254 { color: #e4e4e4; }
|
256
|
+
.term-fgx255 { color: #eeeeee; }
|
data/bin/terminal
CHANGED
data/lib/terminal.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
require "terminal/version"
|
2
|
-
require "terminal/
|
3
|
-
require "terminal/color"
|
4
|
-
require "terminal/reset"
|
2
|
+
require "terminal/screen"
|
5
3
|
require "terminal/renderer"
|
6
4
|
require "terminal/cli"
|
7
5
|
require "terminal/preview"
|
6
|
+
require "terminal/engine" if defined?(Rails)
|
8
7
|
|
9
8
|
module Terminal
|
10
9
|
def self.render(output)
|
11
|
-
Terminal::Renderer.new
|
10
|
+
Terminal::Renderer.new(output).render
|
12
11
|
end
|
13
12
|
end
|
data/lib/terminal/preview.rb
CHANGED
@@ -2,7 +2,30 @@ require 'erb'
|
|
2
2
|
|
3
3
|
module Terminal
|
4
4
|
class Preview
|
5
|
-
class Binding
|
5
|
+
class Binding
|
6
|
+
def initialize(asset_path, raw, rendered)
|
7
|
+
@asset_path = asset_path
|
8
|
+
@raw = raw
|
9
|
+
@rendered = rendered
|
10
|
+
end
|
11
|
+
|
12
|
+
def asset_path(path)
|
13
|
+
File.join(@asset_path, path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def raw
|
17
|
+
# Call out special escape characters to make debugging easier
|
18
|
+
@raw.
|
19
|
+
gsub("\n", "\\n\n").
|
20
|
+
gsub("\r", "\\r").
|
21
|
+
gsub("\b", "\\b").
|
22
|
+
gsub(/\e/, "\\\\e")
|
23
|
+
end
|
24
|
+
|
25
|
+
def rendered
|
26
|
+
@rendered
|
27
|
+
end
|
28
|
+
|
6
29
|
def get_binding
|
7
30
|
binding
|
8
31
|
end
|
@@ -16,15 +39,23 @@ module Terminal
|
|
16
39
|
def render
|
17
40
|
template = File.read(template_path)
|
18
41
|
renderer = ERB.new(template)
|
19
|
-
binding = Binding.new(@raw, @rendered)
|
42
|
+
binding = Binding.new(assets_path, @raw, @rendered)
|
20
43
|
|
21
44
|
renderer.result(binding.get_binding)
|
22
45
|
end
|
23
46
|
|
24
47
|
private
|
25
48
|
|
49
|
+
def root_path
|
50
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
51
|
+
end
|
52
|
+
|
53
|
+
def assets_path
|
54
|
+
File.join(root_path, 'app/assets')
|
55
|
+
end
|
56
|
+
|
26
57
|
def template_path
|
27
|
-
File.join(
|
58
|
+
File.join(root_path, 'lib/terminal/templates/preview.html.erb')
|
28
59
|
end
|
29
60
|
end
|
30
61
|
end
|
data/lib/terminal/renderer.rb
CHANGED
@@ -2,52 +2,30 @@ require 'escape_utils'
|
|
2
2
|
|
3
3
|
module Terminal
|
4
4
|
class Renderer
|
5
|
-
|
6
|
-
|
7
|
-
# [ '\n', '\r', 'a', 'b', '\e123m' ]
|
8
|
-
SPLIT_BY_CHARACTERS = [
|
9
|
-
# \n moves the cursor to a new line
|
10
|
-
# \r moves the cursor to the begining of the line
|
11
|
-
# \b moves the cursor back one
|
12
|
-
'[\n\r\b]',
|
13
|
-
|
14
|
-
# [K Erases from the current cursor position to the end of the current line.
|
15
|
-
'\e\[0?K',
|
16
|
-
|
17
|
-
# Clears tab at the current position
|
18
|
-
'\e\[0?[Gg]',
|
19
|
-
|
20
|
-
# [1K Erases from the current cursor position to the start of the current line.
|
21
|
-
# [2K Erases the entire current line.
|
22
|
-
'\e\[[1-2]K',
|
23
|
-
|
24
|
-
# \e[?D move the cursor back ? many characters
|
25
|
-
'\e\[[\d;]+D',
|
26
|
-
|
27
|
-
# \e[0m reset color information
|
28
|
-
# \e[?m use the ? color going forward
|
29
|
-
'\e\[[\d;]+m',
|
5
|
+
ESCAPE_CONTROL_CHARACTERS = "qQmKGgKAaBbCcDd"
|
6
|
+
MEGABYTES = 1024 * 1024
|
30
7
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
'.'
|
36
|
-
]
|
8
|
+
def initialize(output)
|
9
|
+
@output = output
|
10
|
+
@screen = Screen.new
|
11
|
+
end
|
37
12
|
|
38
|
-
|
13
|
+
def render
|
14
|
+
return "" if @output.nil? || @output.strip.length == 0
|
39
15
|
|
40
|
-
|
41
|
-
|
16
|
+
# First duplicate the string, because we're going to be editing and chopping it
|
17
|
+
# up directly.
|
18
|
+
output = @output.dup
|
42
19
|
|
43
|
-
# Limit the entire size of the output to 4 meg
|
44
|
-
max_total_size = 4 *
|
20
|
+
# Limit the entire size of the output to 4 meg
|
21
|
+
max_total_size = 4 * MEGABYTES
|
45
22
|
if output.bytesize > max_total_size
|
46
23
|
output = output.byteslice(0, max_total_size)
|
47
24
|
output << "\n\nWarning: Terminal has chopped off the rest of the build as it's over the allowed 4 megabyte limit for logs."
|
48
25
|
end
|
49
26
|
|
50
27
|
# Limit each line to (x) chars
|
28
|
+
# TODO: Move this to the screen
|
51
29
|
max_line_length = 50_000
|
52
30
|
output = output.split("\n").map do |line|
|
53
31
|
if line.length > max_line_length
|
@@ -58,154 +36,125 @@ module Terminal
|
|
58
36
|
end
|
59
37
|
end.join("\n")
|
60
38
|
|
61
|
-
#
|
62
|
-
|
39
|
+
# Force encoding on the output first
|
40
|
+
force_encoding!(output)
|
63
41
|
|
64
|
-
#
|
65
|
-
output
|
66
|
-
end
|
42
|
+
# Now do the render the output to the screen
|
43
|
+
render_to_screen(output)
|
67
44
|
|
68
|
-
|
45
|
+
# Convert the screen to a string
|
46
|
+
output = convert_screen_to_string
|
69
47
|
|
70
|
-
|
71
|
-
|
72
|
-
parts = string.scan(SPLIT_BY_CHARACTERS_REGEX)
|
73
|
-
|
74
|
-
lines = []
|
75
|
-
|
76
|
-
index = 0
|
77
|
-
length = string.length
|
78
|
-
|
79
|
-
line = []
|
80
|
-
cursor = 0
|
81
|
-
|
82
|
-
# Every time a color is found, we increment this
|
83
|
-
# counter, every time it resets, we decrement.
|
84
|
-
# We do this so we close all the open spans at the
|
85
|
-
# end of the output.
|
86
|
-
colors_opened = 0
|
87
|
-
|
88
|
-
parts.each do |char|
|
89
|
-
case char
|
90
|
-
when "\n"
|
91
|
-
# Starts writing from a new line
|
92
|
-
lines << line
|
93
|
-
line = []
|
94
|
-
cursor = 0
|
95
|
-
when "\r"
|
96
|
-
# Returns the writing cursor back to the begining of the line
|
97
|
-
cursor = 0
|
98
|
-
when "\e[G", "\e[0G", "\e[g"
|
99
|
-
# TODO: I have no idea how these characters are supposed to work,
|
100
|
-
# but this seems to be produce nicer results that what currently
|
101
|
-
# gets rendered.
|
102
|
-
cursor = 0
|
103
|
-
when "\e[K", "\e[0K"
|
104
|
-
# erases everything after the cursor
|
105
|
-
line = line.fill(" ", cursor..line.length)
|
106
|
-
when "\e[1K"
|
107
|
-
# erases everything before the cursor
|
108
|
-
line = line.fill(" ", 0..cursor)
|
109
|
-
when "\e[2K"
|
110
|
-
# erase entire line
|
111
|
-
line = Array.new(line.length, " ")
|
112
|
-
when "\b"
|
113
|
-
pointer = cursor-1
|
114
|
-
|
115
|
-
# Seek backwards until something that isn't a color is reached. When we
|
116
|
-
# reach it (probably a string) remove the last character of it.
|
117
|
-
# Colors aren't affected by \b
|
118
|
-
while pointer >= 0
|
119
|
-
char_at_pointer = line[pointer]
|
120
|
-
|
121
|
-
unless char_at_pointer.kind_of?(Terminal::Node)
|
122
|
-
line[pointer] = char_at_pointer[0..-2]
|
123
|
-
break
|
124
|
-
end
|
125
|
-
|
126
|
-
pointer -= 1
|
127
|
-
end
|
128
|
-
when /\e\[(\d+)D/
|
129
|
-
backwards = $1.to_i
|
48
|
+
# Escape any HTML
|
49
|
+
output = escape_html(output)
|
130
50
|
|
131
|
-
|
132
|
-
|
51
|
+
# Now convert the colors to HTML
|
52
|
+
convert_to_html(output)
|
53
|
+
end
|
133
54
|
|
134
|
-
|
135
|
-
when /\A\e\[(.*)m\z/
|
136
|
-
color_code = $1.to_s
|
55
|
+
private
|
137
56
|
|
138
|
-
|
139
|
-
|
140
|
-
line[cursor] = Terminal::Reset.new(colors_opened)
|
57
|
+
def force_encoding!(string)
|
58
|
+
string.force_encoding('UTF-8')
|
141
59
|
|
142
|
-
|
143
|
-
|
144
|
-
|
60
|
+
if string.valid_encoding?
|
61
|
+
string
|
62
|
+
else
|
63
|
+
string.force_encoding('ASCII-8BIT').encode!('UTF-8', invalid: :replace, undef: :replace)
|
64
|
+
end
|
65
|
+
end
|
145
66
|
|
146
|
-
|
67
|
+
def render_to_screen(string)
|
68
|
+
# The when cases are ordered by most likely, the lest checks it has to go
|
69
|
+
# through before matching, the faster the render will be. Colors are
|
70
|
+
# usually most likey, so that's first.
|
71
|
+
split_by_escape_character(string).each do |char|
|
72
|
+
# Hackers way of not having to run a regex over every
|
73
|
+
# character.
|
74
|
+
if char.length == 1
|
75
|
+
case char
|
76
|
+
when "\n"
|
77
|
+
@screen.x = 0
|
78
|
+
@screen.y += 1
|
79
|
+
when "\r"
|
80
|
+
@screen.x = 0
|
81
|
+
when "\r"
|
82
|
+
@screen.x = 0
|
83
|
+
when "\b"
|
84
|
+
@screen.x -= 1
|
85
|
+
else
|
86
|
+
@screen << char
|
147
87
|
end
|
148
|
-
|
149
|
-
index += char.length
|
150
|
-
cursor += 1
|
151
88
|
else
|
152
|
-
|
153
|
-
cursor += 1
|
89
|
+
handle_escape_code(char)
|
154
90
|
end
|
155
|
-
|
156
|
-
# The cursor can't go back furthur than 0, so if you \b at the begining
|
157
|
-
# of a line, nothing happens.
|
158
|
-
cursor = 0 if cursor < 0
|
159
|
-
|
160
|
-
index += 1
|
161
|
-
end
|
162
|
-
|
163
|
-
# Be sure to reset any unclosed colors on the last line
|
164
|
-
if colors_opened > 0
|
165
|
-
line << Terminal::Reset.new(colors_opened)
|
166
91
|
end
|
92
|
+
end
|
167
93
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
# Join all the strings back together again
|
173
|
-
lines = lines.map do |parts|
|
174
|
-
completed_line = parts.map(&:to_s).join("")
|
175
|
-
end.join("\n")
|
176
|
-
|
177
|
-
# Now escape all the things
|
178
|
-
lines = EscapeUtils.escape_html(lines)
|
94
|
+
def escape_html(string)
|
95
|
+
EscapeUtils.escape_html(string)
|
96
|
+
end
|
179
97
|
|
180
|
-
|
98
|
+
def convert_screen_to_string
|
99
|
+
@screen.to_s
|
100
|
+
end
|
181
101
|
|
182
|
-
|
183
|
-
|
184
|
-
|
102
|
+
def handle_escape_code(sequence)
|
103
|
+
# Escapes have the following: \e [ (instruction) (code)
|
104
|
+
parts = sequence.match(/\e\[(.*)([#{ESCAPE_CONTROL_CHARACTERS}])/)
|
105
|
+
|
106
|
+
instruction = parts[1].to_s
|
107
|
+
code = parts[2].to_s
|
108
|
+
|
109
|
+
case code
|
110
|
+
when ""
|
111
|
+
# no-op - an empty \e
|
112
|
+
when "m"
|
113
|
+
@screen.color(instruction)
|
114
|
+
when "G", "g"
|
115
|
+
@screen.x = 0
|
116
|
+
when "K", "k"
|
117
|
+
case instruction
|
118
|
+
when nil, "0"
|
119
|
+
# clear everything after the current x co-ordinate
|
120
|
+
@screen.clear(@screen.y, @screen.x, Screen::END_OF_LINE)
|
121
|
+
when "1"
|
122
|
+
# clear everything before the current x co-ordinate
|
123
|
+
@screen.clear(@screen.y, Screen::START_OF_LINE, @screen.x)
|
124
|
+
when "2"
|
125
|
+
@screen.clear(@screen.y, Screen::START_OF_LINE, Screen::END_OF_LINE)
|
126
|
+
end
|
127
|
+
when "A"
|
128
|
+
@screen.up(instruction)
|
129
|
+
when "B"
|
130
|
+
@screen.down(instruction)
|
131
|
+
when "C"
|
132
|
+
@screen.foward(instruction)
|
133
|
+
when "D"
|
134
|
+
@screen.backward(instruction)
|
135
|
+
end
|
136
|
+
end
|
185
137
|
|
186
|
-
|
187
|
-
|
138
|
+
def convert_to_html(string)
|
139
|
+
string = string.gsub(/\e\[([^;m]+);([^;m]+)?;m/) do |match|
|
140
|
+
if $2
|
141
|
+
%{<span class='term-#{$1} term-#{$2}'>}
|
188
142
|
else
|
189
|
-
|
190
|
-
|
191
|
-
"<span class='#{classes.join(" ")}'>"
|
143
|
+
%{<span class='term-#{$1}'>}
|
192
144
|
end
|
193
145
|
end
|
194
146
|
|
195
|
-
|
147
|
+
string = string.gsub("\e[0m", "</span>")
|
148
|
+
|
149
|
+
# Replace empty lines with a non breaking space.
|
150
|
+
string.gsub(/$^/, " ")
|
196
151
|
end
|
197
152
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
string.
|
204
|
-
force_encoding('ASCII-8BIT').
|
205
|
-
encode!('UTF-8',
|
206
|
-
invalid: :replace,
|
207
|
-
undef: :replace)
|
208
|
-
end
|
153
|
+
# Scan the string to create an array of interesting things, for example
|
154
|
+
# it would look like this:
|
155
|
+
# [ '\n', '\r', 'a', 'b', '\e123m' ]
|
156
|
+
def split_by_escape_character(string)
|
157
|
+
string.scan(/[\n\r\b]|\e\[[\d;]*[#{ESCAPE_CONTROL_CHARACTERS}]|./)
|
209
158
|
end
|
210
159
|
end
|
211
160
|
end
|