-
Notifications
You must be signed in to change notification settings - Fork 328
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
275 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* -------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
* ------------------------------------------------------------------------------------------ */ | ||
'use strict'; | ||
|
||
import * as UUID from './utils/uuid'; | ||
import * as Is from './utils/is'; | ||
|
||
import { languages as Languages, Disposable, TextDocument, ProviderResult, Position as VPosition, SelectionRange as VSelectionRange, SelectionRangeKind as VSelectionRangeKind } from 'vscode'; | ||
|
||
import { | ||
ClientCapabilities, CancellationToken, ServerCapabilities, TextDocumentRegistrationOptions, DocumentSelector, StaticRegistrationOptions, | ||
TextDocumentPositionParams, | ||
SelectionRangeRequest, SelectionRangeProviderOptions, SelectionRangeKind, SelectionRange | ||
} from 'vscode-languageserver-protocol'; | ||
|
||
import { TextDocumentFeature, BaseLanguageClient } from './client'; | ||
|
||
function ensure<T, K extends keyof T>(target: T, key: K): T[K] { | ||
if (target[key] === void 0) { | ||
target[key] = {} as any; | ||
} | ||
return target[key]; | ||
} | ||
|
||
export interface ProvideSelectionRangeSignature { | ||
(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VSelectionRange[] | null>; | ||
} | ||
|
||
|
||
export interface SelectionRangeProviderMiddleware { | ||
provideSelectionRanges?: (this: void, document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideSelectionRangeSignature) => ProviderResult<VSelectionRange[]>; | ||
} | ||
|
||
export class SelectionRangeFeature extends TextDocumentFeature<TextDocumentRegistrationOptions> { | ||
constructor(client: BaseLanguageClient) { | ||
super(client, SelectionRangeRequest.type); | ||
} | ||
|
||
public fillClientCapabilities(capabilites: ClientCapabilities): void { | ||
let capability = ensure(ensure(capabilites, 'textDocument')!, 'selectionRange')!; | ||
capability.dynamicRegistration = true; | ||
} | ||
|
||
public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { | ||
if (!capabilities.selectionRangeProvider) { | ||
return; | ||
} | ||
|
||
const implCapabilities = capabilities.selectionRangeProvider as TextDocumentRegistrationOptions & StaticRegistrationOptions & SelectionRangeProviderOptions; | ||
const id = Is.string(implCapabilities.id) && implCapabilities.id.length > 0 ? implCapabilities.id : UUID.generateUuid(); | ||
const selector = implCapabilities.documentSelector || documentSelector; | ||
if (selector) { | ||
this.register(this.messages, { | ||
id, | ||
registerOptions: Object.assign({}, { documentSelector: selector }) | ||
}); | ||
} | ||
} | ||
|
||
protected registerLanguageProvider(options: TextDocumentRegistrationOptions): Disposable { | ||
let client = this._client; | ||
let provideSelectionRanges: ProvideSelectionRangeSignature = (document, position, token) => { | ||
const requestParams: TextDocumentPositionParams = { | ||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), | ||
position: client.code2ProtocolConverter.asPosition(position), | ||
}; | ||
return client.sendRequest(SelectionRangeRequest.type, requestParams, token).then( | ||
(ranges) => this.asSelectionRanges(ranges), | ||
(error: any) => { | ||
client.logFailedRequest(SelectionRangeRequest.type, error); | ||
return Promise.resolve(null); | ||
} | ||
); | ||
}; | ||
let middleware = client.clientOptions.middleware!; | ||
return Languages.registerSelectionRangeProvider(options.documentSelector!, { | ||
provideSelectionRanges(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VSelectionRange[]> { | ||
return middleware.provideSelectionRanges | ||
? middleware.provideSelectionRanges(document, position, token, provideSelectionRanges) | ||
: provideSelectionRanges(document, position, token); | ||
|
||
} | ||
}); | ||
} | ||
|
||
private asSelectionRanges(selectionRanges: SelectionRange[] | null): VSelectionRange[] { | ||
if (!Array.isArray(selectionRanges)) return []; | ||
return selectionRanges.map(r => { | ||
return new VSelectionRange( | ||
this._client.protocol2CodeConverter.asRange(r.range), | ||
this.asSelectionRangeKind(r.kind), | ||
); | ||
}); | ||
} | ||
|
||
private asSelectionRangeKind(kind?: string): VSelectionRangeKind { | ||
switch (kind) { | ||
case SelectionRangeKind.Empty: | ||
return VSelectionRangeKind.Empty; | ||
case SelectionRangeKind.Statement: | ||
return VSelectionRangeKind.Statement; | ||
case SelectionRangeKind.Declaration: | ||
return VSelectionRangeKind.Declaration; | ||
default: | ||
return VSelectionRangeKind.Empty | ||
} | ||
} | ||
} | ||
|
||
declare module 'vscode' { | ||
|
||
export class SelectionRangeKind { | ||
|
||
/** | ||
* Empty Kind. | ||
*/ | ||
static readonly Empty: SelectionRangeKind; | ||
|
||
/** | ||
* The statment kind, its value is `statement`, possible extensions can be | ||
* `statement.if` etc | ||
*/ | ||
static readonly Statement: SelectionRangeKind; | ||
|
||
/** | ||
* The declaration kind, its value is `declaration`, possible extensions can be | ||
* `declaration.function`, `declaration.class` etc. | ||
*/ | ||
static readonly Declaration: SelectionRangeKind; | ||
|
||
readonly value: string; | ||
|
||
private constructor(value: string); | ||
|
||
append(value: string): SelectionRangeKind; | ||
} | ||
|
||
export class SelectionRange { | ||
kind: SelectionRangeKind; | ||
range: Range; | ||
constructor(range: Range, kind: SelectionRangeKind); | ||
} | ||
|
||
export interface SelectionRangeProvider { | ||
/** | ||
* Provide selection ranges starting at a given position. The first range must [contain](#Range.contains) | ||
* position and subsequent ranges must contain the previous range. | ||
*/ | ||
provideSelectionRanges(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<SelectionRange[]>; | ||
} | ||
|
||
export namespace languages { | ||
export function registerSelectionRangeProvider(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable; | ||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#### Selection Range Request (:leftwards_arrow_with_hook:) | ||
|
||
The selection range request is sent from the client to the server to return suggested selection ranges at a given position. | ||
A selection range is a range around the cursor position which the user might be interested in selecting. | ||
Typically, but not neccessary, selection ranges correspond to the nodes of the syntax tree. | ||
The first range must contain the given position. | ||
Position can coincide with the start or end of the first range. | ||
Subsequent ranges must contain the previous range. | ||
|
||
_Request_: | ||
|
||
* method: 'textDocument/selectionRange' | ||
* params: `TextDocumentPositionParams` | ||
|
||
_Response_: | ||
* result: `SelectionRange[] | null`: a list of selection ranges | ||
* error: code and message set in case an exception happens during the 'textDocument/selectionRange' request | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import { RequestType } from 'vscode-jsonrpc'; | ||
import { Range } from 'vscode-languageserver-types'; | ||
import { TextDocumentRegistrationOptions, StaticRegistrationOptions, TextDocumentPositionParams } from './protocol'; | ||
|
||
// ---- capabilities | ||
|
||
export interface SelectionRangeClientCapabilities { | ||
/** | ||
* The text document client capabilities | ||
*/ | ||
textDocument?: { | ||
/** | ||
* Capabilities specific to `textDocument/selectionRange` requests | ||
*/ | ||
selectionRange?: { | ||
/** | ||
* Whether implementation supports dynamic registration for selection range providers. If this is set to `true` | ||
* the client supports the new `(SelectionRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` | ||
* return value for the corresponding server capability as well. | ||
*/ | ||
dynamicRegistration?: boolean; | ||
}; | ||
}; | ||
} | ||
|
||
export interface SelectionRangeProviderOptions { | ||
} | ||
|
||
export interface SelectionRangeServerCapabilities { | ||
/** | ||
* The server provides selection range support. | ||
*/ | ||
selectionRangeProvider?: boolean | SelectionRangeProviderOptions | (SelectionRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions); | ||
} | ||
|
||
/** | ||
* Enum of known selection range kinds | ||
*/ | ||
export enum SelectionRangeKind { | ||
/** | ||
* Empty Kind. | ||
*/ | ||
Empty = '', | ||
/** | ||
* The statment kind, its value is `statement`, possible extensions can be | ||
* `statement.if` etc | ||
*/ | ||
Statement = 'statement', | ||
/** | ||
* The declaration kind, its value is `declaration`, possible extensions can be | ||
* `declaration.function`, `declaration.class` etc. | ||
*/ | ||
Declaration = 'declaration', | ||
} | ||
|
||
/** | ||
* Represents a selection range | ||
*/ | ||
export interface SelectionRange { | ||
/** | ||
* Range of the selection. | ||
*/ | ||
range: Range; | ||
/** | ||
* Describes the kind of the selection range such as `statemet' or 'declaration'. See | ||
* [SelectionRangeKind](#SelectionRangeKind) for an enumeration of standardized kinds. | ||
*/ | ||
kind: string; | ||
} | ||
|
||
/** | ||
* A request to provide selection ranges in a document. The request's | ||
* parameter is of type [TextDocumentPositionParams](#TextDocumentPositionParams), the | ||
* response is of type [SelectionRange[]](#SelectionRange[]) or a Thenable | ||
* that resolves to such. | ||
*/ | ||
export namespace SelectionRangeRequest { | ||
export const type: RequestType<TextDocumentPositionParams, SelectionRange[] | null, any, any> = new RequestType('textDocument/selectionRange'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters