@@ -3,6 +3,10 @@ package main
33import (
44 "fmt"
55 "os"
6+ "os/exec"
7+ "path/filepath"
8+ "runtime"
9+ "strings"
610
711 "github.com/monster0506/meshexec/internal"
812 "github.com/monster0506/meshexec/internal/config"
@@ -83,8 +87,95 @@ var configEditCmd = &cobra.Command{
8387 Use : "edit" ,
8488 Short : "Open configuration in default editor" ,
8589 Run : func (cmd * cobra.Command , args []string ) {
86- // Stub implementation
87- fmt .Fprintln (os .Stderr , "Config edit is not implemented yet." )
90+ logLevel , _ := cmd .Root ().PersistentFlags ().GetString ("log-level" )
91+ verbose , _ := cmd .Root ().PersistentFlags ().GetBool ("verbose" )
92+ if verbose {
93+ logLevel = "debug"
94+ }
95+ manager := config .NewManagerWithLevel (logLevel )
96+
97+ // Respect global --config path
98+ if configPath , _ := cmd .Root ().PersistentFlags ().GetString ("config" ); configPath != "" {
99+ manager .SetConfigPath (configPath )
100+ }
101+
102+ cfgPath := manager .GetConfigPath ()
103+
104+ // Ensure the config file exists
105+ if _ , err := os .Stat (cfgPath ); os .IsNotExist (err ) {
106+ if logger != nil {
107+ logger .Info ("config edit: creating default config as it does not exist" , map [string ]interface {}{"path" : cfgPath })
108+ }
109+ if mkErr := manager .CreateDefaultConfig (); mkErr != nil {
110+ me := internal .NewConfigError ("create_failed" , "failed to create default configuration" , map [string ]interface {}{"error" : mkErr .Error ()})
111+ fmt .Fprintln (os .Stderr , internal .FormatUserError (me ))
112+ os .Exit (1 )
113+ }
114+ }
115+
116+ // Determine editor
117+ editorSpec := os .Getenv ("EDITOR" )
118+ if editorSpec == "" {
119+ editorSpec = os .Getenv ("VISUAL" )
120+ }
121+ var editor string
122+ var editorArgs []string
123+ if strings .TrimSpace (editorSpec ) != "" {
124+ parts := strings .Fields (editorSpec )
125+ editor = parts [0 ]
126+ if len (parts ) > 1 {
127+ editorArgs = parts [1 :]
128+ }
129+ } else {
130+ switch runtime .GOOS {
131+ case "windows" :
132+ editor = "notepad"
133+ case "darwin" :
134+ // Prefer a terminal editor; if unavailable, fall back to open -W -t
135+ if p , err := exec .LookPath ("nano" ); err == nil {
136+ editor = p
137+ } else if p , err := exec .LookPath ("vi" ); err == nil {
138+ editor = p
139+ } else {
140+ editor = "open"
141+ editorArgs = append (editorArgs , "-W" , "-t" )
142+ }
143+ default :
144+ if p , err := exec .LookPath ("nano" ); err == nil {
145+ editor = p
146+ } else if p , err := exec .LookPath ("vi" ); err == nil {
147+ editor = p
148+ } else {
149+ editor = "vi"
150+ }
151+ }
152+ }
153+
154+ // Prepare command
155+ argsWithFile := append (editorArgs , cfgPath )
156+ if logger != nil {
157+ logger .Info ("config edit: opening editor" , map [string ]interface {}{"editor" : editor , "args" : strings .Join (editorArgs , " " ), "path" : cfgPath })
158+ }
159+
160+ c := exec .Command (editor , argsWithFile ... )
161+ c .Stdin = os .Stdin
162+ c .Stdout = os .Stdout
163+ c .Stderr = os .Stderr
164+ if err := c .Run (); err != nil {
165+ me := internal .NewConfigError ("editor_failed" , "failed to open editor" , map [string ]interface {}{"editor" : editor , "error" : err .Error ()})
166+ fmt .Fprintln (os .Stderr , internal .FormatUserError (me ))
167+ os .Exit (1 )
168+ }
169+
170+ // Validate resulting configuration
171+ if _ , err := manager .Load (); err != nil {
172+ me := internal .NewConfigError ("invalid_config" , "configuration invalid after edit" , map [string ]interface {}{"error" : err .Error ()})
173+ fmt .Fprintln (os .Stderr , internal .FormatUserError (me ))
174+ os .Exit (1 )
175+ }
176+
177+ // Success message
178+ fmt .Printf ("Configuration saved to: %s\n " , filepath .Clean (cfgPath ))
88179 },
89180}
90181
0 commit comments