Skip to content

Commit 40a9734

Browse files
WIP: Improve hover text for common kinds of symbols.
1 parent 71505e4 commit 40a9734

File tree

2 files changed

+120
-1
lines changed

2 files changed

+120
-1
lines changed

src/FileIndexer.ts

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export class FileIndexer {
143143
): void {
144144
const documentation = [
145145
'```ts\n' +
146-
this.checker.typeToString(this.checker.getTypeAtLocation(node)) +
146+
this.signatureForDocumentation(node, sym) +
147147
'\n```',
148148
]
149149
const docstring = sym.getDocumentationComment(this.checker)
@@ -331,6 +331,58 @@ export class FileIndexer {
331331
}
332332
return undefined
333333
}
334+
335+
private signatureForDocumentation(
336+
node: ts.Node,
337+
sym: ts.Symbol
338+
): string {
339+
const kind = scriptElementKind(node, sym)
340+
const type = (): string => this.checker.typeToString(this.checker.getTypeAtLocation(node))
341+
switch (kind) {
342+
case ts.ScriptElementKind.localVariableElement:
343+
case ts.ScriptElementKind.variableElement:
344+
return 'var ' + node.getText() + ': ' + type()
345+
case ts.ScriptElementKind.memberVariableElement:
346+
return '(property) ' + node.getText() + ': ' + type()
347+
case ts.ScriptElementKind.parameterElement:
348+
return '(parameter) ' + node.getText() + ': ' + type()
349+
case ts.ScriptElementKind.constElement:
350+
return 'const ' + node.getText() + ': ' + type()
351+
case ts.ScriptElementKind.letElement:
352+
return 'let ' + node.getText() + ': ' + type()
353+
case ts.ScriptElementKind.alias:
354+
return 'type ' + node.getText()
355+
case ts.ScriptElementKind.classElement:
356+
case ts.ScriptElementKind.localClassElement:
357+
return 'class ' + node.getText()
358+
case ts.ScriptElementKind.interfaceElement:
359+
return 'interface ' + node.getText()
360+
case ts.ScriptElementKind.enumElement:
361+
return 'enum ' + node.getText()
362+
case ts.ScriptElementKind.enumMemberElement: {
363+
let suffix = ''
364+
const declaration = sym.declarations?.[0]
365+
if (declaration && ts.isEnumMember(declaration)) {
366+
const constantValue = this.checker.getConstantValue(declaration)
367+
if (constantValue) {
368+
suffix = ' = ' + constantValue.toString()
369+
}
370+
}
371+
return '(enum member) ' + node.getText() + suffix
372+
}
373+
case ts.ScriptElementKind.functionElement:
374+
return 'function ' + node.getText() + type()
375+
case ts.ScriptElementKind.memberFunctionElement:
376+
return '(method) ' + node.getText() + type()
377+
case ts.ScriptElementKind.memberGetAccessorElement:
378+
return 'get ' + node.getText() + ': ' + type()
379+
case ts.ScriptElementKind.memberSetAccessorElement:
380+
return 'set ' + node.getText() + type()
381+
case ts.ScriptElementKind.constructorImplementationElement:
382+
return ''
383+
}
384+
return node.getText() + ': ' + type()
385+
}
334386
}
335387

336388
function isAnonymousContainerOfSymbols(node: ts.Node): boolean {
@@ -343,3 +395,56 @@ function isAnonymousContainerOfSymbols(node: ts.Node): boolean {
343395
ts.isVariableDeclarationList(node)
344396
)
345397
}
398+
399+
function scriptElementKind(
400+
node: ts.Node,
401+
sym: ts.Symbol
402+
): ts.ScriptElementKind {
403+
const flags = sym.getFlags()
404+
if (flags & ts.SymbolFlags.TypeAlias) {
405+
return ts.ScriptElementKind.alias
406+
}
407+
if (flags & ts.SymbolFlags.Class) {
408+
return ts.ScriptElementKind.classElement
409+
}
410+
if (flags & ts.SymbolFlags.Interface) {
411+
return ts.ScriptElementKind.interfaceElement
412+
}
413+
if (flags & ts.SymbolFlags.Enum) {
414+
return ts.ScriptElementKind.enumElement
415+
}
416+
if (flags & ts.SymbolFlags.EnumMember) {
417+
return ts.ScriptElementKind.enumMemberElement
418+
}
419+
if (flags & ts.SymbolFlags.Method) {
420+
return ts.ScriptElementKind.memberFunctionElement
421+
}
422+
if (flags & ts.SymbolFlags.GetAccessor) {
423+
return ts.ScriptElementKind.memberGetAccessorElement
424+
}
425+
if (flags & ts.SymbolFlags.SetAccessor) {
426+
return ts.ScriptElementKind.memberSetAccessorElement
427+
}
428+
if (flags & ts.SymbolFlags.Constructor) {
429+
return ts.ScriptElementKind.constructorImplementationElement
430+
}
431+
if (flags & ts.SymbolFlags.Function) {
432+
return ts.ScriptElementKind.functionElement
433+
}
434+
if (flags & ts.SymbolFlags.Variable) {
435+
if (ts_inline.isParameter(sym)) {
436+
return ts.ScriptElementKind.parameterElement
437+
}
438+
if (node.flags & ts.NodeFlags.Const) {
439+
return ts.ScriptElementKind.constElement
440+
}
441+
if (node.flags & ts.NodeFlags.Let) {
442+
return ts.ScriptElementKind.letElement
443+
}
444+
return ts.ScriptElementKind.variableElement
445+
}
446+
if (flags & ts.SymbolFlags.ClassMember) {
447+
return ts.ScriptElementKind.memberVariableElement
448+
}
449+
return ts.ScriptElementKind.unknown
450+
}

src/TypeScriptInternal.ts

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

0 commit comments

Comments
 (0)