Skip to content

Commit be4de7e

Browse files
WIP: Improve hover text for common kinds of symbols.
1 parent c8ba874 commit be4de7e

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

src/FileIndexer.ts

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,7 @@ export class FileIndexer {
142142
new lsiftyped.SymbolInformation({
143143
symbol: symbol.value,
144144
documentation: [
145-
'```ts\n' +
146-
this.checker.typeToString(this.checker.getTypeAtLocation(node)) +
147-
'\n```',
145+
'```ts\n' + this.signatureForDocumentation(node, sym) + '\n```',
148146
ts.displayPartsToString(sym.getDocumentationComment(this.checker)),
149147
],
150148
})
@@ -322,6 +320,58 @@ export class FileIndexer {
322320
}
323321
return undefined
324322
}
323+
324+
private signatureForDocumentation(
325+
node: ts.Node,
326+
sym: ts.Symbol
327+
): string {
328+
const kind = scriptElementKind(node, sym)
329+
const type = (): string => this.checker.typeToString(this.checker.getTypeAtLocation(node))
330+
switch (kind) {
331+
case ts.ScriptElementKind.localVariableElement:
332+
case ts.ScriptElementKind.variableElement:
333+
return 'var ' + node.getText() + ': ' + type()
334+
case ts.ScriptElementKind.memberVariableElement:
335+
return '(property) ' + node.getText() + ': ' + type()
336+
case ts.ScriptElementKind.parameterElement:
337+
return '(parameter) ' + node.getText() + ': ' + type()
338+
case ts.ScriptElementKind.constElement:
339+
return 'const ' + node.getText() + ': ' + type()
340+
case ts.ScriptElementKind.letElement:
341+
return 'let ' + node.getText() + ': ' + type()
342+
case ts.ScriptElementKind.alias:
343+
return 'type ' + node.getText()
344+
case ts.ScriptElementKind.classElement:
345+
case ts.ScriptElementKind.localClassElement:
346+
return 'class ' + node.getText()
347+
case ts.ScriptElementKind.interfaceElement:
348+
return 'interface ' + node.getText()
349+
case ts.ScriptElementKind.enumElement:
350+
return 'enum ' + node.getText()
351+
case ts.ScriptElementKind.enumMemberElement: {
352+
let suffix = ''
353+
const declaration = sym.declarations?.[0]
354+
if (declaration && ts.isEnumMember(declaration)) {
355+
const constantValue = this.checker.getConstantValue(declaration)
356+
if (constantValue) {
357+
suffix = ' = ' + constantValue.toString()
358+
}
359+
}
360+
return '(enum member) ' + node.getText() + suffix
361+
}
362+
case ts.ScriptElementKind.functionElement:
363+
return 'function ' + node.getText() + type()
364+
case ts.ScriptElementKind.memberFunctionElement:
365+
return '(method) ' + node.getText() + type()
366+
case ts.ScriptElementKind.memberGetAccessorElement:
367+
return 'get ' + node.getText() + ': ' + type()
368+
case ts.ScriptElementKind.memberSetAccessorElement:
369+
return 'set ' + node.getText() + type()
370+
case ts.ScriptElementKind.constructorImplementationElement:
371+
return ''
372+
}
373+
return node.getText() + ': ' + type()
374+
}
325375
}
326376

327377
function isAnonymousContainerOfSymbols(node: ts.Node): boolean {
@@ -334,3 +384,56 @@ function isAnonymousContainerOfSymbols(node: ts.Node): boolean {
334384
ts.isVariableDeclarationList(node)
335385
)
336386
}
387+
388+
function scriptElementKind(
389+
node: ts.Node,
390+
sym: ts.Symbol
391+
): ts.ScriptElementKind {
392+
const flags = sym.getFlags()
393+
if (flags & ts.SymbolFlags.TypeAlias) {
394+
return ts.ScriptElementKind.alias
395+
}
396+
if (flags & ts.SymbolFlags.Class) {
397+
return ts.ScriptElementKind.classElement
398+
}
399+
if (flags & ts.SymbolFlags.Interface) {
400+
return ts.ScriptElementKind.interfaceElement
401+
}
402+
if (flags & ts.SymbolFlags.Enum) {
403+
return ts.ScriptElementKind.enumElement
404+
}
405+
if (flags & ts.SymbolFlags.EnumMember) {
406+
return ts.ScriptElementKind.enumMemberElement
407+
}
408+
if (flags & ts.SymbolFlags.Method) {
409+
return ts.ScriptElementKind.memberFunctionElement
410+
}
411+
if (flags & ts.SymbolFlags.GetAccessor) {
412+
return ts.ScriptElementKind.memberGetAccessorElement
413+
}
414+
if (flags & ts.SymbolFlags.SetAccessor) {
415+
return ts.ScriptElementKind.memberSetAccessorElement
416+
}
417+
if (flags & ts.SymbolFlags.Constructor) {
418+
return ts.ScriptElementKind.constructorImplementationElement
419+
}
420+
if (flags & ts.SymbolFlags.Function) {
421+
return ts.ScriptElementKind.functionElement
422+
}
423+
if (flags & ts.SymbolFlags.Variable) {
424+
if (ts_inline.isParameter(sym)) {
425+
return ts.ScriptElementKind.parameterElement
426+
}
427+
if (node.flags & ts.NodeFlags.Const) {
428+
return ts.ScriptElementKind.constElement
429+
}
430+
if (node.flags & ts.NodeFlags.Let) {
431+
return ts.ScriptElementKind.letElement
432+
}
433+
return ts.ScriptElementKind.variableElement
434+
}
435+
if (flags & ts.SymbolFlags.ClassMember) {
436+
return ts.ScriptElementKind.memberVariableElement
437+
}
438+
return ts.ScriptElementKind.unknown
439+
}

src/TypeScriptInternal.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,17 @@ function isVariableDeclarationInitializedToBareOrAccessedRequire(node: ts.Node):
3636
function isVariableDeclaration(node: ts.Node): node is ts.VariableDeclaration {
3737
return node.kind === ts.SyntaxKind.VariableDeclaration;
3838
}
39+
export function isParameter(sym: ts.Symbol): boolean {
40+
// based on isFirstDeclarationOfSymbolParameter
41+
const declaration = sym.declarations?.[0]
42+
return !!ts.findAncestor(declaration, (node: ts.Node): boolean | 'quit' =>
43+
ts.isParameter(node)
44+
? true
45+
: ts.isBindingElement(node) ||
46+
ts.isObjectBindingPattern(node) ||
47+
ts.isArrayBindingPattern(node)
48+
? false
49+
: 'quit'
50+
)
51+
}
52+

0 commit comments

Comments
 (0)