Skip to content

Commit

Permalink
(GH-327) Format on save code action
Browse files Browse the repository at this point in the history
This adds a code action to format a file based on the `editor.codeActionsOnSave` setting. This can either be a global setting or one specific to the terraform language.
  • Loading branch information
jpogran committed Aug 19, 2021
1 parent 0059475 commit 25d7038
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 2 deletions.
78 changes: 78 additions & 0 deletions internal/langserver/handlers/code_action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package handlers

import (
"context"
"fmt"

lsp "github.com/hashicorp/terraform-ls/internal/protocol"
)

func (h *logHandler) TextDocumentCodeAction(ctx context.Context, params lsp.CodeActionParams) ([]lsp.CodeAction, error) {
var ca []lsp.CodeAction
var wanted map[lsp.CodeActionKind]bool

// TODO: get this from initialize
supported := map[lsp.CodeActionKind]bool{
`source`: true,
`source.fixAll`: true,
`source.formatAll`: true,
`source.formatAll.terraform-ls`: true,
}

// return early if we don't support any code actions
if len(supported) == 0 {
return nil, nil
}

// if Only is empty, assume that the client wants all code actions
// else build mapping of requested and determine if supported
if len(params.Context.Only) == 0 {
wanted = supported
} else {
wanted = make(map[lsp.CodeActionKind]bool)
for _, only := range params.Context.Only {
wanted[only] = supported[only]
}
}

if len(wanted) == 0 {
return nil, fmt.Errorf("could not find a supported code action to execute for %s, wanted %v",
params.TextDocument.URI, params.Context.Only)
}

for action, _ := range wanted {
switch action {
case lsp.Source, lsp.SourceFixAll, `source.formatAll`, `source.formatAll.terraform-ls`:
c, err := terraformFmt(ctx, h, params.TextDocument.URI)
if err != nil {
continue
}
ca = append(ca, c)
}
}

return ca, nil
}

func terraformFmt(ctx context.Context, h *logHandler, uri lsp.DocumentURI) (lsp.CodeAction, error) {
var ca lsp.CodeAction

edits, err := formatDocument(ctx, h, uri)
if err != nil {
return ca, err
}

we := lsp.WorkspaceEdit{
Changes: map[string][]lsp.TextEdit{
string(uri): edits,
},
}

x := lsp.CodeAction{
Title: "Format Document",
Kind: lsp.SourceFixAll,
IsPreferred: false,
Edit: we,
}
return x, nil
}
17 changes: 15 additions & 2 deletions internal/langserver/handlers/formatting.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,23 @@ import (
func (h *logHandler) TextDocumentFormatting(ctx context.Context, params lsp.DocumentFormattingParams) ([]lsp.TextEdit, error) {
var edits []lsp.TextEdit

edits, err := formatDocument(ctx, h, params.TextDocument.URI)
if err != nil {
return edits, err
}

return edits, nil
}

func formatDocument(ctx context.Context, h *logHandler, uri lsp.DocumentURI) ([]lsp.TextEdit, error) {
var edits []lsp.TextEdit

fs, err := lsctx.DocumentStorage(ctx)
if err != nil {
return edits, err
}

fh := ilsp.FileHandlerFromDocumentURI(params.TextDocument.URI)
fh := ilsp.FileHandlerFromDocumentURI(uri)

tfExec, err := module.TerraformExecutorForModule(ctx, fh.Dir())
if err != nil {
Expand All @@ -45,5 +56,7 @@ func (h *logHandler) TextDocumentFormatting(ctx context.Context, params lsp.Docu

changes := hcl.Diff(file, original, formatted)

return ilsp.TextEditsFromDocumentChanges(changes), nil
edits = ilsp.TextEditsFromDocumentChanges(changes)

return edits, nil
}
3 changes: 3 additions & 0 deletions internal/langserver/handlers/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ func initializeResponse(t *testing.T, commandPrefix string) string {
"definitionProvider": true,
"referencesProvider": true,
"documentSymbolProvider": true,
"codeActionProvider": {
"codeActionKinds": ["source", "source.fixAll", "source.formatAll", "source.formatAll.terraform-ls"]
},
"codeLensProvider": {},
"documentLinkProvider": {},
"workspaceSymbolProvider": true,
Expand Down
9 changes: 9 additions & 0 deletions internal/langserver/handlers/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ func (svc *service) Initialize(ctx context.Context, params lsp.InitializeParams)
ResolveProvider: false,
TriggerCharacters: []string{".", "["},
},
CodeActionProvider: lsp.CodeActionOptions{
CodeActionKinds: []lsp.CodeActionKind{
lsp.Source, // "source"
lsp.SourceFixAll, // "source.fixAll"
"source.formatAll",
"source.formatAll.terraform-ls",
},
ResolveProvider: false,
},
DeclarationProvider: lsp.DeclarationOptions{},
DefinitionProvider: true,
CodeLensProvider: lsp.CodeLensOptions{},
Expand Down
13 changes: 13 additions & 0 deletions internal/langserver/handlers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,19 @@ func (svc *service) Assigner() (jrpc2.Assigner, error) {

return handle(ctx, req, lh.TextDocumentHover)
},
"textDocument/codeAction": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := session.CheckInitializationIsConfirmed()
if err != nil {
return nil, err
}

ctx = lsctx.WithClientCapabilities(ctx, cc)
ctx = lsctx.WithDocumentStorage(ctx, svc.fs)
ctx = exec.WithExecutorOpts(ctx, svc.tfExecOpts)
ctx = exec.WithExecutorFactory(ctx, svc.tfExecFactory)

return handle(ctx, req, lh.TextDocumentCodeAction)
},
"textDocument/codeLens": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := session.CheckInitializationIsConfirmed()
if err != nil {
Expand Down

0 comments on commit 25d7038

Please sign in to comment.