From 15ce5958dad5b02c3e1b32ff68fa10362c5d822a Mon Sep 17 00:00:00 2001 From: Myzel394 Date: Mon, 17 Mar 2025 22:10:29 +0100 Subject: [PATCH] feat(wireguard): Add code action: Create peer like this --- .../handlers/wireguard/analyzer/property.go | 26 ++- server/handlers/wireguard/ast/wireguard.go | 2 +- .../wireguard/ast/wireguard_fields.go | 23 +-- .../wireguard/handlers/code-actions.go | 105 +--------- .../handlers/code-actions_create-peer.go | 191 ++++++++++++++++++ .../handlers/code-actions_create-peer_test.go | 42 ++++ .../code-actions_generate-private-key.go | 59 ++++++ .../code-actions_generate-shared-key.go | 50 +++++ .../fetch-code-actions_create-peer.go | 42 ++++ .../handlers/fetch-code-actions_keepalive.go | 59 ++++++ ...o => fetch-code-actions_key-generation.go} | 49 ----- .../lsp/text-document-code-action.go | 1 + .../lsp/workspace-execute-command.go | 6 + 13 files changed, 474 insertions(+), 181 deletions(-) create mode 100644 server/handlers/wireguard/handlers/code-actions_create-peer.go create mode 100644 server/handlers/wireguard/handlers/code-actions_create-peer_test.go create mode 100644 server/handlers/wireguard/handlers/code-actions_generate-private-key.go create mode 100644 server/handlers/wireguard/handlers/code-actions_generate-shared-key.go create mode 100644 server/handlers/wireguard/handlers/fetch-code-actions_create-peer.go create mode 100644 server/handlers/wireguard/handlers/fetch-code-actions_keepalive.go rename server/handlers/wireguard/handlers/{fetch-code-actions.go => fetch-code-actions_key-generation.go} (54%) diff --git a/server/handlers/wireguard/analyzer/property.go b/server/handlers/wireguard/analyzer/property.go index 6fc8e48..89c33b2 100644 --- a/server/handlers/wireguard/analyzer/property.go +++ b/server/handlers/wireguard/analyzer/property.go @@ -22,7 +22,7 @@ func analyzeDNSPropertyContainsFallback( interfaceSection := sections[0] - property := interfaceSection.FindFirstPropertyByName("DNS") + _, property := interfaceSection.FindFirstPropertyByName("DNS") if property == nil { return @@ -44,7 +44,10 @@ func analyzeKeepAlivePropertyIsSet( ) { for _, section := range ctx.document.Indexes.SectionsByName["Peer"] { // If an endpoint is set, then we should only check for the keepalive property - if section.FindFirstPropertyByName("Endpoint") != nil && section.FindFirstPropertyByName("PersistentKeepalive") == nil { + _, endpoint := section.FindFirstPropertyByName("Endpoint") + _, persistentKeepAlive := section.FindFirstPropertyByName("PersistentKeepalive") + + if endpoint != nil && persistentKeepAlive == nil { ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{ Message: "PersistentKeepalive is not set. It is recommended to set this property, as it helps to maintain the connection when users are behind NAT", Severity: &common.SeverityHint, @@ -58,11 +61,11 @@ func analyzeSymmetricPropertiesSet( ctx *analyzerContext, ) { for _, section := range ctx.document.Indexes.SectionsByName["Interface"] { - preUpProperty := section.FindFirstPropertyByName("PreUp") - preDownProperty := section.FindFirstPropertyByName("PreDown") + _, preUpProperty := section.FindFirstPropertyByName("PreUp") + _, preDownProperty := section.FindFirstPropertyByName("PreDown") - postUpProperty := section.FindFirstPropertyByName("PostUp") - postDownProperty := section.FindFirstPropertyByName("PostDown") + _, postUpProperty := section.FindFirstPropertyByName("PostUp") + _, postDownProperty := section.FindFirstPropertyByName("PostDown") if preUpProperty != nil && preDownProperty == nil { ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{ @@ -94,7 +97,7 @@ func analyzeSymmetricPropertiesSet( } } -type key int +type key uint8 const ( lineKey key = iota @@ -109,7 +112,7 @@ func analyzeDuplicateAllowedIPs( ipHostSet := utils.CreateIPv4HostSet() for _, section := range ctx.document.Indexes.SectionsByName["Peer"] { - property := section.FindFirstPropertyByName("AllowedIPs") + _, property := section.FindFirstPropertyByName("AllowedIPs") if property == nil { continue @@ -123,12 +126,15 @@ func analyzeDuplicateAllowedIPs( } if ipContext, _ := ipHostSet.ContainsIP(ipAddress); ipContext != nil { - definedLine := (*ipContext).Value(lineKey).(uint32) + ctxx := *ipContext + definedLineRaw := ctxx.Value(lineKey) + + definedLine := definedLineRaw.(uint32) ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{ Message: fmt.Sprintf("This IP range is already covered on line %d", definedLine+1), Severity: &common.SeverityError, - Range: property.ToLSPRange(), + Range: property.Value.ToLSPRange(), }) } else { ipContext := context.WithValue( diff --git a/server/handlers/wireguard/ast/wireguard.go b/server/handlers/wireguard/ast/wireguard.go index 5c3d520..93f19b4 100644 --- a/server/handlers/wireguard/ast/wireguard.go +++ b/server/handlers/wireguard/ast/wireguard.go @@ -35,7 +35,7 @@ type WGHeader struct { type WGSection struct { common.LocationRange Header WGHeader - // [uint32]WGProperty: line number -> WGProperty + // [uint32]*WGProperty: line number -> *WGProperty Properties *treemap.Map } diff --git a/server/handlers/wireguard/ast/wireguard_fields.go b/server/handlers/wireguard/ast/wireguard_fields.go index 5135153..5a35a39 100644 --- a/server/handlers/wireguard/ast/wireguard_fields.go +++ b/server/handlers/wireguard/ast/wireguard_fields.go @@ -10,11 +10,11 @@ func (c *WGConfig) FindSectionByLine(line uint32) *WGSection { line, func(current *WGSection, target uint32) int { if target < current.Start.Line { - return -1 + return 1 } if target > current.End.Line { - return 1 + return -1 } return 0 @@ -42,28 +42,17 @@ func (c *WGConfig) FindPropertyByLine(line uint32) *WGProperty { return nil } -func (s *WGSection) FindFirstPropertyByName(name string) *WGProperty { +func (s *WGSection) FindFirstPropertyByName(name string) (uint32, *WGProperty) { it := s.Properties.Iterator() for it.Next() { + line := it.Key().(uint32) property := it.Value().(*WGProperty) if property.Key.Name == name { - return property + return line, property } } - return nil -} - -func (s *WGSection) FindPropertyByName(name string) *WGProperty { - it := s.Properties.Iterator() - for it.Next() { - property := it.Value().(*WGProperty) - if property.Key.Name == name { - return property - } - } - - return nil + return 0, nil } func (s *WGSection) GetLastProperty() *WGProperty { diff --git a/server/handlers/wireguard/handlers/code-actions.go b/server/handlers/wireguard/handlers/code-actions.go index 566890b..3f6f16e 100644 --- a/server/handlers/wireguard/handlers/code-actions.go +++ b/server/handlers/wireguard/handlers/code-actions.go @@ -1,9 +1,7 @@ package handlers import ( - "config-lsp/handlers/wireguard" "config-lsp/handlers/wireguard/ast" - wgcommands "config-lsp/handlers/wireguard/commands" protocol "github.com/tliron/glsp/protocol_3_16" ) @@ -13,6 +11,7 @@ type CodeActionName string const ( CodeActionGeneratePrivateKey CodeActionName = "generatePrivateKey" CodeActionGeneratePresharedKey CodeActionName = "generatePresharedKey" + CodeActionCreatePeer CodeActionName = "createPeer" ) type CodeAction interface { @@ -20,105 +19,3 @@ type CodeAction interface { } type CodeActionArgs interface{} - -type CodeActionGeneratePrivateKeyArgs struct { - URI protocol.DocumentUri - Line uint32 -} - -func CodeActionGeneratePrivateKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePrivateKeyArgs { - return CodeActionGeneratePrivateKeyArgs{ - URI: arguments["URI"].(protocol.DocumentUri), - Line: uint32(arguments["Line"].(float64)), - } -} - -func (args CodeActionGeneratePrivateKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) { - privateKey, err := wgcommands.CreateNewPrivateKey() - - if err != nil { - return &protocol.ApplyWorkspaceEditParams{}, err - } - - section := d.Config.FindSectionByLine(args.Line) - property := d.Config.FindPropertyByLine(args.Line) - - if section == nil || property == nil { - return nil, nil - } - - label := "Generate Private Key" - return &protocol.ApplyWorkspaceEditParams{ - Label: &label, - Edit: protocol.WorkspaceEdit{ - Changes: map[protocol.DocumentUri][]protocol.TextEdit{ - args.URI: { - { - NewText: " " + privateKey, - Range: protocol.Range{ - Start: protocol.Position{ - Line: property.End.Line, - Character: property.End.Character, - }, - End: protocol.Position{ - Line: property.End.Line, - Character: property.End.Character, - }, - }, - }, - }, - }, - }, - }, nil -} - -type CodeActionGeneratePresharedKeyArgs struct { - URI protocol.DocumentUri - Line uint32 -} - -func CodeActionGeneratePresharedKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePresharedKeyArgs { - return CodeActionGeneratePresharedKeyArgs{ - URI: arguments["URI"].(protocol.DocumentUri), - Line: uint32(arguments["Line"].(float64)), - } -} - -func (args CodeActionGeneratePresharedKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) { - presharedKey, err := wgcommands.CreatePresharedKey() - - if err != nil { - return &protocol.ApplyWorkspaceEditParams{}, err - } - - section := d.Config.FindSectionByLine(args.Line) - property := d.Config.FindPropertyByLine(args.Line) - - if section == nil || property == nil { - return nil, nil - } - - label := "Generate Preshared Key" - return &protocol.ApplyWorkspaceEditParams{ - Label: &label, - Edit: protocol.WorkspaceEdit{ - Changes: map[protocol.DocumentUri][]protocol.TextEdit{ - args.URI: { - { - NewText: " " + presharedKey, - Range: protocol.Range{ - Start: protocol.Position{ - Line: property.End.Line, - Character: property.End.Character, - }, - End: protocol.Position{ - Line: property.End.Line, - Character: property.End.Character, - }, - }, - }, - }, - }, - }, - }, nil -} diff --git a/server/handlers/wireguard/handlers/code-actions_create-peer.go b/server/handlers/wireguard/handlers/code-actions_create-peer.go new file mode 100644 index 0000000..e97c7aa --- /dev/null +++ b/server/handlers/wireguard/handlers/code-actions_create-peer.go @@ -0,0 +1,191 @@ +package handlers + +import ( + "config-lsp/common" + "config-lsp/handlers/wireguard" + "config-lsp/handlers/wireguard/ast" + wgcommands "config-lsp/handlers/wireguard/commands" + "fmt" + "net" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +type CodeActionCreatePeerArgs struct { + URI protocol.DocumentUri + Line uint32 +} + +func CodeActionCreatePeerArgsFromArguments(arguments map[string]any) CodeActionCreatePeerArgs { + return CodeActionCreatePeerArgs{ + URI: arguments["URI"].(protocol.DocumentUri), + Line: uint32(arguments["Line"].(float64)), + } +} + +func (args CodeActionCreatePeerArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) { + interfaceSection := d.Indexes.SectionsByName["Interface"][0] + section := d.Config.FindSectionByLine(args.Line) + + label := fmt.Sprintf("Add Peer based on peer on line %d", args.Line) + + newSection := section + + // IP Address + ipAddressLine, ipAddress := newSection.FindFirstPropertyByName("AllowedIPs") + _, address := interfaceSection.FindFirstPropertyByName("Address") + if ipAddress != nil && address != nil { + _, network, err := net.ParseCIDR(address.Value.Value) + + if err == nil { + newIPAddress := createNewIP(*network, ipAddress.Value.Value) + + valueEnd := common.Location{ + Line: ipAddress.End.Line, + Character: ipAddress.Value.Start.Character + uint32(len(newIPAddress)) + 1, + } + + newSection.Properties.Put( + ipAddressLine, + &ast.WGProperty{ + LocationRange: common.LocationRange{ + Start: ipAddress.Start, + End: valueEnd, + }, + Key: ipAddress.Key, + RawValue: newIPAddress, + Separator: address.Separator, + Value: &ast.WGPropertyValue{ + LocationRange: common.LocationRange{ + Start: ipAddress.Value.Start, + End: valueEnd, + }, + Value: newIPAddress, + }, + }, + ) + } + } + + // Preshared Key + presharedKeyLine, presharedKey := newSection.FindFirstPropertyByName("PresharedKey") + + if presharedKey != nil { + var newKey string + + if wgcommands.AreWireguardToolsAvailable() { + createdKey, err := wgcommands.CreatePresharedKey() + + if err == nil { + newKey = createdKey + } + } else { + newKey = "[preshared key]" + } + + valueEnd := common.Location{ + Line: presharedKey.End.Line, + Character: presharedKey.Value.Start.Character + uint32(len(newKey)) + 1, + } + newSection.Properties.Put( + presharedKeyLine, + &ast.WGProperty{ + LocationRange: common.LocationRange{ + Start: presharedKey.Start, + End: valueEnd, + }, + Key: presharedKey.Key, + RawValue: newKey, + Separator: presharedKey.Separator, + Value: &ast.WGPropertyValue{ + LocationRange: common.LocationRange{ + Start: presharedKey.Value.Start, + End: valueEnd, + }, + Value: newKey, + }, + }, + ) + } + + lastProperty := newSection.GetLastProperty() + println("last line") + println(lastProperty.End.Line) + println(fmt.Sprintf("~~~%s~~~", writeSection(*newSection))) + newText := writeSection(*newSection) + return &protocol.ApplyWorkspaceEditParams{ + Label: &label, + Edit: protocol.WorkspaceEdit{ + Changes: map[protocol.DocumentUri][]protocol.TextEdit{ + args.URI: { + { + Range: protocol.Range{ + Start: protocol.Position{ + Line: lastProperty.End.Line, + Character: lastProperty.End.Character, + }, + End: protocol.Position{ + Line: lastProperty.End.Line, + Character: lastProperty.End.Character, + }, + }, + NewText: newText, + }, + }, + }, + }, + }, nil +} + +func writeSection(section ast.WGSection) string { + text := "\n\n" + + text += fmt.Sprintf("[%s]\n", section.Header.Name) + + it := section.Properties.Iterator() + for it.Next() { + property := it.Value().(*ast.WGProperty) + text += fmt.Sprintf("%s = %s\n", property.Key.Name, property.Value.Value) + } + + return text +} + +// Try incrementing the IP address +func createNewIP( + network net.IPNet, + rawIP string, +) string { + parsedIP, _, err := net.ParseCIDR(rawIP) + parsedIP = parsedIP.To4() + + if parsedIP == nil { + // IPv6 is not supported + return "" + } + + if err != nil { + return "" + } + + lastAddress := uint32(network.IP[0])<<24 | uint32(network.IP[1])<<16 | uint32(network.IP[2])<<8 | uint32(network.IP[3]) + + networkMask, _ := network.Mask.Size() + for index := range 32 - networkMask { + lastAddress |= 1 << index + } + + newIP := uint32(parsedIP[0])<<24 | uint32(parsedIP[1])<<16 | uint32(parsedIP[2])<<8 | uint32(parsedIP[3]) + newIP += 1 + + if newIP >= lastAddress || newIP == 0 { + // The IP is the last one, which can't be used + // or even worse, it did a whole overflow + return "" + } + + // Here, we successfully incremented the IP correctly + + // Let's return the formatted IP now. + return fmt.Sprintf("%d.%d.%d.%d/32", newIP>>24, newIP>>16&0xFF, newIP>>8&0xFF, newIP&0xFF) +} diff --git a/server/handlers/wireguard/handlers/code-actions_create-peer_test.go b/server/handlers/wireguard/handlers/code-actions_create-peer_test.go new file mode 100644 index 0000000..a993c6a --- /dev/null +++ b/server/handlers/wireguard/handlers/code-actions_create-peer_test.go @@ -0,0 +1,42 @@ +package handlers + +import ( + "net" + "testing" +) + +func TestCreateNewIPSimple24Mask(t *testing.T) { + _, network, _ := net.ParseCIDR("10.0.0.0/24") + newIP := createNewIP(*network, "10.0.0.1/32") + + if newIP != "10.0.0.2/32" { + t.Errorf("Expected 10.0.0.2/32, got %s", newIP) + } +} + +func TestCreateNewIPDoesNotWorkWithLast24Mask(t *testing.T) { + _, network, _ := net.ParseCIDR("10.0.0.0/24") + newIP := createNewIP(*network, "10.0.0.254/32") + + if newIP != "" { + t.Errorf("Expected empty string, got %s", newIP) + } +} + +func TestCreateNewIPDoesNotWorkWithLast24Mask2(t *testing.T) { + _, network, _ := net.ParseCIDR("10.0.0.0/24") + newIP := createNewIP(*network, "10.0.0.255/32") + + if newIP != "" { + t.Errorf("Expected empty string, got %s", newIP) + } +} + +func TestCreateNewIPComplex20Mask(t *testing.T) { + _, network, _ := net.ParseCIDR("10.0.0.0/20") + newIP := createNewIP(*network, "10.0.0.255/32") + + if newIP != "10.0.1.0/32" { + t.Errorf("Expected 10.0.1.0/32, got %s", newIP) + } +} diff --git a/server/handlers/wireguard/handlers/code-actions_generate-private-key.go b/server/handlers/wireguard/handlers/code-actions_generate-private-key.go new file mode 100644 index 0000000..c38d629 --- /dev/null +++ b/server/handlers/wireguard/handlers/code-actions_generate-private-key.go @@ -0,0 +1,59 @@ +package handlers + +import ( + "config-lsp/handlers/wireguard" + wgcommands "config-lsp/handlers/wireguard/commands" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +type CodeActionGeneratePrivateKeyArgs struct { + URI protocol.DocumentUri + Line uint32 +} + +func CodeActionGeneratePrivateKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePrivateKeyArgs { + return CodeActionGeneratePrivateKeyArgs{ + URI: arguments["URI"].(protocol.DocumentUri), + Line: uint32(arguments["Line"].(float64)), + } +} + +func (args CodeActionGeneratePrivateKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) { + privateKey, err := wgcommands.CreateNewPrivateKey() + + if err != nil { + return &protocol.ApplyWorkspaceEditParams{}, err + } + + section := d.Config.FindSectionByLine(args.Line) + property := d.Config.FindPropertyByLine(args.Line) + + if section == nil || property == nil { + return nil, nil + } + + label := "Generate Private Key" + return &protocol.ApplyWorkspaceEditParams{ + Label: &label, + Edit: protocol.WorkspaceEdit{ + Changes: map[protocol.DocumentUri][]protocol.TextEdit{ + args.URI: { + { + NewText: " " + privateKey, + Range: protocol.Range{ + Start: protocol.Position{ + Line: property.End.Line, + Character: property.End.Character, + }, + End: protocol.Position{ + Line: property.End.Line, + Character: property.End.Character, + }, + }, + }, + }, + }, + }, + }, nil +} diff --git a/server/handlers/wireguard/handlers/code-actions_generate-shared-key.go b/server/handlers/wireguard/handlers/code-actions_generate-shared-key.go new file mode 100644 index 0000000..1e84e58 --- /dev/null +++ b/server/handlers/wireguard/handlers/code-actions_generate-shared-key.go @@ -0,0 +1,50 @@ +package handlers + +import ( + "config-lsp/handlers/wireguard" + wgcommands "config-lsp/handlers/wireguard/commands" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +type CodeActionGeneratePresharedKeyArgs struct { + URI protocol.DocumentUri + Line uint32 +} + +func CodeActionGeneratePresharedKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePresharedKeyArgs { + return CodeActionGeneratePresharedKeyArgs{ + URI: arguments["URI"].(protocol.DocumentUri), + Line: uint32(arguments["Line"].(float64)), + } +} + +func (args CodeActionGeneratePresharedKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) { + presharedKey, err := wgcommands.CreatePresharedKey() + + if err != nil { + return &protocol.ApplyWorkspaceEditParams{}, err + } + + section := d.Config.FindSectionByLine(args.Line) + property := d.Config.FindPropertyByLine(args.Line) + + if section == nil || property == nil { + return nil, nil + } + + label := "Generate Preshared Key" + return &protocol.ApplyWorkspaceEditParams{ + Label: &label, + Edit: protocol.WorkspaceEdit{ + Changes: map[protocol.DocumentUri][]protocol.TextEdit{ + args.URI: { + { + NewText: presharedKey, + Range: property.Value.ToLSPRange(), + }, + }, + }, + }, + }, nil +} diff --git a/server/handlers/wireguard/handlers/fetch-code-actions_create-peer.go b/server/handlers/wireguard/handlers/fetch-code-actions_create-peer.go new file mode 100644 index 0000000..4652ae6 --- /dev/null +++ b/server/handlers/wireguard/handlers/fetch-code-actions_create-peer.go @@ -0,0 +1,42 @@ +package handlers + +import ( + "config-lsp/handlers/wireguard" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +func GetAddPeerLikeThis( + d *wireguard.WGDocument, + params *protocol.CodeActionParams, +) []protocol.CodeAction { + // First, check if is on peer line + + line := params.Range.Start.Line + + section := d.Config.FindSectionByLine(line) + + // Check if section can be copied + if section == nil || section.Start.Line != line || section.Header.Name != "Peer" { + return nil + } + + // Then add option + commandID := "wireguard." + CodeActionCreatePeer + command := protocol.Command{ + Title: "Create new Peer based on this one", + Command: string(commandID), + Arguments: []any{ + CodeActionCreatePeerArgs{ + URI: params.TextDocument.URI, + Line: line, + }, + }, + } + return []protocol.CodeAction{ + { + Title: "Create new Peer based on this one", + Command: &command, + }, + } +} diff --git a/server/handlers/wireguard/handlers/fetch-code-actions_keepalive.go b/server/handlers/wireguard/handlers/fetch-code-actions_keepalive.go new file mode 100644 index 0000000..426ad42 --- /dev/null +++ b/server/handlers/wireguard/handlers/fetch-code-actions_keepalive.go @@ -0,0 +1,59 @@ +package handlers + +import ( + "config-lsp/handlers/wireguard" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +func GetKeepaliveCodeActions( + d *wireguard.WGDocument, + params *protocol.CodeActionParams, +) []protocol.CodeAction { + line := params.Range.Start.Line + + for _, section := range d.Indexes.SectionsByName["Peer"] { + if section.Start.Line >= line && line <= section.End.Line { + _, endpoint := section.FindFirstPropertyByName("Endpoint") + _, persistentKeepAlive := section.FindFirstPropertyByName("PersistentKeepalive") + + if endpoint != nil && persistentKeepAlive == nil { + var insertionLine uint32 + lastProperty := section.GetLastProperty() + + if lastProperty == nil { + insertionLine = section.End.Line + } else { + insertionLine = lastProperty.End.Line + 1 + } + + return []protocol.CodeAction{ + { + Title: "Add PersistentKeepalive", + Edit: &protocol.WorkspaceEdit{ + Changes: map[protocol.DocumentUri][]protocol.TextEdit{ + params.TextDocument.URI: { + { + Range: protocol.Range{ + Start: protocol.Position{ + Line: insertionLine, + Character: 0, + }, + End: protocol.Position{ + Line: insertionLine, + Character: 0, + }, + }, + NewText: "PersistentKeepalive = 25\n", + }, + }, + }, + }, + }, + } + } + } + } + + return nil +} diff --git a/server/handlers/wireguard/handlers/fetch-code-actions.go b/server/handlers/wireguard/handlers/fetch-code-actions_key-generation.go similarity index 54% rename from server/handlers/wireguard/handlers/fetch-code-actions.go rename to server/handlers/wireguard/handlers/fetch-code-actions_key-generation.go index f4263f4..5741ed0 100644 --- a/server/handlers/wireguard/handlers/fetch-code-actions.go +++ b/server/handlers/wireguard/handlers/fetch-code-actions_key-generation.go @@ -7,55 +7,6 @@ import ( protocol "github.com/tliron/glsp/protocol_3_16" ) -func GetKeepaliveCodeActions( - d *wireguard.WGDocument, - params *protocol.CodeActionParams, -) []protocol.CodeAction { - line := params.Range.Start.Line - - for _, section := range d.Indexes.SectionsByName["Peer"] { - if section.Start.Line >= line && line <= section.End.Line { - if section.FindPropertyByName("Endpoint") != nil && section.FindFirstPropertyByName("PersistentKeepalive") == nil { - var insertionLine uint32 - lastProperty := section.GetLastProperty() - - if lastProperty == nil { - insertionLine = section.End.Line - } else { - insertionLine = lastProperty.End.Line + 1 - } - - return []protocol.CodeAction{ - { - Title: "Add PersistentKeepalive", - Edit: &protocol.WorkspaceEdit{ - Changes: map[protocol.DocumentUri][]protocol.TextEdit{ - params.TextDocument.URI: { - { - Range: protocol.Range{ - Start: protocol.Position{ - Line: insertionLine, - Character: 0, - }, - End: protocol.Position{ - Line: insertionLine, - Character: 0, - }, - }, - NewText: "PersistentKeepalive = 25\n", - }, - }, - }, - }, - }, - } - } - } - } - - return nil -} - func GetKeyGenerationCodeActions( d *wireguard.WGDocument, params *protocol.CodeActionParams, diff --git a/server/handlers/wireguard/lsp/text-document-code-action.go b/server/handlers/wireguard/lsp/text-document-code-action.go index 98bda8b..4c86674 100644 --- a/server/handlers/wireguard/lsp/text-document-code-action.go +++ b/server/handlers/wireguard/lsp/text-document-code-action.go @@ -15,6 +15,7 @@ func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionPa actions = append(actions, handlers.GetKeyGenerationCodeActions(d, params)...) actions = append(actions, handlers.GetKeepaliveCodeActions(d, params)...) + actions = append(actions, handlers.GetAddPeerLikeThis(d, params)...) if len(actions) > 0 { return actions, nil diff --git a/server/handlers/wireguard/lsp/workspace-execute-command.go b/server/handlers/wireguard/lsp/workspace-execute-command.go index 19cd6fc..01253d6 100644 --- a/server/handlers/wireguard/lsp/workspace-execute-command.go +++ b/server/handlers/wireguard/lsp/workspace-execute-command.go @@ -24,6 +24,12 @@ func WorkspaceExecuteCommand(context *glsp.Context, params *protocol.ExecuteComm d := wireguard.DocumentParserMap[args.URI] + return args.RunCommand(d) + case string(handlers.CodeActionCreatePeer): + args := handlers.CodeActionCreatePeerArgsFromArguments(params.Arguments[0].(map[string]any)) + + d := wireguard.DocumentParserMap[args.URI] + return args.RunCommand(d) }