| /* eslint-disable @typescript-eslint/no-explicit-any */ |
| /*--------------------------------------------------------- |
| * Copyright (C) Microsoft Corporation. All rights reserved. |
| * Licensed under the MIT License. See LICENSE in the project root for license information. |
| *--------------------------------------------------------*/ |
| |
| 'use strict'; |
| |
| import { isAbsolute } from 'path'; |
| import { CancellationToken, CodeLens, Range, TextDocument } from 'vscode'; |
| import { getGoConfig } from './config'; |
| import { GoBaseCodeLensProvider } from './goBaseCodelens'; |
| import { GoDocumentSymbolProvider } from './goOutline'; |
| import { GoReferenceProvider } from './goReferences'; |
| import { getBinPath } from './util'; |
| import vscode = require('vscode'); |
| |
| const methodRegex = /^func\s+\(\s*\w+\s+\*?\w+\s*\)\s+/; |
| |
| class ReferencesCodeLens extends CodeLens { |
| constructor(public document: TextDocument, range: Range) { |
| super(range); |
| } |
| } |
| |
| export class GoReferencesCodeLensProvider extends GoBaseCodeLensProvider { |
| public provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable<CodeLens[]> { |
| if (!this.enabled) { |
| return []; |
| } |
| const codeLensConfig = getGoConfig(document.uri).get<{ [key: string]: any }>('enableCodeLens'); |
| const codelensEnabled = codeLensConfig ? codeLensConfig['references'] : false; |
| if (!codelensEnabled) { |
| return Promise.resolve([]); |
| } |
| |
| const goGuru = getBinPath('guru'); |
| if (!isAbsolute(goGuru)) { |
| return Promise.resolve([]); |
| } |
| |
| return this.provideDocumentSymbols(document, token).then((symbols) => { |
| return symbols.map((symbol) => { |
| let position = symbol.range.start; |
| |
| // Add offset for functions as go-outline returns position at the keyword func instead of func name |
| if (symbol.kind === vscode.SymbolKind.Function) { |
| const funcDecl = document.lineAt(position.line).text.substr(position.character); |
| const match = methodRegex.exec(funcDecl); |
| position = position.translate(0, match ? match[0].length : 5); |
| } |
| return new ReferencesCodeLens(document, new vscode.Range(position, position)); |
| }); |
| }); |
| } |
| |
| public resolveCodeLens?(inputCodeLens: CodeLens, token: CancellationToken): CodeLens | Thenable<CodeLens> { |
| const codeLens = inputCodeLens as ReferencesCodeLens; |
| |
| if (token.isCancellationRequested) { |
| return Promise.resolve(codeLens); |
| } |
| |
| const options = { |
| includeDeclaration: false |
| }; |
| const referenceProvider = new GoReferenceProvider(); |
| return referenceProvider.provideReferences(codeLens.document, codeLens.range.start, options, token).then( |
| (references) => { |
| codeLens.command = { |
| title: references.length === 1 ? '1 reference' : references.length + ' references', |
| command: 'editor.action.showReferences', |
| arguments: [codeLens.document.uri, codeLens.range.start, references] |
| }; |
| return codeLens; |
| }, |
| (err) => { |
| console.log(err); |
| codeLens.command = { |
| title: 'Error finding references', |
| command: '' |
| }; |
| return codeLens; |
| } |
| ); |
| } |
| |
| private async provideDocumentSymbols( |
| document: TextDocument, |
| token: CancellationToken |
| ): Promise<vscode.DocumentSymbol[]> { |
| const symbolProvider = new GoDocumentSymbolProvider(); |
| const isTestFile = document.fileName.endsWith('_test.go'); |
| const symbols = await symbolProvider.provideDocumentSymbols(document, token); |
| return symbols[0].children.filter((symbol) => { |
| if (symbol.kind === vscode.SymbolKind.Interface) { |
| return true; |
| } |
| if (symbol.kind === vscode.SymbolKind.Function) { |
| if ( |
| isTestFile && |
| (symbol.name.startsWith('Test') || |
| symbol.name.startsWith('Example') || |
| symbol.name.startsWith('Benchmark')) |
| ) { |
| return false; |
| } |
| return true; |
| } |
| return false; |
| }); |
| } |
| } |