terminal 0.2 → 0.3.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|