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

Elm Language Server #285

Closed
mandarvaze opened this issue Jul 11, 2019 · 29 comments
Closed

Elm Language Server #285

mandarvaze opened this issue Jul 11, 2019 · 29 comments
Labels

Comments

@mandarvaze
Copy link

First of all, Thanks a bunch for this excellent software.

Does Elm Language Server work with eglot ?
If yes, can you add it to the README ?

@joaotavora
Copy link
Owner

Does Elm Language Server work with eglot ?

I don't know. Possibly. Try it out!

(add-to-list 'eglot-server-programs '(elm-mode . ("elm-language-server" "--stdio")))

You would have to have some elm-mode (don't know if that exists but it's probable). And elm-language-server installed somewhere in your path.

@mandarvaze
Copy link
Author

elm-mode exists: https://github.com/jcollard/elm-mode
But I wonder if it is competing with eglot/lsp for features.

I'll try and report here.

@jamiecollinson
Copy link

Hi @joaotavora , I'm trying to get this to work based on your instructions:

(add-to-list 'eglot-server-programs '(elm-mode . ("elm-language-server" "--stdio")))

You would have to have some elm-mode (don't know if that exists but it's probable). And elm-language-server installed somewhere in your path.

I have elm-mode set up for .elm files, and elm-language-server is installed on my path and working fine - I can run it manually and connect to it via lsp-mode, though I prefer eglot :-)

Eglot reports that it connects successfully:

[eglot] Connected! Server `EGLOT (website/elm-mode)' now managing `elm-mode' buffers in project `website'.

But when I trigger any action like completion at point I get the error:

cl-getf: Wrong type argument: plistp, t

I'm guessing this might be something simple related to the config - is there anything I can do to debug? Would be great to add Elm to the list of supported language servers, and I'm using Elm in production at the moment so would be happy to help out if I can (and grateful to be able to use it with eglot).

@joaotavora
Copy link
Owner

@jamiecollinson this is a bug in Eglot. It might also be a bug in the elm-language-server.

  1. To help us discover where the problem lies in Eglot, please do M-x toggle-debug-on-error and re-do the problem case. You should get a backtrace which you should post here.

  2. To discover what is causing the bug, please type M-x eglot-events-buffer and post the contents here, too.

@jamiecollinson
Copy link

Thanks @joaotavora!

Here's the backtrace I get when triggering completion-at-point:

Debugger entered--Lisp error: (wrong-type-argument plistp t)
  plist-member(t :triggerCharacters)
  cl-getf(t :triggerCharacters)
  eglot-completion-at-point()
  completion--capf-wrapper(eglot-completion-at-point all)
  run-hook-wrapped(completion--capf-wrapper eglot-completion-at-point all)
  completion-at-point()
  complete-symbol(nil)
  funcall-interactively(complete-symbol nil)
  call-interactively(complete-symbol nil nil)
  command-execute(complete-symbol)

I'm not sure the eglot-events-buffer tells much - looks to me that it may not be getting far enough to trigger anything there, but I could be wrong (this is a new blank file where I've typed import Brow and triggered completion which should yield Browser - the simplest example I could think of):

server-notification Mon Sep 30 08:45:25 2019:
(:jsonrpc "2.0" :method "window/logMessage" :params
          (:type 3 :message "A hover was requested"))

server-reply (id:17) Mon Sep 30 08:45:25 2019:
(:jsonrpc "2.0" :id 17 :result nil)

client-notification Mon Sep 30 08:45:26 2019:
(:jsonrpc "2.0" :method "textDocument/didChange" :params
          (:textDocument
           (:uri "file:///Users/jamie/work/focus/website/elm/src/test.elm" :version 32)
           :contentChanges
           [(:text "import Brow")]))

client-request (id:18) Mon Sep 30 08:45:26 2019:
(:jsonrpc "2.0" :id 18 :method "textDocument/hover" :params
          (:textDocument
           (:uri "file:///Users/jamie/work/focus/website/elm/src/test.elm")
           :position
           (:line 0 :character 11)))

server-notification Mon Sep 30 08:45:26 2019:
(:jsonrpc "2.0" :method "window/logMessage" :params
          (:type 3 :message "A hover was requested"))

server-reply (id:18) Mon Sep 30 08:45:26 2019:
(:jsonrpc "2.0" :id 18 :result nil)

@joaotavora
Copy link
Owner

I'm not sure the eglot-events-buffer tells much

What you sent is enough information to start investigating, but the info I need from eglot-events-buffer is not only the most recent events (around the error) but also the first initialization message exchanged between client and server.

@jamiecollinson
Copy link

Apologies - thought you only wanted the most recent, here's a full log from a fresh session with the same scenario:

client-request (id:1) Mon Sep 30 09:10:16 2019:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
          (:processId 26919 :rootPath "/Users/jamie/personal/eglot-test/" :rootUri "file:///Users/jamie/personal/eglot-test/" :initializationOptions nil :capabilities
                      (:workspace
                       (:applyEdit t :executeCommand
                                   (:dynamicRegistration :json-false)
                                   :workspaceEdit
                                   (:documentChanges :json-false)
                                   :didChangeWatchedFiles
                                   (:dynamicRegistration t)
                                   :symbol
                                   (:dynamicRegistration :json-false))
                       :textDocument
                       (:synchronization
                        (:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
                        :completion
                        (:dynamicRegistration :json-false :completionItem
                                              (:snippetSupport t)
                                              :contextSupport t)
                        :hover
                        (:dynamicRegistration :json-false)
                        :signatureHelp
                        (:dynamicRegistration :json-false :signatureInformation
                                              (:parameterInformation
                                               (:labelOffsetSupport t)))
                        :references
                        (:dynamicRegistration :json-false)
                        :definition
                        (:dynamicRegistration :json-false)
                        :documentSymbol
                        (:dynamicRegistration :json-false :symbolKind
                                              (:valueSet
                                               [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]))
                        :documentHighlight
                        (:dynamicRegistration :json-false)
                        :codeAction
                        (:dynamicRegistration :json-false :codeActionLiteralSupport
                                              (:codeActionKind
                                               (:valueSet
                                                ["quickfix" "refactor" "refactor.extract" "refactor.inline" "refactor.rewrite" "source" "source.organizeImports"])))
                        :formatting
                        (:dynamicRegistration :json-false)
                        :rangeFormatting
                        (:dynamicRegistration :json-false)
                        :rename
                        (:dynamicRegistration :json-false)
                        :publishDiagnostics
                        (:relatedInformation :json-false))
                       :experimental nil)))

server-notification Mon Sep 30 09:10:16 2019:
(:jsonrpc "2.0" :method "window/logMessage" :params
          (:type 3 :message "Loading Elm tree-sitter syntax from ../../.nvm/versions/node/v11.14.0/lib/node_modules/@elm-tooling/elm-language-server/out/tree-sitter-elm.wasm"))

server-notification Mon Sep 30 09:10:16 2019:
(:jsonrpc "2.0" :method "window/logMessage" :params
          (:type 3 :message "No elm.json found"))

server-reply (id:1) Mon Sep 30 09:10:17 2019:
(:jsonrpc "2.0" :id 1 :result
          (:capabilities
           (:codeActionProvider t :codeLensProvider
                                (:resolveProvider t)
                                :completionProvider nil :definitionProvider t :documentFormattingProvider t :documentSymbolProvider t :executeCommandProvider
                                (:commands
                                 ["elmLS.elmAnalyseFixer-0ca400c6fa183cab19e7872d38a8b7e4" "elmLS.elmAnalyseFixer.fixAll-0ca400c6fa183cab19e7872d38a8b7e4" "elmLS.elmMakeFixer-fcfce42725fb2e036adedf8dd1e03b9a"])
                                :foldingRangeProvider t :hoverProvider t :referencesProvider t :renameProvider t :textDocumentSync 1 :workspaceSymbolProvider t)))

client-notification Mon Sep 30 09:10:17 2019:
(:jsonrpc "2.0" :method "initialized" :params
          (:__dummy__ t))

client-notification Mon Sep 30 09:10:17 2019:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
          (:textDocument
           (:uri "file:///Users/jamie/personal/eglot-test/test.elm" :version 0 :languageId "elm" :text "module Main exposing (..)\n\nimport Brow\n")))

client-notification Mon Sep 30 09:10:17 2019:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
          (:settings nil))

@nemethf
Copy link
Collaborator

nemethf commented Sep 30, 2019

Isn't this same as issue #278? There's a chance that 6d87de1 fixed this. @jamiecollinson, can you try to run git version of eglot and see whether the issue still persist?

Additionally, if the previous analysis was correct, then the server sends non-standard capabilities reply, because instead of ":completionProvider nil", it should send ":completionProvider :json-false".

@jamiecollinson
Copy link

Thanks @nemethf - just checked and I was using eglot-20190910.1347, I've just updated to the latest from melpa (eglot-20190926.1204) and no longer see any error.

Unfortunately no actions seem to work! I'm new to the LSP specification but I presume the following means the elm-language-server doesn't provide completion but (e.g.) definition, hover, references and rename should work (I've tried them and they don't)?

 server-reply (id:1) Mon Sep 30 12:25:47 2019:
(:jsonrpc "2.0" :id 1 :result
          (:capabilities
           (:codeActionProvider t :codeLensProvider
                                (:resolveProvider t)
                                :completionProvider nil :definitionProvider t :documentFormattingProvider t :documentSymbolProvider t :executeCommandProvider
                                (:commands
                                 ["elmLS.elmAnalyseFixer-73d50de36d004a498adcbf6a5807eb8c" "elmLS.elmAnalyseFixer.fixAll-73d50de36d004a498adcbf6a5807eb8c" "elmLS.elmMakeFixer-52e564f3f1e03b192b3dfe6b2873d2bf"])
                                :foldingRangeProvider t :hoverProvider t :referencesProvider t :renameProvider t :textDocumentSync 1 :workspaceSymbolProvider t)))

I suspect this is problem with the server not eglot, but just in case is there anything you can suggest?

@nemethf
Copy link
Collaborator

nemethf commented Sep 30, 2019

Let me start with saying I have no idea what Elm is. But according to its website, it does support code completion. My guess is the default configuration values of the elm language server are not satisfactory in your environment. It's worth trying to configure them. One way to configure them is through the LSP protocol. Here is an example.

But you're right, "jumping to definition" should work. You can debug the problem with the following. Write a very simple file just having a jump target and an origin. (A function definition and a function call if those terms make sense in elm.) Put the point (cursor) on the origin. Manually start eglot. Wait a couple of seconds. Call xref-find-definitions (by pressing M-.) Then examine the events buffer and the stderr buffer (using M-x eglot-stderr-buffer). Hopefully, reading them will give us some clues.

@jamiecollinson
Copy link

Appreciate you going above and beyond, and thanks for the links to configuration - I'd been wondering that! Elm is a language that compiles to JS, it's strongly inspired by Haskell, and the tooling is downloaded via NPM and installed globally - there's an elm command on my path which handles compilation / repl, so I'm pretty sure that's the source for references, completion etc.

I've created a basic config in the same dir as the source as .dir-locals.el (I also tried a more elaborate config specifying more keys, but with the same result):

((nil (eglot-workspace-configuration . ((elmLS . ((elmPath . "/Users/admin/.nvm/versions/node/v11.14.0/bin/elm")))))))

And I can see that's getting sent to the server from the event log:

client-request (id:1) Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
          (:processId 10590 :rootPath "/Users/admin/personal/elm-eglot/src/" :rootUri "file:///Users/admin/personal/elm-eglot/src/" :initializationOptions nil :capabilities
                      (:workspace
                       (:applyEdit t :executeCommand
                                   (:dynamicRegistration :json-false)
                                   :workspaceEdit
                                   (:documentChanges :json-false)
                                   :didChangeWatchedFiles
                                   (:dynamicRegistration t)
                                   :symbol
                                   (:dynamicRegistration :json-false))
                       :textDocument
                       (:synchronization
                        (:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
                        :completion
                        (:dynamicRegistration :json-false :completionItem
                                              (:snippetSupport t)
                                              :contextSupport t)
                        :hover
                        (:dynamicRegistration :json-false)
                        :signatureHelp
                        (:dynamicRegistration :json-false :signatureInformation
                                              (:parameterInformation
                                               (:labelOffsetSupport t)))
                        :references
                        (:dynamicRegistration :json-false)
                        :definition
                        (:dynamicRegistration :json-false)
                        :documentSymbol
                        (:dynamicRegistration :json-false :symbolKind
                                              (:valueSet
                                               [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]))
                        :documentHighlight
                        (:dynamicRegistration :json-false)
                        :codeAction
                        (:dynamicRegistration :json-false :codeActionLiteralSupport
                                              (:codeActionKind
                                               (:valueSet
                                                ["quickfix" "refactor" "refactor.extract" "refactor.inline" "refactor.rewrite" "source" "source.organizeImports"])))
                        :formatting
                        (:dynamicRegistration :json-false)
                        :rangeFormatting
                        (:dynamicRegistration :json-false)
                        :rename
                        (:dynamicRegistration :json-false)
                        :publishDiagnostics
                        (:relatedInformation :json-false))
                       :experimental nil)))

server-notification Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :method "window/logMessage" :params
          (:type 3 :message "Loading Elm tree-sitter syntax from ../../../.nvm/versions/node/v11.14.0/lib/node_modules/@elm-tooling/elm-language-server/out/tree-sitter-elm.wasm"))

server-notification Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :method "window/logMessage" :params
          (:type 3 :message "No elm.json found"))

server-reply (id:1) Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :id 1 :result
          (:capabilities
           (:codeActionProvider t :codeLensProvider
                                (:resolveProvider t)
                                :completionProvider nil :definitionProvider t :documentFormattingProvider t :documentSymbolProvider t :executeCommandProvider
                                (:commands
                                 ["elmLS.elmAnalyseFixer-f1233c3e46496ea4c3d86528dbf867c1" "elmLS.elmAnalyseFixer.fixAll-f1233c3e46496ea4c3d86528dbf867c1" "elmLS.elmMakeFixer-83da7f2d7b2129b183502fe43a5267ac"])
                                :foldingRangeProvider t :hoverProvider t :referencesProvider t :renameProvider t :textDocumentSync 1 :workspaceSymbolProvider t)))

client-notification Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :method "initialized" :params
          (:__dummy__ t))

client-notification Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
          (:textDocument
           (:uri "file:///Users/admin/personal/elm-eglot/src/test.elm" :version 0 :languageId "elm" :text "module Test exposing (..)\n\n\nhello : String -> String\nhello name =\n    \"Hello \" ++ name\n\n\ntest : String\ntest =\n    hello \"world\"\n")))

client-notification Mon Sep 30 14:53:01 2019:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
          (:settings
           (:elmLS
            ((elmPath . "/Users/admin/.nvm/versions/node/v11.14.0/bin/elm")))))

client-request (id:2) Mon Sep 30 14:53:05 2019:
(:jsonrpc "2.0" :id 2 :method "textDocument/hover" :params
          (:textDocument
           (:uri "file:///Users/admin/personal/elm-eglot/src/test.elm")
           :position
           (:line 10 :character 4)))

server-reply (id:2) ERROR Mon Sep 30 14:53:05 2019:
(:jsonrpc "2.0" :id 2 :error
          (:code -32601 :message "Unhandled method textDocument/hover"))

internal (id:2) ERROR Mon Sep 30 14:53:05 2019:
(:message "error ignored, status set (Unhandled method textDocument/hover)" :id 2 :error -32601)

When I trigger xref-find-definitions I'm prompted for a TAGS file and there's nothing in the eglot stderr buffer (and also I don't see a message in the event log so presume it's not getting that far), does that tell you anything?

In case it helps here's the find definition I was trying - hopefully understandable even without background knowledge of Elm (hello is a function taking a string and returning a string, test is a function taking nothing and returning a string):

Screen Shot 2019-09-30 at 14 51 02

Also in case it helps, this is the config for Elm from lsp-mode which claims to work out of the box:

https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-elm.el

joaotavora added a commit that referenced this issue Sep 30, 2019
Only query :triggerCharacter information if the server has provided
it.  Elm's doesn't, apparently.

* eglot.el (eglot-completion-at-point): Check that completion
capability is a list before treating it like one.
@nemethf
Copy link
Collaborator

nemethf commented Sep 30, 2019

There's a lot going on here.

((nil (eglot-workspace-configuration . ((elmLS . ((elmPath . "/Users/admin/.nvm/versions/node/v11.14.0/bin/elm")))))))

I'm not sure that's the right syntax. Changing the path to a non-existent binary might help to check whether server takes into account the provided value.

(:jsonrpc "2.0" :method "window/logMessage" :params
(:type 3 :message "No elm.json found"))

Can you create an elm.json file? Does it store configuration for the language server or for the compiler?

server-reply (id:1) Mon Sep 30 14:53:01 2019:
...
:definitionProvider t :hoverProvider t

The server says it's a hoverProvider, but ...

server-reply (id:2) ERROR Mon Sep 30 14:53:05 2019:
(:jsonrpc "2.0" :id 2 :error
(:code -32601 :message "Unhandled method textDocument/hover"))

... it doesn't have a textDocument/hover handler. This error might kill the server. Can you check whether the server is still running after an error like this? For example, does it reply with another error to another hover request?

You can try to customize eglot-ignored-server-capabilites to ignore the server's hoverProvider capability and continue debugging.

When I trigger xref-find-definitions I'm prompted for a TAGS file

This is also strange since the server says it's a definitionProvider. What happens when you type: M-: (eglot-xref-backend) RET in the elm buffer?

Also in case it helps, this is the config for Elm from lsp-mode which claims to work out of the box

For me it doesn't. But if you could capture the communication between a working server and a working client, then we would be able to compare that with the events buffer above.

@joaotavora
Copy link
Owner

@nemethf and @jamiecollinson I just refreshed the page and wow that's a big exchange that I can't read right now. I think the fix I pushed to a side branch might solve the issue correctly (and @nemeth I don't think the "handle null capabilities as nil" will do the trick here).

But, I didn't actually try the fix, it is a blind fix because downloading Elm is not an option right now.

But @jamiecollinson your log seems to confirm my suspicion. Elm supports completion, just not with trigger characters . And it seems to signal this by saying :completionProvider <empty-list>, which is different, as @nemethf noted (but I only skimmed his reply) from :completionProvider :json-false. I didn't look up the spec to figure out if this is legal or not.

@jamiecollinson
Copy link

jamiecollinson commented Sep 30, 2019

Thanks so much for the extensive help (I realise this must not be a priority as Elm is rather niche!)

@nemethf your commend about missing elm.json made me realise a possible problem would be the folder structure. The test project is structured in a standard (enforced by elm) way:

eglot-test/
  - elm-stuff/
  - src/
    - test.elm
  - elm.json

I was starting eglot from within a buffer which had test.elm open, so it considered src the root and was missing elm.json in the parent folder. On a hunch I ran git init in the parent folder, restarted eglot from the test.elm buffer and that caused eglot to consider the parent as the project root. I now get hover actions, go to definition and references :-)

lsp-mode seemed to handle this without the git repo so there must be some logic at work in their implementation. Anything I can do to improve this or is there a way to manually override what the eglot project root is?

@joaotavora I'm still not getting completion so I assume that's the :completionProvider issue you've mentioned - anything I can do to test out / help with your possible fix?

@joaotavora
Copy link
Owner

@joaotavora I'm still not getting completion so I assume that's the :completionProvider issue you've mentioned - anything I can do to test out / help with your possible fix?

@nemethf mentioned, quite rightly, that a previous fix might have invalidated the fix that I sent you. I you if try the newest commit we will be able to tell if it was it.

But the bottom line here is that I believe the server is sending non-compliant capabilities. I'll investigate more tomorrow.

@jamiecollinson
Copy link

jamiecollinson commented Oct 1, 2019

Thanks @joaotavora - I've just tried with 6d87de1 and get a similar error to before but with different backtrace:

Debugger entered--Lisp error: (wrong-type-argument plistp t)
  plist-member(t :triggerCharacters)
  cl-getf(t :triggerCharacters)
  (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list))
  (regexp-opt (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list)))
  (looking-back (regexp-opt (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list))) (line-beginning-position))
  (save-excursion (if (car bounds) (progn (goto-char (car bounds)))) (looking-back (regexp-opt (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list))) (line-beginning-position)))
  (list (or (car bounds) (point)) (or (cdr bounds) (point)) (function (lambda (string pred action) (if (eq action (quote metadata)) metadata (funcall (completion-table-dynamic (function (lambda ... ...))) string pred action)))) :annotation-function (function (lambda (obj) (let ((object-once (get-text-property 0 (quote eglot--lsp-completion) obj))) (let* ((--cl-rest-- object-once) (detail (car ...)) (kind (car ...)) (insertTextFormat (car ...))) (eglot--call-with-interface (assoc (quote CompletionItem) eglot--lsp-interface-alist) object-once (function (lambda nil ...))))))) :company-doc-buffer (function (lambda (obj) (let* ((documentation (let (...) (or ... ...))) (formatted (and documentation (eglot--format-markup documentation)))) (if formatted (progn (save-current-buffer (set-buffer ...) (erase-buffer) (insert formatted) (current-buffer))))))) :company-prefix-length (save-excursion (if (car bounds) (progn (goto-char (car bounds)))) (looking-back (regexp-opt (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list))) (line-beginning-position))) :exit-function (function (lambda (comp _status) (let ((comp (if (get-text-property 0 ... comp) comp (cl-find comp strings :test ...)))) (let ((object-once (get-text-property 0 ... comp))) (let* ((--cl-rest-- object-once) (insertTextFormat ...) (insertText ...) (textEdit ...) (additionalTextEdits ...)) (eglot--call-with-interface (assoc ... eglot--lsp-interface-alist) object-once (function ...))))))))
  (progn (list (or (car bounds) (point)) (or (cdr bounds) (point)) (function (lambda (string pred action) (if (eq action (quote metadata)) metadata (funcall (completion-table-dynamic (function ...)) string pred action)))) :annotation-function (function (lambda (obj) (let ((object-once (get-text-property 0 ... obj))) (let* ((--cl-rest-- object-once) (detail ...) (kind ...) (insertTextFormat ...)) (eglot--call-with-interface (assoc ... eglot--lsp-interface-alist) object-once (function ...)))))) :company-doc-buffer (function (lambda (obj) (let* ((documentation (let ... ...)) (formatted (and documentation ...))) (if formatted (progn (save-current-buffer ... ... ... ...)))))) :company-prefix-length (save-excursion (if (car bounds) (progn (goto-char (car bounds)))) (looking-back (regexp-opt (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list))) (line-beginning-position))) :exit-function (function (lambda (comp _status) (let ((comp (if ... comp ...))) (let ((object-once ...)) (let* (... ... ... ... ...) (eglot--call-with-interface ... object-once ...))))))))
  (if completion-capability (progn (list (or (car bounds) (point)) (or (cdr bounds) (point)) (function (lambda (string pred action) (if (eq action (quote metadata)) metadata (funcall (completion-table-dynamic ...) string pred action)))) :annotation-function (function (lambda (obj) (let ((object-once ...)) (let* (... ... ... ...) (eglot--call-with-interface ... object-once ...))))) :company-doc-buffer (function (lambda (obj) (let* ((documentation ...) (formatted ...)) (if formatted (progn ...))))) :company-prefix-length (save-excursion (if (car bounds) (progn (goto-char (car bounds)))) (looking-back (regexp-opt (cl-coerce (cl-getf completion-capability :triggerCharacters) (quote list))) (line-beginning-position))) :exit-function (function (lambda (comp _status) (let ((comp ...)) (let (...) (let* ... ...))))))))
  (let* ((bounds (bounds-of-thing-at-point (quote symbol))) (server (eglot--current-server-or-lose)) (completion-capability (eglot--server-capable :completionProvider)) (sort-completions (function (lambda (completions) (sort completions (function (lambda ... ...)))))) (metadata (list (quote metadata) (cons (quote display-sort-function) sort-completions))) strings) (if completion-capability (progn (list (or (car bounds) (point)) (or (cdr bounds) (point)) (function (lambda (string pred action) (if (eq action ...) metadata (funcall ... string pred action)))) :annotation-function (function (lambda (obj) (let (...) (let* ... ...)))) :company-doc-buffer (function (lambda (obj) (let* (... ...) (if formatted ...)))) :company-prefix-length (save-excursion (if (car bounds) (progn (goto-char ...))) (looking-back (regexp-opt (cl-coerce ... ...)) (line-beginning-position))) :exit-function (function (lambda (comp _status) (let (...) (let ... ...))))))))
  eglot-completion-at-point()
  completion--capf-wrapper(eglot-completion-at-point all)
  run-hook-wrapped(completion--capf-wrapper eglot-completion-at-point all)
  completion-at-point()
  complete-symbol(nil)
  funcall-interactively(complete-symbol nil)
  call-interactively(complete-symbol nil nil)
  command-execute(complete-symbol)

Hope that helps and do let me know if I can help - really appreciate you looking at it (and thanks for yasnippet - only just realised you're the author of that package too!)

@nemethf
Copy link
Collaborator

nemethf commented Oct 1, 2019

I think João meant 6dfdfff and not 6d87de1.

is there a way to manually override what the eglot project root is?

Eglot relies on the built-in project.el for determining the project-root. The project package has some useful features and different ways to define the project-root. But I never tried to understand those alternative methods.

@jamiecollinson
Copy link

Sorry, that was my typo - I'd actually checked out 6dfdfff and copied the wrong hash from above, so I think the backtrace is correct.

@jamiecollinson
Copy link

Re: project.el I'll see what I can find out - I believe that's used by projectile (which I'm using) so that may be related. I'm also not 100% clear whether that should be the responsibility of the server or client (eglot) - it seems to me that ideally the server shouldn't have to worry about details like folder root as it's language specific, but I don't know if that's part of the LSP spec.

@nemethf
Copy link
Collaborator

nemethf commented Oct 1, 2019

Projectile users might find useful code snippets here. They cloud even try to revive that discussion :)

@joaotavora
Copy link
Owner

Sorry, that was my typo - I'd actually checked out 6dfdfff and copied the wrong hash from above, so I think the backtrace is correct.

Are you absolutely sure? I don't want to doubt gratuitously, but your backtrace doesn't seem to have the crucial when statement I added in:

commit 15b9762bb69485725967ca97d50fd7263e1a24fa (master)
Author: João Távora <joaotavora@gmail.com>
Date:   Mon Sep 30 18:06:48 2019 +0200

    Fix #285: unbreak Elm language server which does use :triggerCharacters
    
    Only query :triggerCharacter information if the server has provided
    it.  Elm's doesn't, apparently.
    
    * eglot.el (eglot-completion-at-point): Check that completion
    capability is a list before treating it like one.

diff --git a/eglot.el b/eglot.el
index 723ac3b..4098c41 100644
--- a/eglot.el
+++ b/eglot.el
@@ -1952,10 +1952,11 @@ is not active."
        :company-prefix-length
        (save-excursion
          (when (car bounds) (goto-char (car bounds)))
-         (looking-back
-          (regexp-opt
-           (cl-coerce (cl-getf completion-capability :triggerCharacters) 'list))
-          (line-beginning-position)))
+         (when (listp completion-capability)
+           (looking-back
+            (regexp-opt
+             (cl-coerce (cl-getf completion-capability :triggerCharacters) 'list))
+            (line-beginning-position))))
        :exit-function
        (lambda (comp _status)
          (let ((comp (if (get-text-property 0 'eglot--lsp-completion comp)

Can you confirm you are working with exactly 6dfdfff and also don't have other stale eglot.elc files?

@jamiecollinson
Copy link

Projectile users might find useful code snippets here. They cloud even try to revive that discussion :)

Thanks! I've had a quick read and am actually thinking I can ditch projectile now that project.el is in place and improving - I'd mostly left my config alone since pre Emacs 26, so taking the opportunity to remove some cruft and lighten use of dependencies. flymake also looks much improved so I may see if I can remove flycheck.

@joaotavora - I've just double checked and the version was correct but I must have had a stale .elc as removing it and restarting eglot it's now working - I have completion in addition to hover, goto definition / references etc. Thanks so much and hopefully that means once merged you can add elm to the list of supported language servers.

Do you need to communicate anything with the elm-language-server authors? You must be busy handling all these and I'm happy to help in speaking with them if they're not following the spec in some way.

@joaotavora
Copy link
Owner

Thanks! I've had a quick read and am actually thinking I can ditch projectile now that project.el is in place and improving - I'd mostly left my config alone since pre Emacs 26, so taking the opportunity to remove some cruft and lighten use of dependencies. flymake also looks much improved so I may see if I can remove flycheck.

Nothing against those projects, but these seem like exactly the outcomes that Eglot aims at: making users use fewers packages, and a leaner Emacs.

Thanks so much and hopefully that means once merged you can add elm to the list of supported language servers.

Yes.

Do you need to communicate anything with the elm-language-server authors?

Not really, as far as I can tell the, the server is compliant (regarding the completion capability imbroglio at least). Its issue #298 that has to be reopened, and that has impacts in the php language server, which is non-compliant. Quickly explained:

  • You found a bug in Eglot, and my first commit to this issue was a bug fix.
  • But the bugfix was rendered useless because in 6d87de1 we tried to be lenient towards non-compliant servers that specify non-capabilities in a non-standard way (at least we think they are non-compliant). We thought that woudn't introduce problems elsewhere, but it did, here.

@jamiecollinson
Copy link

Thanks so much, for the help here and your work on eglot and yasnippet.

I work in a couple of other languages so I'll be trying eglot on them too, and will contribute where I can.

@cameron
Copy link

cameron commented Feb 7, 2020

But the bugfix was rendered useless because in 6d87de1 we tried to be lenient towards non-compliant servers that specify non-capabilities in a non-standard way (at least we think they are non-compliant). We thought that woudn't introduce problems elsewhere, but it did, here.

I take it this means eglot and elm are not to be friends in the near term? If so, I will open an issue over at elm-mode to update the readme and close this rabbit hole to others.

@mandarvaze
Copy link
Author

@cameron I think the comment you pointed to is regarding php-language-server (being non-compliant)

elm-language-server seems to be compliant and compatible with eglot once the correct commit is merged.

See below.

Thanks so much and hopefully that means once merged you can add elm to the list of supported language servers.

Yes.

Do you need to communicate anything with the elm-language-server authors?

Not really, as far as I can tell the, the server is compliant (regarding the completion capability imbroglio at least).

@cameron
Copy link

cameron commented Feb 8, 2020

Beautiful, thanks for the clarification!

@aesyondu
Copy link

aesyondu commented May 9, 2020

Thanks so much for the extensive help (I realise this must not be a priority as Elm is rather niche!)

@nemethf your commend about missing elm.json made me realise a possible problem would be the folder structure. The test project is structured in a standard (enforced by elm) way:

eglot-test/
  - elm-stuff/
  - src/
    - test.elm
  - elm.json

I was starting eglot from within a buffer which had test.elm open, so it considered src the root and was missing elm.json in the parent folder. On a hunch I ran git init in the parent folder, restarted eglot from the test.elm buffer and that caused eglot to consider the parent as the project root. I now get hover actions, go to definition and references :-)

lsp-mode seemed to handle this without the git repo so there must be some logic at work in their implementation. Anything I can do to improve this or is there a way to manually override what the eglot project root is?

@joaotavora I'm still not getting completion so I assume that's the :completionProvider issue you've mentioned - anything I can do to test out / help with your possible fix?

This helped me, thanks!

TLDR: git init your folder where elm.json is.

bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 18, 2022
…:triggerCharacters

Only query completionProvider -> triggerCharacter information if the
server has provided it.  Elm's, and probaly other's, do not provide
it, which doesn't mean they don't support completion.

* eglot.el (eglot-completion-at-point): Check that completion
capability is a list before treating it like one.
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
…:triggerCharacters

Only query completionProvider -> triggerCharacter information if the
server has provided it.  Elm's, and probaly other's, do not provide
it, which doesn't mean they don't support completion.

* eglot.el (eglot-completion-at-point): Check that completion
capability is a list before treating it like one.
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
Only query completionProvider -> triggerCharacter information if the
server has provided it.  Elm's, and probaly other's, do not provide
it, which doesn't mean they don't support completion.

* eglot.el (eglot-completion-at-point): Check that completion
capability is a list before treating it like one.

#285: joaotavora/eglot#285
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this issue Oct 12, 2022
Only query completionProvider -> triggerCharacter information if the
server has provided it.  Elm's, and probaly other's, do not provide
it, which doesn't mean they don't support completion.

* eglot.el (eglot-completion-at-point): Check that completion
capability is a list before treating it like one.

GitHub-reference: fix joaotavora/eglot#285
@afrepues
Copy link

For those with an Elm project with no Git repository, this might help:

(add-to-list 'project-find-functions #'project-rootfile-try-detect t)
(add-to-list 'project-rootfile-list "elm.json")

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

No branches or pull requests

7 participants