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

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: 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
8 <link rel="import" href="/static/common/third_party/polymer/polymer.html">
9
10 <link rel="import" href="rpc-descriptor-util.html">
11
12 <!-- The `rpc-completer` element implements Ace editor completer interface
Bons 2016/02/13 17:18:25 newline after <!-- ?
nodir 2016/02/17 02:02:13 Done.
13 based on a protobuf message descriptors.
14 -->
15 <script>
16 'use strict';
17
18 Polymer({
19 is: 'rpc-completer',
20
21 properties: {
22 description: Object, // FileDescriptorSet message
23 rootTypeName: String,
24 rootType: {
25 type: Object,
26 computed: '_resolveType(description, rootTypeName)'
27 }
28 },
29
30 _resolveType: function(desc, name) {
31 return rpcExplorer.descUtil.resolve(desc, name);
32 },
33
34 skipWhitespace: function(text, i) {
35 var space = {
36 ' ': 1,
37 '\n': 1,
38 '\r': 1,
39 '\t': 1
40 };
41 while (space[text.charAt(i)]) {
42 i++;
43 }
44 return i;
45 },
46
47 findMatching: function(text, i, open, close) {
48 var level = 1;
49 for (; i < text.length; i++) {
50 switch (text.charAt(i)) {
51 case open:
52 level++;
53 break;
54 case close:
55 level--;
56 if (level == 0) {
57 return i;
58 }
59 break;
60 }
61 }
62 return -1;
63 },
64
65 // resolves path at the end of text, best effort.
66 // e.g. for text '{ "a": { "b": [' returns ['a', 'b']
67 // For '{ "a": {}, "b": {' returns ['b'].
68 // For '{ "a":' returns ['a'].
69 getCurrentPath: function(text) {
70 var path = [];
71 for (var i = 0; i < text.length;) {
72 // find colon.
Bons 2016/02/13 17:18:25 this comment is too short and doesn't really tell
nodir 2016/02/17 02:02:13 removed
73 i = text.indexOf(':', i);
74 if (i == -1) {
75 break;
76 }
77 var colon = i;
78
79 i++;
80 i = this.skipWhitespace(text, i);
81
82 if (i == text.length || text.charAt(i) == '"' && i + 1 == text.length) {
83 // the path is a field.
84 } else {
85 // is there an array or object after the colon?
86 var closingIndex = null;
87 switch (text.charAt(i)) {
88 case '{':
89 closingIndex = this.findMatching(text, i + 1, '{', '}');
90 break;
91 case '[':
92 closingIndex = this.findMatching(text, i + 1, '[', ']');
93 break;
94 }
95 if (closingIndex == null || closingIndex != -1) {
96 // Not an object/array or closed. Ignore.
97 continue;
98 }
99 }
100
101 // read the name to the left of colon.
102 var secondQuote = text.lastIndexOf('"', colon);
103 if (secondQuote == -1) {
104 return null;
105 }
106
107 var firstQuote = text.lastIndexOf('"', secondQuote - 1);
108 if (firstQuote == -1) {
109 return null;
110 }
111
112 path.push(text.substring(firstQuote + 1, secondQuote));
113 }
114 return path;
115 },
116
117 // returns elements to display in autocomplete.
118 getCompletions: function(editor, session, pos, prefix, callback) {
119 if (!this.rootType) {
120 return;
121 }
122
123 // Get all text left to the current selection.
124 var beforePos = {
125 start: {row: 0, col: 0 },
126 end: session.selection.getRange().start
127 };
128 var text = session.getTextRange(beforePos);
129 // Resolve path.
130 var path = this.getCurrentPath(text);
131 console.log('completion: current path: ', path);
132
133 // Resolve type.
134 var type = this.rootType;
135 var util = rpcExplorer.descUtil;
136 for (var i = 0; i < path.length; i++) {
137 if (type.type != 'message') {
138 return;
139 }
140 var field = util.findByName(type.desc.field, path[i]);
141 if (!field) {
142 console.log('Field ' + path[i] + ' not found')
143 return;
144 }
145 var typeName = field.type_name;
146 if (typeof typeName != 'string') {
147 console.log('Field ' + path[i] + ' is not a message or enum')
148 return;
149 }
150 // referenced types are often prefixed with '.'
151 typeName = util.trimPrefixDot(typeName);
152 type = util.resolve(this.description, typeName);
153 if (!type) {
154 return;
155 }
156 }
157
158 // Automatically surround with quotes.
159 var quoteCount = (text.match(/"/g) || []).length;
160 var shouldQuote = quoteCount % 2 == 0;
161
162 var completions = [];
163 switch (type.type) {
164 case 'message':
165 if (!type.desc.field) {
166 return;
167 }
168 for (var i = 0; i < type.desc.field.length; i++) {
169 var field = type.desc.field[i];
170 var meta = this.fieldTypeName(field);
171 if (field.label == 'LABEL_REPEATED') {
172 meta = 'repeated ' + meta;
173 }
174 completions.push({
175 desc: field,
176 caption: field.name,
177 snippet: this.snippetForField(field, shouldQuote),
178 meta: meta
179 });
180 }
181 break;
182
183 case 'enum':
184 for (var i = 0; i < type.desc.value.length; i++) {
185 var value = type.desc.value[i];
186 var snippet = value.name;
187 if (shouldQuote) {
188 snippet = '"' + snippet + '"';
189 }
190 completions.push({
191 desc: value,
192 caption: value.name,
193 snippet: snippet,
194 meta: '' + value.number
195 })
196 }
197 break;
198 }
199
200 callback(null, completions);
201 },
202
203 snippetForField: function (field, shouldQuote) {
204 // snippet docs:
205 // https://cloud9-sdk.readme.io/docs/snippets
206 var snippet = field.name;
207 if (shouldQuote) {
208 snippet = '"' + snippet + '"';
209 }
210 if (!shouldQuote) {
211 return snippet;
212 }
213
214 snippet += ': ';
215
216 var open = '';
217 var close = '';
218 if (field.label == 'LABEL_REPEATED') {
219 open += '[';
220 close = ']' + close;
221 }
222
223 switch (field.type) {
224 case 'TYPE_MESSAGE':
225 open += '{';
226 close = '}' + close;
227 break;
228 case 'TYPE_STRING':
229 case 'TYPE_ENUM':
230 open += '"';
231 close = '"' + close;
232 break;
233 }
234
235 // ${0} is the position of cursor after insertion.
236 snippet += open + '${0}' + close;
237 return snippet;
238 },
239
240 // Returns leading comments of a completion.
241 // The result is displayed to the right of the selected completion.
242 getDocTooltip: function(completion) {
243 return completion.desc.source_code_info && completion.desc.source_code_info. leading_comments;
Bons 2016/02/13 17:18:25 80 chars
nodir 2016/02/17 02:02:12 Done.
244 },
245
246 scalarTypeNames: {
247 TYPE_DOUBLE: 'double',
248 TYPE_FLOAT: 'float',
249 TYPE_INT64: 'int64',
250 TYPE_UINT64: 'uint64',
251 TYPE_INT32: 'int32',
252 TYPE_FIXED64: 'fixed64',
253 TYPE_FIXED32: 'fixed32',
254 TYPE_BOOL: 'bool',
255 TYPE_STRING: 'string',
256 TYPE_BYTES: 'bytes',
257 TYPE_UINT32: 'uint32',
258 TYPE_SFIXED32: 'sfixed32',
259 TYPE_SFIXED64: 'sfixed64',
260 TYPE_SINT32: 'sint32',
261 TYPE_SINT64: 'sint64',
262 },
263
264 fieldTypeName: function(field) {
265 var name = this.scalarTypeNames[field.type];
266 if (!name) {
267 name = rpcExplorer.descUtil.trimPrefixDot(field.type_name);
268 }
269 return name;
270 }
271
272 })
Bons 2016/02/13 17:18:25 semicolon
nodir 2016/02/17 02:02:13 Done.
273 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698