Files
languageservices/actions-languageserver/src/connection.ts
T

162 lines
5.4 KiB
TypeScript
Raw Normal View History

2022-12-21 13:34:10 +01:00
import {documentLinks, hover, validate, ValidationConfig} from "@github/actions-languageservice";
2022-12-13 14:58:14 -05:00
import {registerLogger, setLogLevel} from "@github/actions-languageservice/log";
import {Octokit} from "@octokit/rest";
2022-12-07 18:56:57 -08:00
import {
CompletionItem,
Connection,
2022-12-21 13:34:10 +01:00
DocumentLink,
DocumentLinkParams,
ExecuteCommandParams,
2022-12-07 18:56:57 -08:00
Hover,
HoverParams,
InitializeParams,
InitializeResult,
TextDocumentPositionParams,
TextDocuments,
TextDocumentSyncKind
} from "vscode-languageserver";
2022-12-13 14:58:14 -05:00
import {TextDocument} from "vscode-languageserver-textdocument";
2023-01-30 17:05:32 -08:00
import {getClient} from "./client";
import {Commands} from "./commands";
2022-12-13 14:58:14 -05:00
import {contextProviders} from "./context-providers";
2023-01-30 17:05:32 -08:00
import {descriptionProvider} from "./description-provider";
2023-02-07 13:48:33 -05:00
import {getFileProvider} from "./file-provider";
2022-12-13 14:58:14 -05:00
import {InitializationOptions, RepositoryContext} from "./initializationOptions";
import {onCompletion} from "./on-completion";
2023-02-07 16:21:08 -05:00
import {ReadFileRequest, Requests} from "./request";
import {fetchActionMetadata} from "./utils/action-metadata";
2022-12-13 14:58:14 -05:00
import {TTLCache} from "./utils/cache";
import {valueProviders} from "./value-providers";
2022-12-07 18:56:57 -08:00
export function initConnection(connection: Connection) {
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
2023-01-30 17:05:32 -08:00
let client: Octokit | undefined;
2022-12-07 18:56:57 -08:00
let repos: RepositoryContext[] = [];
const cache = new TTLCache();
let hasWorkspaceFolderCapability = false;
let hasDiagnosticRelatedInformationCapability = false;
// Register remote console logger with language service
registerLogger(connection.console);
connection.onInitialize((params: InitializeParams) => {
const capabilities = params.capabilities;
hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
hasDiagnosticRelatedInformationCapability = !!(
capabilities.textDocument &&
capabilities.textDocument.publishDiagnostics &&
capabilities.textDocument.publishDiagnostics.relatedInformation
);
const options: InitializationOptions = params.initializationOptions;
2023-01-30 17:05:32 -08:00
if (options.sessionToken) {
client = getClient(options.sessionToken, options.userAgent);
}
2022-12-07 18:56:57 -08:00
if (options.repos) {
repos = options.repos;
}
if (options.logLevel !== undefined) {
setLogLevel(options.logLevel);
}
const result: InitializeResult = {
capabilities: {
textDocumentSync: TextDocumentSyncKind.Full,
completionProvider: {
resolveProvider: false,
triggerCharacters: [":", "."]
},
2022-12-21 13:34:10 +01:00
hoverProvider: true,
documentLinkProvider: {
resolveProvider: false
}
2022-12-07 18:56:57 -08:00
}
};
if (hasWorkspaceFolderCapability) {
result.capabilities.workspace = {
workspaceFolders: {
supported: true
}
};
}
return result;
});
// The content of a text document has changed. This event is emitted
// when the text document first opened or when its content has changed.
documents.onDidChangeContent(change => {
validateTextDocument(change.document);
});
async function validateTextDocument(textDocument: TextDocument): Promise<void> {
const repoContext = repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri));
2022-12-13 14:58:14 -05:00
const config: ValidationConfig = {
2023-01-30 17:05:32 -08:00
valueProviderConfig: valueProviders(client, repoContext, cache),
contextProviderConfig: contextProviders(client, repoContext, cache),
fetchActionMetadata: async action => {
2023-01-30 17:05:32 -08:00
if (client) {
return await fetchActionMetadata(client, cache, action);
2022-12-13 14:58:14 -05:00
}
2023-01-30 17:05:32 -08:00
2022-12-13 14:58:14 -05:00
return undefined;
2023-02-07 13:48:33 -05:00
},
2023-02-07 15:46:50 -05:00
fileProvider: getFileProvider(client, cache, repoContext?.workspaceUri, async path => {
2023-02-07 16:21:08 -05:00
return await connection.sendRequest(Requests.ReadFile, {path} satisfies ReadFileRequest);
2023-02-07 15:46:50 -05:00
})
2022-12-13 14:58:14 -05:00
};
const result = await validate(textDocument, config);
2022-12-07 18:56:57 -08:00
connection.sendDiagnostics({uri: textDocument.uri, diagnostics: result});
}
connection.onCompletion(async ({position, textDocument}: TextDocumentPositionParams): Promise<CompletionItem[]> => {
return await onCompletion(
2023-02-07 18:35:50 -05:00
connection,
2022-12-07 18:56:57 -08:00
position,
documents.get(textDocument.uri)!,
2023-01-30 17:05:32 -08:00
client,
2022-12-07 18:56:57 -08:00
repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri)),
cache
);
});
connection.onHover(async ({position, textDocument}: HoverParams): Promise<Hover | null> => {
2023-02-02 08:57:34 -08:00
const repoContext = repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri));
2023-01-23 16:02:13 -05:00
return hover(documents.get(textDocument.uri)!, position, {
2023-02-02 08:57:34 -08:00
descriptionProvider: descriptionProvider(client, cache),
2023-02-15 14:50:26 -08:00
contextProviderConfig: repoContext && contextProviders(client, repoContext, cache),
fileProvider: getFileProvider(client, cache, repoContext?.workspaceUri, async path => {
return await connection.sendRequest(Requests.ReadFile, {path});
})
2023-01-23 16:02:13 -05:00
});
2022-12-07 18:56:57 -08:00
});
connection.onRequest("workspace/executeCommand", (params: ExecuteCommandParams) => {
if (params.command === Commands.ClearCache) {
cache.clear();
documents.all().forEach(validateTextDocument);
}
});
2022-12-21 13:34:10 +01:00
connection.onDocumentLinks(async ({textDocument}: DocumentLinkParams): Promise<DocumentLink[] | null> => {
return documentLinks(documents.get(textDocument.uri)!);
});
2022-12-07 18:56:57 -08:00
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
// Listen on the connection
connection.listen();
}