This repository was archived by the owner on Dec 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathcode-action-adapter.ts
More file actions
135 lines (128 loc) · 4.63 KB
/
Copy pathcode-action-adapter.ts
File metadata and controls
135 lines (128 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import * as atomIde from 'atom-ide';
import LinterPushV2Adapter from './linter-push-v2-adapter';
import assert = require('assert');
import Convert from '../convert';
import ApplyEditAdapter from './apply-edit-adapter';
import {
CodeAction,
CodeActionParams,
Command,
LanguageClientConnection,
ServerCapabilities,
WorkspaceEdit,
} from '../languageclient';
import {
Range,
TextEditor,
} from 'atom';
export default class CodeActionAdapter {
/**
* @returns A {Boolean} indicating this adapter can adapt the server based on the
* given serverCapabilities.
*/
public static canAdapt(serverCapabilities: ServerCapabilities): boolean {
return serverCapabilities.codeActionProvider === true;
}
/**
* Public: Retrieves code actions for a given editor, range, and context (diagnostics).
* Throws an error if codeActionProvider is not a registered capability.
*
* @param connection A {LanguageClientConnection} to the language server that provides highlights.
* @param serverCapabilities The {ServerCapabilities} of the language server that will be used.
* @param editor The Atom {TextEditor} containing the diagnostics.
* @param range The Atom {Range} to fetch code actions for.
* @param diagnostics An {Array<atomIde$Diagnostic>} to fetch code actions for.
* This is typically a list of diagnostics intersecting `range`.
* @returns A {Promise} of an {Array} of {atomIde$CodeAction}s to display.
*/
public static async getCodeActions(
connection: LanguageClientConnection,
serverCapabilities: ServerCapabilities,
linterAdapter: LinterPushV2Adapter | undefined,
editor: TextEditor,
range: Range,
diagnostics: atomIde.Diagnostic[],
): Promise<atomIde.CodeAction[]> {
if (linterAdapter == null) {
return [];
}
assert(serverCapabilities.codeActionProvider, 'Must have the textDocument/codeAction capability');
const params = CodeActionAdapter.createCodeActionParams(linterAdapter, editor, range, diagnostics);
const actions = await connection.codeAction(params);
return actions.map((action) => CodeActionAdapter.createCodeAction(action, connection));
}
private static createCodeAction(
action: Command | CodeAction,
connection: LanguageClientConnection,
): atomIde.CodeAction {
return {
async apply() {
if (CodeAction.is(action)) {
CodeActionAdapter.applyWorkspaceEdit(action.edit);
await CodeActionAdapter.executeCommand(action.command, connection);
} else {
await CodeActionAdapter.executeCommand(action, connection);
}
},
getTitle(): Promise<string> {
return Promise.resolve(action.title);
},
// tslint:disable-next-line:no-empty
dispose(): void { },
};
}
private static applyWorkspaceEdit(
edit: WorkspaceEdit | undefined,
): void {
if (WorkspaceEdit.is(edit)) {
ApplyEditAdapter.onApplyEdit({ edit });
}
}
private static async executeCommand(
command: any,
connection: LanguageClientConnection,
): Promise<void> {
if (Command.is(command)) {
// eclipse.jdt.ls breaks with the spec and expects the client to handle the command
// https://github.com/eclipse/eclipse.jdt.ls/issues/376
if (command.command === 'java.apply.workspaceEdit') {
if (command.arguments) {
// Guaranteed only ever one element in the arguments array
const edit: WorkspaceEdit = command.arguments[0];
CodeActionAdapter.applyWorkspaceEdit(edit);
}
} else {
await connection.executeCommand({
command: command.command,
arguments: command.arguments,
});
}
}
}
private static createCodeActionParams(
linterAdapter: LinterPushV2Adapter,
editor: TextEditor,
range: Range,
diagnostics: atomIde.Diagnostic[],
): CodeActionParams {
return {
textDocument: Convert.editorToTextDocumentIdentifier(editor),
range: Convert.atomRangeToLSRange(range),
context: {
diagnostics: diagnostics.map((diagnostic) => {
// Retrieve the stored diagnostic code if it exists.
// Until the Linter API provides a place to store the code,
// there's no real way for the code actions API to give it back to us.
const converted = Convert.atomIdeDiagnosticToLSDiagnostic(diagnostic);
if (diagnostic.range != null && diagnostic.text != null) {
const code = linterAdapter.getDiagnosticCode(editor, diagnostic.range, diagnostic.text);
if (code != null) {
converted.code = code;
}
}
return converted;
}),
},
};
}
}