rack-webconsole-pry 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-webconsole-pry (0.1.7)
4
+ rack-webconsole-pry (0.1.8)
5
5
  json
6
6
  multi_json (>= 1.0.3)
7
7
  pry
@@ -2,6 +2,6 @@
2
2
  module Rack
3
3
  class Webconsole
4
4
  # rack-webconsole version number.
5
- VERSION = "0.1.7"
5
+ VERSION = "0.1.8"
6
6
  end
7
7
  end
data/public/webconsole.js CHANGED
@@ -1,5 +1,193 @@
1
1
  (function($) {
2
2
 
3
+ /* AnsiParse */
4
+ ansiparse = function (str) {
5
+ //
6
+ // I'm terrible at writing parsers.
7
+ //
8
+ var matchingControl = null,
9
+ matchingData = null,
10
+ matchingText = '',
11
+ ansiState = [],
12
+ result = [],
13
+ state = {},
14
+ eraseChar;
15
+
16
+ //
17
+ // General workflow for this thing is:
18
+ // \033\[33mText
19
+ // | | |
20
+ // | | matchingText
21
+ // | matchingData
22
+ // matchingControl
23
+ //
24
+ // In further steps we hope it's all going to be fine. It usually is.
25
+ //
26
+
27
+ //
28
+ // Erases a char from the output
29
+ //
30
+ eraseChar = function () {
31
+ var index, text;
32
+ if (matchingText.length) {
33
+ matchingText = matchingText.substr(0, matchingText.length - 1);
34
+ }
35
+ else if (result.length) {
36
+ index = result.length - 1;
37
+ text = result[index].text;
38
+ if (text.length === 1) {
39
+ //
40
+ // A result bit was fully deleted, pop it out to simplify the final output
41
+ //
42
+ result.pop();
43
+ }
44
+ else {
45
+ result[index].text = text.substr(0, text.length - 1);
46
+ }
47
+ }
48
+ };
49
+
50
+ for (var i = 0; i < str.length; i++) {
51
+ if (matchingControl != null) {
52
+ if (matchingControl == '\u001B' && str[i] == '\[') {
53
+ //
54
+ // We've matched full control code. Lets start matching formating data.
55
+ //
56
+
57
+ //
58
+ // "emit" matched text with correct state
59
+ //
60
+ if (matchingText) {
61
+ state.text = matchingText;
62
+ result.push(state);
63
+ state = {};
64
+ matchingText = "";
65
+ }
66
+
67
+ matchingControl = null;
68
+ matchingData = '';
69
+ }
70
+ else {
71
+ //
72
+ // We failed to match anything - most likely a bad control code. We
73
+ // go back to matching regular strings.
74
+ //
75
+ matchingText += matchingControl + str[i];
76
+ matchingControl = null;
77
+ }
78
+ continue;
79
+ }
80
+ else if (matchingData != null) {
81
+ if (str[i] == ';') {
82
+ //
83
+ // `;` separates many formatting codes, for example: `\033[33;43m`
84
+ // means that both `33` and `43` should be applied.
85
+ //
86
+ // TODO: this can be simplified by modifying state here.
87
+ //
88
+ ansiState.push(matchingData);
89
+ matchingData = '';
90
+ }
91
+ else if (str[i] == 'm') {
92
+ //
93
+ // `m` finished whole formatting code. We can proceed to matching
94
+ // formatted text.
95
+ //
96
+ ansiState.push(matchingData);
97
+ matchingData = null;
98
+ matchingText = '';
99
+
100
+ //
101
+ // Convert matched formatting data into user-friendly state object.
102
+ //
103
+ // TODO: DRY.
104
+ //
105
+ ansiState.forEach(function (ansiCode) {
106
+ if (ansiparse.foregroundColors[ansiCode]) {
107
+ state.foreground = ansiparse.foregroundColors[ansiCode];
108
+ }
109
+ else if (ansiparse.backgroundColors[ansiCode]) {
110
+ state.background = ansiparse.backgroundColors[ansiCode];
111
+ }
112
+ else if (ansiCode == 39) {
113
+ delete state.foreground;
114
+ }
115
+ else if (ansiCode == 49) {
116
+ delete state.background;
117
+ }
118
+ else if (ansiparse.styles[ansiCode]) {
119
+ state[ansiparse.styles[ansiCode]] = true;
120
+ }
121
+ else if (ansiCode == 22) {
122
+ state.bold = false;
123
+ }
124
+ else if (ansiCode == 23) {
125
+ state.italic = false;
126
+ }
127
+ else if (ansiCode == 24) {
128
+ state.underline = false;
129
+ }
130
+ });
131
+ ansiState = [];
132
+ }
133
+ else {
134
+ matchingData += str[i];
135
+ }
136
+ continue;
137
+ }
138
+
139
+ if (str[i] == '\u001B') {
140
+ matchingControl = str[i];
141
+ }
142
+ else if (str[i] == '\u0008') {
143
+ eraseChar();
144
+ }
145
+ else {
146
+ matchingText += str[i];
147
+ }
148
+ }
149
+
150
+ if (matchingText) {
151
+ state.text = matchingText + (matchingControl ? matchingControl : '');
152
+ result.push(state);
153
+ }
154
+ return result;
155
+ }
156
+
157
+ ansiparse.foregroundColors = {
158
+ '30': 'black',
159
+ '31': 'red',
160
+ '32': 'green',
161
+ '33': 'yellow',
162
+ '34': 'blue',
163
+ '35': 'magenta',
164
+ '36': 'cyan',
165
+ '37': 'white',
166
+ '90': 'grey'
167
+ };
168
+
169
+ ansiparse.backgroundColors = {
170
+ '40': 'black',
171
+ '41': 'red',
172
+ '42': 'green',
173
+ '43': 'yellow',
174
+ '44': 'blue',
175
+ '45': 'magenta',
176
+ '46': 'cyan',
177
+ '47': 'white'
178
+ };
179
+
180
+ ansiparse.styles = {
181
+ '1': 'bold',
182
+ '3': 'italic',
183
+ '4': 'underline'
184
+ };
185
+
186
+ if (typeof module == "object" && typeof window == "undefined") {
187
+ module.exports = ansiparse;
188
+ }
189
+
190
+ /* app */
3
191
  var webconsole = {
4
192
  history:[],
5
193
  pointer:0,
@@ -10,72 +198,59 @@
10
198
  e.preventDefault();
11
199
  });
12
200
 
13
- var prevStyle = {
14
- color: "#ffffff",
15
- bold: false,
16
- underline: false
17
- }
18
-
19
201
  // colors
20
202
  var colors = {
21
- 30: "#eeeeee",
22
- 31: "#ff6c60",
23
- 32: "#a8ff60",
24
- 33: "#ffffb6",
25
- 34: "#96cbfe",
26
- 35: "#ff73fd",
27
- 36: "#c6c5fe",
28
- 37: "#eeeeee"
203
+ 'black': "#eeeeee",
204
+ 'red': "#ff6c60",
205
+ 'green': "#a8ff60",
206
+ 'yellow': "#ffffb6",
207
+ 'blue': "#96cbfe",
208
+ 'magenta': "#ff73fd",
209
+ 'cyan': "#c6c5fe",
210
+ 'white': "#eeeeee"
29
211
  }
30
212
  var boldColors = {
31
- 30: "#7c7c7c",
32
- 31: "#ffb6b0",
33
- 32: "#ceffac",
34
- 33: "#ffffcb",
35
- 34: "#b5dcfe",
36
- 35: "#ff9cfe",
37
- 36: "#dfdffe",
38
- 37: "#ffffff"
213
+ 'black': "#7c7c7c",
214
+ 'red': "#ffb6b0",
215
+ 'green': "#ceffac",
216
+ 'yellow': "#ffffcb",
217
+ 'blue': "#b5dcfe",
218
+ 'magenta': "#ff9cfe",
219
+ 'cyan': "#dfdffe",
220
+ 'white': "#ffffff"
39
221
  }
40
222
 
41
- function resetBashStyle()
223
+ function subColor(color, elem)
42
224
  {
43
- prevStyle = {
44
- color: colors[37],
45
- bold: 'normal',
46
- underline: 'none'
47
- };
225
+ if (color == undefined) color = 'white';
226
+ if (elem.bold && boldColors[color] != undefined) {
227
+ color = boldColors[color];
228
+ } else if (!elem.bold && colors[color] != undefined) {
229
+ color = colors[color];
230
+ }
231
+ return color;
48
232
  }
49
- function bashColorToHtml(bcolor)
233
+ function parseBashString(str, into)
50
234
  {
51
- // set values
52
- var all = bcolor.split(/;/g)
53
- if (all.indexOf("0") > 0) // ignore anything before 0, since 0 resets
54
- all.splice(0, all.indexOf("0"));
55
- if (all.indexOf("0") >= 0)
56
- resetBashStyle();
57
- if (all.indexOf("1") >= 0)
58
- prevStyle['bold'] = 'bold';
59
- if (all.indexOf("4") >= 0)
60
- prevStyle['underline'] = 'underline';
61
- if (prevStyle['bold'] == 'bold')
62
- colorMap = boldColors;
63
- else
64
- colorMap = colors;
65
- $.each(all, function(idx, val) {
66
- var i = parseInt(val);
67
- if (i > 10 && colorMap[i] != undefined)
68
- prevStyle['color'] = colorMap[i];
235
+ $.each(ansiparse(str), function(idx, elem) {
236
+ if (elem.text.length == 1 && elem.text[0] == '\n') {
237
+ into.append("<br>");
238
+ return true;
239
+ }
240
+ var domElem = $('<span></span>');
241
+ domElem.text(elem.text);
242
+ domElem.html(domElem.text().replace(/\n/g, "<br>"));
243
+ domElem.css('color', subColor(elem.foreground, elem));
244
+ if (elem.bold)
245
+ domElem.css('font-weight', 'bold');
246
+ if (elem.italic)
247
+ domElem.css('font-style', 'italic');
248
+ if (elem.underline)
249
+ domElem.css('text-decoration', 'underline');
250
+ if (elem.background)
251
+ domElem.css('background-color', subColor(elem.background, elem));
252
+ into.append(domElem);
69
253
  });
70
- return 'color:'+prevStyle['color']+';font-weight:'+prevStyle['bold']+
71
- ';text-decoration:'+prevStyle['underline'];
72
- }
73
- function parseBashString(str)
74
- {
75
- str = str.replace(/\u001B\[([0-9;]+)m/g, function(fm, sm) {
76
- return '</span><span style="'+bashColorToHtml(sm)+'">';
77
- }).replace(/\n/g, "<br>");
78
- return '<span>'+str+'</span>';
79
254
  }
80
255
  $("#rack-webconsole form input").keyup(function(event) {
81
256
  function escapeHTML(string) {
@@ -97,10 +272,12 @@
97
272
  data: ({query: webconsole.query.val(), token: "$TOKEN"}),
98
273
  success: function (data) {
99
274
  var query_class = data.previous_multi_line ? 'query_multiline' : 'query';
100
- var result = "<div class='" + query_class + "'>" +
101
- parseBashString(escapeHTML(data.prompt)) + "</div>";
275
+ var result = $("<div class='" + query_class + "'></div>");
276
+ parseBashString(escapeHTML(data.prompt), result);
102
277
  if (!data.multi_line) {
103
- result += "<div class='result'>" + parseBashString(escapeHTML(data.result)) + "</div>";
278
+ var mresult = $("<div class='result'></div>");
279
+ parseBashString(escapeHTML(data.result), mresult);
280
+ result.append(mresult);
104
281
  }
105
282
  $("#rack-webconsole .results").append(result);
106
283
  $("#rack-webconsole .results_wrapper").scrollTop(
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-webconsole-pry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -203,7 +203,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
203
203
  version: '0'
204
204
  segments:
205
205
  - 0
206
- hash: -3970192323891586303
206
+ hash: 1992267155081239539
207
207
  required_rubygems_version: !ruby/object:Gem::Requirement
208
208
  none: false
209
209
  requirements:
@@ -212,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
212
  version: '0'
213
213
  segments:
214
214
  - 0
215
- hash: -3970192323891586303
215
+ hash: 1992267155081239539
216
216
  requirements: []
217
217
  rubyforge_project: rack-webconsole-pry
218
218
  rubygems_version: 1.8.24