mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-24 02:21:30 -05:00
Account for trigger reasons, as implemented by Roslyn.
This commit is contained in:
@@ -1426,17 +1426,22 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyNoSignatureHelp(triggerCharacter: ts.SignatureHelpTriggerCharacter | undefined, 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(triggerCharacter, ts.emptyArray);
|
||||
this.verifySignatureHelpPresence(expectPresent, triggerReason, ts.emptyArray);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const actual = this.getSignatureHelp({ triggerCharacter });
|
||||
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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1455,7 +1460,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
private verifySignatureHelpWorker(options: FourSlashInterface.VerifySignatureHelpOptions) {
|
||||
const help = this.getSignatureHelp({ triggerCharacter: options.triggerCharacter })!;
|
||||
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;
|
||||
@@ -1497,7 +1502,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
const allKeys: ReadonlyArray<keyof FourSlashInterface.VerifySignatureHelpOptions> = [
|
||||
"marker",
|
||||
"triggerCharacter",
|
||||
"triggerReason",
|
||||
"overloadsCount",
|
||||
"docComment",
|
||||
"text",
|
||||
@@ -1769,9 +1774,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
Harness.IO.log(stringify(help.items[help.selectedItemIndex]));
|
||||
}
|
||||
|
||||
private getSignatureHelp({ triggerCharacter }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined {
|
||||
private getSignatureHelp({ triggerReason }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined {
|
||||
return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, {
|
||||
triggerCharacter
|
||||
triggerReason
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1870,7 +1875,12 @@ Actual: ${stringify(fullActual)}`);
|
||||
if (highFidelity) {
|
||||
if (ch === "(" || ch === "," || ch === "<") {
|
||||
/* Signature help*/
|
||||
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset, { triggerCharacter: ch });
|
||||
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset, {
|
||||
triggerReason: {
|
||||
kind: "characterTyped",
|
||||
triggerCharacter: ch
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (prevChar === " " && /A-Za-z_/.test(ch)) {
|
||||
/* Completions */
|
||||
@@ -4081,11 +4091,15 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
public noSignatureHelp(...markers: string[]): void {
|
||||
this.state.verifyNoSignatureHelp(/*triggerCharacter*/ undefined, markers);
|
||||
this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers);
|
||||
}
|
||||
|
||||
public noSignatureHelpForTriggerCharacter(triggerCharacter: ts.SignatureHelpTriggerCharacter, ...markers: string[]): void {
|
||||
this.state.verifyNoSignatureHelp(triggerCharacter, 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 {
|
||||
@@ -4816,7 +4830,7 @@ namespace FourSlashInterface {
|
||||
readonly isVariadic?: boolean;
|
||||
/** @default ts.emptyArray */
|
||||
readonly tags?: ReadonlyArray<ts.JSDocTagInfo>;
|
||||
readonly triggerCharacter?: ts.SignatureHelpTriggerCharacter;
|
||||
readonly triggerReason?: ts.SignatureHelpTriggerReason;
|
||||
}
|
||||
|
||||
export type ArrayOrSingle<T> = T | ReadonlyArray<T>;
|
||||
|
||||
@@ -2067,16 +2067,57 @@ namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
export type SignatureHelpTriggerCharacter = "," | "(" | "<";
|
||||
export type SignatureHelpRetriggerCharacter = SignatureHelpTriggerCharacter | ")";
|
||||
|
||||
/**
|
||||
* Arguments of a signature help request.
|
||||
*/
|
||||
/**
|
||||
* 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.
|
||||
* Reason why signature help was invoked.
|
||||
* See each individual possible
|
||||
*/
|
||||
triggerCharacter?: SignatureHelpTriggerCharacter;
|
||||
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,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1756,12 +1756,12 @@ namespace ts {
|
||||
/**
|
||||
* This is a semantic operation.
|
||||
*/
|
||||
function getSignatureHelpItems(fileName: string, position: number, { triggerCharacter }: SignatureHelpItemsOptions = emptyOptions): SignatureHelpItems | undefined {
|
||||
function getSignatureHelpItems(fileName: string, position: number, { triggerReason }: SignatureHelpItemsOptions = emptyOptions): SignatureHelpItems | undefined {
|
||||
synchronizeHostData();
|
||||
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
|
||||
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, triggerCharacter, cancellationToken);
|
||||
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, triggerReason, cancellationToken);
|
||||
}
|
||||
|
||||
/// Syntactic features
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace ts.SignatureHelp {
|
||||
argumentCount: number;
|
||||
}
|
||||
|
||||
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, triggerCharacter: SignatureHelpTriggerCharacter | undefined, 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,9 +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;
|
||||
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);
|
||||
@@ -55,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) {
|
||||
|
||||
@@ -383,13 +383,50 @@ namespace ts {
|
||||
}
|
||||
|
||||
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",
|
||||
/**
|
||||
* 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.
|
||||
* Character that was responsible for triggering signature help.
|
||||
*/
|
||||
triggerCharacter?: SignatureHelpTriggerCharacter;
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user