oh-my-posh/src/main.go

325 lines
7.4 KiB
Go
Raw Normal View History

2019-03-13 04:14:30 -07:00
package main
import (
2021-02-27 07:41:50 -08:00
_ "embed"
2019-03-13 04:14:30 -07:00
"flag"
"fmt"
2022-01-26 04:09:21 -08:00
"oh-my-posh/color"
"oh-my-posh/environment"
"oh-my-posh/regex"
2020-12-22 10:31:20 -08:00
"os"
"strings"
"time"
2021-03-20 11:32:15 -07:00
"github.com/gookit/config/v2"
2019-03-13 04:14:30 -07:00
)
2020-11-22 06:02:50 -08:00
// Version number of oh-my-posh
var Version = "development"
2020-11-19 16:53:09 -08:00
2021-02-27 07:41:50 -08:00
//go:embed init/omp.ps1
var pwshInit string
//go:embed init/omp.fish
var fishInit string
//go:embed init/omp.bash
var bashInit string
//go:embed init/omp.zsh
var zshInit string
2021-11-13 04:30:41 -08:00
//go:embed init/omp.lua
var cmdInit string
2020-12-22 10:31:20 -08:00
const (
2022-01-26 04:09:21 -08:00
noExe = "echo \"Unable to find Oh My Posh executable\""
2020-12-23 04:48:14 -08:00
zsh = "zsh"
bash = "bash"
pwsh = "pwsh"
fish = "fish"
powershell5 = "powershell"
2021-11-13 04:30:41 -08:00
winCMD = "cmd"
plain = "shell"
2020-12-22 10:31:20 -08:00
)
2019-03-13 04:14:30 -07:00
func main() {
args := &environment.Args{
2019-03-13 04:14:30 -07:00
ErrorCode: flag.Int(
"error",
0,
"Error code of previously executed command"),
PrintConfig: flag.Bool(
"print-config",
false,
2020-11-03 06:07:58 -08:00
"Print the current config in json format"),
2021-03-20 11:32:15 -07:00
ConfigFormat: flag.String(
"config-format",
config.JSON,
"The format to print the config in. Valid options are:\n- json\n- yaml\n- toml\n"),
2020-11-03 06:07:58 -08:00
PrintShell: flag.Bool(
"print-shell",
false,
"Print the current shell name"),
2019-03-13 04:14:30 -07:00
Config: flag.String(
"config",
"",
"Add the path to a configuration you wish to load"),
Shell: flag.String(
"shell",
"",
"Override the shell you are working in"),
PWD: flag.String(
"pwd",
"",
"the path you are working in"),
PSWD: flag.String(
"pswd",
"",
"the powershell path you are working in, useful when working with drives"),
2020-11-19 16:53:09 -08:00
Version: flag.Bool(
"version",
false,
"Print the current version of the binary"),
Debug: flag.Bool(
"debug",
false,
"Print debug information"),
2020-12-06 13:03:40 -08:00
ExecutionTime: flag.Float64(
"execution-time",
0,
"Execution time of the previously executed command"),
Millis: flag.Bool(
"millis",
false,
"Get the current time in milliseconds"),
2020-12-17 23:59:45 -08:00
Eval: flag.Bool(
"eval",
false,
"Run in eval mode"),
2020-12-22 10:31:20 -08:00
Init: flag.Bool(
"init",
false,
"Initialize the shell"),
PrintInit: flag.Bool(
"print-init",
false,
"Print the shell initialization script"),
ExportPNG: flag.Bool(
"export-png",
false,
"Create an image based on the current configuration"),
Author: flag.String(
"author",
"",
"Add the author to the exported image using --export-img"),
CursorPadding: flag.Int(
"cursor-padding",
30,
"Pad the cursor with x when using --export-img"),
RPromptOffset: flag.Int(
"rprompt-offset",
40,
"Offset the right prompt with x when using --export-img"),
2021-11-13 10:35:15 -08:00
RPrompt: flag.Bool(
"rprompt",
false,
"Only print the rprompt block"),
2021-09-17 11:34:43 -07:00
BGColor: flag.String(
"bg-color",
"#151515",
"Set the background color when using --export-img"),
StackCount: flag.Int(
"stack-count",
0,
"The current location stack count"),
2021-06-15 12:23:08 -07:00
Command: flag.String(
"command",
2021-06-05 07:14:44 -07:00
"",
2021-06-15 12:23:08 -07:00
"Render a tooltip based on the command value"),
PrintTransient: flag.Bool(
"print-transient",
false,
"Print the transient prompt"),
2021-11-02 06:53:46 -07:00
Plain: flag.Bool(
"plain",
false,
"Print a plain prompt without ANSI"),
2022-01-16 05:34:05 -08:00
CachePath: flag.Bool(
"cache-path",
false,
"Print the location of the cache"),
2019-03-13 04:14:30 -07:00
}
flag.Parse()
2021-12-30 13:23:45 -08:00
if *args.Version {
fmt.Println(Version)
return
}
env := &environment.ShellEnvironment{}
env.Init(args)
defer env.Close()
2021-12-30 13:23:45 -08:00
if *args.PrintShell {
fmt.Println(env.Shell())
2021-12-30 13:23:45 -08:00
return
}
if *args.Millis {
fmt.Print(time.Now().UnixNano() / 1000000)
return
}
2022-01-16 05:34:05 -08:00
if *args.CachePath {
fmt.Print(env.CachePath())
2022-01-16 05:34:05 -08:00
return
}
2020-12-22 10:31:20 -08:00
if *args.Init {
init := initShell(*args.Shell, *args.Config)
fmt.Print(init)
return
}
if *args.PrintInit {
init := printShellInit(*args.Shell, *args.Config)
fmt.Print(init)
return
}
2019-03-13 04:14:30 -07:00
if *args.PrintConfig {
2021-03-20 11:32:15 -07:00
fmt.Print(exportConfig(*args.Config, *args.ConfigFormat))
2019-03-13 04:14:30 -07:00
return
}
2021-03-20 11:32:15 -07:00
cfg := GetConfig(env)
2022-01-26 04:09:21 -08:00
ansi := &color.Ansi{}
ansi.Init(env.Shell())
var writer color.Writer
2021-11-02 06:53:46 -07:00
if *args.Plain {
2022-01-26 04:09:21 -08:00
writer = &color.PlainWriter{}
2021-11-02 06:53:46 -07:00
} else {
2022-01-26 04:09:21 -08:00
writerColors := cfg.MakeColors(env)
writer = &color.AnsiWriter{
Ansi: ansi,
TerminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors,
2021-11-02 06:53:46 -07:00
}
2020-12-17 23:59:45 -08:00
}
2020-12-26 10:51:21 -08:00
title := &consoleTitle{
2021-04-20 12:30:46 -07:00
env: env,
config: cfg,
ansi: ansi,
2020-12-26 10:51:21 -08:00
}
engine := &engine{
2021-03-20 11:32:15 -07:00
config: cfg,
2020-12-26 10:51:21 -08:00
env: env,
2021-11-02 06:53:46 -07:00
writer: writer,
2020-12-26 10:51:21 -08:00
consoleTitle: title,
2021-04-20 12:30:46 -07:00
ansi: ansi,
2021-11-02 06:53:46 -07:00
plain: *args.Plain,
2019-03-13 04:14:30 -07:00
}
if *args.Debug {
fmt.Print(engine.debug())
return
}
2021-06-15 12:23:08 -07:00
if *args.PrintTransient {
fmt.Print(engine.renderTransientPrompt())
2021-06-15 12:23:08 -07:00
return
}
if len(*args.Command) != 0 {
fmt.Print(engine.renderTooltip(*args.Command))
2021-06-05 07:14:44 -07:00
return
}
2021-11-13 10:35:15 -08:00
if *args.RPrompt {
fmt.Print(engine.renderRPrompt())
return
}
prompt := engine.render()
if !*args.ExportPNG {
fmt.Print(prompt)
2020-12-29 00:13:56 -08:00
return
}
imageCreator := &ImageRenderer{
ansiString: prompt,
author: *args.Author,
cursorPadding: *args.CursorPadding,
rPromptOffset: *args.RPromptOffset,
2021-09-17 11:34:43 -07:00
bgColor: *args.BGColor,
2021-04-20 12:30:46 -07:00
ansi: ansi,
}
imageCreator.init()
match := regex.FindNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, *args.Config)
2021-05-21 11:01:08 -07:00
err := imageCreator.SavePNG(fmt.Sprintf("%s.png", match[str]))
if err != nil {
fmt.Print(err.Error())
}
2019-03-13 04:14:30 -07:00
}
2020-12-22 10:31:20 -08:00
func getExecutablePath(shell string) (string, error) {
2020-12-22 10:31:20 -08:00
executable, err := os.Executable()
if err != nil {
return "", err
}
// On Windows, it fails when the excutable is called in MSYS2 for example
// which uses unix style paths to resolve the executable's location.
// PowerShell knows how to resolve both, so we can swap this without any issue.
executable = strings.ReplaceAll(executable, "\\", "/")
switch shell {
case bash, zsh:
return strings.ReplaceAll(executable, " ", "\\ "), nil
}
return executable, nil
}
func initShell(shell, configFile string) string {
executable, err := getExecutablePath(shell)
2020-12-22 10:31:20 -08:00
if err != nil {
return noExe
}
switch shell {
2021-12-01 10:25:05 -08:00
case pwsh, powershell5:
return fmt.Sprintf("(@(&\"%s\" --print-init --shell=%s --config=\"%s\") -join \"`n\") | Invoke-Expression", executable, shell, configFile)
2021-11-13 04:30:41 -08:00
case zsh, bash, fish, winCMD:
2021-03-20 11:32:15 -07:00
return printShellInit(shell, configFile)
2020-12-22 10:31:20 -08:00
default:
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
}
}
2021-03-20 11:32:15 -07:00
func printShellInit(shell, configFile string) string {
executable, err := getExecutablePath(shell)
2020-12-22 10:31:20 -08:00
if err != nil {
return noExe
}
switch shell {
2021-12-01 10:25:05 -08:00
case pwsh, powershell5:
2021-03-20 11:32:15 -07:00
return getShellInitScript(executable, configFile, pwshInit)
2020-12-23 04:00:50 -08:00
case zsh:
2021-03-20 11:32:15 -07:00
return getShellInitScript(executable, configFile, zshInit)
2020-12-23 04:12:10 -08:00
case bash:
2021-03-20 11:32:15 -07:00
return getShellInitScript(executable, configFile, bashInit)
2020-12-23 04:48:14 -08:00
case fish:
2021-03-20 11:32:15 -07:00
return getShellInitScript(executable, configFile, fishInit)
2021-11-13 04:30:41 -08:00
case winCMD:
return getShellInitScript(executable, configFile, cmdInit)
2020-12-22 10:31:20 -08:00
default:
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
}
}
2021-03-20 11:32:15 -07:00
func getShellInitScript(executable, configFile, script string) string {
2021-02-27 07:41:50 -08:00
script = strings.ReplaceAll(script, "::OMP::", executable)
2021-03-20 11:32:15 -07:00
script = strings.ReplaceAll(script, "::CONFIG::", configFile)
2021-02-27 07:41:50 -08:00
return script
2020-12-22 10:31:20 -08:00
}
func getConsoleBackgroundColor(env environment.Environment, backgroundColorTemplate string) string {
if len(backgroundColorTemplate) == 0 {
return backgroundColorTemplate
}
template := &textTemplate{
Template: backgroundColorTemplate,
2022-01-18 00:48:47 -08:00
Context: nil,
Env: env,
}
2021-04-11 06:24:03 -07:00
text, err := template.render()
if err != nil {
return err.Error()
}
return text
}