From 66a5a8a2b24a4de67e23cc57256c8a707efdc094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20F=C3=A9votte?= Date: Fri, 15 May 2020 00:20:39 +0200 Subject: [PATCH] Automatic detection of system images The compilation process is also streamlined, allowing it to be run directly from Emacs with `M-x eglot-jl-compile-sysimage`. --- README.org | 45 ++++++++++++++++----------------------------- eglot-jl.el | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/README.org b/README.org index 921f162..89d5e1f 100644 --- a/README.org +++ b/README.org @@ -78,32 +78,19 @@ takes some time: around 20 seconds are needed before the server is ready, which manifests itself by the =[eglot:projectName]= indicator showing up in the modeline. -The =compile.jl= script that ships with =eglot-jl= allows compiling a system -image, which can greatly speed-up language server start-up times: - -#+begin_src sh - julia path/to/eglot-jl/compile.jl -#+end_src - -This will take a few minutes to generate a system image in -=path/to/eglot-jl/eglot-jl.X.Y.Z.so= (where =X.Y.Z= is your julia version number, -and the file extension is adapted to your system: =.dylib= for MacOS, =.dll= for -Windows). - -You can then instruct =eglot-jl= to use this system image by adding the -following to your Emacs configuration: - -#+begin_src emacs-lisp - (setq eglot-jl-julia-flags '("--sysimage=/path/to/eglot-jl/eglot-jl.X.Y.Z.so")) -#+end_src - -This should reduce language server startup times to less than 2 seconds. - -Be aware that you should update this system image (by running =compile.jl= -again) when julia changes, or if you update =eglot-jl= itself. If anything goes -wrong with this system image, you can always reset your julia flags to stop -using it: - -#+begin_src emacs-lisp - (setq eglot-jl-julia-flags nil) -#+end_src +As an additional step after installation, =eglot-jl= can compile a custom julia +system image, which can greatly speed-up language server start-up times: simply +run =M-x eglot-jl-compile-sysimage=. + +This will take a few minutes to generate a system image, which =eglot-jl= will +detect and automatically use for subsequent language server runs. This should +reduce language server startup times to 1 or 2 seconds. + +Be aware that each system image is specific to a version of julia. If you switch +to a version for which you haven't (yet) generated a system image, =eglot-jl= +won't find any suitable sysimage, and language server startup times will be high +again. In such situations, you can simply generate a new system image for the +new julia version by running =M-x eglot-jl-compile-sysimage= again. + +If anything goes wrong with system images, you can deactivate this feature +altogether by customizing =eglot-jl-enable-sysimage=. diff --git a/eglot-jl.el b/eglot-jl.el index 0d80cd0..b1725ba 100644 --- a/eglot-jl.el +++ b/eglot-jl.el @@ -60,6 +60,11 @@ The project should have LanguageServer and SymbolServer packages available." :type 'string) +(defcustom eglot-jl-enable-sysimage t + "If t, use a system image if a suitable one is +found. Otherwise, don't even look for a system image." + :type 'boolean) + ;; Make project.el aware of Julia projects (defun eglot-jl--project-try (dir) "Return project instance if DIR is part of a julia project. @@ -71,10 +76,31 @@ Otherwise returns nil" (cl-defmethod project-roots ((project (head julia))) (list (cdr project))) +(defun eglot-jl--sysimage-args () + "Returns a list of command-line switches suitable for sysimage loading. +Return nil if no system image has been found or if system images +have been disabled altogether." + (when eglot-jl-enable-sysimage + (let ((julia-version (with-temp-buffer + (call-process eglot-jl-julia-command nil t nil + "-e" "print(Base.VERSION)") + (buffer-string)))) + (car + (remove nil + (mapcar + (lambda (ext) + (let ((path (expand-file-name + (concat "eglot-jl." julia-version ext) + eglot-jl-base))) + (when (file-exists-p path) + (list "--sysimage" path)))) + '(".dll" ".dylib" ".so"))))))) + (defun eglot-jl--ls-invocation (_interactive) "Return list of strings to be called to start the Julia language server." `(,eglot-jl-julia-command "--startup-file=no" + ,@(eglot-jl--sysimage-args) ,(concat "--project=" eglot-jl-language-server-project) ,@eglot-jl-julia-flags ,(expand-file-name "eglot-jl.jl" eglot-jl-base) @@ -90,5 +116,20 @@ Otherwise returns nil" ;; function instead of strings to find project dir at runtime '(julia-mode . eglot-jl--ls-invocation))) +;;;###autoload +(defun eglot-jl-compile-sysimage () + "Create a compiled system image for the language server. +This reduces subsequent start-up times." + (interactive) + (let ((buffer (get-buffer-create "*eglot-jl sysimage compilation*"))) + (with-current-buffer buffer + (setq buffer-read-only nil) (erase-buffer) (setq buffer-read-only t) + (start-process "eglot-jl-compile-sysimage" (current-buffer) + eglot-jl-julia-command + "--startup-file=no" "--color=no" "--quiet" + (concat "--project=" eglot-jl-base) + (expand-file-name "compile.jl" eglot-jl-base))) + (display-buffer buffer))) + (provide 'eglot-jl) ;;; eglot-jl.el ends here