Chromium Code Reviews| OLD | NEW |
|---|---|
| (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> | |
| OLD | NEW |