[gnome-builder/wip/chergert/php-langserv] wip: php language server



commit 7d45d440c72a70ecf2aa0179d7dc878e46333ed6
Author: Christian Hergert <chergert redhat com>
Date:   Sat Oct 29 21:15:36 2016 -0700

    wip: php language server

 configure.ac                                |    2 +
 plugins/Makefile.am                         |    1 +
 plugins/php-langserv/Makefile.am            |   14 +++
 plugins/php-langserv/configure.ac           |   12 +++
 plugins/php-langserv/php-langserv.plugin    |   13 +++
 plugins/php-langserv/php_langserv_plugin.py |  144 +++++++++++++++++++++++++++
 6 files changed, 186 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e0bd388..a4af29c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -306,6 +306,7 @@ m4_include([plugins/jedi/configure.ac])
 m4_include([plugins/jhbuild/configure.ac])
 m4_include([plugins/meson/configure.ac])
 m4_include([plugins/mingw/configure.ac])
+m4_include([plugins/php-langserv/configure.ac])
 m4_include([plugins/project-tree/configure.ac])
 m4_include([plugins/python-gi-imports-completion/configure.ac])
 m4_include([plugins/python-pack/configure.ac])
@@ -615,6 +616,7 @@ echo "  HTML and Markdown Preview ............ : ${enable_html_preview_plugin}"
 echo "  JHBuild .............................. : ${enable_jhbuild_plugin}"
 echo "  Meson ................................ : ${enable_meson_plugin}"
 echo "  MinGW ................................ : ${enable_mingw_plugin}"
+echo "  PHP Language Server .................. : ${enable_php_langserv_plugin}"
 echo "  Project Creation ..................... : ${enable_create_project_plugin}"
 echo "  Project Tree ......................... : ${enable_project_tree_plugin}"
 echo "  Python GObject Introspection ......... : ${enable_python_gi_imports_completion_plugin}"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 7828dac..b543ecc 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -26,6 +26,7 @@ SUBDIRS = \
        jhbuild \
        mingw \
        meson \
+       php-langserv \
        project-tree \
        python-gi-imports-completion \
        python-pack \
diff --git a/plugins/php-langserv/Makefile.am b/plugins/php-langserv/Makefile.am
new file mode 100644
index 0000000..a658c2a
--- /dev/null
+++ b/plugins/php-langserv/Makefile.am
@@ -0,0 +1,14 @@
+if ENABLE_PHP_LANGSERV_PLUGIN
+
+EXTRA_DIST = $(plugin_DATA)
+
+plugindir = $(libdir)/gnome-builder/plugins
+dist_plugin_DATA = \
+       php-langserv.plugin \
+       php_langserv_plugin.py
+
+endif
+
+include $(top_srcdir)/plugins/Makefile.plugin
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/php-langserv/configure.ac b/plugins/php-langserv/configure.ac
new file mode 100644
index 0000000..4fadc80
--- /dev/null
+++ b/plugins/php-langserv/configure.ac
@@ -0,0 +1,12 @@
+# --enable-php-langserv-plugin=yes/no
+AC_ARG_ENABLE([php-langserv-plugin],
+              [AS_HELP_STRING([--enable-php-langserv-plugin=@<:@yes/no@:>@],
+                              [Build with support for PHP Language Server integration.])],
+              [enable_php_langserv_plugin=$enableval],
+              [enable_php_langserv_plugin=yes])
+
+# for if ENABLE_PHP_LANGSERV_PLUGIN in Makefile.am
+AM_CONDITIONAL(ENABLE_PHP_LANGSERV_PLUGIN, test x$enable_php_langserv_plugin = xyes)
+
+# Ensure our makefile is generated by autoconf
+AC_CONFIG_FILES([plugins/php-langserv/Makefile])
diff --git a/plugins/php-langserv/php-langserv.plugin b/plugins/php-langserv/php-langserv.plugin
new file mode 100644
index 0000000..f13cd9d
--- /dev/null
+++ b/plugins/php-langserv/php-langserv.plugin
@@ -0,0 +1,13 @@
+[Plugin]
+Module=php_langserv_plugin
+Loader=python3
+Name=PHP Language Server Integration
+Description=Provides auto-completion, diagnostics, and other IDE features
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2016 Christian Hergert
+Builtin=true
+X-Completion-Provider-Languages=php
+X-Diagnostic-Provider-Languages=php
+X-Highlighter-Languages=php
+X-Rename-Provider-Languages=php
+X-Symbol-Resolver-Languages=php
diff --git a/plugins/php-langserv/php_langserv_plugin.py b/plugins/php-langserv/php_langserv_plugin.py
new file mode 100644
index 0000000..28c93c7
--- /dev/null
+++ b/plugins/php-langserv/php_langserv_plugin.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+
+#
+# php_langserv_plugin.py
+#
+# Copyright (C) 2016 Christian Hergert <chris dronelabs com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import gi
+import os
+
+gi.require_version('Ide', '1.0')
+gi.require_version('GtkSource', '3.0')
+
+from gi.repository import GLib
+from gi.repository import Gio
+from gi.repository import GObject
+from gi.repository import GtkSource
+from gi.repository import Ide
+
+class PhpService(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):
+        """
+        Stops the PHP Language Server upon request to shutdown the
+        PhpService.
+        """
+        if self._supervisor:
+            supervisor, self._supervisor = self._supervisor, None
+            supervisor.stop()
+
+    def _ensure_started(self):
+        """
+        Start the php service which provides communication with the
+        Php Language Server. We supervise our own instance of the
+        language server and restart it as necessary using the
+        Ide.SubprocessSupervisor.
+
+        Various extension points (diagnostics, symbol providers, etc) use
+        the PhpService to access the php components they need.
+        """
+        # To avoid starting the `php` process unconditionally at startup,
+        # we lazily start it when the first provider tries to bind a client
+        # to it's :client property.
+        if not self._has_started:
+            self._has_started = True
+
+            # Setup a launcher to spawn the php language server
+            launcher = self._create_launcher()
+            launcher.set_clear_env(False)
+
+            # TODO: Discover path to php-language-server.php
+            php_language_server = 
os.path.expanduser("~/Projects/php-language-server/bin/php-language-server.php")
+
+            # Setup our Argv. We want to communicate over STDIN/STDOUT,
+            # so it does not require any command line options.
+            launcher.push_args(["php", php_language_server])
+
+            # 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._php_spawned)
+            self._supervisor.set_launcher(launcher)
+            self._supervisor.start()
+
+    def _php_spawned(self, supervisor, subprocess):
+        """
+        This callback is executed when the `php` process is spawned.
+        We can use the stdin/stdout to create a channel for our
+        LangservClient.
+        """
+        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('php')
+        self._client.start()
+        self.notify('client')
+
+    def _create_launcher(self):
+        """
+        Creates a launcher to be used by the php service. This needs
+        to be run on the host because we do not currently bundle php
+        inside our flatpak.
+
+        In the future, we might be able to rely on the runtime for
+        the tooling. Maybe even the program if flatpak-builder has
+        prebuilt our dependencies.
+        """
+        launcher = Ide.SubprocessLauncher()
+        launcher.set_flags(Gio.SubprocessFlags.STDIN_PIPE |
+                           Gio.SubprocessFlags.STDOUT_PIPE |
+                           Gio.SubprocessFlags.STDERR_SILENCE)
+        launcher.set_cwd(GLib.get_home_dir())
+        launcher.set_run_on_host(True)
+        return launcher
+
+    @classmethod
+    def bind_client(klass, provider):
+        """
+        This helper tracks changes to our client as it might happen when
+        our `php` process has crashed.
+        """
+        context = provider.get_context()
+        self = context.get_service_typed(PhpService)
+        self._ensure_started()
+        self.bind_property('client', provider, 'client', GObject.BindingFlags.SYNC_CREATE)
+
+class PhpDiagnosticProvider(Ide.LangservDiagnosticProvider):
+    def do_load(self):
+        PhpService.bind_client(self)
+
+class PhpSymbolResolver(Ide.LangservSymbolResolver):
+    def do_load(self):
+        PhpService.bind_client(self)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]