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

Instructions for use in Emacs Eglot #57

Open
bscan opened this issue Dec 23, 2022 · 6 comments
Open

Instructions for use in Emacs Eglot #57

bscan opened this issue Dec 23, 2022 · 6 comments
Labels
good first issue Good for newcomers help wanted Extra attention is needed

Comments

@bscan
Copy link
Owner

bscan commented Dec 23, 2022

The upcoming release of Emacs 29 will have eglot as a built-in LSP client. It would be nice to have instructions on how to use the Navigator, and do some basic testing to ensure the key features work.

Getting the Perl Navigator added as a default language server option would be great too:
https://github.com/joaotavora/eglot/blob/e501275e06952889056268dabe08ccd0dbaf23e5/eglot.el#L235

@bscan bscan added help wanted Extra attention is needed good first issue Good for newcomers labels Dec 23, 2022
@HaraldJoerg
Copy link

I use PerlNavigator with eglot occasionally with this invocation in my Emacs configuration (I'm using cperl-mode, for which eglot has no default language server configured):

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               `(cperl-mode . ("node" "/home/haj/devel/perl/PerlNavigator/server/out/server.js" "--stdio"))))

I have installed PerlNavigator from source (as described here), and added the relevant path as documented in the eglot manual. The path to the navigator is installation-specific, therefore this might be useful for documentation, but it is not suitable for inclusion in eglot.
As for basic testing: Is there a list of tests which should be done? Per manual testing I verified that finding a function's definition and symbol completion for functions work. I could not run a test for the perlimports integration: This seems to be disabled per default, and eglot does not allow server-specific configuration items.

For comparison: LSP-mode, another LSP client for Emacs, does allow server-specific configuration, but the perlimports variables have not yet been added to its PerlNavigator support. LSP-mode works around installation specific paths by offering to download and install the server from github (the release file, not the sources) into a known directory of its own.

@bscan
Copy link
Owner Author

bscan commented Dec 24, 2022

Thanks @HaraldJoerg! Other than building from source, npm -g perlnavigator-server also installs the Navigator, but does not include an executable. If I were to include an executable as part of this, npm would automatically add it to the path and perhaps that could be suitable for inclusion in eglot? There are also binaries, although it may take some work to get them listed in the various package managers and automatically updated with each github release.

Sounds like many of the features work already, which is great. There's not a specific list anywhere, but the primary features are syntax checking, perlcritic, perltidy, perlimports, go-to-definition, auto-completion, hover, and outline view.

In terms of configuration, that's unfortunate that eglot does not allow for configuration. Although I could allow configuration via a file somewhere (maybe ~/.perlnavigatorrc or similar). The perlcritic integration is similar in that it checks a variety of places looking for the config; first the lsp specified profile, then the PERLCRITIC environment variable, then ~/.perlcriticrc and then the Navigator's default critic profile.

bscan added a commit that referenced this issue Dec 29, 2022
bscan added a commit that referenced this issue Dec 29, 2022
@bscan bscan closed this as completed in a7b3aab Jan 3, 2023
@bscan
Copy link
Owner Author

bscan commented Jan 3, 2023

Thanks again @HaraldJoerg ! Using your config as a starting point, I was able to get up and running with eglot in emacs. I was able to get a some specific configuration variables set, but I couldn't figure out how to set list variables (e.g. include paths). Pretty good start though. I also fixed a couple minor issues along the way: one startup warning, and an issue with symbol boundaries in goto definition. Essentially, if the cursor is at the beginning of a symbol (e.g. on the sigil of a variable), the navigator did not recognize it as being over the variable.

Leaving this open for now, as I think adding a bin file in the npm install and then including the default config in emacs core would be great.

@bscan bscan reopened this Jan 3, 2023
@HaraldJoerg
Copy link

Some more details about Eglot: Unlike lsp-mode, most of its configuration is not available through the "customize" interface of Emacs. This makes it somewhat clumsy and ... dangerous. So, the example config with setq-defaultoverwrites any configuration which a user might have for other programming languages. Eglot recommends that the variable is set as a directory-local variable, but probably this is out of scope for the PerlNavigator documentation. Fiddling with individual elements within an Emacs lisp variable can be tricky.

Regarding the installation of a callable program somewhere on the path: This would, of course, be a prerequisite for getting it into the Emacs sources. Also, the Emacs folks care about compatibility. So, instead of overwriting the current configuration for perl-mode it might be better to add PerlNavigator as an alternative to eglot-server-programs. As of recently (not in Emacs 29), Perl::LanguageServer has also been added for cperl-mode.
In case of alternatives, if more than one of them happens to be installed: eglot uses the name of the executable to prompt the user for a selection, which emphasizes the need for a dedicated executable (or script): In my setup (as described above), the alternatives are offered as "perl" (for Perl::LanguageServer) and "node" (for PerlNavigator) - slightly irritating, or even misleading, since the availability of "perl" or "node" does not always bring the corresponding language servers.

To get it included into Emacs, I suggest to open an Emacs bug when the starter program "on the path" is available. I can help with that and also suggest a patch. In any case, we should collect feedback from João Távora, who is the main developer and maintainer of Eglot, and from the contributors which did the recent changes to advertise Perl::LanguageServer.

@bkhl
Copy link

bkhl commented May 24, 2024

I can manage to get the language server running and it does show some warnings and expected and so on.

However, it is unusable because I get this error message every second or so:

[eglot] (warning) Server tried to register unsupported capability `workspace/didChangeConfiguration'

Is there some way to get the server to stop doing this thing that Eglot doesn't like, and if so does someone have some Eglot config to do it?

@bkhl
Copy link

bkhl commented Jul 25, 2024

Update: tried again today and have the same problem, but realized the warning above is probably unrelated.

I did

(setq eglot-autoreconnect nil)

to prevent Eglot from trying to restart the server over and over and flood the log, and now the log looks like this:

[internal] Thu Jul 25 16:57:58 2024:
(:message "Running language server: podman run --rm --interactive --volume=/tmp/test/:/tmp/test/:z --workdir=/tmp/test/ localhost/perl-navigator:latest node /opt/PerlNavigator/server/out/server.js --stdio")
[client-request] (id:1) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
          (:processId 5568 :rootPath "/tmp/test/" :rootUri "file:///tmp/test" :initializationOptions #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                   ())
                      :capabilities
                      (:workspace
                       (:applyEdit t :executeCommand
                                   (:dynamicRegistration :json-false)
                                   :workspaceEdit
                                   (:documentChanges t)
                                   :didChangeWatchedFiles
                                   (:dynamicRegistration t)
                                   :symbol
                                   (:dynamicRegistration :json-false)
                                   :configuration t :workspaceFolders t)
                       :textDocument
                       (:synchronization
                        (:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
                        :completion
                        (:dynamicRegistration :json-false :completionItem
                                              (:snippetSupport :json-false :deprecatedSupport t :resolveSupport
                                                               (:properties
                                                                ["documentation" "details" "additionalTextEdits"])
                                                               :tagSupport
                                                               (:valueSet
                                                                [1]))
                                              :contextSupport t)
                        :hover
                        (:dynamicRegistration :json-false :contentFormat
                                              ["plaintext"])
                        :signatureHelp
                        (:dynamicRegistration :json-false :signatureInformation
                                              (:parameterInformation
                                               (:labelOffsetSupport t)
                                               :activeParameterSupport t))
                        :references
                        (:dynamicRegistration :json-false)
                        :definition
                        (:dynamicRegistration :json-false :linkSupport t)
                        :declaration
                        (:dynamicRegistration :json-false :linkSupport t)
                        :implementation
                        (:dynamicRegistration :json-false :linkSupport t)
                        :typeDefinition
                        (:dynamicRegistration :json-false :linkSupport t)
                        :documentSymbol
                        (:dynamicRegistration :json-false :hierarchicalDocumentSymbolSupport t :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"]))
                                              :isPreferredSupport t)
                        :formatting
                        (:dynamicRegistration :json-false)
                        :rangeFormatting
                        (:dynamicRegistration :json-false)
                        :rename
                        (:dynamicRegistration :json-false)
                        :inlayHint
                        (:dynamicRegistration :json-false)
                        :publishDiagnostics
                        (:relatedInformation :json-false :codeDescriptionSupport :json-false :tagSupport
                                             (:valueSet
                                              [1 2])))
                       :window
                       (:workDoneProgress t)
                       :general
                       (:positionEncodings
                        ["utf-32" "utf-8" "utf-16"])
                       :experimental #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
                                                   ()))
                      :workspaceFolders
                      [(:uri "file:///tmp/test" :name "/tmp/test/")]))
[server-reply] (id:1) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 1 :result
          (:capabilities
           (:textDocumentSync 2 :completionProvider
                              (:resolveProvider t :triggerCharacters
                                                ["$" "@" "%" "-" ">" ":"])
                              :definitionProvider t :documentSymbolProvider t :workspaceSymbolProvider t :hoverProvider t :documentFormattingProvider t :documentRangeFormattingProvider t :signatureHelpProvider
                              (:triggerCharacters
                               ["(" "," ")"])
                              :workspace
                              (:workspaceFolders
                               (:supported t)))))
[client-notification] Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :method "initialized" :params #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
                                                            ()))
[client-notification] Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
          (:textDocument
           (:uri "file:///tmp/test/test.pl" :version 0 :languageId "cperl" :text "\n")))
[client-notification] Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
          (:settings
           (:perlnavigator
            (:perlPath "/opt/perl5/bin/perl"))))
[server-request] (id:0) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 0 :method "client/registerCapability" :params
          (:registrations
           [(:id "3b1e62f7-26ea-466a-a612-661c16cb739c" :method "workspace/didChangeConfiguration" :registerOptions nil)]))
[client-reply] (id:0) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 0 :result nil)
[server-request] (id:1) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 1 :method "workspace/configuration" :params
          (:items
           [(:scopeUri "file:///tmp/test/test.pl" :section "perlnavigator")]))
[client-reply] (id:1) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 1 :result
          [(:perlPath "/opt/perl5/bin/perl")])
[server-request] (id:2) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 2 :method "workspace/configuration" :params
          (:items
           [(:scopeUri "file:///tmp/test/test.pl" :section "perlnavigator")]))
[client-reply] (id:2) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 2 :result
          [(:perlPath "/opt/perl5/bin/perl")])
[server-request] (id:3) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 3 :method "workspace/configuration" :params
          (:items
           [(:scopeUri "file:///tmp/test/test.pl" :section "perlnavigator")]))
[client-reply] (id:3) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 3 :result
          [(:perlPath "/opt/perl5/bin/perl")])
[server-request] (id:4) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 4 :method "workspace/configuration" :params
          (:items
           [(:scopeUri "file:///tmp/test/test.pl" :section "perlnavigator")]))
[client-reply] (id:4) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 4 :result
          [(:perlPath "/opt/perl5/bin/perl")])
[stderr] Found settings
[stderr] Found settings
[server-request] (id:5) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 5 :method "workspace/workspaceFolders")
[client-reply] (id:5) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 5 :result
          [(:uri "file:///tmp/test" :name "/tmp/test/")])
[server-request] (id:6) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 6 :method "workspace/workspaceFolders")
[client-reply] (id:6) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 6 :result
          [(:uri "file:///tmp/test" :name "/tmp/test/")])
[server-request] (id:7) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 7 :method "workspace/workspaceFolders")
[client-reply] (id:7) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 7 :result
          [(:uri "file:///tmp/test" :name "/tmp/test/")])
[server-request] (id:8) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 8 :method "workspace/workspaceFolders")
[client-reply] (id:8) Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :id 8 :result
          [(:uri "file:///tmp/test" :name "/tmp/test/")])
[stderr] Now starting perlcritic with: /opt/PerlNavigator/server/src/perl/criticWrapper.pl --file /tmp/test/test.pl
[stderr] Starting perl compilation check with the equivalent of: /opt/perl5/bin/perl -c -Mwarnings -M-warnings=redefine -I /tmp/test/lib -I /opt/PerlNavigator/server/src/perl -MInquisitor /tmp/test/test.pl
[stderr] Starting to look for perl modules with -I /tmp/test/lib /opt/PerlNavigator/server/src/perl/lib_bs22/ModHunter.pl
[stderr] Starting to look for perl modules with -I /tmp/test/lib /opt/PerlNavigator/server/src/perl/lib_bs22/ModHunter.pl
[stderr] Now starting perlcritic with: /opt/PerlNavigator/server/src/perl/criticWrapper.pl --file /tmp/test/test.pl
[stderr] Starting perl compilation check with the equivalent of: /opt/perl5/bin/perl -c -Mwarnings -M-warnings=redefine -I /tmp/test/lib -I /opt/PerlNavigator/server/src/perl -MInquisitor /tmp/test/test.pl
[stderr] Compilation Time: 0.042 seconds
[server-notification] Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///tmp/test/test.pl" :diagnostics
                []))
[stderr] Compilation Time: 0.06 seconds
[server-notification] Thu Jul 25 16:57:58 2024:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///tmp/test/test.pl" :diagnostics
                []))
[stderr] Success running mod hunter
[stderr] Success running mod hunter
[stderr] Critic output: Perlcritic on /tmp/test/test.pl and using profile /opt/PerlNavigator/server/src/perl/defaultCriticProfile 
[stderr] Perl Critic violations:
[stderr] 
[stderr] Perl Critic Time: 0.515 seconds
[stderr] Critic output: Perlcritic on /tmp/test/test.pl and using profile /opt/PerlNavigator/server/src/perl/defaultCriticProfile 
[stderr] Perl Critic violations:
[stderr] 
[stderr] Perl Critic Time: 0.516 seconds
[server-notification] Thu Jul 25 16:57:59 2024:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///tmp/test/test.pl" :diagnostics
                []))
[server-notification] Thu Jul 25 16:57:59 2024:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///tmp/test/test.pl" :diagnostics
                []))
[stderr] Found settings
[server-request] (id:9) Thu Jul 25 16:57:59 2024:
(:jsonrpc "2.0" :id 9 :method "workspace/workspaceFolders")
[client-reply] (id:9) Thu Jul 25 16:57:59 2024:
(:jsonrpc "2.0" :id 9 :result
          [(:uri "file:///tmp/test" :name "/tmp/test/")])
[stderr] Now starting perlcritic with: /opt/PerlNavigator/server/src/perl/criticWrapper.pl --file /tmp/test/test.pl
[stderr] Starting perl compilation check with the equivalent of: /opt/perl5/bin/perl -c -Mwarnings -M-warnings=redefine -I /tmp/test/lib -I /opt/PerlNavigator/server/src/perl -MInquisitor /tmp/test/test.pl
[stderr] Compilation Time: 0.035 seconds
[server-notification] Thu Jul 25 16:57:59 2024:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///tmp/test/test.pl" :diagnostics
                []))
[stderr] Critic output: Perlcritic on /tmp/test/test.pl and using profile /opt/PerlNavigator/server/src/perl/defaultCriticProfile 
[stderr] Perl Critic violations:
[stderr] 
[stderr] Perl Critic Time: 0.345 seconds
[server-notification] Thu Jul 25 16:58:00 2024:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///tmp/test/test.pl" :diagnostics
                []))
[internal] Thu Jul 25 16:58:01 2024:
(:message "Connection state changed" :change "exited abnormally with code 1\n")

----------b---y---e---b---y---e----------
[stderr] 
[stderr] 
[stderr] nil
[stderr] nil
[stderr] Process EGLOT (test/(cperl-mode perl-mode)) stderr finished

Any pointers on how we might find out why the server exists would be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants