diff --git a/docs/installation.md b/docs/installation.md index 85d62ef..644007c 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 3aa6729..5f7ae36 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 b80b18c..3c8b1e0 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 ad02530..859046b 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 fc1d71f..67247f9 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 0000000..a6987f5 --- /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 8f0217b..6a4a12f 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 03b30c8..63697ba 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 29e3161..826d7c9 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 {