fix: enable editing and management of hosts from included SSH config files

• Add SourceFile field to SSHHost struct to track config file origins
• Implement FindHostInAllConfigs() to locate hosts across all config files
• Fix "host not found" errors when editing/deleting hosts from included files
• Add GetAllConfigFiles() and GetAllConfigFilesFromBase() for config discovery
• Create UpdateSSHHostV2() and DeleteSSHHostV2() for cross-file operations
• Display config file source in edit and info forms for better visibility
• Add intelligent file selector for host addition when multiple configs exist
• Support -c parameter context with proper file resolution
• Exclude .backup files from Include directive processing
• Maintain backward compatibility with existing SSH config workflows

Resolves limitation where hosts from included config files could be viewed
but not edited, deleted, or properly managed through the interface.
This commit is contained in:
2025-09-05 17:04:11 +02:00
parent b67f5abbbc
commit be3dcaa1cd
9 changed files with 751 additions and 41 deletions

View File

@@ -61,6 +61,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.helpForm.height = m.height
m.helpForm.styles = m.styles
}
if m.fileSelectorForm != nil {
m.fileSelectorForm.width = m.width
m.fileSelectorForm.height = m.height
m.fileSelectorForm.styles = m.styles
}
return m, nil
case addFormSubmitMsg:
@@ -158,6 +163,21 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.table.Focus()
return m, nil
case fileSelectorMsg:
if msg.cancelled {
// Cancel: return to list view
m.viewMode = ViewList
m.fileSelectorForm = nil
m.table.Focus()
return m, nil
} else {
// File selected: proceed to add form with selected file
m.addForm = NewAddForm("", m.styles, m.width, m.height, msg.selectedFile)
m.viewMode = ViewAdd
m.fileSelectorForm = nil
return m, textinput.Blink
}
case infoFormEditMsg:
// Switch from info to edit mode
editForm, err := NewEditForm(msg.hostName, m.styles, m.width, m.height, m.configFile)
@@ -257,6 +277,13 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.helpForm = newForm
return m, cmd
}
case ViewFileSelector:
if m.fileSelectorForm != nil {
var newForm *fileSelectorModel
newForm, cmd = m.fileSelectorForm.Update(msg)
m.fileSelectorForm = newForm
return m, cmd
}
case ViewList:
// Handle list view keys
return m.handleListViewKeys(msg)
@@ -427,9 +454,40 @@ func (m Model) handleListViewKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
}
case "a":
if !m.searchMode && !m.deleteMode {
// Add a new host
m.addForm = NewAddForm("", m.styles, m.width, m.height, m.configFile)
m.viewMode = ViewAdd
// Check if there are multiple config files starting from the current base config
var configFiles []string
var err error
if m.configFile != "" {
// Use the specified config file as base
configFiles, err = config.GetAllConfigFilesFromBase(m.configFile)
} else {
// Use the default config file as base
configFiles, err = config.GetAllConfigFiles()
}
if err != nil || len(configFiles) <= 1 {
// Only one config file (or error), go directly to add form
var configFile string
if len(configFiles) == 1 {
configFile = configFiles[0]
} else {
configFile = m.configFile
}
m.addForm = NewAddForm("", m.styles, m.width, m.height, configFile)
m.viewMode = ViewAdd
} else {
// Multiple config files, show file selector
fileSelectorForm, err := NewFileSelectorFromBase("Select config file to add host to:", m.styles, m.width, m.height, m.configFile)
if err != nil {
// Fallback to default behavior if file selector fails
m.addForm = NewAddForm("", m.styles, m.width, m.height, m.configFile)
m.viewMode = ViewAdd
} else {
m.fileSelectorForm = fileSelectorForm
m.viewMode = ViewFileSelector
}
}
return m, textinput.Blink
}
case "d":