fix(cli): correct execution logic and improve messages

This commit is contained in:
L. Yeung 2024-08-24 12:19:01 +08:00 committed by Jan De Dobbeleer
parent 48f633e0cb
commit e28d91b854
8 changed files with 102 additions and 76 deletions

View file

@ -3,7 +3,6 @@ package cli
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
@ -50,7 +49,7 @@ You can do the following:
clear(env.CachePath())
case "edit":
cacheFilePath := filepath.Join(env.CachePath(), cache.FileName)
editFileWithEditor(cacheFilePath)
os.Exit(editFileWithEditor(cacheFilePath))
}
},
}
@ -59,25 +58,6 @@ func init() {
RootCmd.AddCommand(getCache)
}
func editFileWithEditor(file string) {
editor := os.Getenv("EDITOR")
var args []string
if strings.Contains(editor, " ") {
splitted := strings.Split(editor, " ")
editor = splitted[0]
args = splitted[1:]
}
args = append(args, file)
cmd := exec.Command(editor, args...)
err := cmd.Run()
if err != nil {
fmt.Println(err.Error())
}
}
func clear(cachePath string) {
// get all files in the cache directory that start with omp.cache and delete them
files, err := os.ReadDir(cachePath)

View file

@ -5,16 +5,18 @@ import (
"os"
"time"
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
"github.com/spf13/cobra"
)
// configCmd represents the config command
var configCmd = &cobra.Command{
Use: "config [export|migrate|edit]",
Use: "config edit",
Short: "Interact with the config",
Long: `Interact with the config.
You can export, migrate or edit the config.`,
You can export, migrate or edit the config (via the editor specified in the environment variable "EDITOR").`,
ValidArgs: []string{
"export",
"migrate",
@ -29,7 +31,13 @@ You can export, migrate or edit the config.`,
}
switch args[0] {
case "edit":
editFileWithEditor(os.Getenv("POSH_THEME"))
env := &runtime.Terminal{
CmdFlags: &runtime.Flags{
Config: configFlag,
},
}
env.ResolveConfigPath()
os.Exit(editFileWithEditor(env.CmdFlags.Config))
case "get":
// only here for backwards compatibility
fmt.Print(time.Now().UnixNano() / 1000000)

View file

@ -4,7 +4,6 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"github.com/jandedobbeleer/oh-my-posh/src/config"
@ -13,9 +12,7 @@ import (
"github.com/spf13/cobra"
)
var (
output string
)
var output string
// exportCmd represents the export command
var exportCmd = &cobra.Command{
@ -27,15 +24,21 @@ You can choose to print the output to stdout, or export your config in the forma
Example usage:
> oh-my-posh config export --config ~/myconfig.omp.json
Exports the ~/myconfig.omp.json config file and prints the result to stdout.
> oh-my-posh config export --config ~/myconfig.omp.json --format toml
Exports the ~/myconfig.omp.json config file to toml and prints the result to stdout.`,
Exports the config file "~/myconfig.omp.json" in TOML format and prints the result to stdout.
> oh-my-posh config export --output ~/new_config.omp.json
Exports the current config to "~/new_config.omp.json" (in JSON format).`,
Args: cobra.NoArgs,
Run: func(_ *cobra.Command, _ []string) {
if len(output) == 0 && len(format) == 0 {
// usage error
fmt.Println("neither output path nor export format is specified")
os.Exit(2)
}
env := &runtime.Terminal{
CmdFlags: &runtime.Flags{
Config: configFlag,
@ -45,15 +48,25 @@ Exports the ~/myconfig.omp.json config file to toml and prints the result to std
defer env.Close()
cfg := config.Load(env)
if len(output) == 0 && len(format) == 0 {
// usage error
os.Exit(2)
validateExportFormat := func() {
format = strings.ToLower(format)
switch format {
case "json", "jsonc":
format = config.JSON
case "toml", "tml":
format = config.TOML
case "yaml", "yml":
format = config.YAML
default:
formats := []string{"json", "jsonc", "toml", "tml", "yaml", "yml"}
// usage error
fmt.Printf("export format must be one of these: %s\n", strings.Join(formats, ", "))
os.Exit(2)
}
}
formats := []string{"json", "jsonc", "toml", "tml", "yaml", "yml"}
if len(format) != 0 && !slices.Contains(formats, format) {
// usage error
os.Exit(2)
if len(format) != 0 {
validateExportFormat()
}
if len(output) == 0 {
@ -65,18 +78,7 @@ Exports the ~/myconfig.omp.json config file to toml and prints the result to std
if len(format) == 0 {
format = strings.TrimPrefix(filepath.Ext(output), ".")
}
switch format {
case "json", "jsonc":
format = config.JSON
case "toml", "tml":
format = config.TOML
case "yaml", "yml":
format = config.YAML
default:
// data error
os.Exit(65)
validateExportFormat()
}
cfg.Write(format)
@ -84,10 +86,7 @@ Exports the ~/myconfig.omp.json config file to toml and prints the result to std
}
func cleanOutputPath(path string, env runtime.Environment) string {
if strings.HasPrefix(path, "~") {
path = strings.TrimPrefix(path, "~")
path = filepath.Join(env.Home(), path)
}
path = runtime.ReplaceTildePrefixWithHomeDir(env, path)
if !filepath.IsAbs(path) {
if absPath, err := filepath.Abs(path); err == nil {

34
src/cli/edit.go Normal file
View file

@ -0,0 +1,34 @@
package cli
import (
"fmt"
"os"
"os/exec"
"strings"
)
func editFileWithEditor(file string) int {
editor := strings.TrimSpace(os.Getenv("EDITOR"))
if len(editor) == 0 {
fmt.Println(`no editor specified in the environment variable "EDITOR"`)
return 1
}
var args []string
if strings.Contains(editor, " ") {
strs := strings.Split(editor, " ")
editor = strs[0]
args = strs[1:]
}
args = append(args, file)
cmd := exec.Command(editor, args...)
err := cmd.Run()
if err != nil {
fmt.Println(err.Error())
return 1
}
return cmd.ProcessState.ExitCode()
}

View file

@ -66,7 +66,6 @@ var printCmd = &cobra.Command{
Plain: plain,
Primary: args[0] == "primary",
Cleared: cleared,
Cached: cached,
NoExitCode: noStatus,
Column: column,
JobCount: jobCount,

View file

@ -98,7 +98,6 @@ type Flags struct {
HasTransient bool
PromptCount int
Cleared bool
Cached bool
NoExitCode bool
Column int
JobCount int

View file

@ -74,7 +74,7 @@ func (term *Terminal) Init() {
term.deviceCache = initCache(cache.FileName)
term.sessionCache = initCache(cache.SessionFileName)
term.resolveConfigPath()
term.ResolveConfigPath()
term.cmdCache = &cache.Command{
Commands: maps.NewConcurrent(),
@ -82,12 +82,10 @@ func (term *Terminal) Init() {
term.tmplCache = &cache.Template{}
if !term.CmdFlags.Cached {
term.SetPromptCount()
}
term.SetPromptCount()
}
func (term *Terminal) resolveConfigPath() {
func (term *Terminal) ResolveConfigPath() {
defer term.Trace(time.Now())
// if the config flag is set, we'll use that over POSH_THEME
@ -129,11 +127,7 @@ func (term *Terminal) resolveConfigPath() {
return
}
configFile := term.CmdFlags.Config
if strings.HasPrefix(configFile, "~") {
configFile = strings.TrimPrefix(configFile, "~")
configFile = filepath.Join(term.Home(), configFile)
}
configFile := ReplaceTildePrefixWithHomeDir(term, term.CmdFlags.Config)
abs, err := filepath.Abs(configFile)
if err != nil {
@ -726,11 +720,14 @@ func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
}
for _, element := range regexes {
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalizedElement, "~") {
normalizedElement = strings.Replace(normalizedElement, "~", home, 1)
normalized := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalized, "~") {
rem := normalized[1:]
if len(rem) == 0 || rem[0] == '/' {
normalized = home + rem
}
}
pattern := fmt.Sprintf("^%s$", normalizedElement)
pattern := fmt.Sprintf("^%s$", normalized)
if goos == WINDOWS || goos == DARWIN {
pattern = "(?i)" + pattern
}
@ -843,9 +840,19 @@ func Base(env Environment, path string) string {
return path
}
func ReplaceTildePrefixWithHomeDir(env Environment, path string) string {
if !strings.HasPrefix(path, "~") {
return path
}
rem := path[1:]
if len(rem) == 0 || IsPathSeparator(env, rem[0]) {
return env.Home() + rem
}
return path
}
func ReplaceHomeDirPrefixWithTilde(env Environment, path string) string {
home := env.Home()
// match Home directory exactly
if !strings.HasPrefix(path, home) {
return path
}

View file

@ -141,7 +141,7 @@ will not be rendered when in one of the excluded locations.
```
The strings specified in these properties are evaluated as [regular expressions][regex]. You
can use any valid regular expression construct, but the regular expression must match the entire directory
can use any valid regular expression construct, but the regular expression must match the **ENTIRE** directory
name. The following will match `/Users/posh/Projects/Foo` but not `/home/Users/posh/Projects/Foo`.
```json
@ -165,8 +165,8 @@ You can also combine these properties:
- Oh My Posh will accept both `/` and `\` as path separators for a folder and will match regardless of which
is used by the current operating system.
- Because the strings are evaluated as regular expressions, if you want to use a `\` in a Windows
directory name, you need to specify it as `\\\\`.
- Because the strings are evaluated as regular expressions, if you want to use a backslash (`\`) in a Windows
directory name, you need to specify it as double backslashes, and if using JSON format you should escape it as `\\\\`.
- The character `~` at the start of a specified folder will match the user's home directory.
- The comparison is case-insensitive on Windows and macOS, but case-sensitive on other operating systems.