You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "ASF GitHub Bot (Jira)" <ji...@apache.org> on 2026/10/07 08:22:00 UTC

[jira] [Commented] (GROOVY-12411) Add a first-party Language Server Protocol implementation (groovy-lsp)

    [ https://issues.apache.org/jira/browse/GROOVY-12411?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18124350#comment-18124350 ] 

ASF GitHub Bot commented on GROOVY-12411:
-----------------------------------------

sonarqubecloud[bot] commented on PR #2936:
URL: https://github.com/apache/groovy/pull/2936#issuecomment-6033961009

   ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=apache_groovy&pullRequest=2936) **Quality Gate failed**  
   Failed conditions  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [C Reliability Rating on New Code](https://sonarcloud.io/project/issues?id=apache_groovy&pullRequest=2936&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true) (required ≥ A)  
     
   <!

> Add a first-party Language Server Protocol implementation (groovy-lsp)
> ----------------------------------------------------------------------
>
>                 Key: GROOVY-12411
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12411
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Daniel Sun
>            Priority: Major
>
> Apache Groovy needs a language server that uses the compiler in this repository. Community servers compile against a published Groovy jar, so parser and type-system changes reach an editor only after that jar is released. This change adds an optional {{groovy-lsp}} module and a {{groovylsp}} command. Editors, and later AI tools, share that language core. It is not a full IDE, and it does not replace Groovy-Eclipse or IntelliJ.
> h2. Why this shape
> The server compiles the open buffers and answers Language Server Protocol (LSP) requests from that snapshot. A language change in this tree shows up in the server without forking a community project. The server refuses edits that would guess: it will not rename an unbound dynamic call, and it will not rewrite every token that happens to spell the same name.
> There is no public extension SPI in this first cut. No ServiceLoader hook, no OSGi bundle, and no second hover or completion API. Static type checking of annotated members is core behavior, not a plugin. A later {{groovy-mcp}} wrapper may call the in-process engine. That wrapper is not part of this change.
> h2. What lands
> * Optional subproject {{groovy-lsp}}. It is not part of {{groovy-all}}.
> * {{groovylsp}} and {{groovylsp.bat}} on the binary distribution. The default transport is stdio. {{\-\-socket}} accepts one TCP client. {{\-\-help}} and {{\-\-version}} print and exit.
> * LSP 3.18, carried by Eclipse LSP4J 1.0. Fields from a newer draft that the server does not understand are ignored. A capability is advertised only when it is implemented.
> * LSP4J is an EPL 2.0 Category B binary. Its sources are not copied into Groovy.
> * Open Groovy buffers compile through semantic analysis. The server does not generate Groovy classes.
> * {{.java}} files in the workspace are joint-compiled with {{JavaAwareCompilationUnit}} ({{memStub}}) and {{javax.tools}} javac, with annotation processing off.
> * After semantic analysis, a core pass type-checks members annotated {{@TypeChecked}} or {{@CompileStatic}}. It skips {{@CompileDynamic}} and {{TypeCheckingMode.SKIP}}, and it does not force static checking on ordinary dynamic Groovy.
> * {{GroovyLanguageEngine}} is the in-process API: file paths, 0-based UTF-16 positions, and short source snippets. Rename returns edits and does not write the files.
> * {{LocatedMessage.toDiagnostic()}} and {{write()}} no longer throw {{NullPointerException}} when the parse context is null. They report the message with no line or column.
> * {{ASTNode}} column javadoc now matches the compiler: columns are 1-based Unicode code points, the end column is exclusive, and a missing position is -1. Getters, setters, and stored values are unchanged. See GROOVY-12085.
> * User guide {{groovy-lsp.adoc}} and contributor map {{subprojects/groovy-lsp/ARCHITECTURE.md}}.
> h2. What an editor gets
> Recognized sources are {{.groovy}}, {{.gvy}}, {{.gy}}, {{.gsh}}, or language id {{groovy}}.
> * *Editing:* incremental sync; completion of keywords, snippets, members, workspace types (with an import edit), and GDK members; Groovydoc filled in when the client resolves a completion item; format, range format, and on-type indent; organize imports, keeping star, static, and alias imports; unused-import hints; code actions to add an import, add a package from the path, implement abstract methods, insert an inferred type, create a missing class stub, add {{@Override}}, and generate accessors, {{toString}}, {{equals}} and {{hashCode}}, and a constructor.
> * *Navigation:* definition, type definition, implementation, declaration, and references. References match the declaration (owner, name, and descriptor), not the bare spelling. Call hierarchy and type hierarchy. Document symbols and workspace symbols. A workspace-symbol query may be a case-insensitive substring or CamelHumps, so {{ASF}} finds {{AbstractServerFactory}}. Folding, selection ranges, document highlight, and document links on imports.
> * *Presentation:* push and pull diagnostics (compiler messages, unused imports, static-type errors on annotated members, and javac messages from a joint compile). Semantic tokens. Inlay hints for declaration types and for parameter names. Code lenses that show a reference count.
> * *Workspace:* workspace folders, watched files, configuration, and progress when the client asks for it. {{workspace/willRenameFiles}} updates one top-level Groovy class whose name matches the file name without its extension. It refuses a script, a file that declares several types, a class name that does not match, and {{.java}}.
> Commands:
> * {{groovy.lsp.organizeImports}}
> * {{groovy.lsp.showReferences}}
> * {{groovy.lsp.gotoSuperMethod}} (nearest overridden method that has source; skips {{Object}} and {{GroovyObject}})
> h2. Rename
> {{methodTarget}} is often empty on a dynamic call. A match by name and arity is enough to display, and not enough to edit.
> ||Feature||When the compiler bound the call||When it did not||
> |Hover|The bound signature|One arity match on a resolved receiver, marked {{_inferred_}}; otherwise the name only|
> |Definition|That method|Every arity match that has source. Never an arbitrary first hit|
> |Rename and prepare-rename|Allowed|Refused|
> A class, method, field, parameter, or bound local is renamed by identity. Renaming a class also renames the file when the class name matches the file name without its extension. An inlay marked {{inferred}} is display only. It does not insert text.
> h2. Groovy and Java in one workspace
> Joint compilation lets Groovy and Java sources in the workspace see each other's types. Go to definition crosses the language boundary through {{JavaSymbolIndex}}, and javac diagnostics are published the same way. javac class files go to a temporary directory and are removed on the next compile. This is not a Java language server. Java completion, Java formatting, and Java-only rename stay with a Java language server. Eclipse JDT and groovy-eclipse remain the stack for a full Java IDE. No source is copied from the EPL server groovy-language-server-edt, and its identifier-scan rename is not adopted.
> ||Question||groovy-lsp||Other Groovy language servers||
> |Which compiler|The compiler in this repository|A published Groovy jar, or JDT plus groovy-eclipse|
> |Java IDE features|Joint type resolution and cross-language definition|Java completion, formatting, and Java-only rename|
> |GDSL and dependency download|Not included|groovyls adds Jenkins GDSL and dependency download|
> |Unbound-call rename|Refused|An identifier-scan fallback exists in groovy-language-server-edt|
> h2. Configuration and safety
> On {{initialized}}, if the client advertised {{workspace/configuration}}, the server asks for the {{groovy}} section without blocking the JSON-RPC reader. The client can also push {{workspace/didChangeConfiguration}}.
> ||Key||Meaning||
> |classpath|Extra jars and directories. The server does not run Gradle or Maven|
> |sourcePaths|Extra source roots, relative to a workspace folder when not absolute|
> |grapeEnabled|Allow {{@Grab}} while compiling. Default is off|
> |astTestEnabled|Allow {{@ASTTest}} while compiling. Default is off|
> Any other key in the {{groovy}} section is stored as text. The server does not interpret it and does not download anything for it. Changing it builds a new class loader and recompiles.
> When classpath and source paths are empty, the server looks for {{src/main/groovy}}, {{src/test/groovy}}, {{src/main/java}}, and {{src/test/java}}, then {{src}}, then the workspace folder itself, plus jars directly under {{lib}} or {{libs}}.
> Diagnostics are limited to the file that owns them. Unchanged buffers are not compiled again. {{@Grab}} and {{@ASTTest}} stay off unless the client turns them on, because both can run code at compile time.
> h2. Out of scope
> * A full Java language server.
> * GDSL and Jenkins pipeline descriptors.
> * Invoking Gradle or Maven, including the Tooling API.
> * A debugger or a test runner.
> * Renaming by identifier text.
> * Name-span fields on {{AnnotatedNode}}. Identifier ranges stay inside groovy-lsp.
> * A public plugin SPI.
> h2. Positions
> This is not an LSP break. Compiler columns are already 1-based Unicode code points (GROOVY-12085). LSP positions stay 0-based in the encoding chosen at initialize: {{utf-16}} unless the client offers {{utf-8}} or {{utf-32}}. The server converts both ways, including characters outside the Basic Multilingual Plane. Existing clients keep sending positions as they do today.
> h2. Running
> {code}
> groovylsp
> groovylsp --stdio
> groovylsp --socket PORT
> groovylsp --help
> groovylsp --version
> {code}
> An editor should start that process and speak JSON-RPC on stdin and stdout. While the server is on stdio, standard output is redirected to standard error so a print from Groovy code cannot corrupt the protocol stream.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)