mirror of
https://github.com/jlengrand/elm-language-client-vscode.git
synced 2026-03-10 08:11:17 +00:00
Fix linting
This commit is contained in:
23
.vscode/launch.json
vendored
23
.vscode/launch.json
vendored
@@ -7,8 +7,12 @@
|
||||
"request": "launch",
|
||||
"name": "Launch Client",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
|
||||
"outFiles": ["${workspaceRoot}/client/out/**/*.js"],
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceRoot}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/client/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": {
|
||||
"type": "npm",
|
||||
"script": "watch"
|
||||
@@ -20,7 +24,9 @@
|
||||
"name": "Attach to Server",
|
||||
"port": 6009,
|
||||
"restart": true,
|
||||
"outFiles": ["${workspaceRoot}/server/out/**/*.js"]
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/server/out/**/*.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Language Server E2E Test",
|
||||
@@ -32,13 +38,18 @@
|
||||
"--extensionTestsPath=${workspaceRoot}/client/out/test",
|
||||
"${workspaceRoot}/client/testFixture"
|
||||
],
|
||||
"outFiles": ["${workspaceRoot}/client/out/test/**/*.js"]
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/client/out/test/**/*.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Client + Server",
|
||||
"configurations": ["Launch Client", "Attach to Server"]
|
||||
"configurations": [
|
||||
"Launch Client",
|
||||
"Attach to Server"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,89 +1,88 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
import { workspace, ExtensionContext } from 'vscode';
|
||||
import { ExtensionContext, workspace } from "vscode";
|
||||
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind
|
||||
} from 'vscode-languageclient';
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind,
|
||||
} from "vscode-languageclient";
|
||||
|
||||
import * as path from 'path';
|
||||
import * as path from "path";
|
||||
|
||||
let client: LanguageClient;
|
||||
|
||||
export async function activate(context: ExtensionContext) {
|
||||
// We get activated if there is one or more elm.json file in the workspace
|
||||
// Start one server for each directory with an elm.json
|
||||
// and watch Elm files in those directories.
|
||||
let elmJsons = await workspace.findFiles('**/elm.json');
|
||||
for (let uri of elmJsons) {
|
||||
startClient(path.dirname(uri.fsPath), context);
|
||||
}
|
||||
// TODO: watch for addition and removal of 'elm.json' files
|
||||
// and start and stop clients for those directories.
|
||||
// We get activated if there is one or more elm.json file in the workspace
|
||||
// Start one server for each directory with an elm.json
|
||||
// and watch Elm files in those directories.
|
||||
const elmJsons = await workspace.findFiles("**/elm.json");
|
||||
for (const uri of elmJsons) {
|
||||
startClient(path.dirname(uri.fsPath), context);
|
||||
}
|
||||
// TODO: watch for addition and removal of 'elm.json' files
|
||||
// and start and stop clients for those directories.
|
||||
}
|
||||
|
||||
|
||||
let clients: Map<string, LanguageClient> = new Map();
|
||||
const clients: Map<string, LanguageClient> = new Map();
|
||||
function startClient(dir: string, context: ExtensionContext) {
|
||||
if (clients.has(dir)) {
|
||||
// Client was already started for this directory
|
||||
return;
|
||||
}
|
||||
if (clients.has(dir)) {
|
||||
// Client was already started for this directory
|
||||
return;
|
||||
}
|
||||
|
||||
let serverModule = context.asAbsolutePath(
|
||||
path.join('server', 'out', 'index.js')
|
||||
);
|
||||
// The debug options for the server
|
||||
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
|
||||
let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
|
||||
const serverModule = context.asAbsolutePath(
|
||||
path.join("server", "out", "index.js"),
|
||||
);
|
||||
// The debug options for the server
|
||||
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
|
||||
const debugOptions = { execArgv: ["--nolazy", "--inspect=6009"] };
|
||||
|
||||
// If the extension is launched in debug mode then the debug server options are used
|
||||
// Otherwise the run options are used
|
||||
let serverOptions: ServerOptions = {
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
debug: {
|
||||
module: serverModule,
|
||||
transport: TransportKind.ipc,
|
||||
options: debugOptions
|
||||
}
|
||||
};
|
||||
// If the extension is launched in debug mode then the debug server options are used
|
||||
// Otherwise the run options are used
|
||||
const serverOptions: ServerOptions = {
|
||||
debug: {
|
||||
module: serverModule,
|
||||
options: debugOptions,
|
||||
transport: TransportKind.ipc,
|
||||
},
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
};
|
||||
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
// Register the server for Elm documents in the directory
|
||||
documentSelector: [
|
||||
{
|
||||
scheme: 'file',
|
||||
pattern: path.join(dir, '**', '*.elm')
|
||||
}
|
||||
],
|
||||
// Notify the server about file changes to 'elm.json'
|
||||
synchronize: {
|
||||
fileEvents: workspace.createFileSystemWatcher(path.join(dir, 'elm.json'))
|
||||
}
|
||||
};
|
||||
// Options to control the language client
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
// Register the server for Elm documents in the directory
|
||||
documentSelector: [
|
||||
{
|
||||
pattern: path.join(dir, "**", "*.elm"),
|
||||
scheme: "file",
|
||||
},
|
||||
],
|
||||
// Notify the server about file changes to 'elm.json'
|
||||
synchronize: {
|
||||
fileEvents: workspace.createFileSystemWatcher(path.join(dir, "elm.json")),
|
||||
},
|
||||
};
|
||||
|
||||
// Create the language client and start the client.
|
||||
client = new LanguageClient(
|
||||
'elmLanguageServer',
|
||||
'Elm Language Server',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
// Create the language client and start the client.
|
||||
client = new LanguageClient(
|
||||
"elmLanguageServer",
|
||||
"Elm Language Server",
|
||||
serverOptions,
|
||||
clientOptions,
|
||||
);
|
||||
|
||||
// Start the client. This will also launch the server
|
||||
client.start();
|
||||
client.info(`Starting language server for ${dir}`);
|
||||
clients.set(dir, client);
|
||||
// Start the client. This will also launch the server
|
||||
client.start();
|
||||
client.info(`Starting language server for ${dir}`);
|
||||
clients.set(dir, client);
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> {
|
||||
let promises: Thenable<void>[] = [];
|
||||
for (let client of clients.values()) {
|
||||
promises.push(client.stop());
|
||||
}
|
||||
return Promise.all(promises).then(() => undefined);
|
||||
const promises: Array<Thenable<void>> = [];
|
||||
for (const client of clients.values()) {
|
||||
promises.push(client.stop());
|
||||
}
|
||||
return Promise.all(promises).then(() => undefined);
|
||||
}
|
||||
|
||||
@@ -2,43 +2,43 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as assert from 'assert';
|
||||
import { getDocUri, activate } from './helper';
|
||||
import * as assert from "assert";
|
||||
import * as vscode from "vscode";
|
||||
import { activate, getDocUri } from "./helper";
|
||||
|
||||
describe('Should do completion', () => {
|
||||
const docUri = getDocUri('completion.txt');
|
||||
describe("Should do completion", () => {
|
||||
const docUri = getDocUri("completion.txt");
|
||||
|
||||
it('Completes JS/TS in txt file', async () => {
|
||||
await testCompletion(docUri, new vscode.Position(0, 0), {
|
||||
items: [
|
||||
{ label: 'JavaScript', kind: vscode.CompletionItemKind.Text },
|
||||
{ label: 'TypeScript', kind: vscode.CompletionItemKind.Text }
|
||||
]
|
||||
});
|
||||
});
|
||||
it("Completes JS/TS in txt file", async () => {
|
||||
await testCompletion(docUri, new vscode.Position(0, 0), {
|
||||
items: [
|
||||
{ label: "JavaScript", kind: vscode.CompletionItemKind.Text },
|
||||
{ label: "TypeScript", kind: vscode.CompletionItemKind.Text },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function testCompletion(
|
||||
docUri: vscode.Uri,
|
||||
position: vscode.Position,
|
||||
expectedCompletionList: vscode.CompletionList
|
||||
docUri: vscode.Uri,
|
||||
position: vscode.Position,
|
||||
expectedCompletionList: vscode.CompletionList,
|
||||
) {
|
||||
await activate(docUri);
|
||||
await activate(docUri);
|
||||
|
||||
// Executing the command `vscode.executeCompletionItemProvider` to simulate triggering completion
|
||||
const actualCompletionList = (await vscode.commands.executeCommand(
|
||||
'vscode.executeCompletionItemProvider',
|
||||
docUri,
|
||||
position
|
||||
)) as vscode.CompletionList;
|
||||
// Executing the command `vscode.executeCompletionItemProvider` to simulate triggering completion
|
||||
const actualCompletionList = (await vscode.commands.executeCommand(
|
||||
"vscode.executeCompletionItemProvider",
|
||||
docUri,
|
||||
position,
|
||||
)) as vscode.CompletionList;
|
||||
|
||||
assert.equal(actualCompletionList.items.length, expectedCompletionList.items.length);
|
||||
expectedCompletionList.items.forEach((expectedItem, i) => {
|
||||
const actualItem = actualCompletionList.items[i];
|
||||
assert.equal(actualItem.label, expectedItem.label);
|
||||
assert.equal(actualItem.kind, expectedItem.kind);
|
||||
});
|
||||
assert.equal(actualCompletionList.items.length, expectedCompletionList.items.length);
|
||||
expectedCompletionList.items.forEach((expectedItem, i) => {
|
||||
const actualItem = actualCompletionList.items[i];
|
||||
assert.equal(actualItem.label, expectedItem.label);
|
||||
assert.equal(actualItem.kind, expectedItem.kind);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,41 +2,41 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
import * as vscode from 'vscode'
|
||||
import * as assert from 'assert'
|
||||
import { getDocUri, activate } from './helper'
|
||||
import * as assert from "assert";
|
||||
import * as vscode from "vscode";
|
||||
import { activate, getDocUri } from "./helper";
|
||||
|
||||
describe('Should get diagnostics', () => {
|
||||
const docUri = getDocUri('diagnostics.txt')
|
||||
describe("Should get diagnostics", () => {
|
||||
const docUri = getDocUri("diagnostics.txt");
|
||||
|
||||
it('Diagnoses uppercase texts', async () => {
|
||||
it("Diagnoses uppercase texts", async () => {
|
||||
await testDiagnostics(docUri, [
|
||||
{ message: 'ANY is all uppercase.', range: toRange(0, 0, 0, 3), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
|
||||
{ message: 'ANY is all uppercase.', range: toRange(0, 14, 0, 17), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
|
||||
{ message: 'OS is all uppercase.', range: toRange(0, 18, 0, 20), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' }
|
||||
])
|
||||
})
|
||||
})
|
||||
{ message: "ANY is all uppercase.", range: toRange(0, 0, 0, 3), severity: vscode.DiagnosticSeverity.Warning, source: "ex" },
|
||||
{ message: "ANY is all uppercase.", range: toRange(0, 14, 0, 17), severity: vscode.DiagnosticSeverity.Warning, source: "ex" },
|
||||
{ message: "OS is all uppercase.", range: toRange(0, 18, 0, 20), severity: vscode.DiagnosticSeverity.Warning, source: "ex" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
function toRange(sLine: number, sChar: number, eLine: number, eChar: number) {
|
||||
const start = new vscode.Position(sLine, sChar)
|
||||
const end = new vscode.Position(eLine, eChar)
|
||||
return new vscode.Range(start, end)
|
||||
const start = new vscode.Position(sLine, sChar);
|
||||
const end = new vscode.Position(eLine, eChar);
|
||||
return new vscode.Range(start, end);
|
||||
}
|
||||
|
||||
async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: vscode.Diagnostic[]) {
|
||||
await activate(docUri)
|
||||
await activate(docUri);
|
||||
|
||||
const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
|
||||
|
||||
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);
|
||||
|
||||
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
|
||||
const actualDiagnostic = actualDiagnostics[i]
|
||||
assert.equal(actualDiagnostic.message, expectedDiagnostic.message)
|
||||
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range)
|
||||
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity)
|
||||
})
|
||||
}
|
||||
const actualDiagnostic = actualDiagnostics[i];
|
||||
assert.equal(actualDiagnostic.message, expectedDiagnostic.message);
|
||||
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range);
|
||||
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as path from "path";
|
||||
import * as vscode from "vscode";
|
||||
|
||||
export let doc: vscode.TextDocument;
|
||||
export let editor: vscode.TextEditor;
|
||||
@@ -16,33 +16,33 @@ export let platformEol: string;
|
||||
* Activates the vscode.lsp-sample extension
|
||||
*/
|
||||
export async function activate(docUri: vscode.Uri) {
|
||||
// The extensionId is `publisher.name` from package.json
|
||||
const ext = vscode.extensions.getExtension('vscode.lsp-sample');
|
||||
await ext.activate();
|
||||
try {
|
||||
doc = await vscode.workspace.openTextDocument(docUri);
|
||||
editor = await vscode.window.showTextDocument(doc);
|
||||
await sleep(2000); // Wait for server activation
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
// The extensionId is `publisher.name` from package.json
|
||||
const ext = vscode.extensions.getExtension("vscode.lsp-sample");
|
||||
await ext.activate();
|
||||
try {
|
||||
doc = await vscode.workspace.openTextDocument(docUri);
|
||||
editor = await vscode.window.showTextDocument(doc);
|
||||
await sleep(2000); // Wait for server activation
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export const getDocPath = (p: string) => {
|
||||
return path.resolve(__dirname, '../../testFixture', p);
|
||||
return path.resolve(__dirname, "../../testFixture", p);
|
||||
};
|
||||
export const getDocUri = (p: string) => {
|
||||
return vscode.Uri.file(getDocPath(p));
|
||||
return vscode.Uri.file(getDocPath(p));
|
||||
};
|
||||
|
||||
export async function setTestContent(content: string): Promise<boolean> {
|
||||
const all = new vscode.Range(
|
||||
doc.positionAt(0),
|
||||
doc.positionAt(doc.getText().length)
|
||||
);
|
||||
return editor.edit(eb => eb.replace(all, content));
|
||||
const all = new vscode.Range(
|
||||
doc.positionAt(0),
|
||||
doc.positionAt(doc.getText().length),
|
||||
);
|
||||
return editor.edit((eb) => eb.replace(all, content));
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
import * as testRunner from 'vscode/lib/testrunner';
|
||||
import * as testRunner from "vscode/lib/testrunner";
|
||||
|
||||
testRunner.configure({
|
||||
ui: 'bdd',
|
||||
timeout: 100000,
|
||||
ui: "bdd",
|
||||
useColors: true,
|
||||
timeout: 100000
|
||||
});
|
||||
|
||||
module.exports = testRunner;
|
||||
module.exports = testRunner;
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"lib": ["es6"],
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
import {
|
||||
ClientCapabilities,
|
||||
ServerCapabilities,
|
||||
TextDocumentSyncKind,
|
||||
} from 'vscode-languageserver';
|
||||
ClientCapabilities,
|
||||
ServerCapabilities,
|
||||
TextDocumentSyncKind,
|
||||
} from "vscode-languageserver";
|
||||
|
||||
export class CapabilityCalculator {
|
||||
private clientCapabilities: ClientCapabilities;
|
||||
private clientCapabilities: ClientCapabilities;
|
||||
|
||||
constructor(clientCapabilities: ClientCapabilities) {
|
||||
this.clientCapabilities = clientCapabilities;
|
||||
}
|
||||
constructor(clientCapabilities: ClientCapabilities) {
|
||||
this.clientCapabilities = clientCapabilities;
|
||||
}
|
||||
|
||||
get capabilities(): ServerCapabilities {
|
||||
this.clientCapabilities;
|
||||
get capabilities(): ServerCapabilities {
|
||||
this.clientCapabilities;
|
||||
|
||||
return {
|
||||
// Perform incremental syncs
|
||||
// Incremental sync is disabled for now due to not being able to get the
|
||||
// old text in ASTProvider
|
||||
// textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
textDocumentSync: TextDocumentSyncKind.Full,
|
||||
// documentHighlightProvider: true,
|
||||
// foldingRangeProvider: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
// Perform incremental syncs
|
||||
// Incremental sync is disabled for now due to not being able to get the
|
||||
// old text in ASTProvider
|
||||
// textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
textDocumentSync: TextDocumentSyncKind.Full,
|
||||
// documentHighlightProvider: true,
|
||||
// foldingRangeProvider: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
import { Tree } from 'tree-sitter';
|
||||
import { Tree } from "tree-sitter";
|
||||
|
||||
export interface IForest {
|
||||
getTree(uri: string): Tree;
|
||||
setTree(uri: string, tree: Tree): void;
|
||||
removeTree(uri: string): boolean;
|
||||
getTree(uri: string): Tree;
|
||||
setTree(uri: string, tree: Tree): void;
|
||||
removeTree(uri: string): boolean;
|
||||
}
|
||||
|
||||
export class Forest implements IForest {
|
||||
private trees: Map<string, Tree>;
|
||||
private trees: Map<string, Tree>;
|
||||
|
||||
constructor() {
|
||||
this.trees = new Map();
|
||||
}
|
||||
constructor() {
|
||||
this.trees = new Map();
|
||||
}
|
||||
|
||||
public getTree(uri: string): Tree {
|
||||
return this.trees.get(uri);
|
||||
}
|
||||
public getTree(uri: string): Tree {
|
||||
return this.trees.get(uri);
|
||||
}
|
||||
|
||||
public setTree(uri: string, tree: Tree): void {
|
||||
this.trees.set(uri, tree);
|
||||
}
|
||||
public setTree(uri: string, tree: Tree): void {
|
||||
this.trees.set(uri, tree);
|
||||
}
|
||||
|
||||
public removeTree(uri: string): boolean {
|
||||
return this.trees.delete(uri);
|
||||
}
|
||||
}
|
||||
public removeTree(uri: string): boolean {
|
||||
return this.trees.delete(uri);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import {
|
||||
createConnection,
|
||||
IConnection,
|
||||
InitializeParams,
|
||||
ProposedFeatures,
|
||||
} from 'vscode-languageserver';
|
||||
createConnection,
|
||||
IConnection,
|
||||
InitializeParams,
|
||||
ProposedFeatures,
|
||||
} from "vscode-languageserver";
|
||||
|
||||
import { ILanguageServer } from './server';
|
||||
import { rebuildTreeSitter } from './util/rebuilder';
|
||||
import { ILanguageServer } from "./server";
|
||||
import { rebuildTreeSitter } from "./util/rebuilder";
|
||||
|
||||
const connection: IConnection = createConnection(ProposedFeatures.all);
|
||||
|
||||
connection.onInitialize(async (params: InitializeParams) => {
|
||||
connection.console.info('Initializing Elm language server...');
|
||||
connection.console.info("Initializing Elm language server...");
|
||||
|
||||
connection.console.info('Rebuilding tree-sitter for local Electron version');
|
||||
const rebuildResult: [void | Error, void | Error] = await rebuildTreeSitter();
|
||||
for (const result of rebuildResult) {
|
||||
if (result) {
|
||||
connection.console.error('Rebuild failed!');
|
||||
connection.console.error(result.toString());
|
||||
connection.console.info("Rebuilding tree-sitter for local Electron version");
|
||||
const rebuildResult: [void | Error, void | Error] = await rebuildTreeSitter();
|
||||
for (const result of rebuildResult) {
|
||||
if (result) {
|
||||
connection.console.error("Rebuild failed!");
|
||||
connection.console.error(result.toString());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
connection.console.info('Rebuild succeeded!');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
connection.console.info("Rebuild succeeded!");
|
||||
|
||||
const { Server } = await import('./server');
|
||||
const server: ILanguageServer = new Server(connection, params);
|
||||
const { Server } = await import("./server");
|
||||
const server: ILanguageServer = new Server(connection, params);
|
||||
|
||||
return server.capabilities;
|
||||
return server.capabilities;
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
connection.listen();
|
||||
|
||||
@@ -2,30 +2,30 @@ import { Point as TSPosition } from 'tree-sitter';
|
||||
import { Position as VSPosition } from 'vscode-languageserver';
|
||||
|
||||
export class Position {
|
||||
private row: number;
|
||||
private col: number;
|
||||
private row: number;
|
||||
private col: number;
|
||||
|
||||
constructor(row: number, col: number) {
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
}
|
||||
constructor(row: number, col: number) {
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
public static FROM_VS_POSITION(position: VSPosition): Position {
|
||||
return new Position(position.line, position.character);
|
||||
}
|
||||
public static FROM_VS_POSITION(position: VSPosition): Position {
|
||||
return new Position(position.line, position.character);
|
||||
}
|
||||
|
||||
public static FROM_TS_POSITION(position: TSPosition): Position {
|
||||
return new Position(position.row, position.column);
|
||||
}
|
||||
public static FROM_TS_POSITION(position: TSPosition): Position {
|
||||
return new Position(position.row, position.column);
|
||||
}
|
||||
|
||||
public toVSPosition(): VSPosition {
|
||||
return VSPosition.create(this.row, this.col);
|
||||
}
|
||||
public toVSPosition(): VSPosition {
|
||||
return VSPosition.create(this.row, this.col);
|
||||
}
|
||||
|
||||
public toTSPosition(): TSPosition {
|
||||
return {
|
||||
row: this.row,
|
||||
column: this.col,
|
||||
};
|
||||
}
|
||||
public toTSPosition(): TSPosition {
|
||||
return {
|
||||
row: this.row,
|
||||
column: this.col,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,91 @@
|
||||
import * as Parser from 'tree-sitter';
|
||||
import * as Parser from "tree-sitter";
|
||||
// tslint:disable-next-line no-duplicate-imports
|
||||
import { Point, SyntaxNode, Tree } from 'tree-sitter';
|
||||
import * as TreeSitterElm from 'tree-sitter-elm';
|
||||
import { Point, SyntaxNode, Tree } from "tree-sitter";
|
||||
import * as TreeSitterElm from "tree-sitter-elm";
|
||||
|
||||
import {
|
||||
DidChangeTextDocumentParams,
|
||||
DidCloseTextDocumentParams,
|
||||
DidOpenTextDocumentParams,
|
||||
IConnection,
|
||||
TextDocumentIdentifier,
|
||||
TextDocumentItem,
|
||||
VersionedTextDocumentIdentifier,
|
||||
} from 'vscode-languageserver';
|
||||
DidChangeTextDocumentParams,
|
||||
DidCloseTextDocumentParams,
|
||||
DidOpenTextDocumentParams,
|
||||
IConnection,
|
||||
TextDocumentIdentifier,
|
||||
TextDocumentItem,
|
||||
VersionedTextDocumentIdentifier,
|
||||
} from "vscode-languageserver";
|
||||
|
||||
import { IForest } from '../forest';
|
||||
import { Position } from '../position';
|
||||
import { IForest } from "../forest";
|
||||
import { Position } from "../position";
|
||||
|
||||
export class ASTProvider {
|
||||
private connection: IConnection;
|
||||
private forest: IForest;
|
||||
private parser: Parser;
|
||||
private connection: IConnection;
|
||||
private forest: IForest;
|
||||
private parser: Parser;
|
||||
|
||||
constructor(connection: IConnection, forest: IForest) {
|
||||
this.connection = connection;
|
||||
this.forest = forest;
|
||||
this.parser = new Parser();
|
||||
this.parser.setLanguage(TreeSitterElm);
|
||||
constructor(connection: IConnection, forest: IForest) {
|
||||
this.connection = connection;
|
||||
this.forest = forest;
|
||||
this.parser = new Parser();
|
||||
this.parser.setLanguage(TreeSitterElm);
|
||||
|
||||
this.connection.onDidOpenTextDocument(this.handleOpenTextDocument);
|
||||
this.connection.onDidChangeTextDocument(this.handleChangeTextDocument);
|
||||
this.connection.onDidCloseTextDocument(this.handleCloseTextDocument);
|
||||
}
|
||||
this.connection.onDidOpenTextDocument(this.handleOpenTextDocument);
|
||||
this.connection.onDidChangeTextDocument(this.handleChangeTextDocument);
|
||||
this.connection.onDidCloseTextDocument(this.handleCloseTextDocument);
|
||||
}
|
||||
|
||||
protected handleOpenTextDocument = async (params: DidOpenTextDocumentParams): Promise<void> => {
|
||||
this.connection.console.log('Opened text document, going to parse it');
|
||||
const document: TextDocumentItem = params.textDocument;
|
||||
const tree: Tree = this.parser.parse(document.text);
|
||||
this.forest.setTree(document.uri, tree);
|
||||
};
|
||||
|
||||
protected handleChangeTextDocument = async (
|
||||
params: DidChangeTextDocumentParams
|
||||
): Promise<void> => {
|
||||
this.connection.console.log('Changed text document, going to parse it');
|
||||
const document: VersionedTextDocumentIdentifier = params.textDocument;
|
||||
let tree: Tree = this.forest.getTree(document.uri);
|
||||
if (tree !== undefined) {
|
||||
for (const changeEvent of params.contentChanges) {
|
||||
if (changeEvent.range && changeEvent.rangeLength) {
|
||||
// range is range of the change. end is exclusive
|
||||
// rangeLength is length of text removed
|
||||
// text is new text
|
||||
const { range, rangeLength, text } = changeEvent;
|
||||
const startIndex: number = range.start.line * range.start.character;
|
||||
const oldEndIndex: number = startIndex + rangeLength - 1;
|
||||
tree.edit({
|
||||
startIndex, // index in old doc the change started
|
||||
oldEndIndex, // end index for old version of text
|
||||
newEndIndex: range.end.line * range.end.character - 1, // end index for new version of text
|
||||
protected handleOpenTextDocument = async (params: DidOpenTextDocumentParams): Promise<void> => {
|
||||
this.connection.console.log("Opened text document, going to parse it");
|
||||
const document: TextDocumentItem = params.textDocument;
|
||||
const tree: Tree = this.parser.parse(document.text);
|
||||
this.forest.setTree(document.uri, tree);
|
||||
}
|
||||
|
||||
startPosition: Position.FROM_VS_POSITION(range.start).toTSPosition(), // position in old doc change started
|
||||
oldEndPosition: this.computeEndPosition(startIndex, oldEndIndex, tree), // position in old doc change ended.
|
||||
newEndPosition: Position.FROM_VS_POSITION(range.end).toTSPosition(), // position in new doc change ended
|
||||
});
|
||||
tree = this.parser.parse(text, tree);
|
||||
} else {
|
||||
tree = this.buildTree(changeEvent.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected handleChangeTextDocument = async (
|
||||
params: DidChangeTextDocumentParams,
|
||||
): Promise<void> => {
|
||||
this.connection.console.log("Changed text document, going to parse it");
|
||||
const document: VersionedTextDocumentIdentifier = params.textDocument;
|
||||
let tree: Tree = this.forest.getTree(document.uri);
|
||||
if (tree !== undefined) {
|
||||
for (const changeEvent of params.contentChanges) {
|
||||
if (changeEvent.range && changeEvent.rangeLength) {
|
||||
// range is range of the change. end is exclusive
|
||||
// rangeLength is length of text removed
|
||||
// text is new text
|
||||
const { range, rangeLength, text } = changeEvent;
|
||||
const startIndex: number = range.start.line * range.start.character;
|
||||
const oldEndIndex: number = startIndex + rangeLength - 1;
|
||||
tree.edit({
|
||||
startIndex, // index in old doc the change started
|
||||
oldEndIndex, // end index for old version of text
|
||||
newEndIndex: range.end.line * range.end.character - 1, // end index for new version of text
|
||||
|
||||
this.forest.setTree(document.uri, tree);
|
||||
};
|
||||
startPosition: Position.FROM_VS_POSITION(range.start).toTSPosition(), // position in old doc change started
|
||||
oldEndPosition: this.computeEndPosition(startIndex, oldEndIndex, tree), // position in old doc change ended.
|
||||
newEndPosition: Position.FROM_VS_POSITION(range.end).toTSPosition(), // position in new doc change ended
|
||||
});
|
||||
tree = this.parser.parse(text, tree);
|
||||
} else {
|
||||
tree = this.buildTree(changeEvent.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected handleCloseTextDocument = async (params: DidCloseTextDocumentParams): Promise<void> => {
|
||||
const document: TextDocumentIdentifier = params.textDocument;
|
||||
this.forest.removeTree(document.uri);
|
||||
};
|
||||
this.forest.setTree(document.uri, tree);
|
||||
}
|
||||
|
||||
private buildTree = (text: string): Tree => {
|
||||
return this.parser.parse(text);
|
||||
};
|
||||
protected handleCloseTextDocument = async (params: DidCloseTextDocumentParams): Promise<void> => {
|
||||
const document: TextDocumentIdentifier = params.textDocument;
|
||||
this.forest.removeTree(document.uri);
|
||||
}
|
||||
|
||||
private computeEndPosition = (startIndex: number, endIndex: number, tree: Tree): Point => {
|
||||
// TODO handle case where this method call fails for whatever reason
|
||||
const node: SyntaxNode = tree.rootNode.descendantForIndex(startIndex, endIndex);
|
||||
private buildTree = (text: string): Tree => {
|
||||
return this.parser.parse(text);
|
||||
}
|
||||
|
||||
return node.endPosition;
|
||||
};
|
||||
}
|
||||
private computeEndPosition = (startIndex: number, endIndex: number, tree: Tree): Point => {
|
||||
// TODO handle case where this method call fails for whatever reason
|
||||
const node: SyntaxNode = tree.rootNode.descendantForIndex(startIndex, endIndex);
|
||||
|
||||
return node.endPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import { Connection, InitializeParams, InitializeResult } from 'vscode-languageserver';
|
||||
import { Connection, InitializeParams, InitializeResult } from "vscode-languageserver";
|
||||
|
||||
import { CapabilityCalculator } from './capabilityCalculator';
|
||||
import { Forest } from './forest';
|
||||
import { ASTProvider } from './providers/astProvider';
|
||||
import { CapabilityCalculator } from "./capabilityCalculator";
|
||||
import { Forest } from "./forest";
|
||||
import { ASTProvider } from "./providers/astProvider";
|
||||
|
||||
export interface ILanguageServer {
|
||||
readonly capabilities: InitializeResult;
|
||||
readonly capabilities: InitializeResult;
|
||||
}
|
||||
|
||||
export class Server implements ILanguageServer {
|
||||
public connection: Connection;
|
||||
private calculator: CapabilityCalculator;
|
||||
private forest: Forest;
|
||||
public connection: Connection;
|
||||
private calculator: CapabilityCalculator;
|
||||
private forest: Forest;
|
||||
|
||||
constructor(connection: Connection, params: InitializeParams) {
|
||||
this.connection = connection;
|
||||
this.forest = new Forest();
|
||||
constructor(connection: Connection, params: InitializeParams) {
|
||||
this.connection = connection;
|
||||
this.forest = new Forest();
|
||||
|
||||
this.registerProviders();
|
||||
}
|
||||
this.registerProviders();
|
||||
}
|
||||
|
||||
get capabilities(): InitializeResult {
|
||||
return {
|
||||
capabilities: this.calculator.capabilities,
|
||||
};
|
||||
}
|
||||
get capabilities(): InitializeResult {
|
||||
return {
|
||||
capabilities: this.calculator.capabilities,
|
||||
};
|
||||
}
|
||||
|
||||
private registerProviders(): void {
|
||||
new ASTProvider(this.connection, this.forest);
|
||||
// new DocumentHighlightProvider(this.connection, this.forest);
|
||||
// new FoldingRangeProvider(this.connection, this.forest);
|
||||
}
|
||||
}
|
||||
private registerProviders(): void {
|
||||
new ASTProvider(this.connection, this.forest);
|
||||
// new DocumentHighlightProvider(this.connection, this.forest);
|
||||
// new FoldingRangeProvider(this.connection, this.forest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
import * as cp from 'child_process';
|
||||
import Uri from 'vscode-uri/lib/umd'
|
||||
import {
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
TextDocument,
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
ProposedFeatures,
|
||||
InitializeParams,
|
||||
DidChangeConfigurationNotification,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
TextDocumentPositionParams,
|
||||
Range,
|
||||
Position,
|
||||
TextEdit
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
TextDocument,
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
ProposedFeatures,
|
||||
InitializeParams,
|
||||
DidChangeConfigurationNotification,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
TextDocumentPositionParams,
|
||||
Range,
|
||||
Position,
|
||||
TextEdit
|
||||
} from 'vscode-languageserver';
|
||||
// import { ElmAnalyse } from './elmAnalyse';
|
||||
|
||||
@@ -32,187 +32,187 @@ let hasWorkspaceFolderCapability: boolean = false;
|
||||
let rootPath: string = undefined;
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
let capabilities = params.capabilities;
|
||||
this.rootPath = params.rootPath;
|
||||
let capabilities = params.capabilities;
|
||||
this.rootPath = params.rootPath;
|
||||
|
||||
// Does the client support the `workspace/configuration` request?
|
||||
// If not, we will fall back using global settings
|
||||
hasConfigurationCapability =
|
||||
capabilities.workspace && !!capabilities.workspace.configuration;
|
||||
hasWorkspaceFolderCapability =
|
||||
capabilities.workspace && !!capabilities.workspace.workspaceFolders;
|
||||
// Does the client support the `workspace/configuration` request?
|
||||
// If not, we will fall back using global settings
|
||||
hasConfigurationCapability =
|
||||
capabilities.workspace && !!capabilities.workspace.configuration;
|
||||
hasWorkspaceFolderCapability =
|
||||
capabilities.workspace && !!capabilities.workspace.workspaceFolders;
|
||||
|
||||
return {
|
||||
capabilities: {
|
||||
textDocumentSync: documents.syncKind,
|
||||
// Tell the client that the server supports code completion
|
||||
completionProvider: {
|
||||
resolveProvider: true
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
capabilities: {
|
||||
textDocumentSync: documents.syncKind,
|
||||
// Tell the client that the server supports code completion
|
||||
completionProvider: {
|
||||
resolveProvider: true
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
connection.onInitialized(() => {
|
||||
if (hasConfigurationCapability) {
|
||||
// Register for all configuration changes.
|
||||
connection.client.register(
|
||||
DidChangeConfigurationNotification.type,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
connection.workspace.onDidChangeWorkspaceFolders(_event => {
|
||||
connection.console.log('Workspace folder change event received.');
|
||||
});
|
||||
}
|
||||
if (hasConfigurationCapability) {
|
||||
// Register for all configuration changes.
|
||||
connection.client.register(
|
||||
DidChangeConfigurationNotification.type,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
connection.workspace.onDidChangeWorkspaceFolders(_event => {
|
||||
connection.console.log('Workspace folder change event received.');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
documents.onDidOpen(params => {
|
||||
// const elmAnalyseIssues: IElmIssue[] = [];
|
||||
// const elmAnalyse = new ElmAnalyse(elmAnalyseIssues);
|
||||
// runLinter(connection, this.rootPath, params.document);
|
||||
validateTextDocument(params.document);
|
||||
// const elmAnalyseIssues: IElmIssue[] = [];
|
||||
// const elmAnalyse = new ElmAnalyse(elmAnalyseIssues);
|
||||
// runLinter(connection, this.rootPath, params.document);
|
||||
validateTextDocument(params.document);
|
||||
});
|
||||
|
||||
documents.onDidSave(params => {
|
||||
// const elmAnalyseIssues: IElmIssue[] = [];
|
||||
// const elmAnalyse = new ElmAnalyse(elmAnalyseIssues);
|
||||
// runLinter(connection, this.rootPath, params.document);
|
||||
// const elmAnalyseIssues: IElmIssue[] = [];
|
||||
// const elmAnalyse = new ElmAnalyse(elmAnalyseIssues);
|
||||
// runLinter(connection, this.rootPath, params.document);
|
||||
|
||||
validateTextDocument(params.document);
|
||||
validateTextDocument(params.document);
|
||||
});
|
||||
|
||||
async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
connection.console.log('Validate text');
|
||||
// let uri = Uri.parse(textDocument.uri);
|
||||
connection.console.log('Validate text');
|
||||
// let uri = Uri.parse(textDocument.uri);
|
||||
|
||||
// let diagnostics: Diagnostic[] = []
|
||||
// try {
|
||||
// await Compiler.compileToString(uri.fsPath, { report: 'json' })
|
||||
// let diagnostics: Diagnostic[] = []
|
||||
// try {
|
||||
// await Compiler.compileToString(uri.fsPath, { report: 'json' })
|
||||
|
||||
// var x = await Compiler.findAllDependencies(uri.fsPath);
|
||||
// connection.console.log(x);
|
||||
|
||||
// } catch (err) {
|
||||
// const issues = JSON.parse(err.message.split('\n')[1]);
|
||||
// const byFile = issues.reduce((acc: any, issue: any) => {
|
||||
// if (acc[issue.file]) {
|
||||
// acc[issue.file].push(issue);
|
||||
// } else {
|
||||
// acc[issue.file] = [issue];
|
||||
// }
|
||||
|
||||
// return acc;
|
||||
// }, {});
|
||||
|
||||
// Object.keys(byFile).forEach((file: string) => {
|
||||
// byFile[file].map((issue: any) => {
|
||||
// diagnostics.push( {
|
||||
// severity: DiagnosticSeverity.Error,
|
||||
// source: "Elm",
|
||||
// message: issue.details,
|
||||
// range: {
|
||||
// start: {
|
||||
// line: issue.region.start.line - 1,
|
||||
// character: issue.region.start.column - 1,
|
||||
// },
|
||||
// end: {
|
||||
// line: issue.region.end.line - 1,
|
||||
// character: issue.region.end.column - 1,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// });
|
||||
// }
|
||||
// finally {
|
||||
// connection.sendDiagnostics({
|
||||
// uri: textDocument.uri,
|
||||
// diagnostics: diagnostics,
|
||||
// });
|
||||
// }
|
||||
// var x = await Compiler.findAllDependencies(uri.fsPath);
|
||||
// connection.console.log(x);
|
||||
|
||||
// } catch (err) {
|
||||
// const issues = JSON.parse(err.message.split('\n')[1]);
|
||||
// const byFile = issues.reduce((acc: any, issue: any) => {
|
||||
// if (acc[issue.file]) {
|
||||
// acc[issue.file].push(issue);
|
||||
// } else {
|
||||
// acc[issue.file] = [issue];
|
||||
// }
|
||||
|
||||
// return acc;
|
||||
// }, {});
|
||||
|
||||
// Object.keys(byFile).forEach((file: string) => {
|
||||
// byFile[file].map((issue: any) => {
|
||||
// diagnostics.push( {
|
||||
// severity: DiagnosticSeverity.Error,
|
||||
// source: "Elm",
|
||||
// message: issue.details,
|
||||
// range: {
|
||||
// start: {
|
||||
// line: issue.region.start.line - 1,
|
||||
// character: issue.region.start.column - 1,
|
||||
// },
|
||||
// end: {
|
||||
// line: issue.region.end.line - 1,
|
||||
// character: issue.region.end.column - 1,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// });
|
||||
// }
|
||||
// finally {
|
||||
// connection.sendDiagnostics({
|
||||
// uri: textDocument.uri,
|
||||
// diagnostics: diagnostics,
|
||||
// });
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
connection.onDidChangeWatchedFiles(_change => {
|
||||
// Monitored files have change in VSCode
|
||||
connection.console.log('We received an file change event');
|
||||
// Monitored files have change in VSCode
|
||||
connection.console.log('We received an file change event');
|
||||
});
|
||||
|
||||
// This handler provides the initial list of the completion items.
|
||||
connection.onCompletion(
|
||||
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
|
||||
// The pass parameter contains the position of the text document in
|
||||
// which code complete got requested. For the example we ignore this
|
||||
// info and always provide the same completion items.
|
||||
return [
|
||||
{
|
||||
label: 'TypeScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 1
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 2
|
||||
}
|
||||
];
|
||||
}
|
||||
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
|
||||
// The pass parameter contains the position of the text document in
|
||||
// which code complete got requested. For the example we ignore this
|
||||
// info and always provide the same completion items.
|
||||
return [
|
||||
{
|
||||
label: 'TypeScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 1
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 2
|
||||
}
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
// This handler resolve additional information for the item selected in
|
||||
// the completion list.
|
||||
connection.onCompletionResolve(
|
||||
(item: CompletionItem): CompletionItem => {
|
||||
if (item.data === 1) {
|
||||
(item.detail = 'TypeScript details'),
|
||||
(item.documentation = 'TypeScript documentation');
|
||||
} else if (item.data === 2) {
|
||||
(item.detail = 'JavaScript details'),
|
||||
(item.documentation = 'JavaScript documentation');
|
||||
}
|
||||
return item;
|
||||
}
|
||||
(item: CompletionItem): CompletionItem => {
|
||||
if (item.data === 1) {
|
||||
(item.detail = 'TypeScript details'),
|
||||
(item.documentation = 'TypeScript documentation');
|
||||
} else if (item.data === 2) {
|
||||
(item.detail = 'JavaScript details'),
|
||||
(item.documentation = 'JavaScript documentation');
|
||||
}
|
||||
return item;
|
||||
}
|
||||
);
|
||||
|
||||
connection.onDocumentFormatting(params => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
const text = document.getText();
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
const text = document.getText();
|
||||
|
||||
const wholeDocument = Range.create(
|
||||
Position.create(0, 0),
|
||||
document.positionAt(text.length - 1),
|
||||
);
|
||||
const wholeDocument = Range.create(
|
||||
Position.create(0, 0),
|
||||
document.positionAt(text.length - 1),
|
||||
);
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const cmd = cp.exec('elm-format --stdin', (err, stdout) => {
|
||||
err ? reject(err) : resolve(stdout);
|
||||
});
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const cmd = cp.exec('elm-format --stdin', (err, stdout) => {
|
||||
err ? reject(err) : resolve(stdout);
|
||||
});
|
||||
|
||||
cmd.stdin.write(text);
|
||||
cmd.stdin.end();
|
||||
})
|
||||
.then(formattedText => {
|
||||
return [TextEdit.replace(wholeDocument, formattedText)];
|
||||
})
|
||||
.catch(_err => {
|
||||
// if ((<string>err.message).indexOf('SYNTAX PROBLEM') >= 0) {
|
||||
// return new LServer.ResponseError(
|
||||
// LServer.ErrorCodes.ParseError,
|
||||
// 'Running elm-format failed. Check the file for syntax errors.',
|
||||
// );
|
||||
// } else {
|
||||
// return new LServer.ResponseError(
|
||||
// LServer.ErrorCodes.InternalError,
|
||||
// 'Running elm-format failed. Install from ' +
|
||||
// "https://github.com/avh4/elm-format and make sure it's on your path",
|
||||
// );
|
||||
// }
|
||||
return [];
|
||||
});
|
||||
cmd.stdin.write(text);
|
||||
cmd.stdin.end();
|
||||
})
|
||||
.then(formattedText => {
|
||||
return [TextEdit.replace(wholeDocument, formattedText)];
|
||||
})
|
||||
.catch(_err => {
|
||||
// if ((<string>err.message).indexOf('SYNTAX PROBLEM') >= 0) {
|
||||
// return new LServer.ResponseError(
|
||||
// LServer.ErrorCodes.ParseError,
|
||||
// 'Running elm-format failed. Check the file for syntax errors.',
|
||||
// );
|
||||
// } else {
|
||||
// return new LServer.ResponseError(
|
||||
// LServer.ErrorCodes.InternalError,
|
||||
// 'Running elm-format failed. Install from ' +
|
||||
// "https://github.com/avh4/elm-format and make sure it's on your path",
|
||||
// );
|
||||
// }
|
||||
return [];
|
||||
});
|
||||
});
|
||||
|
||||
// Make the text document manager listen on the connection
|
||||
|
||||
@@ -1,45 +1,46 @@
|
||||
import * as path from 'path';
|
||||
import * as prebuildInstall from 'prebuild-install';
|
||||
import * as path from "path";
|
||||
import * as prebuildInstall from "prebuild-install";
|
||||
import { RemoteClient, RemoteConsole } from "vscode-languageserver";
|
||||
|
||||
function packageToGithubRepo(name: string): string {
|
||||
let repo: string;
|
||||
switch (name) {
|
||||
case 'tree-sitter':
|
||||
repo = 'node-tree-sitter';
|
||||
break;
|
||||
default:
|
||||
repo = name;
|
||||
}
|
||||
let repo: string;
|
||||
switch (name) {
|
||||
case "tree-sitter":
|
||||
repo = "node-tree-sitter";
|
||||
break;
|
||||
default:
|
||||
repo = name;
|
||||
}
|
||||
|
||||
return repo;
|
||||
return repo;
|
||||
}
|
||||
|
||||
function downloadUrl(name: string, version: string, treeSitterRepo: boolean): string {
|
||||
const repo: string = packageToGithubRepo(name);
|
||||
let urlBase: string = `https://github.com/tree-sitter/${repo}/releases/download/v${version}/`;
|
||||
if (!treeSitterRepo) {
|
||||
urlBase = `https://github.com/razzeee/${repo}/releases/download/v${version}/`;
|
||||
}
|
||||
const prebuild: string = `${name}-v${version}-electron-v${process.versions.modules}-${
|
||||
process.platform
|
||||
}-${process.arch}.tar.gz`;
|
||||
const repo: string = packageToGithubRepo(name);
|
||||
let urlBase: string = `https://github.com/tree-sitter/${repo}/releases/download/v${version}/`;
|
||||
if (!treeSitterRepo) {
|
||||
urlBase = `https://github.com/razzeee/${repo}/releases/download/v${version}/`;
|
||||
}
|
||||
const prebuild: string = `${name}-v${version}-electron-v${process.versions.modules}-${
|
||||
process.platform
|
||||
}-${process.arch}.tar.gz`;
|
||||
|
||||
return `${urlBase}${prebuild}`;
|
||||
return `${urlBase}${prebuild}`;
|
||||
}
|
||||
|
||||
function fetchPrebuild(name: string, treeSitterRepo: boolean): Promise<void | Error> {
|
||||
const pkgRoot: string = path.resolve(path.join(__dirname, '../../node_modules', name));
|
||||
//tslint:disable-next-line non-literal-require
|
||||
const pkg: { name: string; version: string } = require(`${pkgRoot}/package.json`);
|
||||
const url: string = downloadUrl(pkg.name, pkg.version, treeSitterRepo);
|
||||
const pkgRoot: string = path.resolve(path.join(__dirname, "../../node_modules", name));
|
||||
// tslint:disable-next-line non-literal-require
|
||||
const pkg: { name: string; version: string } = require(`${pkgRoot}/package.json`);
|
||||
const url: string = downloadUrl(pkg.name, pkg.version, treeSitterRepo);
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
prebuildInstall.download(url, { pkg, path: pkgRoot }, (err: Error) => {
|
||||
err ? rej(err) : res();
|
||||
});
|
||||
});
|
||||
return new Promise((res, rej) => {
|
||||
prebuildInstall.download(url, { pkg, path: pkgRoot }, (err: Error) => {
|
||||
err ? rej(err) : res();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function rebuildTreeSitter(): Promise<[void | Error, void | Error]> {
|
||||
return Promise.all([fetchPrebuild('tree-sitter', true), fetchPrebuild('tree-sitter-elm', false)]);
|
||||
}
|
||||
return Promise.all([fetchPrebuild("tree-sitter", true), fetchPrebuild("tree-sitter-elm", false)]);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,15 @@
|
||||
"sourceMap": true,
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"lib": ["es6"]
|
||||
"lib": [
|
||||
"es6"
|
||||
]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
||||
@@ -4,7 +4,9 @@
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"lib": [ "es6" ],
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": [
|
||||
@@ -15,7 +17,11 @@
|
||||
".vscode-test"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "./client" },
|
||||
{ "path": "./server" }
|
||||
{
|
||||
"path": "./client"
|
||||
},
|
||||
{
|
||||
"path": "./server"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user