visual-studio-code - Signature Help Provider is working incorrectly in custom extension
问题描述
We have written some time ago custom extension in VS Code for our internal programming language. We used as starting point built-in PHP extension. It worked fine until one moment (not sure exactly which). Signature Help Provider highlights random parameters. However, in our code, parameter index is correct. I have no idea what is wrong and how SignatureHelp class works.
Here is screenshot how it behaves:
And here is code for SignatureHelp (it's mostly untouched old built-in PHP code. Variable activeP contains correct index, its SignatureHelp class doing something wrong):
'use strict';
var vscode_1 = require("vscode");
var myLangGlobals = require("./myLangGlobals");
var markedTextUtil_1 = require("./utils/markedTextUtil");
var _NL = '\n'.charCodeAt(0);
var _TAB = '\t'.charCodeAt(0);
var _WSB = ' '.charCodeAt(0);
var _LBracket = '['.charCodeAt(0);
var _RBracket = ']'.charCodeAt(0);
var _LCurly = '{'.charCodeAt(0);
var _RCurly = '}'.charCodeAt(0);
var _LParent = '('.charCodeAt(0);
var _RParent = ')'.charCodeAt(0);
var _Comma = ','.charCodeAt(0);
var _Quote = '\''.charCodeAt(0);
var _DQuote = '"'.charCodeAt(0);
var _USC = '_'.charCodeAt(0);
var _a = 'a'.charCodeAt(0);
var _z = 'z'.charCodeAt(0);
var _A = 'A'.charCodeAt(0);
var _Z = 'Z'.charCodeAt(0);
var _0 = '0'.charCodeAt(0);
var _9 = '9'.charCodeAt(0);
var BOF = 0;
var BackwardIterator = (function () {
function BackwardIterator(model, offset, lineNumber) {
this.lineNumber = lineNumber;
this.offset = offset;
this.line = model.lineAt(this.lineNumber).text;
this.model = model;
}
BackwardIterator.prototype.hasNext = function () {
return this.lineNumber >= 0;
};
BackwardIterator.prototype.next = function () {
if (this.offset < 0) {
if (this.lineNumber > 0) {
this.lineNumber--;
this.line = this.model.lineAt(this.lineNumber).text;
this.offset = this.line.length - 1;
return _NL;
}
this.lineNumber = -1;
return BOF;
}
var ch = this.line.charCodeAt(this.offset);
this.offset--;
return ch;
};
return BackwardIterator;
}());
var myLangSignatureHelpProvider = (function () {
function myLangSignatureHelpProvider() {
}
myLangSignatureHelpProvider.prototype.provideSignatureHelp = function (document, position, token) {
var enable = vscode_1.workspace.getConfiguration('myLang').get('suggest.basic', true);
if (!enable) {
return null;
}
var iterator = new BackwardIterator(document, position.character - 1, position.line);
var paramIndex = this.readArguments(iterator);
if (paramIndex < 0) {
return null;
}
var ident = this.readIdent(iterator);
if (!ident) {
return null;
}
ident = ident.toLowerCase();
var entry = myLangGlobals.globalfunctions[ident];
if (!entry) {
return null;
}
var signature = entry.name;
var args = entry.args;
var argCnt = args ? args.length : 0;
if (entry.type) {
signature = entry.type + ' ' + signature;
}
if (args) {
signature += '(';
for (let i = 0; i < argCnt; ++i) {
if (i) {
signature += ', ';
}
signature += args[i].name;
}
signature += ');';
}
var activeP = Math.min(paramIndex, Math.max(argCnt - 1, 0));
var signatureInfo = new vscode_1.SignatureInformation(
signature,
new vscode_1.MarkdownString(
entry.description + '\n\n---\n\n' +
markedTextUtil_1.textToMarkedString('Version: ' + entry.version) + '\n\n' +
markedTextUtil_1.textToMarkedString('Documented on: ' + entry.date)
)
);
if (args) {
for (let i = 0; i < argCnt; ++i) {
signatureInfo.parameters.push({ label: args[i].name, documentation: args[i].description });
}
}
// TODO: understand, why it highlights incorrect parameter, activeP is correct
var ret = new vscode_1.SignatureHelp();
ret.signatures.push(signatureInfo);
ret.activeSignature = 0;
ret.activeParameter = activeP;
return Promise.resolve(ret);
};
myLangSignatureHelpProvider.prototype.readArguments = function (iterator) {
var parentNesting = 0;
var bracketNesting = 0;
var curlyNesting = 0;
var paramCount = 0;
while (iterator.hasNext()) {
var ch = iterator.next();
switch (ch) {
case _LParent:
parentNesting--;
if (parentNesting < 0) {
return paramCount;
}
break;
case _RParent:
parentNesting++;
break;
case _LCurly:
curlyNesting--;
break;
case _RCurly:
curlyNesting++;
break;
case _LBracket:
bracketNesting--;
break;
case _RBracket:
bracketNesting++;
break;
case _DQuote:
case _Quote:
while (iterator.hasNext() && ch !== iterator.next()) {
}
break;
case _Comma:
if (!parentNesting && !bracketNesting && !curlyNesting) {
paramCount++;
}
break;
}
}
return -1;
};
myLangSignatureHelpProvider.prototype.isIdentPart = function (ch) {
if (ch === _USC ||
ch >= _a && ch <= _z ||
ch >= _A && ch <= _Z ||
ch >= _0 && ch <= _9 ||
ch >= 0x80 && ch <= 0xFFFF) {
return true;
}
return false;
};
myLangSignatureHelpProvider.prototype.readIdent = function (iterator) {
var identStarted = false;
var ident = '';
while (iterator.hasNext()) {
var ch = iterator.next();
if (!identStarted && (ch === _WSB || ch === _TAB || ch === _NL)) {
continue;
}
if (this.isIdentPart(ch)) {
identStarted = true;
ident = String.fromCharCode(ch) + ident;
}
else if (identStarted) {
return ident;
}
}
return ident;
};
return myLangSignatureHelpProvider;
}());
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = myLangSignatureHelpProvider;
解决方案
您的主要问题在于
signatureInfo.parameters.push({ label: args[i].name, documentation: args[i].description });
由于您有多个具有相同名称的参数,因此仅使用名称作为label
. 而不是label: string
使用label: [number, number]
. 请参阅API 文档中的ParameterInfo。
旁注:这个 JavaScript 是从 TypeScript 生成的吗?如果是这样,请提供 TypeScript 源代码。自动生成的代码不那么容易阅读。
推荐阅读
- python - 在海龟图形中使用 clear() 函数时如何停止闪烁
- c# - Blazor 创建服务,从 SQL Server 存储过程中提取数据
- matlab - 需要帮助构建 STL 文件
- sql - 如何将计数用于 case 语句
- google-analytics - Google Analytics Report API v4 在没有明显原因的情况下多次返回 503
- node.js - 使用 Nodejs Sharp 模块时出错。模块解析失败:意外字符 '' (1: 0)
- vb.net - 在 Outlook Web App 上通过 VB.NET 下载电子邮件附件
- swift - CALayer垂直居中文本XCode 11.6
- javascript - 如何在反应导航反应导航中通过注销重置用户历史记录?
- python - 我正在尝试通过 Rs485 从 RasPi 与 arduino 通信。我在 RasPi 端使用 USB 到 Rs485 转换器,在 arduino 端使用 Max485 芯片