Merge pull request #24915 from Microsoft/triggerSignatureHelpIArdlyKnowSignatureHelp
Trigger characters in signature help
This commit is contained in:
commit
e13fd0c568
|
@ -1426,18 +1426,22 @@ Actual: ${stringify(fullActual)}`);
|
|||
}
|
||||
}
|
||||
|
||||
public verifyNoSignatureHelp(markers: ReadonlyArray<string>) {
|
||||
public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: ReadonlyArray<string>) {
|
||||
if (markers.length) {
|
||||
for (const marker of markers) {
|
||||
this.goToMarker(marker);
|
||||
this.verifyNoSignatureHelp(ts.emptyArray);
|
||||
this.verifySignatureHelpPresence(expectPresent, triggerReason, ts.emptyArray);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const actual = this.getSignatureHelp();
|
||||
if (actual) {
|
||||
this.raiseError(`Expected no signature help, but got "${stringify(actual)}"`);
|
||||
const actual = this.getSignatureHelp({ triggerReason });
|
||||
if (expectPresent !== !!actual) {
|
||||
if (actual) {
|
||||
this.raiseError(`Expected no signature help, but got "${stringify(actual)}"`);
|
||||
}
|
||||
else {
|
||||
this.raiseError("Expected signature help, but none was returned.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1456,7 +1460,7 @@ Actual: ${stringify(fullActual)}`);
|
|||
}
|
||||
|
||||
private verifySignatureHelpWorker(options: FourSlashInterface.VerifySignatureHelpOptions) {
|
||||
const help = this.getSignatureHelp()!;
|
||||
const help = this.getSignatureHelp({ triggerReason: options.triggerReason })!;
|
||||
const selectedItem = help.items[help.selectedItemIndex];
|
||||
// Argument index may exceed number of parameters
|
||||
const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined;
|
||||
|
@ -1498,6 +1502,7 @@ Actual: ${stringify(fullActual)}`);
|
|||
|
||||
const allKeys: ReadonlyArray<keyof FourSlashInterface.VerifySignatureHelpOptions> = [
|
||||
"marker",
|
||||
"triggerReason",
|
||||
"overloadsCount",
|
||||
"docComment",
|
||||
"text",
|
||||
|
@ -1724,7 +1729,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));
|
||||
}
|
||||
|
||||
|
@ -1765,12 +1770,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({ triggerReason }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined {
|
||||
return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, {
|
||||
triggerReason
|
||||
});
|
||||
}
|
||||
|
||||
public printCompletionListMembers(preferences: ts.UserPreferences | undefined) {
|
||||
|
@ -1866,13 +1873,18 @@ 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, {
|
||||
triggerReason: {
|
||||
kind: "characterTyped",
|
||||
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) {
|
||||
|
@ -2505,7 +2517,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);
|
||||
|
@ -2585,7 +2597,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,
|
||||
|
@ -3030,7 +3042,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);
|
||||
}
|
||||
|
@ -3094,7 +3106,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, "move to new file");
|
||||
}
|
||||
|
||||
|
@ -3136,14 +3148,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);
|
||||
|
@ -3340,7 +3352,7 @@ Actual: ${stringify(fullActual)}`);
|
|||
|
||||
public getEditsForFileRename({ oldPath, newPath, newFileContents }: FourSlashInterface.GetEditsForFileRenameOptions): void {
|
||||
const test = (fileContents: { readonly [fileName: string]: string }, description: string): void => {
|
||||
const changes = this.languageService.getEditsForFileRename(oldPath, newPath, this.formatCodeSettings, ts.defaultPreferences);
|
||||
const changes = this.languageService.getEditsForFileRename(oldPath, newPath, this.formatCodeSettings, ts.emptyOptions);
|
||||
this.testNewFileContents(changes, fileContents, description);
|
||||
};
|
||||
|
||||
|
@ -3354,7 +3366,7 @@ Actual: ${stringify(fullActual)}`);
|
|||
test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -4042,7 +4054,15 @@ namespace FourSlashInterface {
|
|||
}
|
||||
|
||||
public noSignatureHelp(...markers: string[]): void {
|
||||
this.state.verifyNoSignatureHelp(markers);
|
||||
this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers);
|
||||
}
|
||||
|
||||
public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: string[]): void {
|
||||
this.state.verifySignatureHelpPresence(/*expectPresent*/ false, reason, markers);
|
||||
}
|
||||
|
||||
public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: string[]): void {
|
||||
this.state.verifySignatureHelpPresence(/*expectPresent*/ true, reason, markers);
|
||||
}
|
||||
|
||||
public signatureHelp(...options: VerifySignatureHelpOptions[]): void {
|
||||
|
@ -4757,6 +4777,7 @@ namespace FourSlashInterface {
|
|||
readonly isVariadic?: boolean;
|
||||
/** @default ts.emptyArray */
|
||||
readonly tags?: ReadonlyArray<ts.JSDocTagInfo>;
|
||||
readonly triggerReason?: ts.SignatureHelpTriggerReason;
|
||||
}
|
||||
|
||||
export interface VerifyNavigateToOptions {
|
||||
|
|
|
@ -449,8 +449,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));
|
||||
|
|
|
@ -477,7 +477,7 @@ namespace ts.server {
|
|||
|
||||
this.hostConfiguration = {
|
||||
formatCodeOptions: getDefaultFormatCodeSettings(this.host),
|
||||
preferences: defaultPreferences,
|
||||
preferences: emptyOptions,
|
||||
hostInfo: "Unknown host",
|
||||
extraFileExtensions: []
|
||||
};
|
||||
|
|
|
@ -1789,6 +1789,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
|
||||
|
@ -2062,10 +2066,58 @@ namespace ts.server.protocol {
|
|||
argumentCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments of a signature help request.
|
||||
*/
|
||||
export type SignatureHelpTriggerCharacter = "," | "(" | "<";
|
||||
export type SignatureHelpRetriggerCharacter = SignatureHelpTriggerCharacter | ")";
|
||||
|
||||
/**
|
||||
* Arguments of a signature help request.
|
||||
*/
|
||||
export interface SignatureHelpRequestArgs extends FileLocationRequestArgs {
|
||||
/**
|
||||
* Reason why signature help was invoked.
|
||||
* See each individual possible
|
||||
*/
|
||||
triggerReason?: SignatureHelpTriggerReason;
|
||||
}
|
||||
|
||||
export type SignatureHelpTriggerReason =
|
||||
| SignatureHelpInvokedReason
|
||||
| SignatureHelpCharacterTypedReason
|
||||
| SignatureHelpRetriggeredReason;
|
||||
|
||||
/**
|
||||
* Signals that the user manually requested signature help.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
*/
|
||||
export interface SignatureHelpInvokedReason {
|
||||
kind: "invoked";
|
||||
triggerCharacter?: undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the signature help request came from a user typing a character.
|
||||
* Depending on the character and the syntactic context, the request may or may not be served a result.
|
||||
*/
|
||||
export interface SignatureHelpCharacterTypedReason {
|
||||
kind: "characterTyped";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter: SignatureHelpTriggerCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that this signature help request came from typing a character or moving the cursor.
|
||||
* This should only occur if a signature help session was already active and the editor needs to see if it should adjust.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
* `triggerCharacter` can be `undefined` for a retrigger caused by a cursor move.
|
||||
*/
|
||||
export interface SignatureHelpRetriggeredReason {
|
||||
kind: "retrigger";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter?: SignatureHelpRetriggerCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -432,7 +432,7 @@ namespace ts.server {
|
|||
|
||||
if (preferences) {
|
||||
if (!this.preferences) {
|
||||
this.preferences = defaultPreferences;
|
||||
this.preferences = emptyOptions;
|
||||
}
|
||||
this.preferences = { ...this.preferences, ...preferences };
|
||||
}
|
||||
|
|
|
@ -1434,7 +1434,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;
|
||||
}
|
||||
|
|
|
@ -1396,7 +1396,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
|
||||
|
@ -1414,7 +1414,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,
|
||||
|
@ -1756,12 +1756,12 @@ namespace ts {
|
|||
/**
|
||||
* This is a semantic operation.
|
||||
*/
|
||||
function getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems | undefined {
|
||||
function getSignatureHelpItems(fileName: string, position: number, { triggerReason }: SignatureHelpItemsOptions = emptyOptions): SignatureHelpItems | undefined {
|
||||
synchronizeHostData();
|
||||
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
|
||||
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken);
|
||||
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, triggerReason, cancellationToken);
|
||||
}
|
||||
|
||||
/// Syntactic features
|
||||
|
@ -1940,7 +1940,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);
|
||||
|
@ -1952,7 +1952,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);
|
||||
|
@ -1961,7 +1961,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);
|
||||
|
@ -1970,7 +1970,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);
|
||||
}
|
||||
|
||||
|
@ -2219,7 +2219,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));
|
||||
|
@ -2231,7 +2231,7 @@ namespace ts {
|
|||
positionOrRange: number | TextRange,
|
||||
refactorName: string,
|
||||
actionName: string,
|
||||
preferences: UserPreferences = defaultPreferences,
|
||||
preferences: UserPreferences = emptyOptions,
|
||||
): RefactorEditInfo | undefined {
|
||||
synchronizeHostData();
|
||||
const file = getValidSourceFile(fileName);
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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, triggerReason: SignatureHelpTriggerReason | undefined, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
|
||||
// Decide whether to show signature help
|
||||
|
@ -29,6 +29,13 @@ namespace ts.SignatureHelp {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
if (shouldCarefullyCheckContext(triggerReason)) {
|
||||
// In the middle of a string, don't provide signature help unless the user explicitly requested it.
|
||||
if (isInString(sourceFile, position, startingToken)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const argumentInfo = getContainingArgumentInfo(startingToken, position, sourceFile);
|
||||
if (!argumentInfo) return undefined;
|
||||
|
||||
|
@ -50,6 +57,11 @@ namespace ts.SignatureHelp {
|
|||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
|
||||
}
|
||||
|
||||
function shouldCarefullyCheckContext(reason: SignatureHelpTriggerReason | undefined) {
|
||||
// Only need to be careful if the user typed a character and signature help wasn't showing.
|
||||
return !!reason && reason.kind === "characterTyped";
|
||||
}
|
||||
|
||||
function getCandidateInfo(argumentInfo: ArgumentListInfo, checker: TypeChecker): { readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
|
||||
const { invocation } = argumentInfo;
|
||||
if (invocation.kind === InvocationKind.Call) {
|
||||
|
|
|
@ -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,53 @@ namespace ts {
|
|||
includeInsertTextCompletions?: boolean;
|
||||
}
|
||||
|
||||
export type SignatureHelpTriggerCharacter = "," | "(" | "<";
|
||||
export type SignatureHelpRetriggerCharacter = SignatureHelpTriggerCharacter | ")";
|
||||
|
||||
export interface SignatureHelpItemsOptions {
|
||||
triggerReason?: SignatureHelpTriggerReason;
|
||||
}
|
||||
|
||||
export type SignatureHelpTriggerReason =
|
||||
| SignatureHelpInvokedReason
|
||||
| SignatureHelpCharacterTypedReason
|
||||
| SignatureHelpRetriggeredReason;
|
||||
|
||||
/**
|
||||
* Signals that the user manually requested signature help.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
*/
|
||||
export interface SignatureHelpInvokedReason {
|
||||
kind: "invoked";
|
||||
triggerCharacter?: undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the signature help request came from a user typing a character.
|
||||
* Depending on the character and the syntactic context, the request may or may not be served a result.
|
||||
*/
|
||||
export interface SignatureHelpCharacterTypedReason {
|
||||
kind: "characterTyped";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter: SignatureHelpTriggerCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that this signature help request came from typing a character or moving the cursor.
|
||||
* This should only occur if a signature help session was already active and the editor needs to see if it should adjust.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
* `triggerCharacter` can be `undefined` for a retrigger caused by a cursor move.
|
||||
*/
|
||||
export interface SignatureHelpRetriggeredReason {
|
||||
kind: "retrigger";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter?: SignatureHelpRetriggerCharacter;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1525,13 +1525,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'");
|
||||
|
@ -1557,11 +1557,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, "");
|
||||
|
@ -2201,7 +2201,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
|
||||
|
@ -2215,7 +2215,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`);
|
||||
});
|
||||
|
||||
|
@ -8701,7 +8701,7 @@ export const x = 10;`
|
|||
|
||||
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: [{
|
||||
|
|
|
@ -9963,7 +9963,7 @@ declare namespace ts {
|
|||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
const defaultPreferences: UserPreferences;
|
||||
const emptyOptions: {};
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
@ -9987,7 +9987,7 @@ declare namespace ts {
|
|||
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined;
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan | undefined;
|
||||
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;
|
||||
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined;
|
||||
|
@ -10048,13 +10048,54 @@ declare namespace ts {
|
|||
type OrganizeImportsScope = CombinedCodeFixScope;
|
||||
type CompletionsTriggerCharacter = "." | '"' | "'" | "`" | "/" | "@" | "<";
|
||||
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;
|
||||
/** @deprecated Use includeCompletionsWithInsertText */
|
||||
includeInsertTextCompletions?: boolean;
|
||||
}
|
||||
type SignatureHelpTriggerCharacter = "," | "(" | "<";
|
||||
type SignatureHelpRetriggerCharacter = SignatureHelpTriggerCharacter | ")";
|
||||
interface SignatureHelpItemsOptions {
|
||||
triggerReason?: SignatureHelpTriggerReason;
|
||||
}
|
||||
type SignatureHelpTriggerReason = SignatureHelpInvokedReason | SignatureHelpCharacterTypedReason | SignatureHelpRetriggeredReason;
|
||||
/**
|
||||
* Signals that the user manually requested signature help.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
*/
|
||||
interface SignatureHelpInvokedReason {
|
||||
kind: "invoked";
|
||||
triggerCharacter?: undefined;
|
||||
}
|
||||
/**
|
||||
* Signals that the signature help request came from a user typing a character.
|
||||
* Depending on the character and the syntactic context, the request may or may not be served a result.
|
||||
*/
|
||||
interface SignatureHelpCharacterTypedReason {
|
||||
kind: "characterTyped";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter: SignatureHelpTriggerCharacter;
|
||||
}
|
||||
/**
|
||||
* Signals that this signature help request came from typing a character or moving the cursor.
|
||||
* This should only occur if a signature help session was already active and the editor needs to see if it should adjust.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
* `triggerCharacter` can be `undefined` for a retrigger caused by a cursor move.
|
||||
*/
|
||||
interface SignatureHelpRetriggeredReason {
|
||||
kind: "retrigger";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter?: SignatureHelpRetriggerCharacter;
|
||||
}
|
||||
interface ApplyCodeActionCommandResult {
|
||||
successMessage: string;
|
||||
}
|
||||
|
@ -11247,7 +11288,7 @@ declare namespace ts.Rename {
|
|||
function getRenameInfo(program: Program, sourceFile: SourceFile, position: number): RenameInfo;
|
||||
}
|
||||
declare namespace ts.SignatureHelp {
|
||||
function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationToken): SignatureHelpItems | undefined;
|
||||
function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, triggerReason: SignatureHelpTriggerReason | undefined, cancellationToken: CancellationToken): SignatureHelpItems | undefined;
|
||||
interface ArgumentInfoForCompletions {
|
||||
readonly invocation: CallLikeExpression;
|
||||
readonly argumentIndex: number;
|
||||
|
@ -11944,7 +11985,7 @@ declare namespace ts {
|
|||
getQuickInfoAtPosition(fileName: string, position: number): string;
|
||||
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:
|
||||
* { canRename: boolean, localizedErrorMessage: string, displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, triggerSpan: { start; length } }
|
||||
|
@ -12979,7 +13020,23 @@ declare namespace ts.server.protocol {
|
|||
argumentIndex: number;
|
||||
argumentCount: number;
|
||||
}
|
||||
type SignatureHelpTriggerCharacter = "," | "(" | "<";
|
||||
type SignatureHelpRetriggerCharacter = SignatureHelpTriggerCharacter | ")";
|
||||
interface SignatureHelpRequestArgs extends FileLocationRequestArgs {
|
||||
triggerReason?: SignatureHelpTriggerReason;
|
||||
}
|
||||
type SignatureHelpTriggerReason = SignatureHelpInvokedReason | SignatureHelpCharacterTypedReason | SignatureHelpRetriggeredReason;
|
||||
interface SignatureHelpInvokedReason {
|
||||
kind: "invoked";
|
||||
triggerCharacter?: undefined;
|
||||
}
|
||||
interface SignatureHelpCharacterTypedReason {
|
||||
kind: "characterTyped";
|
||||
triggerCharacter: SignatureHelpTriggerCharacter;
|
||||
}
|
||||
interface SignatureHelpRetriggeredReason {
|
||||
kind: "retrigger";
|
||||
triggerCharacter?: SignatureHelpRetriggerCharacter;
|
||||
}
|
||||
interface SignatureHelpRequest extends FileLocationRequest {
|
||||
command: CommandTypes.SignatureHelp;
|
||||
|
|
45
tests/baselines/reference/api/typescript.d.ts
vendored
45
tests/baselines/reference/api/typescript.d.ts
vendored
|
@ -4740,7 +4740,7 @@ declare namespace ts {
|
|||
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined;
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan | undefined;
|
||||
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;
|
||||
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined;
|
||||
|
@ -4800,13 +4800,54 @@ declare namespace ts {
|
|||
type OrganizeImportsScope = CombinedCodeFixScope;
|
||||
type CompletionsTriggerCharacter = "." | '"' | "'" | "`" | "/" | "@" | "<";
|
||||
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;
|
||||
/** @deprecated Use includeCompletionsWithInsertText */
|
||||
includeInsertTextCompletions?: boolean;
|
||||
}
|
||||
type SignatureHelpTriggerCharacter = "," | "(" | "<";
|
||||
type SignatureHelpRetriggerCharacter = SignatureHelpTriggerCharacter | ")";
|
||||
interface SignatureHelpItemsOptions {
|
||||
triggerReason?: SignatureHelpTriggerReason;
|
||||
}
|
||||
type SignatureHelpTriggerReason = SignatureHelpInvokedReason | SignatureHelpCharacterTypedReason | SignatureHelpRetriggeredReason;
|
||||
/**
|
||||
* Signals that the user manually requested signature help.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
*/
|
||||
interface SignatureHelpInvokedReason {
|
||||
kind: "invoked";
|
||||
triggerCharacter?: undefined;
|
||||
}
|
||||
/**
|
||||
* Signals that the signature help request came from a user typing a character.
|
||||
* Depending on the character and the syntactic context, the request may or may not be served a result.
|
||||
*/
|
||||
interface SignatureHelpCharacterTypedReason {
|
||||
kind: "characterTyped";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter: SignatureHelpTriggerCharacter;
|
||||
}
|
||||
/**
|
||||
* Signals that this signature help request came from typing a character or moving the cursor.
|
||||
* This should only occur if a signature help session was already active and the editor needs to see if it should adjust.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
* `triggerCharacter` can be `undefined` for a retrigger caused by a cursor move.
|
||||
*/
|
||||
interface SignatureHelpRetriggeredReason {
|
||||
kind: "retrigger";
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter?: SignatureHelpRetriggerCharacter;
|
||||
}
|
||||
interface ApplyCodeActionCommandResult {
|
||||
successMessage: string;
|
||||
}
|
||||
|
|
|
@ -139,7 +139,6 @@ declare namespace FourSlashInterface {
|
|||
file(name: string, content?: string, scriptKindName?: string): any;
|
||||
select(startMarker: string, endMarker: string): void;
|
||||
selectRange(range: Range): void;
|
||||
selectAllInFile(fileName: string): void;
|
||||
}
|
||||
class verifyNegatable {
|
||||
private negative;
|
||||
|
@ -179,7 +178,7 @@ declare namespace FourSlashInterface {
|
|||
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
|
||||
codeFix(options: {
|
||||
description: string,
|
||||
newFileContent?: NewFileContent,
|
||||
newFileContent?: string | { readonly [fileName: string]: string },
|
||||
newRangeContent?: string,
|
||||
errorCode?: number,
|
||||
index?: number,
|
||||
|
@ -191,7 +190,6 @@ declare namespace FourSlashInterface {
|
|||
applicableRefactorAvailableForRange(): void;
|
||||
|
||||
refactorAvailable(name: string, actionName?: string): void;
|
||||
refactorsAvailable(names: ReadonlyArray<string>): void;
|
||||
refactor(options: {
|
||||
name: string;
|
||||
actionName: string;
|
||||
|
@ -257,14 +255,16 @@ declare namespace FourSlashInterface {
|
|||
* For each of starts, asserts the ranges that are referenced from there.
|
||||
* This uses the 'findReferences' command instead of 'getReferencesAtPosition', so references are grouped by their definition.
|
||||
*/
|
||||
referenceGroups(starts: ArrayOrSingle<string> | ArrayOrSingle<Range>, parts: Array<FourSlashInterface.ReferenceGroup>): void;
|
||||
referenceGroups(starts: ArrayOrSingle<string> | ArrayOrSingle<Range>, parts: Array<{ definition: ReferencesDefinition, ranges: Range[] }>): void;
|
||||
singleReferenceGroup(definition: ReferencesDefinition, ranges?: Range[]): void;
|
||||
rangesAreOccurrences(isWriteAccess?: boolean): void;
|
||||
rangesWithSameTextAreRenameLocations(): void;
|
||||
rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] });
|
||||
findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]): void;
|
||||
noSignatureHelp(...markers: string[]): void;
|
||||
signatureHelp(...options: VerifySignatureHelpOptions[]): void;
|
||||
noSignatureHelpForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: string[]): void
|
||||
signatureHelpPresentForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: string[]): void
|
||||
signatureHelp(...options: VerifySignatureHelpOptions[], ): void;
|
||||
// Checks that there are no compile errors.
|
||||
noErrors(): void;
|
||||
numberOfErrorsInCurrentFile(expected: number): void;
|
||||
|
@ -336,7 +336,7 @@ declare namespace FourSlashInterface {
|
|||
getEditsForFileRename(options: {
|
||||
oldPath: string;
|
||||
newPath: string;
|
||||
newFileContents: { readonly [fileName: string]: string };
|
||||
newFileContents: { [fileName: string]: string };
|
||||
}): void;
|
||||
moveToNewFile(options: {
|
||||
readonly newFileContents: { readonly [fileName: string]: string };
|
||||
|
@ -357,7 +357,7 @@ declare namespace FourSlashInterface {
|
|||
enableFormatting(): void;
|
||||
disableFormatting(): void;
|
||||
|
||||
applyRefactor(options: { refactorName: string, actionName: string, actionDescription: string, newContent: NewFileContent }): void;
|
||||
applyRefactor(options: { refactorName: string, actionName: string, actionDescription: string, newContent: string }): void;
|
||||
}
|
||||
class debug {
|
||||
printCurrentParameterHelp(): void;
|
||||
|
@ -512,10 +512,6 @@ declare namespace FourSlashInterface {
|
|||
text: string;
|
||||
range: Range;
|
||||
}
|
||||
interface ReferenceGroup {
|
||||
readonly definition: ReferencesDefinition;
|
||||
readonly ranges: ReadonlyArray<Range>;
|
||||
}
|
||||
interface Diagnostic {
|
||||
message: string;
|
||||
/** @default `test.ranges()[0]` */
|
||||
|
@ -565,6 +561,47 @@ declare namespace FourSlashInterface {
|
|||
argumentCount?: number;
|
||||
isVariadic?: boolean;
|
||||
tags?: ReadonlyArray<JSDocTagInfo>;
|
||||
triggerReason?: SignatureHelpTriggerReason;
|
||||
}
|
||||
|
||||
export type SignatureHelpTriggerReason =
|
||||
| SignatureHelpInvokedReason
|
||||
| SignatureHelpCharacterTypedReason
|
||||
| SignatureHelpRetriggeredReason;
|
||||
|
||||
/**
|
||||
* Signals that the user manually requested signature help.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
*/
|
||||
export interface SignatureHelpInvokedReason {
|
||||
kind: "invoked",
|
||||
triggerCharacter?: undefined,
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the signature help request came from a user typing a character.
|
||||
* Depending on the character and the syntactic context, the request may or may not be served a result.
|
||||
*/
|
||||
export interface SignatureHelpCharacterTypedReason {
|
||||
kind: "characterTyped",
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that this signature help request came from typing a character or moving the cursor.
|
||||
* This should only occur if a signature help session was already active and the editor needs to see if it should adjust.
|
||||
* The language service will unconditionally attempt to provide a result.
|
||||
* `triggerCharacter` can be `undefined` for a retrigger caused by a cursor move.
|
||||
*/
|
||||
export interface SignatureHelpRetriggeredReason {
|
||||
kind: "retrigger",
|
||||
/**
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter?: string,
|
||||
}
|
||||
|
||||
interface VerifyNavigateToOptions {
|
||||
|
@ -589,7 +626,6 @@ declare namespace FourSlashInterface {
|
|||
}
|
||||
|
||||
type ArrayOrSingle<T> = T | ReadonlyArray<T>;
|
||||
type NewFileContent = string | { readonly [fileName: string]: string };
|
||||
}
|
||||
declare function verifyOperationIsCancelled(f: any): void;
|
||||
declare var test: FourSlashInterface.test_;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////function foo<T>(x: T): T {
|
||||
//// throw null;
|
||||
////}
|
||||
////
|
||||
////foo("/**/")
|
||||
|
||||
goTo.marker();
|
||||
for (const triggerCharacter of ["<", "(", ","]) {
|
||||
edit.insert(triggerCharacter);
|
||||
verify.noSignatureHelpForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter,
|
||||
});
|
||||
verify.signatureHelpPresentForTriggerReason({
|
||||
kind: "retrigger",
|
||||
triggerCharacter,
|
||||
});
|
||||
edit.backspace();
|
||||
}
|
||||
verify.signatureHelpPresentForTriggerReason(/*triggerReason*/ undefined);
|
||||
verify.signatureHelpPresentForTriggerReason({ kind: "invoked" });
|
Loading…
Reference in a new issue