Skip to content
This repository has been archived by the owner on Feb 16, 2022. It is now read-only.

Commit

Permalink
feat: add code completion using gopls
Browse files Browse the repository at this point in the history
  • Loading branch information
maku693 committed Jul 18, 2021
1 parent 31c6150 commit cffc273
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,3 +1,4 @@
.DS_Store
logs/
node_modules/
*.log
116 changes: 116 additions & 0 deletions Go.novaextension/Scripts/gopls.js
@@ -0,0 +1,116 @@
let client = null;

const debugAddress = "localhost:6060";

// TODO: make this Disposable class
async function start() {
stop();
console.log("initializing gopls...");

// Try to get gopls path from config
let goplsPath = nova.config.get("go.gopls-path");

// Try to get gopls path from PATH unless custom configuration provided
if (!goplsPath) {
goplsPath = await new Promise((resolve, reject) => {
const which = new Process("/usr/bin/env", {
args: ["which", "gopls"],
});
nova.subscriptions.add(
which.onDidExit((status) => {
if (status !== 0) reject(false);
})
);
nova.subscriptions.add(
which.onStdout((text) => {
resolve(text.trim());
})
);
which.start();
});
}

// If we can't find gopls, use the default path
if (!goplsPath) {
let gobin = nova.environment.GOBIN;
if (!gobin) {
const gopath = await new Promise((resolve, reject) => {
const go = new Process("/usr/bin/env", {
args: ["go", "env", "GOPATH"],
});
nova.subscriptions.add(
go.onDidExit((status) => {
if (status !== 0) {
reject(`go env GOPATH exited with status code: ${status}`);
}
})
);
nova.subscriptions.add(
go.onStdout((text) => {
resolve(text.trim());
})
);
go.start();
});
gobin = nova.path.join(gopath, "bin");
}
goplsPath = nova.path.join(gobin, "gopls");
}

console.log(`gopls path: ${goplsPath}`);

// Create the client
let serverOptions = {
type: "stdio",
path: goplsPath,
args: [],
};
if (nova.inDevMode()) {
console.log(`debug information will be available on ${debugAddress}`);

const logDir = nova.path.join(nova.workspace.path, "logs");
await new Promise((resolve, reject) => {
const mkdir = new Process("/usr/bin/env", {
args: ["mkdir", "-p", logDir],
});
nova.subscriptions.add(
mkdir.onDidExit((status) => {
if (status !== 0) {
reject(status);
}
resolve(status);
})
);

mkdir.start();
});
const logFile = nova.path.join(logDir, "gopls.log");
console.log(`gopls log file: ${logFile}`);

serverOptions.args.push("-debug", debugAddress);
serverOptions.args.push("-logfile", logFile);
serverOptions.args.push("-rpc.trace");
serverOptions.args.push("-v");
serverOptions.args.push("-vv");
}

client = new LanguageClient("gopls", "Go Language Server", serverOptions, {
syntaxes: ["go", "gomod"],
});
nova.subscriptions.add(client);

console.log("starting language client...");
client.start();
}

function stop() {
nova.subscriptions.dispose();

if (client) {
client.stop();
client = null;
}
}

exports.start = start;
exports.stop = stop;
69 changes: 69 additions & 0 deletions Go.novaextension/Scripts/main.js
@@ -0,0 +1,69 @@
const gopls = require("gopls.js");

exports.activate = function () {
console.log("activating");

(async () => {
await start();
if (nova.config.get("go.enable-gopls")) {
await gopls.start();
}
console.log("activation completed");
})().catch((err) => {
if (!nova.inDevMode()) return;
console.error("error activating:", err);
});
};

exports.deactivate = function () {
console.log("deactivating");
console.log("deactivation completed");
};

async function start() {
// Check if the go command is available
const isGoAvailable = await new Promise((resolve, reject) => {
const which = new Process("/usr/bin/env", {
args: ["which", "go"],
});
nova.subscriptions.add(
which.onDidExit((status) => {
if (status !== 0) {
reject(false);
return;
}
resolve(true);
})
);
which.start();
});
if (!isGoAvailable) {
throw new Error("cannot find go executable");
}

// Check if the go version is correct
const goVersion = await new Promise((resolve, reject) => {
const go = new Process("/usr/bin/env", {
args: ["go", "version"],
});
nova.subscriptions.add(
go.onDidExit((status) => {
if (status !== 0) {
reject(`go version exited with status code: ${status}`);
}
})
);
nova.subscriptions.add(
go.onStdout((text) => {
resolve(text.trim());
})
);
go.start();
});
if (!versionRegexp.exec(goVersion)) {
throw new Error(`${goVersion} is not compatible with this extension`);
}
console.log(goVersion);
}

const versionRegexp = /go version go1\.[\d]+(?:\.[\d])?(?:[\w\d]+)? darwin\/[\w\d]+/;
29 changes: 28 additions & 1 deletion Go.novaextension/extension.json
Expand Up @@ -6,6 +6,33 @@
"version": "0.3.4",
"min_runtime": "4.0",
"categories": ["languages", "completions"],
"main": "main.js",
"activationEvents": [
"onLanguage:go",
"onWorkspaceContains:go.mod",
"onWorkspaceContains:go.sum"
],
"entitlements": {
"process": true
},
"bugs": "https://github.com/maku693/go-nova/issues/new",
"repository": "https://github.com/maku693/go-nova"
"repository": "https://github.com/maku693/go-nova",
"config": [
{
"key": "go.enable-gopls",
"title": "Use Language Server (gopls) (Experimental)",
"description": "Whether to enable code completion using gopls.\nYou should have a valid go installation to enable this option.",
"type": "boolean",
"default": false,
"children": [
{
"key": "go.gopls-path",
"title": "gopls path",
"description": "Path to gopls executable.\nIf empty, the extension try to infer executable path from $PATH and $GOBIN.",
"type": "path",
"default": ""
}
]
}
]
}

0 comments on commit cffc273

Please sign in to comment.