From 63f7de83b81720f350b8de3f399f609daeeb0df2 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Wed, 13 Feb 2019 11:41:32 +0000 Subject: [PATCH] feat: definitions for out-of-project files --- lib/auto-languageclient.ts | 51 +++++++++++++++++++++++++++++++++++--- lib/server-manager.ts | 9 +++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/lib/auto-languageclient.ts b/lib/auto-languageclient.ts index 410e1011..bb39d757 100644 --- a/lib/auto-languageclient.ts +++ b/lib/auto-languageclient.ts @@ -26,7 +26,13 @@ import * as Utils from "./utils" import { Socket } from "net" import { LanguageClientConnection } from "./languageclient" import { ConsoleLogger, FilteredLogger, Logger } from "./logger" -import { LanguageServerProcess, ServerManager, ActiveServer } from "./server-manager.js" +import { + LanguageServerProcess, + ServerManager, + ActiveServer, + normalizePath, + considerAdditionalPath, +} from "./server-manager.js" import { Disposable, CompositeDisposable, Point, Range, TextEditor } from "atom" import * as ac from "atom/autocomplete-plus" import { basename } from "path" @@ -391,6 +397,7 @@ export default class AutoLanguageClient { connection, capabilities: initializeResponse.capabilities, disposable: new CompositeDisposable(), + additionalPaths: new Set(), } this.postInitialization(newServer) connection.initialized() @@ -481,10 +488,22 @@ export default class AutoLanguageClient { /** (Optional) Finds the project path. If there is a custom logic for finding projects override this method. */ protected determineProjectPath(textEditor: TextEditor): string | null { const filePath = textEditor.getPath() - if (filePath == null) { + // TODO can filePath be null + if (filePath === null || filePath === undefined) { return null } - return this._serverManager.getNormalizedProjectPaths().find((d) => filePath.startsWith(d)) || null + const projectPath = this._serverManager.getNormalizedProjectPaths().find((d) => filePath.startsWith(d)) + if (projectPath !== undefined) { + return projectPath + } + + const serverWithClaim = this._serverManager + .getActiveServers() + .find((server) => server.additionalPaths?.has(path.dirname(filePath))) + if (serverWithClaim !== undefined) { + return normalizePath(serverWithClaim.projectPath) + } + return null } /** @@ -678,7 +697,21 @@ export default class AutoLanguageClient { } this.definitions = this.definitions || new DefinitionAdapter() - return this.definitions.getDefinition(server.connection, server.capabilities, this.getLanguageName(), editor, point) + const query = await this.definitions.getDefinition( + server.connection, + server.capabilities, + this.getLanguageName(), + editor, + point + ) + + if (query !== null && this.serversSupportDefinitionDestinations() && server.additionalPaths !== undefined) { + for (const def of query.definitions) { + considerAdditionalPath(server as ActiveServer & { additionalPaths: Set }, def.path) + } + } + + return query } // Outline View via LS documentSymbol--------------------------------- @@ -965,6 +998,16 @@ export default class AutoLanguageClient { .forEach((line) => this.logger.warn(`stderr ${line}`)) } + /** + * Indicates that the language server can support LSP functionality for out of project files indicated by + * `textDocument/definition` responses. + * + * Default: false + */ + protected serversSupportDefinitionDestinations(): boolean { + return false + } + private getServerAdapter( server: ActiveServer, adapter: T diff --git a/lib/server-manager.ts b/lib/server-manager.ts index a5109ee9..357de66f 100644 --- a/lib/server-manager.ts +++ b/lib/server-manager.ts @@ -22,6 +22,8 @@ export interface ActiveServer { process: LanguageServerProcess connection: ls.LanguageClientConnection capabilities: ls.ServerCapabilities + /** Out of project directories that this server can also support. */ + additionalPaths?: Set } interface RestartCounter { @@ -343,3 +345,10 @@ export function normalizedProjectPathToWorkspaceFolder(normalizedProjectPath: st export function normalizePath(projectPath: string): string { return !projectPath.endsWith(path.sep) ? path.join(projectPath, path.sep) : projectPath } + +/** Considers a path for inclusion in `additionalPaths`. */ +export function considerAdditionalPath(server: ActiveServer & { additionalPaths: Set }, additionalPath: string): void { + if (!additionalPath.startsWith(server.projectPath)) { + server.additionalPaths.add(path.dirname(additionalPath)) + } +}