diff --git a/handlers/aliases/commands/aliases-command.go b/handlers/aliases/commands/aliases-command.go new file mode 100644 index 0000000..7ad9475 --- /dev/null +++ b/handlers/aliases/commands/aliases-command.go @@ -0,0 +1,45 @@ +package commands + +import ( + "os/exec" + "strings" +) + +func IsNewAliasesCommandAvailable() bool { + _, err := exec.LookPath("newaliases") + + return err == nil +} + +func IsSendmailCommandAvailable() bool { + _, err := exec.LookPath("sendmail") + + return err == nil +} + +func IsPostfixCommandAvailable() bool { + _, err := exec.LookPath("postfix") + + return err == nil +} + +func CanSendTestMails() bool { + return IsSendmailCommandAvailable() && IsPostfixCommandAvailable() +} + +func UpdateAliasesDatabase() error { + cmd := exec.Command("newaliases") + + err := cmd.Run() + + return err +} + +func SendTestMail(address string, content string) error { + cmd := exec.Command("sendmail", address) + cmd.Stdin = strings.NewReader(content) + + err := cmd.Run() + + return err +} diff --git a/handlers/aliases/commands/aliases-commands_test.go b/handlers/aliases/commands/aliases-commands_test.go new file mode 100644 index 0000000..fee1097 --- /dev/null +++ b/handlers/aliases/commands/aliases-commands_test.go @@ -0,0 +1,11 @@ +package commands + +import "testing" + +func TestAreAliasesCommandsAvailable( + t *testing.T, +) { + if !IsNewAliasesCommandAvailable() { + t.Skip("Aliases tools not available") + } +} diff --git a/handlers/aliases/handlers/code-actions.go b/handlers/aliases/handlers/code-actions.go new file mode 100644 index 0000000..a8eedd4 --- /dev/null +++ b/handlers/aliases/handlers/code-actions.go @@ -0,0 +1,51 @@ +package handlers + +import ( + "config-lsp/handlers/aliases" + "config-lsp/handlers/aliases/commands" + "fmt" + "time" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +type CodeActionName string + +const ( + CodeActionSendTestMail CodeActionName = "sendTestMail" +) + +type CodeAction interface { + RunCommand(*aliases.AliasesDocument) (*protocol.ApplyWorkspaceEditParams, error) +} + +type CodeActionArgs interface{} + +type CodeActionSendTestMailArgs struct { + URI protocol.DocumentUri + User string +} + +func CodeActionSendTestMailArgsFromArguments(arguments map[string]interface{}) CodeActionSendTestMailArgs { + return CodeActionSendTestMailArgs{ + URI: arguments["URI"].(protocol.DocumentUri), + User: arguments["User"].(string), + } +} + +func (args CodeActionSendTestMailArgs) RunCommand(d *aliases.AliasesDocument) (*protocol.ApplyWorkspaceEditParams, error) { + content := fmt.Sprintf( + `Subject: Test mail from %s + +This is a test mail from config-lsp. +It is intended for the user %s. +`, + time.Now().Format(time.RFC1123), + args.User, + ) + + address := fmt.Sprintf("%s@localhost.localdomain", args.User) + commands.SendTestMail(address, content) + + return &protocol.ApplyWorkspaceEditParams{}, nil +} diff --git a/handlers/aliases/handlers/fetch-code-actions.go b/handlers/aliases/handlers/fetch-code-actions.go new file mode 100644 index 0000000..5a76437 --- /dev/null +++ b/handlers/aliases/handlers/fetch-code-actions.go @@ -0,0 +1,59 @@ +package handlers + +import ( + "config-lsp/handlers/aliases" + "config-lsp/handlers/aliases/ast" + "config-lsp/handlers/aliases/commands" + "fmt" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +type disabledExplanation struct { + Reason string +} + +func FetchCodeActions( + d *aliases.AliasesDocument, + params *protocol.CodeActionParams, +) []protocol.CodeAction { + line := params.Range.Start.Line + + rawEntry, found := d.Parser.Aliases.Get(line) + + if !found { + return nil + } + + entry := rawEntry.(*ast.AliasEntry) + + if entry.Key != nil { + address := fmt.Sprintf("%s@localhost.localdomain", entry.Key.Value) + + commandID := "aliases." + CodeActionSendTestMail + command := protocol.Command{ + Title: fmt.Sprintf("Send a test mail to %s", address), + Command: string(commandID), + Arguments: []any{ + CodeActionSendTestMailArgs{ + URI: params.TextDocument.URI, + User: entry.Key.Value, + }, + }, + } + codeAction := &protocol.CodeAction{ + Title: fmt.Sprintf("Send a test mail to %s", address), + Command: &command, + } + + if !commands.CanSendTestMails() { + codeAction.Disabled.Reason = "postfix is required to send test mails" + } + + return []protocol.CodeAction{ + *codeAction, + } + } + + return nil +} diff --git a/handlers/aliases/lsp/text-document-code-action.go b/handlers/aliases/lsp/text-document-code-action.go index 37950bd..ba73911 100644 --- a/handlers/aliases/lsp/text-document-code-action.go +++ b/handlers/aliases/lsp/text-document-code-action.go @@ -1,14 +1,16 @@ package lsp import ( + "config-lsp/handlers/aliases" + "config-lsp/handlers/aliases/handlers" + "github.com/tliron/glsp" protocol "github.com/tliron/glsp/protocol_3_16" ) func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) { - // document := hosts.DocumentParserMap[params.TextDocument.URI] - // - // actions := make([]protocol.CodeAction, 0, 1) + d := aliases.DocumentParserMap[params.TextDocument.URI] + actions := handlers.FetchCodeActions(d, params) - return nil, nil + return actions, nil } diff --git a/handlers/aliases/lsp/workspace-execute-command.go b/handlers/aliases/lsp/workspace-execute-command.go index 41f5298..8cad016 100644 --- a/handlers/aliases/lsp/workspace-execute-command.go +++ b/handlers/aliases/lsp/workspace-execute-command.go @@ -1,21 +1,25 @@ package lsp import ( + "config-lsp/handlers/aliases" + "config-lsp/handlers/aliases/handlers" + "strings" + "github.com/tliron/glsp" protocol "github.com/tliron/glsp/protocol_3_16" ) func WorkspaceExecuteCommand(context *glsp.Context, params *protocol.ExecuteCommandParams) (*protocol.ApplyWorkspaceEditParams, error) { - // _, command, _ := strings.Cut(params.Command, ".") - // - // switch command { - // case string(handlers.CodeActionInlineAliases): - // args := handlers.CodeActionInlineAliasesArgsFromArguments(params.Arguments[0].(map[string]any)) - // - // document := hosts.DocumentParserMap[args.URI] - // - // return args.RunCommand(*document.Parser) - // } + _, command, _ := strings.Cut(params.Command, ".") + + switch command { + case string(handlers.CodeActionSendTestMail): + args := handlers.CodeActionSendTestMailArgsFromArguments(params.Arguments[0].(map[string]any)) + + d := aliases.DocumentParserMap[args.URI] + + return args.RunCommand(d) + } return nil, nil }