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

Unified 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: 80 chars 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « server/static/rpcexplorer/index.html ('k') | server/static/rpcexplorer/rpc-descriptor-util.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: server/static/rpcexplorer/rpc-completer.html
diff --git a/server/static/rpcexplorer/rpc-completer.html b/server/static/rpcexplorer/rpc-completer.html
new file mode 100644
index 0000000000000000000000000000000000000000..db41603deb5fdcfa45d3209443aa615c84ac3a38
--- /dev/null
+++ b/server/static/rpcexplorer/rpc-completer.html
@@ -0,0 +1,305 @@
+<!--
+ Copyright 2016 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+ -->
+
+<link rel="import" href="../bower_components/polymer/polymer.html">
+
+<link rel="import" href="rpc-descriptor-util.html">
+
+<!--
+ The `rpc-completer` element implements Ace editor completer interface
+ based on a protobuf message descriptors.
+-->
+<script>
+ 'use strict';
+
+ Polymer({
+ is: 'rpc-completer',
+
+ properties: {
+ /** @type {FileDescriptorSet} */
+ description: Object,
+
+ rootTypeName: String,
+
+ /** @type {DescriptorProto} */
+ rootType: {
+ type: Object,
+ computed: '_resolveType(description, rootTypeName)'
+ }
+ },
+
+
+ /**
+ * Returns elements to display in autocomplete.
+ */
+ getCompletions: function(editor, session, pos, prefix, callback) {
+ if (!this.rootType) {
+ return;
+ }
+
+ // Get all text left to the current selection.
+ var beforePos = {
+ start: {row: 0, col: 0},
+ end: session.selection.getRange().start
+ };
+ var text = session.getTextRange(beforePos);
+ var completions = this.getCompletionsForText(this.rootType, text);
+ if (completions) {
+ callback(null, completions);
+ }
+ },
+
+ /**
+ * Returns leading comments of a completion.
+ * The result is displayed to the right of the selected completion.
+ */
+ getDocTooltip: function(completion) {
+ return completion.docTooltip;
+ },
+
+ getCompletionsForText: function(type, text) {
+ // Resolve path.
+ var path = this.getCurrentPath(text);
+ if (path == null) {
+ return [];
+ }
+
+ // Resolve type.
+ var util = rpcExplorer.descUtil;
+ for (var i = 0; i < path.length; i++) {
+ if (type.type != 'messageType') {
+ return [];
+ }
+ var field = util.findByName(type.desc.field, path[i]);
+ if (!field) {
+ console.log('Field ' + path[i] + ' not found')
+ return [];
+ }
+ var typeName = field.type_name;
+ if (typeof typeName != 'string') {
+ console.log('Field ' + path[i] + ' is not a message or enum')
+ return [];
+ }
+ // Referenced types are often prefixed with '.'.
+ typeName = util.trimPrefixDot(typeName);
+ type = util.resolve(this.description, typeName);
+ if (!type) {
+ return [];
+ }
+ }
+
+ // Automatically surround with quotes.
+ var quoteCount = (text.match(/"/g) || []).length;
+ var shouldQuote = quoteCount % 2 === 0;
+
+ function docTooltip(desc) {
+ var info = desc.source_code_info;
+ return info && info.leading_comments || '';
+ }
+
+ var completions = [];
+ switch (type.type) {
+ case 'messageType':
+ if (!type.desc.field) {
+ break;
+ }
+ for (var i = 0; i < type.desc.field.length; i++) {
+ var field = type.desc.field[i];
+ var meta = this.fieldTypeName(field);
+ if (field.label === 'LABEL_REPEATED') {
+ meta = 'repeated ' + meta;
+ }
+ completions.push({
+ caption: field.name,
+ snippet: this.snippetForField(field, shouldQuote),
+ meta: meta,
+ docTooltip: docTooltip(field)
+ });
+ }
+ break;
+
+ case 'enumType':
+ for (var i = 0; i < type.desc.value.length; i++) {
+ var value = type.desc.value[i];
+ var snippet = value.name;
+ if (shouldQuote) {
+ snippet = '"' + snippet + '"';
+ }
+ completions.push({
+ caption: value.name,
+ snippet: snippet,
+ meta: '' + value.number,
+ docTooltip: docTooltip(value)
+ });
+ }
+ break;
+ }
+ return completions;
+ },
+
+ snippetForField: function(field, shouldQuote) {
+ // snippet docs:
+ // https://cloud9-sdk.readme.io/docs/snippets
+ var snippet = field.name;
+ if (shouldQuote) {
+ snippet = '"' + snippet + '"';
+ }
+ if (!shouldQuote) {
+ return snippet;
+ }
+
+ snippet += ': ';
+
+ var open = '';
+ var close = '';
+ if (field.label === 'LABEL_REPEATED') {
+ open += '[';
+ close = ']' + close;
+ }
+
+ switch (field.type) {
+ case 'TYPE_MESSAGE':
+ open += '{';
+ close = '}' + close;
+ break;
+ case 'TYPE_STRING':
+ case 'TYPE_ENUM':
+ open += '"';
+ close = '"' + close;
+ break;
+ }
+
+ // ${0} is the position of cursor after insertion.
+ snippet += open + '${0}' + close;
+ return snippet;
+ },
+
+ /**
+ * Resolves path at the end of text, best effort.
+ * e.g. for text '{ "a": { "b": [' returns ['a', 'b']
+ * For '{ "a": {}, "b": {' returns ['b'].
+ * For '{ "a":' returns ['a'].
+ */
+ getCurrentPath: function(text) {
+ var path = [];
+ for (var i = 0; i < text.length;) {
+ i = text.indexOf(':', i);
+ if (i === -1) {
+ break;
+ }
+ var colon = i;
+
+ i++;
+ i = this._skipWhitespace(text, i);
+
+ if (i === text.length ||
+ text.charAt(i) === '"' && i+1 === text.length) {
+ // the path is a field.
+ } else if (text.charAt(i) in {'{':0, '[': 0}) {
+ // there is an array or object after the colon
+ var closingIndex = this.findMatching(text, i);
+ if (closingIndex !== -1) {
+ // Not an object/array or closed. Ignore.
+ continue;
+ }
+ } else {
+ continue
+ }
+
+ // read the name to the left of colon.
+ var secondQuote = text.lastIndexOf('"', colon);
+ if (secondQuote === -1) {
+ return null;
+ }
+
+ var firstQuote = text.lastIndexOf('"', secondQuote - 1);
+ if (firstQuote === -1) {
+ return null;
+ }
+
+ path.push(text.substring(firstQuote + 1, secondQuote));
+ }
+ return path;
+ },
+
+ /** Finds index of the matching brace. */
+ findMatching: function(text, i) {
+ var level = 0;
+ var open = text.charAt(i);
+ var close;
+ switch (open) {
+ case '{':
+ close = '}';
+ break;
+
+ case '[':
+ close = ']';
+ break;
+
+ default:
+ throw Error('Unexpected brace: ' + open);
+ }
+
+ for (; i < text.length; i++) {
+ switch (text.charAt(i)) {
+ case open:
+ level++;
+ break;
+ case close:
+ level--;
+ if (level === 0) {
+ return i;
+ }
+ break;
+ }
+ }
+ return -1;
+ },
+
+ _resolveType: function(desc, name) {
+ return rpcExplorer.descUtil.resolve(desc, name);
+ },
+
+ _scalarTypeNames: {
+ TYPE_DOUBLE: 'double',
+ TYPE_FLOAT: 'float',
+ TYPE_INT64: 'int64',
+ TYPE_UINT64: 'uint64',
+ TYPE_INT32: 'int32',
+ TYPE_FIXED64: 'fixed64',
+ TYPE_FIXED32: 'fixed32',
+ TYPE_BOOL: 'bool',
+ TYPE_STRING: 'string',
+ TYPE_BYTES: 'bytes',
+ TYPE_UINT32: 'uint32',
+ TYPE_SFIXED32: 'sfixed32',
+ TYPE_SFIXED64: 'sfixed64',
+ TYPE_SINT32: 'sint32',
+ TYPE_SINT64: 'sint64',
+ },
+
+ fieldTypeName: function(field) {
+ var name = this._scalarTypeNames[field.type];
+ if (!name) {
+ name = rpcExplorer.descUtil.trimPrefixDot(field.type_name);
+ }
+ return name;
+ },
+
+ _skipWhitespace: function(text, i) {
+ var space = {
+ ' ': 1,
+ '\n': 1,
+ '\r': 1,
+ '\t': 1
+ };
+ while (space[text.charAt(i)]) {
+ i++;
+ }
+ return i;
+ }
+ });
+</script>
« no previous file with comments | « server/static/rpcexplorer/index.html ('k') | server/static/rpcexplorer/rpc-descriptor-util.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698