Skip to content

Commit 498dbb5

Browse files
author
fasfsfgs
committed
signature helper for special forms
1 parent f3dbe98 commit 498dbb5

1 file changed

Lines changed: 45 additions & 10 deletions

File tree

src/clojureSignature.ts

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import * as cljParser from './cljParser';
88
const PARAMETER_OPEN = `[`;
99
const PARAMETER_CLOSE = `]`;
1010
const PARAMETER_REST = `&`;
11+
const UNSUPPORTED_SIGNATURE_NAMES = ['.', 'new', 'fn', 'set!']; // they have forms that do not follow the same rules as other special forms
12+
const SPECIAL_FORM_PARAMETER_REST = `*`;
1113

1214
export class ClojureSignatureProvider extends ClojureProvider implements vscode.SignatureHelpProvider {
1315

@@ -21,23 +23,58 @@ export class ClojureSignatureProvider extends ClojureProvider implements vscode.
2123

2224
return new Promise<vscode.SignatureHelp>((resolve, reject) => {
2325
this.getNREPL().info(exprInfo.functionName, ns, info => {
24-
resolve(getSignatureHelp(info, exprInfo.parameterPosition));
26+
if (!info.name) // sometimes info brings just a list of suggestions (example: .MAX_VALUE)
27+
return resolve();
28+
29+
if (!!info['special-form'])
30+
return resolve(getSpecialFormSignatureHelp(info, exprInfo.parameterPosition));
31+
32+
return resolve(getFunctionSignatureHelp(info, exprInfo.parameterPosition));
2533
});
2634
});
2735
}
2836

2937
}
3038

31-
function getSignatureHelp(info, parameterPosition): vscode.SignatureHelp {
32-
const signatures = getSignatureInfos(info);
39+
function getSpecialFormSignatureHelp(info: any, parameterPosition: number): vscode.SignatureHelp {
40+
if (UNSUPPORTED_SIGNATURE_NAMES.indexOf(info.name) > -1) {
41+
const signatureHelp = new vscode.SignatureHelp();
42+
signatureHelp.signatures = [new vscode.SignatureInformation(`${info.name} *special form* ${info['forms-str']}`, info.doc)];
43+
signatureHelp.activeSignature = 0;
44+
45+
return signatureHelp;
46+
}
47+
48+
const forms: string = info['forms-str'];
49+
const [functionName, ...parameters] = forms.substring(3, forms.length - 1).split(' ');
50+
const parameterInfos = parameters.map(parameter => new vscode.ParameterInformation(parameter));
51+
52+
const sigInfo = new vscode.SignatureInformation(`${info.name} *special form* [${parameterInfos.map(pi => pi.label).join(`\n`)}]`, info.doc);
53+
sigInfo.parameters = parameterInfos;
54+
55+
if (parameterPosition + 1 > sigInfo.parameters.length && sigInfo.parameters[sigInfo.parameters.length - 1].label.endsWith(SPECIAL_FORM_PARAMETER_REST))
56+
parameterPosition = sigInfo.parameters.length - 1;
57+
58+
const signatureHelp = new vscode.SignatureHelp();
59+
signatureHelp.signatures = [sigInfo];
60+
signatureHelp.activeParameter = parameterPosition;
61+
signatureHelp.activeSignature = 0;
62+
63+
return signatureHelp;
64+
}
65+
66+
function getFunctionSignatureHelp(info: any, parameterPosition: number): vscode.SignatureHelp {
67+
const signatures = getFunctionSignatureInfos(info);
3368
signatures.sort((sig1, sig2) => sig1.parameters.length - sig2.parameters.length);
3469

3570
let activeSignature = signatures.findIndex(signature => signature.parameters.length >= parameterPosition + 1);
3671
if (activeSignature === -1) {
3772
activeSignature = signatures.findIndex(signature => signature.parameters.some(param => param.label.startsWith(PARAMETER_REST)));
38-
if (activeSignature != -1)
73+
if (activeSignature !== -1)
3974
parameterPosition = signatures[activeSignature].parameters.length - 1;
4075
}
76+
if (activeSignature === -1)
77+
activeSignature = 0;
4178

4279
const signatureHelp = new vscode.SignatureHelp();
4380
signatureHelp.signatures = signatures;
@@ -47,7 +84,7 @@ function getSignatureHelp(info, parameterPosition): vscode.SignatureHelp {
4784
return signatureHelp;
4885
}
4986

50-
function getSignatureInfos(info: any): vscode.SignatureInformation[] {
87+
function getFunctionSignatureInfos(info: any): vscode.SignatureInformation[] {
5188
const arglists: string = info['arglists-str'];
5289

5390
const sigParamStarts: number[] = [];
@@ -69,15 +106,15 @@ function getSignatureInfos(info: any): vscode.SignatureInformation[] {
69106
return sigParamStarts
70107
.map((sigParamStart, index) => arglists.substring(sigParamStart, sigParamStops[index] + 1))
71108
.map(signatureParameter => {
72-
const parameterInfos = getParameterInfos(signatureParameter);
109+
const parameterInfos = getFunctionParameterInfos(signatureParameter);
73110
const sigInfo = new vscode.SignatureInformation(`${info.ns}/${info.name} [${parameterInfos.map(pi => pi.label).join(`\n`)}]`);
74111
sigInfo.documentation = info.doc;
75112
sigInfo.parameters = parameterInfos;
76113
return sigInfo;
77114
});
78115
}
79116

80-
function getParameterInfos(signatureParameter: string): vscode.ParameterInformation[] {
117+
function getFunctionParameterInfos(signatureParameter: string): vscode.ParameterInformation[] {
81118
signatureParameter = signatureParameter.substring(1, signatureParameter.length - 1); // removing external brackets
82119
const paramStarts: number[] = [];
83120
const paramStops: number[] = [];
@@ -112,7 +149,5 @@ function getParameterInfos(signatureParameter: string): vscode.ParameterInformat
112149

113150
return paramStarts
114151
.map((paramStart, index) => signatureParameter.substring(paramStart, paramStops[index] + 1))
115-
.map(parameter => {
116-
return new vscode.ParameterInformation(parameter);
117-
});
152+
.map(parameter => new vscode.ParameterInformation(parameter));
118153
}

0 commit comments

Comments
 (0)