Skip to content

fix/modify types for clangd #28

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

Merged
merged 3 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ This is beta software. Please let me know by creating an issue if you run into a

## Contributing

Please keep PRs small and open Issues first for anything substantial. AI slop OK as long as it is tested, passes checks, and doesn't smell too bad.
Please keep PRs small and open Issues first for anything substantial. AI slop O.K. as long as it is tested, passes checks, and doesn't smell too bad.

### Setup

Expand Down
22 changes: 21 additions & 1 deletion cmd/generate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,35 @@ Types have been modified to always be union types. A method generator has also b
## Use

From the root of the repo, run

```bash
go run ./cmd/generate_protocol
```

This will generate LSP message types in `internal/protocol`

## Key Differences from gopls

The main difference from the gopls implementation is in the handling of union types. While gopls simplifies some union types to single types for backward compatibility and easy operability with gopls, this implementation preserves the full union types as specified in the LSP spec.

### Custom Field Additions

The generator supports adding custom fields to generated types through the `additionalFields` map in `tables.go`. This allows extending LSP types with non-standard fields needed for specific language servers.

e.g.

```go
// additionalFields defines extra fields to add to specific types during generation
// The key is the Go struct name (after applying goName), the value is a slice of field definitions
var additionalFields = map[string][]string{
"BaseSymbolInformation": {
"Score float64 `json:\"score,omitempty\"` // Added for clangd compatibility",
},
}
```

This adds a `Score` field to the `BaseSymbolInformation` type, necessary for `clangd`.

## Attribution

This folder, and the code generated by the generate command is based on code from the Go tools repository, specifically the gopls language server. It has been modified to prioritize LSP specification compliance over backward compatibility.
Expand All @@ -38,7 +58,7 @@ exact version can be tied to a githash. By default, the command will download th

The specification has five sections

1. Requests, which describe the Request and Response types for request methods (e.g., *textDocument/didChange*),
1. Requests, which describe the Request and Response types for request methods (e.g., _textDocument/didChange_),
2. Notifications, which describe the Request types for notification methods,
3. Structures, which describe named struct-like types,
4. TypeAliases, which describe type aliases,
Expand Down
2 changes: 1 addition & 1 deletion cmd/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func propStar(name string, t NameType, gotype string) (string, string) {
star = "" // passed by reference, so no need for *
} else {
switch gotype {
case "bool", "uint32", "int32", "string", "interface{}":
case "bool", "uint32", "int32", "string", "interface{}", "any":
star = "" // gopls compatibility if t.Optional
}
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/generate/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func generateMethodForRequest(out *bytes.Buffer, r *Request) {
}
if notNil(r.Result) {
resultType = goplsName(r.Result)
if resultType == "interface{}" || resultType == "string" {
if resultType == "interface{}" || resultType == "string" || resultType == "any" {
} else if strings.HasPrefix(resultType, "*") {
resultType = "*protocol." + resultType[1:]
} else if strings.HasPrefix(resultType, "[]") {
Expand Down
12 changes: 10 additions & 2 deletions cmd/generate/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,21 @@ func genStructs(model *Model) {
for _, ex := range s.Mixins {
fmt.Fprintf(out, "\t%s\n", goName(ex.Name))
}

// Add any additional fields defined in additionalFields map
if additionalFields, ok := additionalFields[nm]; ok {
for _, field := range additionalFields {
fmt.Fprintf(out, "\t%s\n", field)
}
}

out.WriteString("}\n")
types[nm] = out.String()
}

// base types
// (For URI and DocumentUri, see ../uri.go.)
types["LSPAny"] = "type LSPAny = interface{}\n"
types["LSPAny"] = "type LSPAny = any\n"
// A special case, the only previously existing Or type
types["DocumentDiagnosticReport"] = "type DocumentDiagnosticReport = Or_DocumentDiagnosticReport // (alias) \n"

Expand Down Expand Up @@ -320,7 +328,7 @@ func genGenTypes() {
sort.Strings(names)
fmt.Fprintf(out, "// created for Or %v\n", names)
fmt.Fprintf(out, "type %s struct {%s\n", nm, linex(nt.line+1))
fmt.Fprintf(out, "\tValue interface{} `json:\"value\"`\n")
fmt.Fprintf(out, "\tValue any `json:\"value\"`\n")

case "and":
fmt.Fprintf(out, "// created for And\n")
Expand Down
12 changes: 10 additions & 2 deletions cmd/generate/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,21 @@ var disambiguate = map[string]adjust{
// which entries of disambiguate got used
var usedDisambiguate = make(map[string]bool)

// additionalFields defines extra fields to add to specific types during generation
// The key is the Go struct name (after applying goName), the value is a slice of field definitions
var additionalFields = map[string][]string{
"BaseSymbolInformation": {
"Score float64 `json:\"score,omitempty\"` // added for clangd compatibility",
},
}

// For spec compliance, we keep only essential type mappings that don't override OR types
var goplsType = map[string]string{
"ConfigurationParams": "ParamConfiguration",
// "DocumentUri": "DocumentUri",
"InitializeParams": "ParamInitialize",
"LSPAny": "interface{}",
"[]LSPAny": "[]interface{}",
"LSPAny": "any",
"[]LSPAny": "[]any",
"[]uinteger": "[]uint32",
"boolean": "bool",
"decimal": "float64",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No hover information available for this position on the following line:
Loading
Loading