Implemented support for trigger characters in signature help.

This commit is contained in:
Daniel Rosenwasser
2018-06-12 15:48:40 -07:00
parent 61fb222cd2
commit 5e3c96bb9a
16 changed files with 109 additions and 56 deletions
+28 -21
View File
@@ -1435,16 +1435,15 @@ Actual: ${stringify(fullActual)}`);
}
}
public verifyNoSignatureHelp(markers: ReadonlyArray<string>) {
public verifyNoSignatureHelp(triggerCharacter: ts.SignatureHelpTriggerCharacter | undefined, markers: ReadonlyArray<string>) {
if (markers.length) {
for (const marker of markers) {
this.goToMarker(marker);
this.verifyNoSignatureHelp(ts.emptyArray);
this.verifyNoSignatureHelp(triggerCharacter, ts.emptyArray);
}
return;
}
const actual = this.getSignatureHelp();
const actual = this.getSignatureHelp({ triggerCharacter });
if (actual) {
this.raiseError(`Expected no signature help, but got "${stringify(actual)}"`);
}
@@ -1465,7 +1464,7 @@ Actual: ${stringify(fullActual)}`);
}
private verifySignatureHelpWorker(options: FourSlashInterface.VerifySignatureHelpOptions) {
const help = this.getSignatureHelp()!;
const help = this.getSignatureHelp({ triggerCharacter: options.triggerCharacter })!;
const selectedItem = help.items[help.selectedItemIndex];
// Argument index may exceed number of parameters
const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined;
@@ -1507,6 +1506,7 @@ Actual: ${stringify(fullActual)}`);
const allKeys: ReadonlyArray<keyof FourSlashInterface.VerifySignatureHelpOptions> = [
"marker",
"triggerCharacter",
"overloadsCount",
"docComment",
"text",
@@ -1733,7 +1733,7 @@ Actual: ${stringify(fullActual)}`);
}
public printCurrentParameterHelp() {
const help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
const help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, /*options*/ undefined);
Harness.IO.log(stringify(help));
}
@@ -1774,12 +1774,14 @@ Actual: ${stringify(fullActual)}`);
}
public printCurrentSignatureHelp() {
const help = this.getSignatureHelp()!;
const help = this.getSignatureHelp(ts.emptyOptions)!;
Harness.IO.log(stringify(help.items[help.selectedItemIndex]));
}
private getSignatureHelp(): ts.SignatureHelpItems | undefined {
return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
private getSignatureHelp({ triggerCharacter }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined {
return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, {
triggerCharacter
});
}
public printCompletionListMembers(preferences: ts.UserPreferences | undefined) {
@@ -1875,13 +1877,13 @@ Actual: ${stringify(fullActual)}`);
offset++;
if (highFidelity) {
if (ch === "(" || ch === ",") {
if (ch === "(" || ch === "," || ch === "<") {
/* Signature help*/
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset);
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset, { triggerCharacter: ch });
}
else if (prevChar === " " && /A-Za-z_/.test(ch)) {
/* Completions */
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, ts.defaultPreferences);
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, ts.emptyOptions);
}
if (i % checkCadence === 0) {
@@ -2514,7 +2516,7 @@ Actual: ${stringify(fullActual)}`);
`Expected '${fixId}'. Available action ids: ${ts.mapDefined(this.getCodeFixes(this.activeFile.fileName), a => a.fixId)}`);
ts.Debug.assertEqual(fixWithId!.fixAllDescription, fixAllDescription);
const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.defaultPreferences);
const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.emptyOptions);
assert.deepEqual<ReadonlyArray<{}> | undefined>(commands, expectedCommands);
assert(changes.every(c => c.fileName === this.activeFile.fileName), "TODO: support testing codefixes that touch multiple files");
this.applyChanges(changes);
@@ -2594,7 +2596,7 @@ Actual: ${stringify(fullActual)}`);
* Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found.
* @param fileName Path to file where error should be retrieved from.
*/
private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.defaultPreferences): ts.CodeFixAction[] {
private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.emptyOptions): ts.CodeFixAction[] {
const diagnosticsForCodeFix = this.getDiagnostics(fileName, /*includeSuggestions*/ true).map(diagnostic => ({
start: diagnostic.start,
length: diagnostic.length,
@@ -3072,7 +3074,7 @@ Actual: ${stringify(fullActual)}`);
this.raiseError(`Expected action description to be ${JSON.stringify(actionDescription)}, got: ${JSON.stringify(action.description)}`);
}
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName, ts.defaultPreferences)!;
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName, ts.emptyOptions)!;
for (const edit of editInfo.edits) {
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
}
@@ -3124,7 +3126,7 @@ Actual: ${stringify(fullActual)}`);
const action = ts.first(refactor.actions);
assert(action.name === "Move to a new file" && action.description === "Move to a new file");
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.defaultPreferences)!;
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!;
this.testNewFileContents(editInfo.edits, options.newFileContents);
}
@@ -3162,14 +3164,14 @@ Actual: ${stringify(fullActual)}`);
formattingOptions = formattingOptions || this.formatCodeSettings;
const markerPos = this.getMarkerByName(markerName).position;
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, markerPos, ts.defaultPreferences);
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, markerPos, ts.emptyOptions);
const applicableRefactorToApply = ts.find(applicableRefactors, refactor => refactor.name === refactorNameToApply);
if (!applicableRefactorToApply) {
this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`);
}
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName, ts.defaultPreferences)!;
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName, ts.emptyOptions)!;
for (const edit of editInfo.edits) {
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
@@ -3358,11 +3360,11 @@ Actual: ${stringify(fullActual)}`);
}
public getEditsForFileRename(options: FourSlashInterface.GetEditsForFileRenameOptions): void {
const changes = this.languageService.getEditsForFileRename(options.oldPath, options.newPath, this.formatCodeSettings, ts.defaultPreferences);
const changes = this.languageService.getEditsForFileRename(options.oldPath, options.newPath, this.formatCodeSettings, ts.emptyOptions);
this.testNewFileContents(changes, options.newFileContents);
}
private getApplicableRefactors(positionOrRange: number | ts.TextRange, preferences = ts.defaultPreferences): ReadonlyArray<ts.ApplicableRefactorInfo> {
private getApplicableRefactors(positionOrRange: number | ts.TextRange, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
return this.languageService.getApplicableRefactors(this.activeFile.fileName, positionOrRange, preferences) || ts.emptyArray;
}
}
@@ -4038,7 +4040,11 @@ namespace FourSlashInterface {
}
public noSignatureHelp(...markers: string[]): void {
this.state.verifyNoSignatureHelp(markers);
this.state.verifyNoSignatureHelp(/*triggerCharacter*/ undefined, markers);
}
public noSignatureHelpForTriggerCharacter(triggerCharacter: ts.SignatureHelpTriggerCharacter, ...markers: string[]): void {
this.state.verifyNoSignatureHelp(triggerCharacter, markers);
}
public signatureHelp(...options: VerifySignatureHelpOptions[]): void {
@@ -4765,6 +4771,7 @@ namespace FourSlashInterface {
readonly isVariadic?: boolean;
/** @default ts.emptyArray */
readonly tags?: ReadonlyArray<ts.JSDocTagInfo>;
readonly triggerCharacter?: ts.SignatureHelpTriggerCharacter;
}
export type ArrayOrSingle<T> = T | ReadonlyArray<T>;
+2 -2
View File
@@ -434,8 +434,8 @@ namespace Harness.LanguageService {
getBreakpointStatementAtPosition(fileName: string, position: number): ts.TextSpan {
return unwrapJSONCallResult(this.shim.getBreakpointStatementAtPosition(fileName, position));
}
getSignatureHelpItems(fileName: string, position: number): ts.SignatureHelpItems {
return unwrapJSONCallResult(this.shim.getSignatureHelpItems(fileName, position));
getSignatureHelpItems(fileName: string, position: number, options: ts.SignatureHelpItemsOptions | undefined): ts.SignatureHelpItems {
return unwrapJSONCallResult(this.shim.getSignatureHelpItems(fileName, position, options));
}
getRenameInfo(fileName: string, position: number): ts.RenameInfo {
return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position));
+1 -1
View File
@@ -471,7 +471,7 @@ namespace ts.server {
this.hostConfiguration = {
formatCodeOptions: getDefaultFormatCodeSettings(this.host),
preferences: defaultPreferences,
preferences: emptyOptions,
hostInfo: "Unknown host",
extraFileExtensions: []
};
+11
View File
@@ -1787,6 +1787,10 @@ namespace ts.server.protocol {
* Optional prefix to apply to possible completions.
*/
prefix?: string;
/**
* Character that was responsible for triggering completion.
* Should be `undefined` if a user manually requested completion.
*/
triggerCharacter?: CompletionsTriggerCharacter;
/**
* @deprecated Use UserPreferences.includeCompletionsForModuleExports
@@ -2048,10 +2052,17 @@ namespace ts.server.protocol {
argumentCount: number;
}
export type SignatureHelpTriggerCharacter = "," | "(" | "<";
/**
* Arguments of a signature help request.
*/
export interface SignatureHelpRequestArgs extends FileLocationRequestArgs {
/**
* Character that was responsible for triggering signature help.
* Should be `undefined` if a user manually requested completion.
*/
triggerCharacter?: SignatureHelpTriggerCharacter;
}
/**
+1 -1
View File
@@ -419,7 +419,7 @@ namespace ts.server {
if (preferences) {
if (!this.preferences) {
this.preferences = defaultPreferences;
this.preferences = emptyOptions;
}
this.preferences = { ...this.preferences, ...preferences };
}
+1 -1
View File
@@ -1398,7 +1398,7 @@ namespace ts.server {
const { file, project } = this.getFileAndProject(args);
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
const position = this.getPosition(args, scriptInfo);
const helpItems = project.getLanguageService().getSignatureHelpItems(file, position);
const helpItems = project.getLanguageService().getSignatureHelpItems(file, position, args);
if (!helpItems) {
return undefined;
}
+10 -10
View File
@@ -1425,7 +1425,7 @@ namespace ts {
return [...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken)];
}
function getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions = defaultPreferences): CompletionInfo | undefined {
function getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions = emptyOptions): CompletionInfo | undefined {
// Convert from deprecated options names to new names
const fullPreferences: UserPreferences = {
...identity<UserPreferences>(options), // avoid excess property check
@@ -1443,7 +1443,7 @@ namespace ts {
options.triggerCharacter);
}
function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions: FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences = defaultPreferences): CompletionEntryDetails | undefined {
function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions: FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences = emptyOptions): CompletionEntryDetails | undefined {
synchronizeHostData();
return Completions.getCompletionEntryDetails(
program,
@@ -1769,12 +1769,12 @@ namespace ts {
/**
* This is a semantic operation.
*/
function getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems | undefined {
function getSignatureHelpItems(fileName: string, position: number, { triggerCharacter }: SignatureHelpItemsOptions = emptyOptions): SignatureHelpItems | undefined {
synchronizeHostData();
const sourceFile = getValidSourceFile(fileName);
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken);
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, triggerCharacter, cancellationToken);
}
/// Syntactic features
@@ -1953,7 +1953,7 @@ namespace ts {
return [];
}
function getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences = defaultPreferences): ReadonlyArray<CodeFixAction> {
function getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): ReadonlyArray<CodeFixAction> {
synchronizeHostData();
const sourceFile = getValidSourceFile(fileName);
const span = createTextSpanFromBounds(start, end);
@@ -1965,7 +1965,7 @@ namespace ts {
});
}
function getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences = defaultPreferences): CombinedCodeActions {
function getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): CombinedCodeActions {
synchronizeHostData();
Debug.assert(scope.type === "file");
const sourceFile = getValidSourceFile(scope.fileName);
@@ -1974,7 +1974,7 @@ namespace ts {
return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext, preferences });
}
function organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences = defaultPreferences): ReadonlyArray<FileTextChanges> {
function organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): ReadonlyArray<FileTextChanges> {
synchronizeHostData();
Debug.assert(scope.type === "file");
const sourceFile = getValidSourceFile(scope.fileName);
@@ -1983,7 +1983,7 @@ namespace ts {
return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences);
}
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = defaultPreferences): ReadonlyArray<FileTextChanges> {
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): ReadonlyArray<FileTextChanges> {
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences);
}
@@ -2233,7 +2233,7 @@ namespace ts {
};
}
function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = defaultPreferences): ApplicableRefactorInfo[] {
function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions): ApplicableRefactorInfo[] {
synchronizeHostData();
const file = getValidSourceFile(fileName);
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences));
@@ -2245,7 +2245,7 @@ namespace ts {
positionOrRange: number | TextRange,
refactorName: string,
actionName: string,
preferences: UserPreferences = defaultPreferences,
preferences: UserPreferences = emptyOptions,
): RefactorEditInfo | undefined {
synchronizeHostData();
const file = getValidSourceFile(fileName);
+3 -3
View File
@@ -158,7 +158,7 @@ namespace ts {
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string;
getBreakpointStatementAtPosition(fileName: string, position: number): string;
getSignatureHelpItems(fileName: string, position: number): string;
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): string;
/**
* Returns a JSON-encoded value of the type:
@@ -769,10 +769,10 @@ namespace ts {
/// SIGNATUREHELP
public getSignatureHelpItems(fileName: string, position: number): string {
public getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): string {
return this.forwardJSONCall(
`getSignatureHelpItems('${fileName}', ${position})`,
() => this.languageService.getSignatureHelpItems(fileName, position)
() => this.languageService.getSignatureHelpItems(fileName, position, options)
);
}
+6 -1
View File
@@ -19,7 +19,7 @@ namespace ts.SignatureHelp {
argumentCount: number;
}
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, triggerCharacter: SignatureHelpTriggerCharacter | undefined, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
const typeChecker = program.getTypeChecker();
// Decide whether to show signature help
@@ -29,6 +29,11 @@ namespace ts.SignatureHelp {
return undefined;
}
// In the middle of a string, don't provide signature help unless the user explicitly requested it.
if (triggerCharacter !== undefined && isInString(sourceFile, position, startingToken)) {
return undefined;
}
const argumentInfo = getContainingArgumentInfo(startingToken, position, sourceFile);
if (!argumentInfo) return undefined;
+16 -3
View File
@@ -242,7 +242,7 @@ namespace ts {
readonly allowTextChangesInNewFiles?: boolean;
}
/* @internal */
export const defaultPreferences: UserPreferences = {};
export const emptyOptions = {};
//
// Public services of a language service instance associated
@@ -292,7 +292,7 @@ namespace ts {
getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems | undefined;
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
getRenameInfo(fileName: string, position: number): RenameInfo;
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] | undefined;
@@ -371,7 +371,10 @@ namespace ts {
export type CompletionsTriggerCharacter = "." | '"' | "'" | "`" | "/" | "@" | "<";
export interface GetCompletionsAtPositionOptions extends UserPreferences {
/** If the editor is asking for completions because a certain character was typed, and not because the user explicitly requested them, this should be set. */
/**
* If the editor is asking for completions because a certain character was typed
* (as opposed to when the user explicitly requested them) this should be set.
*/
triggerCharacter?: CompletionsTriggerCharacter;
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
@@ -379,6 +382,16 @@ namespace ts {
includeInsertTextCompletions?: boolean;
}
export type SignatureHelpTriggerCharacter = "," | "(" | "<";
export interface SignatureHelpItemsOptions {
/**
* If the editor is asking for signature help because a certain character was typed
* (as opposed to when the user explicitly requested them) this should be set.
*/
triggerCharacter?: SignatureHelpTriggerCharacter;
}
export interface ApplyCodeActionCommandResult {
successMessage: string;
}
@@ -8,7 +8,7 @@ namespace ts {
`;
it("can cancel signature help mid-request", () => {
verifyOperationCancelledAfter(file, 4, service => // Two calls are top-level in services, one is the root type, and the second should be for the parameter type
service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"))!,
service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"), emptyOptions)!,
r => assert.exists(r.items[0])
);
});
@@ -124,7 +124,7 @@ namespace ts {
endPosition: selectionRange.end,
host: notImplementedHost,
formatContext: formatting.getFormatContext(testFormatOptions),
preferences: defaultPreferences,
preferences: emptyOptions,
};
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
@@ -188,7 +188,7 @@ namespace ts {
endPosition: selectionRange.end,
host: notImplementedHost,
formatContext: formatting.getFormatContext(testFormatOptions),
preferences: defaultPreferences,
preferences: emptyOptions,
};
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
+2 -2
View File
@@ -270,7 +270,7 @@ export const Other = 1;
content: "function F() { }",
};
const languageService = makeLanguageService(testFile);
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatOptions, defaultPreferences);
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatOptions, emptyOptions);
assert.isEmpty(changes);
});
@@ -741,7 +741,7 @@ export * from "lib";
function runBaseline(baselinePath: string, testFile: TestFSWithWatch.File, ...otherFiles: TestFSWithWatch.File[]) {
const { path: testPath, content: testContent } = testFile;
const languageService = makeLanguageService(testFile, ...otherFiles);
const changes = languageService.organizeImports({ type: "file", fileName: testPath }, testFormatOptions, defaultPreferences);
const changes = languageService.organizeImports({ type: "file", fileName: testPath }, testFormatOptions, emptyOptions);
assert.equal(changes.length, 1);
assert.equal(changes[0].fileName, testPath);
@@ -1497,13 +1497,13 @@ namespace ts.projectSystem {
service.checkNumberOfProjects({ externalProjects: 1 });
checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]);
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, defaultPreferences)!;
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, emptyOptions)!;
// should contain completions for string
assert.isTrue(completions1.entries.some(e => e.name === "charAt"), "should contain 'charAt'");
assert.isFalse(completions1.entries.some(e => e.name === "toExponential"), "should not contain 'toExponential'");
service.closeClientFile(f2.path);
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, defaultPreferences)!;
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, emptyOptions)!;
// should contain completions for string
assert.isFalse(completions2.entries.some(e => e.name === "charAt"), "should not contain 'charAt'");
assert.isTrue(completions2.entries.some(e => e.name === "toExponential"), "should contain 'toExponential'");
@@ -1529,11 +1529,11 @@ namespace ts.projectSystem {
service.checkNumberOfProjects({ externalProjects: 1 });
checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]);
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, defaultPreferences)!;
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, emptyOptions)!;
assert.isTrue(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'");
service.closeClientFile(f2.path);
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, defaultPreferences)!;
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, emptyOptions)!;
assert.isFalse(completions2.entries.some(e => e.name === "somelongname"), "should not contain 'somelongname'");
const sf2 = service.externalProjects[0].getLanguageService().getProgram()!.getSourceFile(f2.path)!;
assert.equal(sf2.text, "");
@@ -2173,7 +2173,7 @@ namespace ts.projectSystem {
// Check identifiers defined in HTML content are available in .ts file
const project = configuredProjectAt(projectService, 0);
let completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 1, defaultPreferences);
let completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 1, emptyOptions);
assert(completions && completions.entries[0].name === "hello", `expected entry hello to be in completion list`);
// Close HTML file
@@ -2187,7 +2187,7 @@ namespace ts.projectSystem {
checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]);
// Check identifiers defined in HTML content are not available in .ts file
completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5, defaultPreferences);
completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5, emptyOptions);
assert(completions && completions.entries[0].name !== "hello", `unexpected hello entry in completion list`);
});
@@ -8613,7 +8613,7 @@ new C();`
Debug.assert(!!project.resolveModuleNames);
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatOptions, defaultPreferences);
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatOptions, emptyOptions);
assert.deepEqual<ReadonlyArray<FileTextChanges>>(edits, [{
fileName: "/user.ts",
textChanges: [{
+3 -1
View File
@@ -262,7 +262,8 @@ declare namespace FourSlashInterface {
rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] });
findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]): void;
noSignatureHelp(...markers: string[]): void;
signatureHelp(...options: VerifySignatureHelpOptions[]): void;
noSignatureHelpForTriggerCharacter(triggerCharacter: string, ...markers: string[]): void
signatureHelp(...options: VerifySignatureHelpOptions[], ): void;
// Checks that there are no compile errors.
noErrors(): void;
numberOfErrorsInCurrentFile(expected: number): void;
@@ -560,6 +561,7 @@ declare namespace FourSlashInterface {
argumentCount?: number;
isVariadic?: boolean;
tags?: ReadonlyArray<JSDocTagInfo>;
triggerCharacter?: string;
}
interface JSDocTagInfo {
@@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
////function foo<T>(x: T): T {
//// throw null;
////}
////
////foo("/**/")
goTo.marker();
for (const triggerCharacter of ["<", "(", ","]) {
edit.insert(triggerCharacter);
verify.noSignatureHelpForTriggerCharacter(triggerCharacter);
edit.backspace();
}
verify.signatureHelp({ triggerCharacter: undefined });