From a0a34482ac558429d62256e32a7572482edfbcc2 Mon Sep 17 00:00:00 2001 From: Art Moskvin Date: Thu, 9 Oct 2025 14:45:43 +0200 Subject: [PATCH] Add Java language server support --- docs/installation.md | 6 +++ docs/quickstart.md | 2 +- openapi.yaml | 2 +- pkg/lsp/service.go | 1 + pkg/lsp/utils.go | 1 + pkg/lsp/v2/languages/java_lsp.go | 66 +++++++++++++++++++++++++++++++ pkg/lsp/v2/languages/languages.go | 3 +- pkg/project/manager.go | 2 +- pkg/project/v2/manager.go | 2 +- 9 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 pkg/lsp/v2/languages/java_lsp.go diff --git a/docs/installation.md b/docs/installation.md index 85d62efd..644007c5 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -71,6 +71,12 @@ To build Hide from source, follow these steps: npm install -g typescript-language-server ``` + For Java, install the [Eclipse JDT Language Server](https://projects.eclipse.org/projects/eclipse.jdt.ls). Ensure the `jdtls` binary is available on your `PATH`. For example, using Homebrew: + + ```bash + brew install jdtls + ``` + For Go, install the `gopls` package: ```bash diff --git a/docs/quickstart.md b/docs/quickstart.md index 3aa67291..5f7ae36a 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -203,7 +203,7 @@ print(file) #129 | ) ``` -It turns out there was a typo in my patch but Hide noticed it and highlighted the line with the error. Like a normal IDE, Hide runs continuous diagnostics on the code using LSP servers and highlights errors. Currently, Hide provides diagnostics for Python, JavaScript, TypeScript, and Go, and we can add more languages if needed. Let us know in the GitHub Issues if you need support for other languages. +It turns out there was a typo in my patch but Hide noticed it and highlighted the line with the error. Like a normal IDE, Hide runs continuous diagnostics on the code using LSP servers and highlights errors. Currently, Hide provides diagnostics for Python, Java, JavaScript, TypeScript, and Go, and we can add more languages if needed. Let us know in the GitHub Issues if you need support for other languages. !!! note diff --git a/openapi.yaml b/openapi.yaml index b80b18cf..3c8b1e08 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -412,7 +412,7 @@ components: type: array items: type: string - enum: [Go, JavaScript, Python, TypeScript] + enum: [Go, Java, JavaScript, Python, TypeScript] devcontainer: $ref: '#/components/schemas/DevContainerConfig' diff --git a/pkg/lsp/service.go b/pkg/lsp/service.go index ad025308..859046bb 100644 --- a/pkg/lsp/service.go +++ b/pkg/lsp/service.go @@ -22,6 +22,7 @@ type ( var LspServerExecutables = map[LanguageId]Command{ Go: NewCommand("gopls", []string{}), + Java: NewCommand("jdtls", []string{}), Python: NewCommand("pyright-langserver", []string{"--stdio"}), JavaScript: NewCommand("typescript-language-server", []string{"--stdio"}), TypeScript: NewCommand("typescript-language-server", []string{"--stdio"}), diff --git a/pkg/lsp/utils.go b/pkg/lsp/utils.go index fc1d71f9..67247f93 100644 --- a/pkg/lsp/utils.go +++ b/pkg/lsp/utils.go @@ -12,6 +12,7 @@ import ( // For reference see https://github.com/go-enry/go-enry/blob/master/data/languageInfo.go const ( Go = LanguageId("Go") + Java = LanguageId("Java") JavaScript = LanguageId("JavaScript") Python = LanguageId("Python") TypeScript = LanguageId("TypeScript") diff --git a/pkg/lsp/v2/languages/java_lsp.go b/pkg/lsp/v2/languages/java_lsp.go new file mode 100644 index 00000000..a6987f52 --- /dev/null +++ b/pkg/lsp/v2/languages/java_lsp.go @@ -0,0 +1,66 @@ +package lang + +import ( + "context" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +var _ Adapter = (*jdtls)(nil) + +type jdtls struct{} + +type jdtlsVersion struct { + Version string `json:"version"` +} + +func (a *jdtls) Name() ServerName { + return "jdtls" +} + +func (a *jdtls) FetchLatestServerVersion(ctx context.Context, delegate Delegate) (interface{}, error) { + // jdtls does not expose a simple version endpoint. We rely on the binary + // being present on PATH and treat it as "latest". + return jdtlsVersion{Version: "latest"}, nil +} + +func (a *jdtls) FetchServerBinary(ctx context.Context, version interface{}, delegate Delegate) (*Binary, error) { + path, err := exec.LookPath("jdtls") + if err != nil { + return nil, fmt.Errorf("jdtls language server not found in PATH: %w", err) + } + + dataDir := filepath.Join(delegate.ProjectRootPath(), ".jdtls") + if err := os.MkdirAll(dataDir, 0o755); err != nil { + return nil, fmt.Errorf("failed to create jdtls data directory: %w", err) + } + + return &Binary{ + Name: a.Name(), + Path: path, + Arguments: []string{ + "-data", dataDir, + }, + }, nil +} + +func (a *jdtls) InitializationOptions(ctx context.Context, delegate Delegate) json.RawMessage { + return nil +} + +func (a *jdtls) WorkspaceConfiguration(ctx context.Context, delegate Delegate) (json.RawMessage, error) { + return nil, nil +} + +func (a *jdtls) CodeActions() ([]protocol.CodeActionKind, error) { + return nil, nil +} + +func (a *jdtls) Languages() []LanguageID { + return []LanguageID{Java} +} diff --git a/pkg/lsp/v2/languages/languages.go b/pkg/lsp/v2/languages/languages.go index 8f0217be..6a4a12f2 100644 --- a/pkg/lsp/v2/languages/languages.go +++ b/pkg/lsp/v2/languages/languages.go @@ -6,6 +6,7 @@ type LanguageID = string // For reference see https://github.com/go-enry/go-enry/blob/master/data/languageInfo.go const ( Go LanguageID = "Go" + Java LanguageID = "Java" JavaScript LanguageID = "JavaScript" Python LanguageID = "Python" TypeScript LanguageID = "TypeScript" @@ -15,5 +16,5 @@ const ( ) var Adapters = []Adapter{ - new(gopls), new(tsserver), + new(gopls), new(tsserver), new(jdtls), } diff --git a/pkg/project/manager.go b/pkg/project/manager.go index 03b30c8a..63697ba5 100644 --- a/pkg/project/manager.go +++ b/pkg/project/manager.go @@ -28,7 +28,7 @@ const MaxDiagnosticsDelay = time.Second * 1 type CreateProjectRequest struct { Repository model.Repository `json:"repository" validate:"required"` DevContainer *devcontainer.Config `json:"devcontainer,omitempty"` - Languages []lsp.LanguageId `json:"languages,omitempty" validate:"dive,oneof=Go JavaScript Python TypeScript"` + Languages []lsp.LanguageId `json:"languages,omitempty" validate:"dive,oneof=Go Java JavaScript Python TypeScript"` } type TaskResult struct { diff --git a/pkg/project/v2/manager.go b/pkg/project/v2/manager.go index 29e3161d..826d7c94 100644 --- a/pkg/project/v2/manager.go +++ b/pkg/project/v2/manager.go @@ -25,7 +25,7 @@ type Repository struct { type CreateProjectRequest struct { Repository Repository `json:"repository" validate:"required"` DevContainer *devcontainer.Config `json:"devcontainer,omitempty"` - Languages []lang.LanguageID `json:"languages,omitempty" validate:"dive,oneof=Go JavaScript Python TypeScript"` + Languages []lang.LanguageID `json:"languages,omitempty" validate:"dive,oneof=Go Java JavaScript Python TypeScript"` } type Manager interface {