mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-02-02 05:41:10 -08:00
fix(cli): correct execution logic and improve messages
This commit is contained in:
parent
48f633e0cb
commit
e28d91b854
|
@ -3,7 +3,6 @@ package cli
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -50,7 +49,7 @@ You can do the following:
|
||||||
clear(env.CachePath())
|
clear(env.CachePath())
|
||||||
case "edit":
|
case "edit":
|
||||||
cacheFilePath := filepath.Join(env.CachePath(), cache.FileName)
|
cacheFilePath := filepath.Join(env.CachePath(), cache.FileName)
|
||||||
editFileWithEditor(cacheFilePath)
|
os.Exit(editFileWithEditor(cacheFilePath))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -59,25 +58,6 @@ func init() {
|
||||||
RootCmd.AddCommand(getCache)
|
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) {
|
func clear(cachePath string) {
|
||||||
// get all files in the cache directory that start with omp.cache and delete them
|
// get all files in the cache directory that start with omp.cache and delete them
|
||||||
files, err := os.ReadDir(cachePath)
|
files, err := os.ReadDir(cachePath)
|
||||||
|
|
|
@ -5,16 +5,18 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// configCmd represents the config command
|
// configCmd represents the config command
|
||||||
var configCmd = &cobra.Command{
|
var configCmd = &cobra.Command{
|
||||||
Use: "config [export|migrate|edit]",
|
Use: "config edit",
|
||||||
Short: "Interact with the config",
|
Short: "Interact with the config",
|
||||||
Long: `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{
|
ValidArgs: []string{
|
||||||
"export",
|
"export",
|
||||||
"migrate",
|
"migrate",
|
||||||
|
@ -29,7 +31,13 @@ You can export, migrate or edit the config.`,
|
||||||
}
|
}
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "edit":
|
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":
|
case "get":
|
||||||
// only here for backwards compatibility
|
// only here for backwards compatibility
|
||||||
fmt.Print(time.Now().UnixNano() / 1000000)
|
fmt.Print(time.Now().UnixNano() / 1000000)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
|
@ -13,9 +12,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var output string
|
||||||
output string
|
|
||||||
)
|
|
||||||
|
|
||||||
// exportCmd represents the export command
|
// exportCmd represents the export command
|
||||||
var exportCmd = &cobra.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:
|
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
|
> 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,
|
Args: cobra.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
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{
|
env := &runtime.Terminal{
|
||||||
CmdFlags: &runtime.Flags{
|
CmdFlags: &runtime.Flags{
|
||||||
Config: configFlag,
|
Config: configFlag,
|
||||||
|
@ -45,15 +48,25 @@ Exports the ~/myconfig.omp.json config file to toml and prints the result to std
|
||||||
defer env.Close()
|
defer env.Close()
|
||||||
cfg := config.Load(env)
|
cfg := config.Load(env)
|
||||||
|
|
||||||
if len(output) == 0 && len(format) == 0 {
|
validateExportFormat := func() {
|
||||||
// usage error
|
format = strings.ToLower(format)
|
||||||
os.Exit(2)
|
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 {
|
||||||
if len(format) != 0 && !slices.Contains(formats, format) {
|
validateExportFormat()
|
||||||
// usage error
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(output) == 0 {
|
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 {
|
if len(format) == 0 {
|
||||||
format = strings.TrimPrefix(filepath.Ext(output), ".")
|
format = strings.TrimPrefix(filepath.Ext(output), ".")
|
||||||
}
|
validateExportFormat()
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Write(format)
|
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 {
|
func cleanOutputPath(path string, env runtime.Environment) string {
|
||||||
if strings.HasPrefix(path, "~") {
|
path = runtime.ReplaceTildePrefixWithHomeDir(env, path)
|
||||||
path = strings.TrimPrefix(path, "~")
|
|
||||||
path = filepath.Join(env.Home(), path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !filepath.IsAbs(path) {
|
if !filepath.IsAbs(path) {
|
||||||
if absPath, err := filepath.Abs(path); err == nil {
|
if absPath, err := filepath.Abs(path); err == nil {
|
||||||
|
|
34
src/cli/edit.go
Normal file
34
src/cli/edit.go
Normal 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()
|
||||||
|
}
|
|
@ -66,7 +66,6 @@ var printCmd = &cobra.Command{
|
||||||
Plain: plain,
|
Plain: plain,
|
||||||
Primary: args[0] == "primary",
|
Primary: args[0] == "primary",
|
||||||
Cleared: cleared,
|
Cleared: cleared,
|
||||||
Cached: cached,
|
|
||||||
NoExitCode: noStatus,
|
NoExitCode: noStatus,
|
||||||
Column: column,
|
Column: column,
|
||||||
JobCount: jobCount,
|
JobCount: jobCount,
|
||||||
|
|
|
@ -98,7 +98,6 @@ type Flags struct {
|
||||||
HasTransient bool
|
HasTransient bool
|
||||||
PromptCount int
|
PromptCount int
|
||||||
Cleared bool
|
Cleared bool
|
||||||
Cached bool
|
|
||||||
NoExitCode bool
|
NoExitCode bool
|
||||||
Column int
|
Column int
|
||||||
JobCount int
|
JobCount int
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (term *Terminal) Init() {
|
||||||
term.deviceCache = initCache(cache.FileName)
|
term.deviceCache = initCache(cache.FileName)
|
||||||
term.sessionCache = initCache(cache.SessionFileName)
|
term.sessionCache = initCache(cache.SessionFileName)
|
||||||
|
|
||||||
term.resolveConfigPath()
|
term.ResolveConfigPath()
|
||||||
|
|
||||||
term.cmdCache = &cache.Command{
|
term.cmdCache = &cache.Command{
|
||||||
Commands: maps.NewConcurrent(),
|
Commands: maps.NewConcurrent(),
|
||||||
|
@ -82,12 +82,10 @@ func (term *Terminal) Init() {
|
||||||
|
|
||||||
term.tmplCache = &cache.Template{}
|
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())
|
defer term.Trace(time.Now())
|
||||||
|
|
||||||
// if the config flag is set, we'll use that over POSH_THEME
|
// if the config flag is set, we'll use that over POSH_THEME
|
||||||
|
@ -129,11 +127,7 @@ func (term *Terminal) resolveConfigPath() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
configFile := term.CmdFlags.Config
|
configFile := ReplaceTildePrefixWithHomeDir(term, term.CmdFlags.Config)
|
||||||
if strings.HasPrefix(configFile, "~") {
|
|
||||||
configFile = strings.TrimPrefix(configFile, "~")
|
|
||||||
configFile = filepath.Join(term.Home(), configFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
abs, err := filepath.Abs(configFile)
|
abs, err := filepath.Abs(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -726,11 +720,14 @@ func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, element := range regexes {
|
for _, element := range regexes {
|
||||||
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
|
normalized := strings.ReplaceAll(element, "\\\\", "/")
|
||||||
if strings.HasPrefix(normalizedElement, "~") {
|
if strings.HasPrefix(normalized, "~") {
|
||||||
normalizedElement = strings.Replace(normalizedElement, "~", home, 1)
|
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 {
|
if goos == WINDOWS || goos == DARWIN {
|
||||||
pattern = "(?i)" + pattern
|
pattern = "(?i)" + pattern
|
||||||
}
|
}
|
||||||
|
@ -843,9 +840,19 @@ func Base(env Environment, path string) string {
|
||||||
return path
|
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 {
|
func ReplaceHomeDirPrefixWithTilde(env Environment, path string) string {
|
||||||
home := env.Home()
|
home := env.Home()
|
||||||
// match Home directory exactly
|
|
||||||
if !strings.HasPrefix(path, home) {
|
if !strings.HasPrefix(path, home) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
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`.
|
name. The following will match `/Users/posh/Projects/Foo` but not `/home/Users/posh/Projects/Foo`.
|
||||||
|
|
||||||
```json
|
```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
|
- 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.
|
is used by the current operating system.
|
||||||
- Because the strings are evaluated as regular expressions, if you want to use a `\` in a Windows
|
- 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 `\\\\`.
|
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 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.
|
- The comparison is case-insensitive on Windows and macOS, but case-sensitive on other operating systems.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue