Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential issue of lsp-julia--rls-command #49

Open
xukai92 opened this issue Mar 31, 2021 · 8 comments
Open

Potential issue of lsp-julia--rls-command #49

xukai92 opened this issue Mar 31, 2021 · 8 comments

Comments

@xukai92
Copy link

xukai92 commented Mar 31, 2021

I'm a bit confused of the function, especially this part https://github.com/non-Jedi/lsp-julia/blob/master/lsp-julia.el#L279-L289

In short, this essentially gives something like

julia --startup-file=no --history-file=no -eimport Pkg; Pkg.instantiate(); ...

instead of

julia --startup-file=no --history-file=no -e 'import Pkg; Pkg.instantiate(); ...'

i.e. the quotation is missing.

How the current master is working at all?

PS: I found this when making lsp-julia work over TRAMP, which I have to add the quotation around all the part after -e to make things work.

@gdkrmr
Copy link
Owner

gdkrmr commented Apr 1, 2021

How the current master is working at all?

Magic? :-)

Thanks for noting, if you have already fixed it, could you make a PR?

@xukai92
Copy link
Author

xukai92 commented Apr 1, 2021

Actually adding quotes would fail the local version, but works with the TRAMP version.
For more context, here are the related codes for the TRAMP version (note the "'" I added around the body codes)

  (defun lsp-julia--rls-command-remote ()
    "The command to lauch the Julia Language Server."
    `(,lsp-julia-command
      ,@lsp-julia-flags
      ,(concat "-e "
               "'"
               "import Pkg; Pkg.instantiate(); "
               "using InteractiveUtils, Sockets, SymbolServer, LanguageServer; "
               "Union{Int64, String}(x::String) = x; "
               "server = LanguageServer.LanguageServerInstance("
               "stdin, stdout, "
               (lsp-julia--get-root-remote) ", "
               (lsp-julia--get-depot-path) ", "
               "nothing, "
               (lsp-julia--symbol-server-store-path-to-jl-no-expand) "); "
               "run(server);"
               "'")))

  (lsp-register-client
    (make-lsp-client :new-connection (lsp-tramp-connection 'lsp-julia--rls-command-remote)
                     :major-modes '(julia-mode ess-julia-mode)
                     :server-id 'julia-ls-remote
                     :remote? t))

Here lsp-julia--get-root-remote and lsp-julia--symbol-server-store-path-to-jl-no-expand are just some of my work-arounds to handle TRAMP path.
This version works well for me.

However, if I use the same quotes in the local version, i.e.

 (defun lsp-julia--rls-command()
    "The command to lauch the Julia Language Server."
    `(,lsp-julia-command
      ,@lsp-julia-flags
      ,(concat "-e "
               "'"
               "import Pkg; Pkg.instantiate(); "
               "using InteractiveUtils, Sockets, SymbolServer, LanguageServer; "
               "Union{Int64, String}(x::String) = x; "
               "server = LanguageServer.LanguageServerInstance("
               "stdin, stdout, "
               (lsp-julia--get-root) ", "
               (lsp-julia--get-depot-path) ", "
               "nothing, "
               (lsp-julia--symbol-server-store-path-to-jl) "); "
               "run(server);"
               "'")))

I would get

Process julia-ls stderr finished
ERROR: syntax: cannot juxtapose string literal
Stacktrace:
 [1] top-level scope
   @ none:1

I think it might trace down to the difference between lsp-stdio-connection and lsp-tramp-connection, which call the rls-command? :|

@gdkrmr
Copy link
Owner

gdkrmr commented Apr 1, 2021

How is your setup? I have never gotten lsp-julia to work with remote projects. You open a file from a julia project on the remote server and want the language server to spawn that same server? Is it possible to have a local language server work on the remote files?

lsp-tramp-connection is provided by lsp-mode, right?

@xukai92
Copy link
Author

xukai92 commented Apr 1, 2021

How is your setup?

This is my full setup (contains hacks/bugfixes collected from multiple places, see my comments in codes)

FULL SETUP

;; Julia over TRAMP
(after! tramp
  ;; Ignore "Remote file error: Forbidden reentrant call of Tramp"
  ;; Ref: https://www.gnu.org/software/tramp/
  (setq debug-ignored-errors
        (cons 'remote-file-error debug-ignored-errors))

  (add-to-list 'tramp-remote-path "~/bin")
  (add-to-list 'tramp-remote-path 'tramp-own-remote-path))

;; To make lsp-mode work over TRAMP
;; Ref: https://github.com/emacs-lsp/lsp-mode/pull/2531
(after! tramp
  (defun lsp-tramp-connection (local-command &optional generate-error-file-fn)
  "Create LSP stdio connection named name.
LOCAL-COMMAND is either list of strings, string or function which
returns the command to execute."
  ;; 2.5.0-pre (as built from native-comp branch before M Albinus released tramp-2.5)
  ;; worked fine
  (defvar tramp-version)
  (defvar tramp-connection-properties)
  (when (version< tramp-version "2.5.0-pre")
    (lsp-warn
     "Your tramp version - %s - might fail to work with remote LSP. Update to version 2.5 or greater (available on elpa)"
     tramp-version))
  ;; Force a direct asynchronous process.
  (add-to-list 'tramp-connection-properties
               (list (regexp-quote (file-remote-p default-directory))
                     "direct-async-process" t))
  (list :connect (lambda (filter sentinel name environment-fn)
                   (let* ((final-command (lsp-resolve-final-function
                                          local-command))
                          (stderr-buf (or (when generate-error-file-fn
                                            (funcall generate-error-file-fn name))
                                          (format "/tmp/%s-%s-stderr" name
                                                  (cl-incf lsp--stderr-index))))
                          (process-name (generate-new-buffer-name name))
                          (process-environment
                           (lsp--compute-process-environment environment-fn))
                          (proc (make-process
                                 :name process-name
                                 :buffer (format "*%s*" process-name)
                                 :command final-command
                                 :connection-type 'pipe
                                 :coding 'no-conversion
                                 :noquery t
                                 :filter filter
                                 :sentinel sentinel
                                 :stderr stderr-buf
                                 :file-handler t)))
                     (cons proc proc)))
        :test? (lambda () (-> local-command lsp-resolve-final-function
                              lsp-server-present?)))))

;; Register lsp-julia for remote mode
(after! lsp-julia
  (defun lsp-julia--get-root-remote ()
    "Get the (Julia) project root directory of the current file over TRAMP."
    (concat "\""
            (tramp-file-name-localname
              (tramp-dissect-file-name
                (expand-file-name
                  (or (locate-dominating-file default-directory "Project.toml")
                      (locate-dominating-file default-directory "JuliaProject.toml")
                      lsp-julia-default-environment))))
            "\""))

  (defun lsp-julia--symbol-server-store-path-to-jl-no-expand ()
    "Convert the variable `lsp-julia-symbol-server-store-path' to a
    string or \"nothing\" if `nil'"
    (if lsp-julia-symbol-server-store-path
        (let ((sssp lsp-julia-symbol-server-store-path))
          (make-directory sssp t)
          (concat "\"" sssp "\""))
      "nothing"))

  (defun lsp-julia--rls-command-remote ()
    "The command to lauch the Julia Language Server."
    `(,lsp-julia-command
      ,@lsp-julia-flags
      ,(concat "-e "
               "'"
               "import Pkg; Pkg.instantiate(); "
               "using InteractiveUtils, Sockets, SymbolServer, LanguageServer; "
               "Union{Int64, String}(x::String) = x; "
               "server = LanguageServer.LanguageServerInstance("
               "stdin, stdout, "
               (lsp-julia--get-root-remote) ", "
               (lsp-julia--get-depot-path) ", "
               "nothing, "
               (lsp-julia--symbol-server-store-path-to-jl-no-expand) "); "
               "run(server);"
               "'")))

  (lsp-register-client
    (make-lsp-client :new-connection (lsp-tramp-connection 'lsp-julia--rls-command-remote)
                     :major-modes '(julia-mode ess-julia-mode)
                     :server-id 'julia-ls-remote
                     ;;:multi-root t
                     :remote? t)))

This setup pataches a recent PR in lsp-mode.
Along with this, you have to upgrade TRAMP to 2.5.0.
The setup for the lsp-julia is straightfoward -- only need to make sure all pathes are the remote ones.

You open a file from a julia project on the remote server and want the language server to spawn that same server?

Exactly. My config above does this.

Is it possible to have a local language server work on the remote files?

I don't know but I suppose this would be hard as the dependencies are on the remote.

lsp-tramp-connection is provided by lsp-mode, right?

Yes :)

@tecosaur
Copy link

tecosaur commented Feb 7, 2022

@xukai92 I've just come across this thread after looking for a way to get a remote lsp server working. Do you think your work could be turned into a PR?

@ordicker
Copy link

Making lsp-julia works remotely won't be great.

@gdkrmr
Copy link
Owner

gdkrmr commented Feb 12, 2023

I have tried #61 and it doesn't work locally. I think emacs calls julia --project=... is a single command. I have also tried creating a single string and calling that with the same result.

I have also tried implementing the solution by @xukai92 and get the same error on the remote machine. maybe this is a path issue, I didn't have time to check.

@uncomfyhalomacro
Copy link

I just saw this issue. I made a script for this instead to fix some corner cases https://codeberg.org/uncomfyhalomacro/erudite-macs/src/branch/main/scripts. and to use that, i made a this huge elisp code

(with-eval-after-load "lsp-julia"
      (add-to-list 'lsp-language-id-configuration '(julia-ts-mode . "julia"))
      (setq
       lsp-julia-command "julia"
       lsp-julia-package-dir "@emacs-lspconfig"
       lsp-julia-flags `(,(concat "--project=" lsp-julia-package-dir)
                         "--startup-file=no"
                         "--history-file=no"
                         ,(concat "-J" (shell-command-to-string "julia --startup-file=no --history-file=no -e 'print(homedir())'") "/.julia/environments/emacs-lspconfig/languageserver.so"))
       lsp-julia-default-environment (string-trim(shell-command-to-string "julia --startup-file=no --history-file=no -e 'print(dirname(Base.active_project()))'")))

      (defun lsp-julia-update-languageserver()
        "Custom command to update the Julia Language Server."
        (interactive)
        (setq lsp-julia-update-flags `(,(concat "--project=" lsp-julia-package-dir)
                                       "--startup-file=no"
                                       "--history-file=no"))
        (apply 'start-process
               "lsp-julia-languageserver-updater"
               "*lsp-julia-languageserver-updater*"
               lsp-julia-command
               (append lsp-julia-update-flags
                       (list (expand-file-name "scripts/julia-ls-update-or-install.jl" user-emacs-directory)))))

      (defun lsp-julia--get-root ()
        "Get the (Julia) project root directory of the current file. Customized."
        (concat ""
                (expand-file-name
                 (or (locate-dominating-file buffer-file-name "Project.toml")
                     (locate-dominating-file buffer-file-name "JuliaProject.toml")
                     lsp-julia-default-environment))
                ""))

      (defvar julia-ls-script "" "Path to Julia Script")

      (setq julia-ls-script
            (expand-file-name "scripts/julia-ls.jl" user-emacs-directory))

      (defun lsp-julia--rls-command ()
        "This is a custom command to launch the Julia Language Server.
                   The reason being that I am using Julia inside a distrobox."
        `(,lsp-julia-command
          ,@lsp-julia-flags
          ,julia-ls-script
          ,(buffer-file-name)))
      (lsp-register-client
       (make-lsp-client :new-connection (lsp-tramp-connection 'lsp-julia--rls-command)
                        :activation-fn (lsp-activate-on "julia")
                        :major-modes '(julia-mode julia-ts-mode)
                        :remote? t
                        :priority '1
                        :server-id 'lsp-julia-remote))
      (lsp-register-client
       (make-lsp-client :new-connection (lsp-stdio-connection 'lsp-julia--rls-command)
                        :major-modes '(julia-mode julia-ts-mode)
                        :server-id 'julia-ls
                        :multi-root t))
      ))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants