Skip to content

Commit f97bb60

Browse files
Initial work on classified quick info.
1 parent 80bab05 commit f97bb60

File tree

3 files changed

+214
-24
lines changed

3 files changed

+214
-24
lines changed

src/compiler/checker.ts

Lines changed: 143 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ module ts {
2323
return undefined;
2424
}
2525

26+
interface SymbolWriter {
27+
write(text: string, kind: SymbolDisplayPartKind, symbol: Symbol): void;
28+
displayPartKind(symbol: Symbol): SymbolDisplayPartKind;
29+
clear(): void;
30+
}
31+
32+
interface DisplayPartsSymbolWriter extends SymbolWriter {
33+
displayParts(): SymbolDisplayPart[];
34+
}
35+
36+
interface StringSymbolWriter extends SymbolWriter {
37+
string(): string;
38+
}
39+
2640
/// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
2741
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
2842
/// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors.
@@ -62,7 +76,9 @@ module ts {
6276
getTypeOfNode: getTypeOfNode,
6377
getApparentType: getApparentType,
6478
typeToString: typeToString,
79+
typeToDisplayParts: undefined,
6580
symbolToString: symbolToString,
81+
symbolToDisplayParts: symbolToDisplayParts,
6682
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType,
6783
getRootSymbol: getRootSymbol,
6884
getContextualType: getContextualType,
@@ -895,51 +911,154 @@ module ts {
895911
{ accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: firstIdentifierName };
896912
}
897913

914+
var displayPartWriters: DisplayPartsSymbolWriter[] = [];
915+
var stringWriters: StringSymbolWriter[] = [];
916+
917+
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
918+
var flags = symbol.flags;
919+
920+
if (flags & SymbolFlags.Variable) {
921+
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter
922+
? SymbolDisplayPartKind.ParameterName
923+
: SymbolDisplayPartKind.LocalName;
924+
}
925+
else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.PropertyName; }
926+
else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.EnumMemberName; }
927+
else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.FunctionName; }
928+
else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.ClassName; }
929+
else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.InterfaceName; }
930+
else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.EnumName; }
931+
else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.ModuleName; }
932+
else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.MethodName; }
933+
else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.TypeParameterName; }
934+
935+
return SymbolDisplayPartKind.Text;
936+
}
937+
938+
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
939+
if (displayPartWriters.length == 0) {
940+
var displayParts: SymbolDisplayPart[] = [];
941+
return {
942+
displayParts: () => displayParts,
943+
write: (text, kind, symbol) => displayParts.push({ text: text, kind: kind, symbol: symbol }),
944+
clear: () => displayParts = [],
945+
displayPartKind: displayPartKind
946+
};
947+
}
948+
949+
return displayPartWriters.pop();
950+
}
951+
952+
function getStringWriter(): StringSymbolWriter {
953+
if (stringWriters.length == 0) {
954+
var str = "";
955+
956+
return {
957+
string: () => str,
958+
write: text => str += text,
959+
clear: () => str = "",
960+
displayPartKind: (symbol: Symbol): SymbolDisplayPartKind => undefined
961+
};
962+
}
963+
964+
return stringWriters.pop();
965+
}
966+
967+
function releaseDisplayPartWriter(writer: DisplayPartsSymbolWriter) {
968+
writer.clear();
969+
displayPartWriters.push(writer);
970+
}
971+
972+
function releaseStringWriter(writer: StringSymbolWriter) {
973+
writer.clear()
974+
stringWriters.push(writer);
975+
}
976+
977+
function symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[] {
978+
var writer = getDisplayPartWriter();
979+
writeSymbol(symbol, enclosingDeclaration, meaning, writer);
980+
981+
var result = writer.displayParts();
982+
releaseDisplayPartWriter(writer);
983+
984+
return result;
985+
}
986+
987+
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string {
988+
var writer = getStringWriter();
989+
writeSymbol(symbol, enclosingDeclaration, meaning, writer);
990+
991+
var result = writer.string();
992+
releaseStringWriter(writer);
993+
994+
return result;
995+
}
996+
898997
// Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
899998
// Meaning needs to be specified if the enclosing declaration is given
900-
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
901-
function getSymbolName(symbol: Symbol) {
999+
function writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: SymbolWriter): void {
1000+
function writeSymbolName(symbol: Symbol): void {
9021001
if (symbol.declarations && symbol.declarations.length > 0) {
9031002
var declaration = symbol.declarations[0];
9041003
if (declaration.name) {
905-
return identifierToString(declaration.name);
1004+
writer.write(identifierToString(declaration.name), writer.displayPartKind(symbol), symbol);
1005+
return;
9061006
}
9071007
}
908-
return symbol.name;
1008+
1009+
writer.write(symbol.name, writer.displayPartKind(symbol), symbol);
9091010
}
9101011

911-
// Get qualified name
912-
if (enclosingDeclaration &&
913-
// TypeParameters do not need qualification
914-
!(symbol.flags & SymbolFlags.TypeParameter)) {
915-
var symbolName: string;
916-
while (symbol) {
917-
var isFirstName = !symbolName;
1012+
var needsDot = false;
1013+
function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void {
1014+
if (symbol) {
9181015
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning);
9191016

920-
var currentSymbolName: string;
1017+
if (!accessibleSymbolChain ||
1018+
needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
1019+
1020+
// Go up and add our parent.
1021+
walkSymbol(
1022+
getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol),
1023+
getQualifiedLeftMeaning(meaning));
1024+
}
1025+
9211026
if (accessibleSymbolChain) {
922-
currentSymbolName = ts.map(accessibleSymbolChain, accessibleSymbol => getSymbolName(accessibleSymbol)).join(".");
1027+
for (var i = 0, n = accessibleSymbolChain.length; i < n; i++) {
1028+
if (needsDot) {
1029+
writer.write(".", SymbolDisplayPartKind.Punctuation, /*symbol:*/ undefined);
1030+
}
1031+
1032+
writeSymbolName(accessibleSymbolChain[i]);
1033+
needsDot = true;
1034+
}
9231035
}
9241036
else {
9251037
// If we didn't find accessible symbol chain for this symbol, break if this is external module
926-
if (!isFirstName && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
927-
break;
1038+
if (!needsDot && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
1039+
return;
9281040
}
929-
currentSymbolName = getSymbolName(symbol);
930-
}
931-
symbolName = currentSymbolName + (isFirstName ? "" : ("." + symbolName));
932-
if (accessibleSymbolChain && !needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
933-
break;
1041+
1042+
if (needsDot) {
1043+
writer.write(".", SymbolDisplayPartKind.Punctuation, /*symbol:*/ undefined);
1044+
}
1045+
1046+
writeSymbolName(symbol);
1047+
needsDot = true;
9341048
}
935-
symbol = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
936-
meaning = getQualifiedLeftMeaning(meaning);
9371049
}
1050+
}
1051+
1052+
// Get qualified name
1053+
if (enclosingDeclaration &&
1054+
// TypeParameters do not need qualification
1055+
!(symbol.flags & SymbolFlags.TypeParameter)) {
9381056

939-
return symbolName;
1057+
walkSymbol(symbol, meaning);
1058+
return;
9401059
}
9411060

942-
return getSymbolName(symbol);
1061+
return writeSymbolName(symbol);
9431062
}
9441063

9451064
function writeSymbolToTextWriter(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter) {

src/compiler/types.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,8 @@ module ts {
638638
getApparentType(type: Type): ApparentType;
639639
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
640640
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
641+
typeToDisplayParts(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[];
642+
symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[];
641643
getFullyQualifiedName(symbol: Symbol): string;
642644
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
643645
getRootSymbol(symbol: Symbol): Symbol;
@@ -1169,6 +1171,42 @@ module ts {
11691171
verticalTab = 0x0B, // \v
11701172
}
11711173

1174+
export class SymbolDisplayPart {
1175+
constructor(public text: string,
1176+
public kind: SymbolDisplayPartKind,
1177+
public symbol: Symbol) {
1178+
}
1179+
}
1180+
1181+
export enum SymbolDisplayPartKind {
1182+
AliasName,
1183+
ClassName,
1184+
EnumName,
1185+
EventName,
1186+
FieldName,
1187+
InterfaceName,
1188+
Keyword,
1189+
LabelName,
1190+
LineBreak,
1191+
NumericLiteral,
1192+
StringLiteral,
1193+
LocalName,
1194+
MethodName,
1195+
ModuleName,
1196+
NamespaceName,
1197+
Operator,
1198+
ParameterName,
1199+
PropertyName,
1200+
Punctuation,
1201+
Space,
1202+
AnonymousTypeIndicator,
1203+
Text,
1204+
TypeParameterName,
1205+
EnumMemberName,
1206+
FunctionName,
1207+
RegularExpressionLiteral,
1208+
}
1209+
11721210
export interface CancellationToken {
11731211
isCancellationRequested(): boolean;
11741212
}

src/services/services.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ module ts {
495495
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails;
496496

497497
getTypeAtPosition(fileName: string, position: number): TypeInfo;
498+
getQuickInfo(fileName: string, position: number): SymbolDisplayPart[];
498499

499500
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TypeScript.TextSpan;
500501

@@ -652,6 +653,14 @@ module ts {
652653
text: string;
653654
}
654655

656+
export class QuickInfo {
657+
constructor(public kind: string,
658+
public kindModifiers: string,
659+
public textSpan: TypeScript.TextSpan,
660+
public displayParts: SymbolDisplayPart[]) {
661+
}
662+
}
663+
655664
export class TypeInfo {
656665
constructor(
657666
public memberName: TypeScript.MemberName,
@@ -2212,6 +2221,29 @@ module ts {
22122221
}
22132222

22142223
/// QuickInfo
2224+
function getQuickInfo(fileName: string, position: number): SymbolDisplayPart[] {
2225+
synchronizeHostData();
2226+
2227+
fileName = TypeScript.switchToForwardSlashes(fileName);
2228+
var sourceFile = getSourceFile(fileName);
2229+
var node = getNodeAtPosition(sourceFile, position);
2230+
if (!node) {
2231+
return undefined;
2232+
}
2233+
2234+
var symbol = typeInfoResolver.getSymbolInfo(node);
2235+
return symbol ? typeInfoResolver.symbolToDisplayParts(symbol) : [];
2236+
//var type = symbol && typeInfoResolver.getTypeOfSymbol(symbol);
2237+
//if (type) {
2238+
// return new TypeInfo(
2239+
// new TypeScript.MemberNameString(typeInfoResolver.typeToString(type)),
2240+
// "", typeInfoResolver.symbolToString(symbol, getContainerNode(node)),
2241+
// getSymbolKind(symbol), TypeScript.TextSpan.fromBounds(node.pos, node.end));
2242+
//}
2243+
2244+
//return undefined;
2245+
}
2246+
22152247
function getTypeAtPosition(fileName: string, position: number): TypeInfo {
22162248
synchronizeHostData();
22172249

@@ -4026,6 +4058,7 @@ module ts {
40264058
getCompletionsAtPosition: getCompletionsAtPosition,
40274059
getCompletionEntryDetails: getCompletionEntryDetails,
40284060
getTypeAtPosition: getTypeAtPosition,
4061+
getQuickInfo: getQuickInfo,
40294062
getSignatureHelpItems: (filename, position): SignatureHelpItems => null,
40304063
getSignatureHelpCurrentArgumentState: (fileName, position, applicableSpanStart): SignatureHelpState => null,
40314064
getDefinitionAtPosition: getDefinitionAtPosition,

0 commit comments

Comments
 (0)