Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1006)

Side by Side Diff: server/static/rpcexplorer/rpc-completer.html

Issue 1695893004: RPC Explorer (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@rpcepxlorer-deps
Patch Set: refactoring and tests Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!--
2 Copyright 2016 The Chromium Authors. All rights reserved.
3 Use of this source code is governed by a BSD-style license that can be
4 found in the LICENSE file.
5 -->
6
7 <link rel="import" href="../bower_components/polymer/polymer.html">
8
9 <link rel="import" href="rpc-descriptor-util.html">
10
11 <!--
12 The `rpc-completer` element implements Ace editor completer interface
13 based on a protobuf message descriptors.
14 -->
15 <script>
16 'use strict';
17
18 Polymer({
19 is: 'rpc-completer',
20
21 properties: {
22 /** @type {FileDescriptorSet} */
23 description: Object,
24
25 rootTypeName: String,
26
27 /** @type {DescriptorProto} */
28 rootType: {
29 type: Object,
30 computed: '_resolveType(description, rootTypeName)'
31 }
32 },
33
34
35 /**
36 * Returns elements to display in autocomplete.
37 */
38 getCompletions: function(editor, session, pos, prefix, callback) {
39 if (!this.rootType) {
40 return;
41 }
42
43 // Get all text left to the current selection.
44 var beforePos = {
45 start: {row: 0, col: 0 },
Bons 2016/02/23 15:52:28 extra space after 0. either do {row: 0, col: 0} or
nodir 2016/02/23 18:32:25 Done.
46 end: session.selection.getRange().start
47 };
48 var text = session.getTextRange(beforePos);
49 var completions = this.getCompletionsForText(this.rootType, text);
50 if (completions) {
51 callback(null, completions);
52 }
53 },
54
55 /**
56 * Returns leading comments of a completion.
57 * The result is displayed to the right of the selected completion.
58 */
59 getDocTooltip: function(completion) {
60 return completion.docTooltip;
61 },
62
63 getCompletionsForText: function(type, text) {
64 // Resolve path.
65 var path = this.getCurrentPath(text);
66 if (path == null) {
67 console.log('completion: could not compute path');
Bons 2016/02/23 15:52:28 console.error?
nodir 2016/02/23 18:32:25 removed it. It was rather for debugging, does not
68 return [];
69 }
70 console.log('completion: current path: ', path);
Bons 2016/02/23 15:52:28 remove?
nodir 2016/02/23 18:32:25 Done.
71
72 // Resolve type.
73 var util = rpcExplorer.descUtil;
74 for (var i = 0; i < path.length; i++) {
75 if (type.type != 'messageType') {
76 return [];
77 }
78 var field = util.findByName(type.desc.field, path[i]);
79 if (!field) {
80 console.log('Field ' + path[i] + ' not found')
81 return [];
82 }
83 var typeName = field.type_name;
84 if (typeof typeName != 'string') {
85 console.log('Field ' + path[i] + ' is not a message or enum')
86 return [];
87 }
88 // referenced types are often prefixed with '.'
Bons 2016/02/23 15:52:28 Capitalize 'referenced'
nodir 2016/02/23 18:32:25 Done.
89 typeName = util.trimPrefixDot(typeName);
90 type = util.resolve(this.description, typeName);
91 if (!type) {
92 return [];
93 }
94 }
95
96 console.log('completion: current type: ', type.desc.name);
Bons 2016/02/23 15:52:28 remove?
nodir 2016/02/23 18:32:25 Done.
97
98 // Automatically surround with quotes.
99 var quoteCount = (text.match(/"/g) || []).length;
100 var shouldQuote = quoteCount % 2 === 0;
101
102 function docTooltip(desc) {
103 var info = desc.source_code_info;
104 return info && info.leading_comments || '';
105 }
106
107 var completions = [];
108 switch (type.type) {
109 case 'messageType':
110 if (!type.desc.field) {
111 break;
112 }
113 for (var i = 0; i < type.desc.field.length; i++) {
114 var field = type.desc.field[i];
115 var meta = this.fieldTypeName(field);
116 if (field.label === 'LABEL_REPEATED') {
117 meta = 'repeated ' + meta;
118 }
119 completions.push({
120 caption: field.name,
121 snippet: this.snippetForField(field, shouldQuote),
122 meta: meta,
123 docTooltip: docTooltip(field)
124 });
125 }
126 break;
127
128 case 'enumType':
129 for (var i = 0; i < type.desc.value.length; i++) {
130 var value = type.desc.value[i];
131 var snippet = value.name;
132 if (shouldQuote) {
133 snippet = '"' + snippet + '"';
134 }
135 completions.push({
136 caption: value.name,
137 snippet: snippet,
138 meta: '' + value.number,
139 docTooltip: docTooltip(value)
140 });
141 }
142 break;
143 }
144 return completions;
145 },
146
147 snippetForField: function(field, shouldQuote) {
148 // snippet docs:
149 // https://cloud9-sdk.readme.io/docs/snippets
150 var snippet = field.name;
151 if (shouldQuote) {
152 snippet = '"' + snippet + '"';
153 }
154 if (!shouldQuote) {
155 return snippet;
156 }
157
158 snippet += ': ';
159
160 var open = '';
161 var close = '';
162 if (field.label === 'LABEL_REPEATED') {
163 open += '[';
164 close = ']' + close;
165 }
166
167 switch (field.type) {
168 case 'TYPE_MESSAGE':
169 open += '{';
170 close = '}' + close;
171 break;
172 case 'TYPE_STRING':
173 case 'TYPE_ENUM':
174 open += '"';
175 close = '"' + close;
176 break;
177 }
178
179 // ${0} is the position of cursor after insertion.
180 snippet += open + '${0}' + close;
181 return snippet;
182 },
183
184 /**
185 * Resolves path at the end of text, best effort.
186 * e.g. for text '{ "a": { "b": [' returns ['a', 'b']
187 * For '{ "a": {}, "b": {' returns ['b'].
188 * For '{ "a":' returns ['a'].
189 */
190 getCurrentPath: function(text) {
191 var path = [];
192 for (var i = 0; i < text.length;) {
193 i = text.indexOf(':', i);
194 if (i === -1) {
195 break;
196 }
197 var colon = i;
198
199 i++;
200 i = this._skipWhitespace(text, i);
201
202 if (i === text.length || text.charAt(i) === '"' && i+1 === text.length) {
203 // the path is a field.
204 } else if (text.charAt(i) in {'{':0, '[': 0}) {
205 // there is an array or object after the colon
206 var closingIndex = this.findMatching(text, i);
207 if (closingIndex !== -1) {
208 // Not an object/array or closed. Ignore.
209 continue;
210 }
211 } else {
212 continue
213 }
214
215 // read the name to the left of colon.
216 var secondQuote = text.lastIndexOf('"', colon);
217 if (secondQuote === -1) {
218 return null;
219 }
220
221 var firstQuote = text.lastIndexOf('"', secondQuote - 1);
222 if (firstQuote === -1) {
223 return null;
224 }
225
226 path.push(text.substring(firstQuote + 1, secondQuote));
227 }
228 return path;
229 },
230
231 /** Finds index of the matching brace. */
232 findMatching: function(text, i) {
233 var level = 0;
234 var open = text.charAt(i);
235 var close;
236 switch (open) {
237 case '{':
238 close = '}';
239 break;
240
241 case '[':
242 close = ']';
243 break;
244
245 default:
246 throw Error('Unexpected brace: ' + open);
247 }
248
249 for (; i < text.length; i++) {
250 switch (text.charAt(i)) {
251 case open:
252 level++;
253 break;
254 case close:
255 level--;
256 if (level === 0) {
257 return i;
258 }
259 break;
260 }
261 }
262 return -1;
263 },
264
265 _resolveType: function(desc, name) {
266 return rpcExplorer.descUtil.resolve(desc, name);
267 },
268
269 _scalarTypeNames: {
270 TYPE_DOUBLE: 'double',
271 TYPE_FLOAT: 'float',
272 TYPE_INT64: 'int64',
273 TYPE_UINT64: 'uint64',
274 TYPE_INT32: 'int32',
275 TYPE_FIXED64: 'fixed64',
276 TYPE_FIXED32: 'fixed32',
277 TYPE_BOOL: 'bool',
278 TYPE_STRING: 'string',
279 TYPE_BYTES: 'bytes',
280 TYPE_UINT32: 'uint32',
281 TYPE_SFIXED32: 'sfixed32',
282 TYPE_SFIXED64: 'sfixed64',
283 TYPE_SINT32: 'sint32',
284 TYPE_SINT64: 'sint64',
285 },
286
287 fieldTypeName: function(field) {
288 var name = this._scalarTypeNames[field.type];
289 if (!name) {
290 name = rpcExplorer.descUtil.trimPrefixDot(field.type_name);
291 }
292 return name;
293 },
294
295 _skipWhitespace: function(text, i) {
296 var space = {
297 ' ': 1,
298 '\n': 1,
299 '\r': 1,
300 '\t': 1
301 };
302 while (space[text.charAt(i)]) {
303 i++;
304 }
305 return i;
306 }
307 });
308 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698