Skip to content
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
357 changes: 33 additions & 324 deletions internal/tui/commands.go

Large diffs are not rendered by default.

203 changes: 107 additions & 96 deletions internal/tui/commands/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,129 +6,140 @@ import (
"path/filepath"
"strings"

"tusshi/internal/config"
"tusshi/internal/validation"
)

const tabAll = "All"

// AddConfig triggers creation of a new configuration file.
func AddConfig(mgr *config.Manager, parts []string) func(Context) {
return func(ctx Context) {
if len(parts) < 2 {
ctx.SetError("Usage: :add-config <filename>")
return
}
type addConfigCmd struct{}

arg := parts[1]
var targetPath string
if filepath.IsAbs(arg) || strings.HasPrefix(arg, "~/") {
targetPath = arg
} else {
targetPath = filepath.Join(filepath.Dir(mgr.PrimaryPath), arg)
}
func (c *addConfigCmd) Keys() []string { return []string{"addconf", "add-config"} }
func (c *addConfigCmd) Description() string { return "Add a new config file" }
func (c *addConfigCmd) Execute(ctx Context, parts []string) {
if len(parts) < 2 {
ctx.SetError("Usage: :add-config <filename>")
return
}

if err := validation.ValidateConfigName(filepath.Base(targetPath)); err != nil {
ctx.SetError("Invalid config name: " + err.Error())
return
}
mgr := ctx.GetManager()
arg := parts[1]
var targetPath string
if filepath.IsAbs(arg) || strings.HasPrefix(arg, "~/") {
targetPath = arg
} else {
targetPath = filepath.Join(filepath.Dir(mgr.PrimaryPath), arg)
}

if err := mgr.AddConfigFile(targetPath); err != nil {
ctx.SetError("Add config error: " + err.Error())
} else {
ctx.SetAlert(fmt.Sprintf("Created config file %q.", filepath.Base(targetPath)))
ctx.SetActiveTab(targetPath)
}
ctx.Reload()
if err := validation.ValidateConfigName(filepath.Base(targetPath)); err != nil {
ctx.SetError("Invalid config name: " + err.Error())
return
}

if err := mgr.AddConfigFile(targetPath); err != nil {
ctx.SetError("Add config error: " + err.Error())
} else {
ctx.SetAlert(fmt.Sprintf("Created config file %q.", filepath.Base(targetPath)))
ctx.SetActiveTab(targetPath)
}
ctx.Reload()
}

// RenameConfig triggers renaming of an existing configuration file.
func RenameConfig(mgr *config.Manager, parts []string) func(Context) {
return func(ctx Context) {
activeTab := ctx.GetActiveTab()

var oldName, newName string
switch {
case len(parts) == 2:
if activeTab == tabAll {
ctx.SetError("Cannot rename from 'All' tab. Usage: :rename-config <old-name> <new-name>")
return
}
oldName = activeTab
newName = parts[1]
case len(parts) >= 3:
oldName = parts[1]
newName = parts[2]
default:
if activeTab == tabAll {
ctx.SetError("Usage: :rename-config <old-name> <new-name>")
} else {
ctx.SetError("Usage: :rename-config <new-name>")
}
return
}
type renameConfigCmd struct{}

func (c *renameConfigCmd) Keys() []string { return []string{"mvconf", "rename-config"} }
func (c *renameConfigCmd) Description() string { return "Rename a config file" }
func (c *renameConfigCmd) Execute(ctx Context, parts []string) {
mgr := ctx.GetManager()
activeTab := ctx.GetActiveTab()

oldPath, found := mgr.FindConfigFile(oldName)
if !found {
ctx.SetError(fmt.Sprintf("Config file %q not found", oldName))
var oldName, newName string
switch {
case len(parts) == 2:
if activeTab == tabAll {
ctx.SetError("Cannot rename from 'All' tab. Usage: :rename-config <old-name> <new-name>")
return
}

var newPath string
if filepath.IsAbs(newName) || strings.HasPrefix(newName, "~/") {
newPath = newName
oldName = activeTab
newName = parts[1]
case len(parts) >= 3:
oldName = parts[1]
newName = parts[2]
default:
if activeTab == tabAll {
ctx.SetError("Usage: :rename-config <old-name> <new-name>")
} else {
newPath = filepath.Join(filepath.Dir(mgr.PrimaryPath), newName)
ctx.SetError("Usage: :rename-config <new-name>")
}
return
}

if err := validation.ValidateConfigName(filepath.Base(newPath)); err != nil {
ctx.SetError("Invalid config name: " + err.Error())
return
}
oldPath, found := mgr.FindConfigFile(oldName)
if !found {
ctx.SetError(fmt.Sprintf("Config file %q not found", oldName))
return
}

if err := mgr.RenameConfigFile(oldPath, newPath); err != nil {
ctx.SetError("Rename config error: " + err.Error())
} else {
ctx.SetAlert(fmt.Sprintf("Renamed config file to %q.", filepath.Base(newPath)))
if activeTab == oldPath {
ctx.SetActiveTab(newPath)
}
var newPath string
if filepath.IsAbs(newName) || strings.HasPrefix(newName, "~/") {
newPath = newName
} else {
newPath = filepath.Join(filepath.Dir(mgr.PrimaryPath), newName)
}

if err := validation.ValidateConfigName(filepath.Base(newPath)); err != nil {
ctx.SetError("Invalid config name: " + err.Error())
return
}

if err := mgr.RenameConfigFile(oldPath, newPath); err != nil {
ctx.SetError("Rename config error: " + err.Error())
} else {
ctx.SetAlert(fmt.Sprintf("Renamed config file to %q.", filepath.Base(newPath)))
if activeTab == oldPath {
ctx.SetActiveTab(newPath)
}
ctx.Reload()
}
ctx.Reload()
}

// DeleteConfig triggers deletion of a configuration file when it contains no connections.
func DeleteConfig(mgr *config.Manager, parts []string) func(Context) {
return func(ctx Context) {
activeTab := ctx.GetActiveTab()
type deleteConfigCmd struct{}

var targetName string
if len(parts) >= 2 {
targetName = parts[1]
} else {
if activeTab == tabAll {
ctx.SetError("Usage: :delete-config <filename> (or switch to a tab and run :delete-config)")
return
}
targetName = activeTab
}
func (c *deleteConfigCmd) Keys() []string { return []string{"rmconf", "delete-config"} }
func (c *deleteConfigCmd) Description() string { return "Delete empty config file" }
func (c *deleteConfigCmd) Execute(ctx Context, parts []string) {
mgr := ctx.GetManager()
activeTab := ctx.GetActiveTab()

targetPath, found := mgr.FindConfigFile(targetName)
if !found {
ctx.SetError(fmt.Sprintf("Config file %q not found", targetName))
var targetName string
if len(parts) >= 2 {
targetName = parts[1]
} else {
if activeTab == tabAll {
ctx.SetError("Usage: :delete-config <filename> (or switch to a tab and run :delete-config)")
return
}
targetName = activeTab
}

if err := mgr.DeleteConfigFile(targetPath); err != nil {
ctx.SetError("Delete config error: " + err.Error())
} else {
ctx.SetAlert(fmt.Sprintf("Deleted config file %q.", filepath.Base(targetPath)))
if activeTab == targetPath {
ctx.SetActiveTab(tabAll)
}
targetPath, found := mgr.FindConfigFile(targetName)
if !found {
ctx.SetError(fmt.Sprintf("Config file %q not found", targetName))
return
}

if err := mgr.DeleteConfigFile(targetPath); err != nil {
ctx.SetError("Delete config error: " + err.Error())
} else {
ctx.SetAlert(fmt.Sprintf("Deleted config file %q.", filepath.Base(targetPath)))
if activeTab == targetPath {
ctx.SetActiveTab(tabAll)
}
ctx.Reload()
}
ctx.Reload()
}

func init() {
Register(&addConfigCmd{})
Register(&renameConfigCmd{})
Register(&deleteConfigCmd{})
}
19 changes: 0 additions & 19 deletions internal/tui/commands/delete.go

This file was deleted.

17 changes: 0 additions & 17 deletions internal/tui/commands/form.go

This file was deleted.

21 changes: 16 additions & 5 deletions internal/tui/commands/help.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package commands

// Help triggers opening the interactive help dialog.
func Help() func(Context) {
return func(ctx Context) {
ctx.OpenHelp()
}
type helpCommand struct{}

func (h *helpCommand) Keys() []string {
return []string{"h", "help", "?"}
}

func (h *helpCommand) Description() string {
return "Show this help overlay"
}

func (h *helpCommand) Execute(ctx Context, _ []string) {
ctx.OpenHelp()
}

func init() {
Register(&helpCommand{})
}
Loading
Loading