package openfolder import ( "errors" "os/exec" "strings" ) // OpenLocationCustom executes a user-defined command string, substituting %1 // with the given path. The command string is split into executable + arguments // using shell-like quoting rules (double quotes are respected). // // Example command: doublecmd.exe -C -T -P L -L "%1" func OpenLocationCustom(command string, path string) error { expanded := strings.ReplaceAll(command, "%1", path) args, err := splitCommand(expanded) if err != nil { return err } if len(args) == 0 { return errors.New("open_location_command: empty command after expansion") } return exec.Command(args[0], args[1:]...).Start() } // splitCommand splits a command string into tokens, respecting double-quoted // segments. Quotes are removed from the resulting tokens. Backslash escaping // of a double quote (\") inside a quoted segment is supported. func splitCommand(s string) ([]string, error) { var tokens []string var current strings.Builder inQuote := false hasToken := false for i := 0; i < len(s); i++ { ch := s[i] switch { case ch == '"': inQuote = !inQuote hasToken = true // even empty quotes produce a token part case ch == '\\' && inQuote && i+1 < len(s) && s[i+1] == '"': // escaped quote inside a quoted segment current.WriteByte('"') i++ // skip the next quote case (ch == ' ' || ch == '\t') && !inQuote: if hasToken { tokens = append(tokens, current.String()) current.Reset() hasToken = false } default: current.WriteByte(ch) hasToken = true } } if inQuote { return nil, errors.New("open_location_command: unterminated double quote") } if hasToken { tokens = append(tokens, current.String()) } return tokens, nil }