support referencesCodeLens.showOnAllFunctions
Make codeLens same as VScode
This commit is contained in:
parent
4fa163e554
commit
d10bab9072
7 changed files with 151 additions and 127 deletions
|
@ -145,6 +145,7 @@ for guide of coc.nvim's configuration.
|
|||
implementations, default: `true`
|
||||
- `typescript.referencesCodeLens.enable`:Enable codeLens for references,
|
||||
default: `true`
|
||||
- `typescript.referencesCodeLens.showOnAllFunctions`: Enable/disable references CodeLens on all functions in typescript files. Default: `false`
|
||||
- `typescript.preferences.importModuleSpecifier` default: `"auto"`
|
||||
- `typescript.preferences.importModuleSpecifierEnding` default: `"auto"`
|
||||
- `typescript.preferences.quoteStyle` default: `"single"`
|
||||
|
@ -209,6 +210,7 @@ for guide of coc.nvim's configuration.
|
|||
- `javascript.updateImportsOnFileMove.enable` default: `true`
|
||||
- `javascript.implementationsCodeLens.enable` default: `true`
|
||||
- `javascript.referencesCodeLens.enable` default: `true`
|
||||
- `javascript.referencesCodeLens.showOnAllFunctions`: Enable/disable references CodeLens on all functions in JavaScript files default: `false`
|
||||
- `javascript.preferences.importModuleSpecifier` default: `"auto"`
|
||||
- `javascript.preferences.importModuleSpecifierEnding` default: `"auto"`
|
||||
- `javascript.preferences.quoteStyle` default: `"single"`
|
||||
|
|
12
package.json
12
package.json
|
@ -293,6 +293,12 @@
|
|||
"default": true,
|
||||
"description": "Enable codeLens for references"
|
||||
},
|
||||
"typescript.referencesCodeLens.showOnAllFunctions": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable references CodeLens on all functions in typescript files.",
|
||||
"scope": "window"
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": {
|
||||
"type": "string",
|
||||
"default": "shortest",
|
||||
|
@ -547,6 +553,12 @@
|
|||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"javascript.referencesCodeLens.showOnAllFunctions": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable references CodeLens on all functions in JavaScript files.",
|
||||
"scope": "window"
|
||||
},
|
||||
"javascript.preferences.importModuleSpecifier": {
|
||||
"type": "string",
|
||||
"default": "shortest",
|
||||
|
|
|
@ -46,7 +46,8 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider
|
|||
|
||||
public constructor(
|
||||
protected client: ITypeScriptServiceClient,
|
||||
private cachedResponse: CachedNavTreeResponse
|
||||
private cachedResponse: CachedNavTreeResponse,
|
||||
protected modeId: string
|
||||
) {}
|
||||
|
||||
public get onDidChangeCodeLenses(): Event<void> {
|
||||
|
@ -116,38 +117,31 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider
|
|||
)
|
||||
}
|
||||
}
|
||||
protected getSymbolRange(
|
||||
document: TextDocument,
|
||||
item: Proto.NavigationTree
|
||||
): Range | null {
|
||||
if (!item) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// TS 3.0+ provides a span for just the symbol
|
||||
if ((item as any).nameSpan) {
|
||||
return typeConverters.Range.fromTextSpan((item as any).nameSpan)
|
||||
}
|
||||
export function getSymbolRange(
|
||||
document: TextDocument,
|
||||
item: Proto.NavigationTree
|
||||
): Range | null {
|
||||
if (item.nameSpan) {
|
||||
return typeConverters.Range.fromTextSpan(item.nameSpan)
|
||||
}
|
||||
|
||||
// In older versions, we have to calculate this manually. See #23924
|
||||
const span = item.spans && item.spans[0]
|
||||
if (!span) {
|
||||
return null
|
||||
}
|
||||
// In older versions, we have to calculate this manually. See #23924
|
||||
const span = item.spans && item.spans[0]
|
||||
if (!span) {
|
||||
return null
|
||||
}
|
||||
|
||||
const range = typeConverters.Range.fromTextSpan(span)
|
||||
const text = document.getText(range)
|
||||
const range = typeConverters.Range.fromTextSpan(span)
|
||||
const text = document.getText(range)
|
||||
|
||||
const identifierMatch = new RegExp(
|
||||
`^(.*?(\\b|\\W))${escapeRegExp(item.text || '')}(\\b|\\W)`,
|
||||
'gm'
|
||||
)
|
||||
const match = identifierMatch.exec(text)
|
||||
const prefixLength = match ? match.index + match[1].length : 0
|
||||
const startOffset = document.offsetAt(range.start) + prefixLength
|
||||
return {
|
||||
start: document.positionAt(startOffset),
|
||||
end: document.positionAt(startOffset + item.text.length)
|
||||
}
|
||||
const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${escapeRegExp(item.text || '')}(\\b|\\W)`, 'gm')
|
||||
const match = identifierMatch.exec(text)
|
||||
const prefixLength = match ? match.index + match[1].length : 0
|
||||
const startOffset = document.offsetAt(range.start) + prefixLength
|
||||
return {
|
||||
start: document.positionAt(startOffset),
|
||||
end: document.positionAt(startOffset + item.text.length)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { TextDocument } from 'coc.nvim'
|
|||
import * as Proto from '../protocol'
|
||||
import * as PConst from '../protocol.const'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import { TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'
|
||||
import { TypeScriptBaseCodeLensProvider, getSymbolRange } from './baseCodeLensProvider'
|
||||
|
||||
export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider {
|
||||
public async resolveCodeLens(
|
||||
|
@ -21,43 +21,39 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
|||
filepath,
|
||||
codeLens.range.start
|
||||
)
|
||||
try {
|
||||
const response = await this.client.execute('implementation', args, token, { lowPriority: true })
|
||||
if (response && response.type == 'response' && response.body) {
|
||||
const locations = response.body
|
||||
.map(reference => {
|
||||
return {
|
||||
uri: this.client.toResource(reference.file),
|
||||
range: {
|
||||
start: typeConverters.Position.fromLocation(reference.start),
|
||||
end: {
|
||||
line: reference.start.line,
|
||||
character: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// Exclude original from implementations
|
||||
.filter(
|
||||
location => !(
|
||||
location.uri.toString() === uri &&
|
||||
location.range.start.line === codeLens.range.start.line &&
|
||||
location.range.start.character ===
|
||||
codeLens.range.start.character
|
||||
)
|
||||
)
|
||||
|
||||
codeLens.command = this.getCommand(locations, codeLens)
|
||||
return codeLens
|
||||
const response = await this.client.execute('implementation', args, token, { lowPriority: true })
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
codeLens.command = {
|
||||
title: response.type === 'cancelled'
|
||||
? 'cancelled'
|
||||
: 'could not determine implementation',
|
||||
command: ''
|
||||
}
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
|
||||
codeLens.command = {
|
||||
title: '0 implementations',
|
||||
command: ''
|
||||
return codeLens
|
||||
}
|
||||
const locations = response.body
|
||||
.map(reference => {
|
||||
return {
|
||||
uri: this.client.toResource(reference.file),
|
||||
range: {
|
||||
start: typeConverters.Position.fromLocation(reference.start),
|
||||
end: {
|
||||
line: reference.start.line,
|
||||
character: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// Exclude original from implementations
|
||||
.filter(
|
||||
location => !(
|
||||
location.uri.toString() === uri &&
|
||||
location.range.start.line === codeLens.range.start.line &&
|
||||
location.range.start.character ===
|
||||
codeLens.range.start.character
|
||||
)
|
||||
)
|
||||
codeLens.command = this.getCommand(locations, codeLens)
|
||||
return codeLens
|
||||
}
|
||||
|
||||
|
@ -84,7 +80,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
|||
): Range | null {
|
||||
switch (item.kind) {
|
||||
case PConst.Kind.interface:
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
|
||||
case PConst.Kind.class:
|
||||
case PConst.Kind.method:
|
||||
|
@ -92,7 +88,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
|||
case PConst.Kind.memberGetAccessor:
|
||||
case PConst.Kind.memberSetAccessor:
|
||||
if (item.kindModifiers.match(/\babstract\b/g)) {
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { CancellationToken, CodeLens, Range } from 'vscode-languageserver-protocol'
|
||||
import { TextDocument } from 'coc.nvim'
|
||||
import { CancellationToken, Position, Range } from 'vscode-languageserver-protocol'
|
||||
import { TextDocument, workspace, CodeLens } from 'coc.nvim'
|
||||
import { ExecutionTarget } from '../typescriptService'
|
||||
import * as Proto from '../protocol'
|
||||
import * as PConst from '../protocol.const'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import { TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'
|
||||
import { TypeScriptBaseCodeLensProvider, getSymbolRange } from './baseCodeLensProvider'
|
||||
|
||||
export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider {
|
||||
public resolveCodeLens(
|
||||
public async resolveCodeLens(
|
||||
codeLens: CodeLens,
|
||||
token: CancellationToken
|
||||
): Promise<CodeLens> {
|
||||
|
@ -20,47 +21,35 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase
|
|||
filepath,
|
||||
codeLens.range.start
|
||||
)
|
||||
return this.client
|
||||
.execute('references', args, token, {
|
||||
lowPriority: true
|
||||
})
|
||||
.then(response => {
|
||||
if (!response || response.type != 'response' || !response.body) {
|
||||
throw codeLens
|
||||
}
|
||||
let response = await this.client.execute('references', args, token, {
|
||||
lowPriority: true,
|
||||
executionTarget: ExecutionTarget.Semantic
|
||||
})
|
||||
if (!response || response.type != 'response' || !response.body) {
|
||||
codeLens.command = {
|
||||
title: response.type === 'cancelled'
|
||||
? 'cancelled'
|
||||
: 'could not determine references',
|
||||
command: ''
|
||||
}
|
||||
return codeLens
|
||||
}
|
||||
|
||||
const locations = response.body.refs
|
||||
.map(reference =>
|
||||
typeConverters.Location.fromTextSpan(
|
||||
this.client.toResource(reference.file),
|
||||
reference
|
||||
)
|
||||
)
|
||||
.filter(
|
||||
location =>
|
||||
// Exclude original definition from references
|
||||
!(
|
||||
location.uri.toString() === uri &&
|
||||
location.range.start.line === codeLens.range.start.line &&
|
||||
location.range.start.character ===
|
||||
codeLens.range.start.character
|
||||
)
|
||||
)
|
||||
const locations = response.body.refs
|
||||
.filter(reference => !reference.isDefinition)
|
||||
.map(reference =>
|
||||
typeConverters.Location.fromTextSpan(
|
||||
this.client.toResource(reference.file),
|
||||
reference
|
||||
)
|
||||
)
|
||||
|
||||
codeLens.command = {
|
||||
title: locations.length === 1 ? '1 reference' : `${locations.length} references`,
|
||||
command: locations.length ? 'editor.action.showReferences' : '',
|
||||
arguments: [uri, codeLens.range.start, locations]
|
||||
}
|
||||
return codeLens
|
||||
})
|
||||
.catch(() => {
|
||||
codeLens.command = {
|
||||
title: '0 references',
|
||||
command: ''
|
||||
}
|
||||
return codeLens
|
||||
})
|
||||
codeLens.command = {
|
||||
title: locations.length === 1 ? '1 reference' : `${locations.length} references`,
|
||||
command: locations.length ? 'editor.action.showReferences' : '',
|
||||
arguments: [uri, codeLens.range.start, locations]
|
||||
}
|
||||
return codeLens
|
||||
}
|
||||
|
||||
protected extractSymbol(
|
||||
|
@ -69,37 +58,68 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase
|
|||
parent: Proto.NavigationTree | null
|
||||
): Range | null {
|
||||
if (parent && parent.kind === PConst.Kind.enum) {
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
|
||||
switch (item.kind) {
|
||||
case PConst.Kind.function: {
|
||||
const showOnAllFunctions = workspace.getConfiguration(this.modeId).get<boolean>('referencesCodeLens.showOnAllFunctions')
|
||||
if (showOnAllFunctions) {
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case PConst.Kind.const:
|
||||
case PConst.Kind.let:
|
||||
case PConst.Kind.variable:
|
||||
case PConst.Kind.function:
|
||||
// Only show references for exported variables
|
||||
if (!item.kindModifiers.match(/\bexport\b/)) {
|
||||
break
|
||||
if (/\bexport\b/.test(item.kindModifiers)) {
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
// fallthrough
|
||||
break
|
||||
|
||||
case PConst.Kind.class:
|
||||
if (item.text === '<class>') {
|
||||
break
|
||||
}
|
||||
// fallthrough
|
||||
return getSymbolRange(document, item)
|
||||
|
||||
case PConst.Kind.method:
|
||||
case PConst.Kind.memberVariable:
|
||||
case PConst.Kind.memberGetAccessor:
|
||||
case PConst.Kind.memberSetAccessor:
|
||||
case PConst.Kind.constructorImplementation:
|
||||
case PConst.Kind.interface:
|
||||
case PConst.Kind.type:
|
||||
case PConst.Kind.enum:
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
|
||||
case PConst.Kind.method:
|
||||
case PConst.Kind.memberGetAccessor:
|
||||
case PConst.Kind.memberSetAccessor:
|
||||
case PConst.Kind.constructorImplementation:
|
||||
case PConst.Kind.memberVariable:
|
||||
// Don't show if child and parent have same start
|
||||
// For https://github.com/microsoft/vscode/issues/90396
|
||||
if (parent &&
|
||||
comparePosition(typeConverters.Position.fromLocation(parent.spans[0].start), typeConverters.Position.fromLocation(item.spans[0].start)) == 0
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Only show if parent is a class type object (not a literal)
|
||||
switch (parent?.kind) {
|
||||
case PConst.Kind.class:
|
||||
case PConst.Kind.interface:
|
||||
case PConst.Kind.type:
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function comparePosition(position: Position, other: Position): number {
|
||||
if (position.line > other.line) return 1
|
||||
if (other.line == position.line && position.character > other.character) return 1
|
||||
if (other.line == position.line && position.character == other.character) return 0
|
||||
return -1
|
||||
}
|
||||
|
|
|
@ -149,10 +149,10 @@ export default class LanguageProvider {
|
|||
'tsserver', [CodeActionKind.QuickFix]))
|
||||
let cachedResponse = new CachedNavTreeResponse()
|
||||
if (this.client.apiVersion.gte(API.v206) && conf.get<boolean>('referencesCodeLens.enable')) {
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ReferencesCodeLensProvider(client, cachedResponse)))
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ReferencesCodeLensProvider(client, cachedResponse, this.description.id)))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v220) && conf.get<boolean>('implementationsCodeLens.enable')) {
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ImplementationsCodeLensProvider(client, cachedResponse)))
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ImplementationsCodeLensProvider(client, cachedResponse, this.description.id)))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v350)) {
|
||||
this._register(languages.registerSelectionRangeProvider(languageIds, new SmartSelection(this.client)))
|
||||
|
|
|
@ -34,7 +34,7 @@ export interface TypeScriptServerPlugin {
|
|||
readonly languages: string[]
|
||||
}
|
||||
|
||||
export enum ExectuionTarget {
|
||||
export enum ExecutionTarget {
|
||||
Semantic,
|
||||
Syntax
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ export type ExecConfig = {
|
|||
readonly lowPriority?: boolean
|
||||
readonly nonRecoverable?: boolean
|
||||
readonly cancelOnResourceChange?: string
|
||||
readonly executionTarget?: ExectuionTarget
|
||||
readonly executionTarget?: ExecutionTarget
|
||||
}
|
||||
|
||||
export interface TypeScriptRequestTypes {
|
||||
|
|
Loading…
Reference in a new issue