mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
WIP: snippet support on emitter, adding snippets in completions
This commit is contained in:
@@ -351,6 +351,10 @@ namespace ts {
|
||||
return formatEnum(kind, (ts as any).SyntaxKind, /*isFlags*/ false);
|
||||
}
|
||||
|
||||
export function formatSnippetKind(kind: SnippetKind | undefined): string {
|
||||
return formatEnum(kind, (ts as any).SnippetKind, /*isFlags*/ false);
|
||||
}
|
||||
|
||||
export function formatNodeFlags(flags: NodeFlags | undefined): string {
|
||||
return formatEnum(flags, (ts as any).NodeFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
+31
-1
@@ -1302,7 +1302,13 @@ namespace ts {
|
||||
currentParenthesizerRule = undefined;
|
||||
}
|
||||
|
||||
function pipelineEmitWithHintWorker(hint: EmitHint, node: Node): void {
|
||||
function pipelineEmitWithHintWorker(hint: EmitHint, node: Node, allowSnippets = true): void {
|
||||
if (allowSnippets) {
|
||||
const snippet = getSnippetElement(node);
|
||||
if (snippet) {
|
||||
return emitSnippetNode(hint, node, snippet);
|
||||
}
|
||||
}
|
||||
if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile));
|
||||
if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier));
|
||||
if (hint === EmitHint.JsxAttributeValue) return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true);
|
||||
@@ -1937,6 +1943,30 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Snippet Elements
|
||||
//
|
||||
|
||||
function emitSnippetNode(hint: EmitHint, node: Node, snippet: SnippetElement) {
|
||||
switch (snippet.kind) {
|
||||
case SnippetKind.Placeholder:
|
||||
return emitPlaceholder(hint, node, snippet);
|
||||
case SnippetKind.TabStop:
|
||||
return emitTabStop(snippet);
|
||||
}
|
||||
}
|
||||
|
||||
function emitPlaceholder(hint: EmitHint, node: Node, snippet: Placeholder) {
|
||||
// write(`\$\{${order}:${defaultText}\}`);
|
||||
write(`\$\{${snippet.order}:`);
|
||||
pipelineEmitWithHintWorker(hint, node, /*allowSnippets*/ false);
|
||||
write(`\}`);
|
||||
}
|
||||
|
||||
function emitTabStop(snippet: TabStop) {
|
||||
write(`\$${snippet.order}`);
|
||||
}
|
||||
|
||||
//
|
||||
// Identifiers
|
||||
//
|
||||
|
||||
@@ -256,6 +256,22 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SnippetElement of a node.
|
||||
*/
|
||||
export function getSnippetElement(node: Node): SnippetElement | undefined {
|
||||
return node.emitNode?.snippetElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SnippetElement of a node.
|
||||
*/
|
||||
export function setSnippetElement<T extends Node>(node: T, snippet: SnippetElement): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.snippetElement = snippet;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function ignoreSourceNewlines<T extends Node>(node: T): T {
|
||||
getOrCreateEmitNode(node).flags |= EmitFlags.IgnoreSourceNewlines;
|
||||
|
||||
@@ -6740,16 +6740,14 @@ namespace ts {
|
||||
snippetElement?: SnippetElement; // Snippet element of the node
|
||||
}
|
||||
|
||||
export interface SnippetElement {
|
||||
kind: SnippetKind;
|
||||
}
|
||||
export type SnippetElement = TabStop | Placeholder;
|
||||
|
||||
export interface TabStop extends SnippetElement {
|
||||
export interface TabStop {
|
||||
kind: SnippetKind.TabStop;
|
||||
order: number;
|
||||
}
|
||||
|
||||
export interface PlaceHolder extends SnippetElement {
|
||||
export interface Placeholder {
|
||||
kind: SnippetKind.Placeholder;
|
||||
order: number;
|
||||
}
|
||||
|
||||
@@ -3142,7 +3142,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function isKeyword(token: SyntaxKind): boolean {
|
||||
export function isKeyword(token: SyntaxKind): token is KeywordSyntaxKind {
|
||||
return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
|
||||
}
|
||||
|
||||
@@ -3327,7 +3327,7 @@ namespace ts {
|
||||
return node.escapedText === "push" || node.escapedText === "unshift";
|
||||
}
|
||||
|
||||
export function isParameterDeclaration(node: VariableLikeDeclaration) {
|
||||
export function isParameterDeclaration(node: VariableLikeDeclaration): node is ParameterDeclaration {
|
||||
const root = getRootDeclaration(node);
|
||||
return root.kind === SyntaxKind.Parameter;
|
||||
}
|
||||
|
||||
@@ -760,8 +760,11 @@ namespace ts.Completions {
|
||||
let body;
|
||||
if (preferences.includeCompletionsWithSnippetText) {
|
||||
isSnippet = true;
|
||||
const tabStopStatement = factory.createExpressionStatement(factory.createIdentifier("$1"));
|
||||
body = factory.createBlock([tabStopStatement], /* multiline */ true);
|
||||
// const tabStopStatement = factory.createExpressionStatement(factory.createIdentifier("$1"));
|
||||
// body = factory.createBlock([tabStopStatement], /* multiline */ true);
|
||||
const emptyStatement = factory.createExpressionStatement(factory.createIdentifier(""));
|
||||
setSnippetElement(emptyStatement, { kind: SnippetKind.TabStop, order: 0 });
|
||||
body = factory.createBlock([emptyStatement], /* multiline */ true);
|
||||
}
|
||||
else {
|
||||
body = factory.createBlock([], /* multiline */ true);
|
||||
@@ -813,6 +816,7 @@ namespace ts.Completions {
|
||||
concatenate([factory.createModifier(SyntaxKind.OverrideKeyword)], node.modifiers),
|
||||
);
|
||||
}
|
||||
addSnippets(node);
|
||||
completionNodes.push(node);
|
||||
},
|
||||
body);
|
||||
@@ -823,6 +827,32 @@ namespace ts.Completions {
|
||||
return { insertText, isSnippet };
|
||||
}
|
||||
|
||||
|
||||
function addSnippets(node: Node): void {
|
||||
let order = 1;
|
||||
addSnippetsWorker(node);
|
||||
|
||||
function addSnippetsWorker(node: Node) {
|
||||
if (isVariableLike(node) && isParameterDeclaration(node)) {
|
||||
// Placeholder
|
||||
setSnippetElement(node.name, { kind: SnippetKind.Placeholder, order });
|
||||
order += 1;
|
||||
if (node.type) {
|
||||
setSnippetElement(node.type, { kind: SnippetKind.Placeholder, order });
|
||||
order += 1;
|
||||
}
|
||||
}
|
||||
else if (isFunctionLikeDeclaration(node)) {
|
||||
if (node.type) {
|
||||
setSnippetElement(node.type, { kind: SnippetKind.Placeholder, order });
|
||||
order += 1;
|
||||
}
|
||||
}
|
||||
|
||||
forEachChild(node, addSnippetsWorker);
|
||||
}
|
||||
}
|
||||
|
||||
function originToCompletionEntryData(origin: SymbolOriginInfoExport): CompletionEntryData | undefined {
|
||||
return {
|
||||
exportName: origin.exportName,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* @internal */
|
||||
namespace ts.snippets {
|
||||
// interface SnippetWriter extends EmitTextWriter, PrintHandlers {}
|
||||
|
||||
// function createSnippetWriter(newLine: string): SnippetWriter {
|
||||
// const substituteNode = (hint: EmitHint, node: Node) => {
|
||||
// switch (hint) {
|
||||
// case EmitHint.IdentifierName:
|
||||
// // >> TODO: do escaping here
|
||||
// return node;
|
||||
// }
|
||||
// return node;
|
||||
// };
|
||||
|
||||
// const writer = createTextWriter(newLine);
|
||||
|
||||
|
||||
// return {
|
||||
// ...writer,
|
||||
// substituteNode,
|
||||
// };
|
||||
// }
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
"preProcess.ts",
|
||||
"rename.ts",
|
||||
"smartSelection.ts",
|
||||
"snippets.ts",
|
||||
"signatureHelp.ts",
|
||||
"inlayHints.ts",
|
||||
"sourcemaps.ts",
|
||||
|
||||
Reference in New Issue
Block a user