[gnome-builder] go-langserv: Import an LSP integration for Go
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] go-langserv: Import an LSP integration for Go
- Date: Sat, 20 Jan 2018 08:49:11 +0000 (UTC)
commit a4dc151f20aed0681aca921b0e5348cd06f09c2b
Author: Henry Finucane <h finucane gmail com>
Date: Sat Jan 6 17:29:24 2018 -0800
go-langserv: Import an LSP integration for Go
This adds a basic language server client for the go-langserv language
server. Due to the stability of that language server, only the symbol
resolver interface is currently implemented.
Fixes #343
meson_options.txt | 1 +
src/plugins/go-langserv/README.md | 39 ++++++++
src/plugins/go-langserv/go-langserv.plugin | 8 ++
src/plugins/go-langserv/go_langserver_plugin.py | 122 ++++++++++++++++++++++++
src/plugins/go-langserv/meson.build | 13 +++
src/plugins/meson.build | 2 +
6 files changed, 185 insertions(+)
---
diff --git a/meson_options.txt b/meson_options.txt
index f4a00e222..5d279fe8a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -42,6 +42,7 @@ option('with_gettext', type: 'boolean')
option('with_git', type: 'boolean')
option('with_gjs_symbols', type: 'boolean')
option('with_gnome_code_assistance', type: 'boolean')
+option('with_go_langserv', type: 'boolean')
option('with_history', type: 'boolean')
option('with_html_completion', type: 'boolean')
option('with_html_preview', type: 'boolean')
diff --git a/src/plugins/go-langserv/README.md b/src/plugins/go-langserv/README.md
new file mode 100644
index 000000000..86dc2fa42
--- /dev/null
+++ b/src/plugins/go-langserv/README.md
@@ -0,0 +1,39 @@
+# a quick langserver plugin for go
+
+Meant to wrap [Sourcegraph's](https://github.com/sourcegraph/go-langserver)
+`go-langserver`. It's a straight copy & paste of the rust-langserver
+implementation, with some sketchy additional `bash` magic to try and better
+support flatpak-packaged Builder.
+
+## Installing and testing
+
+1. Install `go`. Its tooling is stable, 'apt install' or 'yum install' will be fine.
+2. Set up your go environment-
+```
+export GOPATH=$HOME/go
+export PATH="$GOPATH/bin:$PATH"
+go get github.com/sourcegraph/go-langserver
+go install github.com/sourcegraph/go-langserver
+```
+3. Launch Builder, open ~/go/src/github.com/sourcegraph as a project
+4. Right click on a method and click 'go to definition'
+
+## Runtime configuration
+Go has a simple environment convention for managing source code. All user code
+imports come from $GOPATH/src, so to manage separate projects, you can change
+your $GOPATH- think of it as a one-variable equivalent to Python's
+`virtualenv`. Developing inside of $GOPATH/src/$PROJECT is the encouraged way
+to do things, but you don't have to. Newer versions of Go define a default
+'global scrum' $GOPATH in $HOME/go.
+
+The standard library is in $GOROOT/src. If you manually install `go` to a place
+that isn't `/usr/local/go`, you'll need to set this, but normally you don't have
+to worry about it.
+
+## Bugs:
+* I have to disable the rust-langserver extension, or else it seems to take
+ precedence
+* `go-langserver` claims to support formatting, but I don't know how to ask
+ Builder to ask it to do that
+* `go-langserver` has recently merged completion support, but it seems crashy
+ from Builder
diff --git a/src/plugins/go-langserv/go-langserv.plugin b/src/plugins/go-langserv/go-langserv.plugin
new file mode 100644
index 000000000..e41ce2e7a
--- /dev/null
+++ b/src/plugins/go-langserv/go-langserv.plugin
@@ -0,0 +1,8 @@
+[Plugin]
+Module=go_langserver_plugin
+Loader=python3
+Name=Go Language Server Plugin
+Description=Provides LSP integration for Go
+Copyright=Copyright © 2018 Henry Finucane
+Builtin=true
+X-Symbol-Resolver-Languages=go
diff --git a/src/plugins/go-langserv/go_langserver_plugin.py b/src/plugins/go-langserv/go_langserver_plugin.py
new file mode 100644
index 000000000..630b2b59b
--- /dev/null
+++ b/src/plugins/go-langserv/go_langserver_plugin.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+
+import os
+import json
+import gi
+
+gi.require_version('Ide', '1.0')
+
+from gi.repository import GLib
+from gi.repository import Gio
+from gi.repository import GObject
+from gi.repository import Ide
+
+DEV_MODE = os.getenv('DEV_MODE') and True or False
+
+class GoService(Ide.Object, Ide.Service):
+ _client = None
+ _has_started = False
+ _supervisor = None
+
+ @GObject.Property(type=Ide.LangservClient)
+ def client(self):
+ return self._client
+
+ @client.setter
+ def client(self, value):
+ self._client = value
+ self.notify('client')
+
+ def do_stop(self):
+ if self._supervisor:
+ supervisor, self._supervisor = self._supervisor, None
+ supervisor.stop()
+
+ def _which_go_lanserver(self):
+ path = os.path.expanduser('~/go/bin/go-langserver')
+ if os.path.exists(path):
+ return path
+ return "go-langserver"
+
+ def _ensure_started(self):
+ # To avoid starting the process unconditionally at startup, lazily
+ # start it when the first provider tries to bind a client to its
+ # :client property.
+ if not self._has_started:
+ self._has_started = True
+
+ launcher = self._create_launcher()
+ launcher.set_clear_env(False)
+
+ # Locate the directory of the project and run go-langserver from there
+ workdir = self.get_context().get_vcs().get_working_directory()
+ launcher.set_cwd(workdir.get_path())
+
+ # Bash will load the host $PATH and $GOPATH (and optionally $GOROOT) for us.
+ # This does mean there will be a possible .bashrc vs .bash_profile
+ # discrepancy. Possibly there is a better native way to make sure that
+ # builder running in flatpak can run processes in the host context with
+ # the host's $PATH.
+ launcher.push_argv("/bin/bash")
+ launcher.push_argv("--login")
+ launcher.push_argv("-c")
+ launcher.push_argv('exec %s %s' % (
+ self._which_go_lanserver(),
+ "-trace" if DEV_MODE else ""))
+
+ # Spawn our peer process and monitor it for
+ # crashes. We may need to restart it occasionally.
+ self._supervisor = Ide.SubprocessSupervisor()
+ self._supervisor.connect('spawned', self._ls_spawned)
+ self._supervisor.set_launcher(launcher)
+ self._supervisor.start()
+
+ def _ls_spawned(self, supervisor, subprocess):
+ stdin = subprocess.get_stdin_pipe()
+ stdout = subprocess.get_stdout_pipe()
+ io_stream = Gio.SimpleIOStream.new(stdout, stdin)
+
+ if self._client:
+ self._client.stop()
+
+ self._client = Ide.LangservClient.new(self.get_context(), io_stream)
+ self._client.add_language('go')
+ self._client.start()
+ self.notify('client')
+
+ def _create_launcher(self):
+ flags = Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE
+ if not DEV_MODE:
+ flags |= Gio.SubprocessFlags.STDERR_SILENCE
+ launcher = Ide.SubprocessLauncher()
+ launcher.set_flags(flags)
+ launcher.set_cwd(GLib.get_home_dir())
+ launcher.set_run_on_host(True)
+ return launcher
+
+ @classmethod
+ def bind_client(klass, provider):
+ context = provider.get_context()
+ self = context.get_service_typed(GoService)
+ self._ensure_started()
+ self.bind_property('client', provider, 'client', GObject.BindingFlags.SYNC_CREATE)
+
+# This is the only up-to-date looking list of supported things lsp things:
+# https://github.com/sourcegraph/go-langserver/blob/master/langserver/handler.go#L226
+
+class GoSymbolResolver(Ide.LangservSymbolResolver, Ide.SymbolResolver):
+ def do_load(self):
+ GoService.bind_client(self)
+
+## This is supported as of a few weeks ago, but at least for me, it seems
+## awfully crashy, so I'm going to leave it disabled by default so as to
+## not give a bad impression
+#class GoCompletionProvider(Ide.LangservCompletionProvider, GtkSource.CompletionProvider,
Ide.CompletionProvider):
+# def do_load(self, context):
+# GoService.bind_client(self)
+
+## Could not validate that this works, though `go-langserver` says it does.
+## Calling out to `gofmt` is probably the more canonical route
+#class GoFormatter(Ide.LangservFormatter, Ide.Formatter):
+# def do_load(self):
+# GoService.bind_client(self)
diff --git a/src/plugins/go-langserv/meson.build b/src/plugins/go-langserv/meson.build
new file mode 100644
index 000000000..2e665ba3b
--- /dev/null
+++ b/src/plugins/go-langserv/meson.build
@@ -0,0 +1,13 @@
+if get_option('with_go_langserv')
+
+install_data('go_langserver_plugin.py', install_dir: plugindir)
+
+configure_file(
+ input: 'go-langserv.plugin',
+ output: 'go-langserv.plugin',
+ configuration: configuration_data(),
+ install: true,
+ install_dir: plugindir,
+)
+
+endif
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index 2c63078fa..b0ae89ff4 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -35,6 +35,7 @@ subdir('gettext')
subdir('git')
subdir('gjs-symbols')
subdir('gnome-code-assistance')
+subdir('go-langserv')
subdir('history')
subdir('html-completion')
subdir('html-preview')
@@ -113,6 +114,7 @@ status += [
'Git ................... : @0@'.format(get_option('with_git')),
'GJS Symbol Resolver ... : @0@'.format(get_option('with_gjs_symbols')),
'GNOME Code Assistance . : @0@'.format(get_option('with_gnome_code_assistance')),
+ 'Go Language Server .... : @0@'.format(get_option('with_go_langserv')),
'History ............... : @0@'.format(get_option('with_history')),
'HTML Completion ....... : @0@'.format(get_option('with_html_completion')),
'HTML Preview .......... : @0@'.format(get_option('with_html_preview')),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]