Skip to content
This repository has been archived by the owner on May 4, 2023. It is now read-only.

Server optimizations #81

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions server/src/diagnostics/ignore-violation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ import { CodeActionParams } from 'vscode-languageserver';
export const provideIgnoreFixCodeActions = (
document: TextDocument,
range: Range,
context: CodeActionParams
context: CodeActionParams,
shouldComputeEdit: boolean | undefined = false
): CodeAction[] => {
const diagnostics = context.context.diagnostics
.filter(diagnostic => diagnostic.source?.toLocaleString().indexOf(DIAGNOSTIC_SOURCE) != -1);

const ignoreFixes: CodeAction[] = [];
for (const diagnostic of diagnostics) {
ignoreFixes.push(createIgnoreFix(diagnostic, document));
ignoreFixes.push(createIgnoreFix(diagnostic, document, shouldComputeEdit));
}

return ignoreFixes;
Expand All @@ -39,14 +40,15 @@ export const provideIgnoreFixCodeActions = (
*/
export const createIgnoreFix = (
diagnostic: Diagnostic,
document: TextDocument
document: TextDocument,
shouldComputeEdit: boolean | undefined = false
): CodeAction => {
const ruleIdentifier = diagnostic.code;
const title = ruleIdentifier
? `Ignore rule ${ruleIdentifier}`
: "Ignore rule";

return {
const ignoreFix: CodeAction = {
title: title,
kind: CodeActionKind.QuickFix,
/**
Expand All @@ -73,6 +75,11 @@ export const createIgnoreFix = (
documentUri: document.uri
}
};
if (shouldComputeEdit) {
// @ts-ignore
ignoreFix.edit = createIgnoreWorkspaceEdit(document, ignoreFix.diagnostics[0]?.range);
}
return ignoreFix;
};

/**
Expand Down
15 changes: 11 additions & 4 deletions server/src/rosie/rosiefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,12 @@ const validateOffsetsAndCreateTextEdit = (
*/
export const provideApplyFixCodeActions = (
document: TextDocument,
range: Range
range: Range,
shouldComputeEdit: boolean | undefined = false
): CodeAction[] => {
const fixes = getFixesForDocument(document.uri, range);
return fixes
? fixes?.map(rosieFix => createRuleFix(document, rosieFix))
? fixes?.map(rosieFix => createRuleFix(document, rosieFix, shouldComputeEdit))
: [];
};

Expand All @@ -139,13 +140,14 @@ export const provideApplyFixCodeActions = (
*/
export const createRuleFix = (
document: TextDocument,
rosieFix: RosieFix
rosieFix: RosieFix,
shouldComputeEdit: boolean | undefined = false
): CodeAction => {
/*
From CodeAction's documentation:
If a code action provides an edit and a command, first the edit is executed and then the command.
*/
return {
const ruleFix: CodeAction = {
title: `Fix: ${rosieFix.description}`,
kind: CodeActionKind.QuickFix,
//Registers the 'codiga.applyFix' command for this CodeAction, so that we can execute further
Expand All @@ -165,4 +167,9 @@ export const createRuleFix = (
rosieFixEdits: rosieFix.edits
}
};
if (shouldComputeEdit) {
const rosieFixEdits = ruleFix.data.rosieFixEdits as RosieFixEdit[];
createAndSetRuleFixCodeActionEdit(ruleFix, document, rosieFixEdits);
}
return ruleFix;
};
49 changes: 27 additions & 22 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,27 @@ const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
let hasConfigurationCapability: boolean;
let hasWorkspaceCapability: boolean;
let hasWorkspaceFoldersCapability: boolean;
let hasDiagnosticCapability: boolean;
let hasApplyEditCapability: boolean;
let hasCodeActionLiteralSupport: boolean;
let hasCodeActionResolveSupport: boolean;
let hasCodeActionDataSupport: boolean;

let clientName: string | undefined;
let clientVersion: string | undefined;
/**
* This is set to true for clients that don't support codeAction/resolve,
* or they support it, but they announce their support incorrectly, e.g. due to a bug.
*/
let isShouldComputeEditInCodeAction: boolean | undefined = false;

/**
* Starts to initialize the language server.
*
* In case of VS Code, upon opening a different folder in the same window, the server is shut down,
* and a new language client is initialized.
*
* The language server presumes that diagnostics are supported by the client application, otherwise the integration
* of the server would not make much sense, thus there is no check for the textDocument/publishDiagnostics capability.
*/
connection.onInitialize((_params: InitializeParams) => {
//https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_didChangeConfiguration
Expand All @@ -82,12 +89,6 @@ connection.onInitialize((_params: InitializeParams) => {
cacheWorkspaceFolders(_params.rootUri ? [_params.rootUri] : []);
}

//https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_publishDiagnostics
hasDiagnosticCapability = !!(
_params.capabilities.textDocument &&
_params.capabilities.textDocument.publishDiagnostics
);

//https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_executeCommand
//https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_applyEdit
hasApplyEditCapability = !!(hasWorkspaceCapability && _params.capabilities.workspace?.applyEdit);
Expand All @@ -102,20 +103,23 @@ connection.onInitialize((_params: InitializeParams) => {
hasCodeActionResolveSupport = !!(_params.capabilities.textDocument?.codeAction?.resolveSupport);
hasCodeActionDataSupport = !!(_params.capabilities.textDocument?.codeAction?.dataSupport);

//If there is no support for diagnostics, which is the core functionality and purpose of the Rosie platform,
// return with no capability, and don't register any further event handler.
if (!hasDiagnosticCapability)
return { capabilities: {} };

//Retrieves client information, so that we can use it in the User-Agent header of GraphQL requests
clientName = _params.clientInfo?.name;
clientVersion = _params.clientInfo?.version;
//The condition for Eclipse can be removed, when
// https://github.com/eclipse/lsp4e/commit/2cf0a803936635a62d7fad2d05fde78bc7ce6a17 is released.
if (clientName?.startsWith("Eclipse IDE")) {
isShouldComputeEditInCodeAction = true;
}

/**
* Runs when the configuration, e.g. the Codiga API Token changes.
*/
connection.onDidChangeConfiguration(async _change => {
cacheCodigaApiToken(_change.settings?.codiga?.api?.token);
if (_change.settings?.codiga?.api?.token)
cacheCodigaApiToken(_change.settings?.codiga?.api?.token);
else if (_change.settings?.codigaApiToken)
cacheCodigaApiToken(_change.settings?.codigaApiToken);

documents.all().forEach(validateTextDocument);
});
Expand All @@ -134,8 +138,8 @@ connection.onInitialize((_params: InitializeParams) => {
if (hasApplyEditCapability && hasCodeActionLiteralSupport && params.context.diagnostics.length > 0) {
const document = documents.get(params.textDocument.uri);
if (document) {
codeActions.push(...provideApplyFixCodeActions(document, params.range));
const ignoreFixes = provideIgnoreFixCodeActions(document, params.range, params);
codeActions.push(...provideApplyFixCodeActions(document, params.range, isShouldComputeEditInCodeAction));
const ignoreFixes = provideIgnoreFixCodeActions(document, params.range, params, isShouldComputeEditInCodeAction);
codeActions.push(...ignoreFixes);
}
}
Expand All @@ -150,7 +154,7 @@ connection.onInitialize((_params: InitializeParams) => {
* only when we actually need that information, kind of lazy evaluation.
*/
connection.onCodeActionResolve(codeAction => {
if (codeAction.data) {
if (!isShouldComputeEditInCodeAction && codeAction.data) {
if (codeAction.data.fixKind === "rosie.rule.fix") {
const document = documents.get(codeAction.data.documentUri);
if (document) {
Expand Down Expand Up @@ -275,16 +279,17 @@ connection.onInitialized(async () => {
- if `onDidChangeConfiguration()` cached the value in the meantime, we don't update the cache (e.g. Jupyter Lab)
- if `onDidChangeConfiguration()` didn't cache the value, we use the returned value (e.g. VS Code)
*/
const apiToken = await connection.workspace.getConfiguration("codiga.api.token");
let apiToken = await connection.workspace.getConfiguration("codiga.api.token");
if (!apiToken) {
apiToken = await connection.workspace.getConfiguration("codigaApiToken");
}

if (!getApiToken()) {
cacheCodigaApiToken(apiToken);
}

//Start the rules cache updater only if the client supports diagnostics
if (hasDiagnosticCapability) {
setAllTextDocumentsValidator(() => documents.all().forEach(validateTextDocument));
refreshCachePeriodic();
}
setAllTextDocumentsValidator(() => documents.all().forEach(validateTextDocument));
refreshCachePeriodic();
});

/**
Expand Down