2022-01-26 23:38:46 -08:00
|
|
|
package engine
|
2019-03-13 04:14:30 -07:00
|
|
|
|
|
|
|
import (
|
2021-03-20 11:32:15 -07:00
|
|
|
"bytes"
|
|
|
|
json2 "encoding/json"
|
2020-11-11 09:52:45 -08:00
|
|
|
"errors"
|
2021-03-20 11:32:15 -07:00
|
|
|
"fmt"
|
2022-01-26 04:09:21 -08:00
|
|
|
"oh-my-posh/color"
|
2022-01-26 22:44:35 -08:00
|
|
|
"oh-my-posh/console"
|
2022-01-26 01:23:18 -08:00
|
|
|
"oh-my-posh/environment"
|
2019-03-13 04:14:30 -07:00
|
|
|
"os"
|
2022-01-31 04:33:36 -08:00
|
|
|
"path/filepath"
|
2021-03-27 04:04:43 -07:00
|
|
|
"strings"
|
2020-12-20 17:20:48 -08:00
|
|
|
|
2021-03-20 11:32:15 -07:00
|
|
|
"github.com/gookit/config/v2"
|
|
|
|
"github.com/gookit/config/v2/json"
|
|
|
|
"github.com/gookit/config/v2/toml"
|
|
|
|
"github.com/gookit/config/v2/yaml"
|
2021-06-08 11:16:55 -07:00
|
|
|
"github.com/mitchellh/mapstructure"
|
2019-03-13 04:14:30 -07:00
|
|
|
)
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
const (
|
|
|
|
JSON string = "json"
|
|
|
|
YAML string = "yaml"
|
|
|
|
TOML string = "toml"
|
2022-02-02 03:24:31 -08:00
|
|
|
|
|
|
|
configVersion = 1
|
2022-01-31 04:33:36 -08:00
|
|
|
)
|
|
|
|
|
2021-03-20 11:32:15 -07:00
|
|
|
// Config holds all the theme for rendering the prompt
|
|
|
|
type Config struct {
|
2022-02-02 03:24:31 -08:00
|
|
|
Version int `json:"version"`
|
2022-01-31 04:33:36 -08:00
|
|
|
FinalSpace bool `json:"final_space,omitempty"`
|
|
|
|
OSC99 bool `json:"osc99,omitempty"`
|
|
|
|
ConsoleTitle bool `json:"console_title,omitempty"`
|
|
|
|
ConsoleTitleStyle console.Style `json:"console_title_style,omitempty"`
|
|
|
|
ConsoleTitleTemplate string `json:"console_title_template,omitempty"`
|
|
|
|
TerminalBackground string `json:"terminal_background,omitempty"`
|
|
|
|
Blocks []*Block `json:"blocks,omitempty"`
|
|
|
|
Tooltips []*Segment `json:"tooltips,omitempty"`
|
|
|
|
TransientPrompt *TransientPrompt `json:"transient_prompt,omitempty"`
|
|
|
|
Palette color.Palette `json:"palette,omitempty"`
|
|
|
|
|
|
|
|
format string
|
|
|
|
origin string
|
|
|
|
eval bool
|
|
|
|
updated bool
|
2022-01-26 04:09:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// MakeColors creates instance of AnsiColors to use in AnsiWriter according to
|
|
|
|
// environment and configuration.
|
|
|
|
func (cfg *Config) MakeColors(env environment.Environment) color.AnsiColors {
|
|
|
|
cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1"
|
|
|
|
return color.MakeColors(cfg.Palette, !cacheDisabled)
|
2021-06-15 12:23:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type TransientPrompt struct {
|
2022-01-31 04:33:36 -08:00
|
|
|
Template string `json:"template,omitempty"`
|
|
|
|
Background string `json:"background,omitempty"`
|
|
|
|
Foreground string `json:"foreground,omitempty"`
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
func (cfg *Config) exitWithError(err error) {
|
|
|
|
if err == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer os.Exit(1)
|
|
|
|
if cfg.eval {
|
2021-09-09 11:02:00 -07:00
|
|
|
fmt.Println("echo \"Oh My Posh Error:\n\"", err.Error())
|
|
|
|
return
|
|
|
|
}
|
2021-05-18 11:31:12 -07:00
|
|
|
fmt.Println("Oh My Posh Error:\n", err.Error())
|
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
// LoadConfig returns the default configuration including possible user overrides
|
|
|
|
func LoadConfig(env environment.Environment) *Config {
|
|
|
|
cfg := loadConfig(env)
|
2022-02-02 04:40:58 -08:00
|
|
|
// only migrate automatically when the switch isn't set
|
|
|
|
if !*env.Args().Migrate && cfg.Version != configVersion {
|
2022-02-02 04:27:07 -08:00
|
|
|
cfg.Backup()
|
2022-02-02 03:24:31 -08:00
|
|
|
cfg.Migrate(env)
|
|
|
|
cfg.Write()
|
|
|
|
}
|
2021-03-20 11:32:15 -07:00
|
|
|
return cfg
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
func loadConfig(env environment.Environment) *Config {
|
2021-03-20 11:32:15 -07:00
|
|
|
var cfg Config
|
2022-01-23 12:37:51 -08:00
|
|
|
configFile := *env.Args().Config
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.eval = *env.Args().Eval
|
2021-03-20 11:32:15 -07:00
|
|
|
if configFile == "" {
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.exitWithError(errors.New("NO CONFIG"))
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
2021-03-20 11:32:15 -07:00
|
|
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.exitWithError(err)
|
2020-11-11 09:52:45 -08:00
|
|
|
}
|
2020-12-20 17:20:48 -08:00
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.origin = configFile
|
|
|
|
cfg.format = strings.TrimPrefix(filepath.Ext(configFile), ".")
|
|
|
|
|
2021-03-20 11:32:15 -07:00
|
|
|
config.AddDriver(yaml.Driver)
|
|
|
|
config.AddDriver(json.Driver)
|
|
|
|
config.AddDriver(toml.Driver)
|
|
|
|
config.WithOptions(func(opt *config.Options) {
|
2021-06-08 11:16:55 -07:00
|
|
|
opt.DecoderConfig = &mapstructure.DecoderConfig{
|
2022-01-31 04:33:36 -08:00
|
|
|
TagName: "json",
|
2021-06-08 11:16:55 -07:00
|
|
|
}
|
2021-03-20 11:32:15 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
err := config.LoadFiles(configFile)
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.exitWithError(err)
|
2020-12-20 17:20:48 -08:00
|
|
|
|
2021-03-20 11:32:15 -07:00
|
|
|
err = config.BindStruct("", &cfg)
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.exitWithError(err)
|
2021-03-20 11:32:15 -07:00
|
|
|
|
2021-06-15 12:23:08 -07:00
|
|
|
// initialize default values
|
|
|
|
if cfg.TransientPrompt == nil {
|
|
|
|
cfg.TransientPrompt = &TransientPrompt{}
|
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
return &cfg
|
2021-03-20 11:32:15 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
func (cfg *Config) sync() {
|
|
|
|
if !cfg.updated {
|
|
|
|
return
|
2021-03-20 11:32:15 -07:00
|
|
|
}
|
2022-01-31 04:33:36 -08:00
|
|
|
var structMap map[string]interface{}
|
|
|
|
inrec, _ := json2.Marshal(cfg)
|
|
|
|
_ = json2.Unmarshal(inrec, &structMap)
|
|
|
|
// remove empty structs
|
|
|
|
for k, v := range structMap {
|
|
|
|
if smap, OK := v.(map[string]interface{}); OK && len(smap) == 0 {
|
|
|
|
delete(structMap, k)
|
|
|
|
}
|
2021-03-20 11:32:15 -07:00
|
|
|
}
|
2022-01-31 04:33:36 -08:00
|
|
|
config.SetData(structMap)
|
|
|
|
}
|
2021-03-20 11:32:15 -07:00
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
func (cfg *Config) Export(format string) string {
|
|
|
|
cfg.sync()
|
2021-03-20 11:32:15 -07:00
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
if len(format) != 0 {
|
|
|
|
cfg.format = format
|
2021-03-20 11:32:15 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
config.AddDriver(yaml.Driver)
|
|
|
|
config.AddDriver(toml.Driver)
|
|
|
|
|
|
|
|
var result bytes.Buffer
|
|
|
|
|
|
|
|
if cfg.format == JSON {
|
|
|
|
data := config.Data()
|
|
|
|
data["$schema"] = "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json"
|
|
|
|
jsonEncoder := json2.NewEncoder(&result)
|
|
|
|
jsonEncoder.SetEscapeHTML(false)
|
|
|
|
jsonEncoder.SetIndent("", " ")
|
|
|
|
err := jsonEncoder.Encode(data)
|
|
|
|
cfg.exitWithError(err)
|
2022-02-01 07:40:15 -08:00
|
|
|
return escapeGlyphs(result.String())
|
2021-03-20 11:32:15 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
_, err := config.DumpTo(&result, cfg.format)
|
|
|
|
cfg.exitWithError(err)
|
|
|
|
var prefix string
|
|
|
|
switch cfg.format {
|
|
|
|
case YAML:
|
|
|
|
prefix = "# yaml-language-server: $schema=https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\n\n"
|
|
|
|
case TOML:
|
|
|
|
prefix = "#:schema https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\n\n"
|
|
|
|
}
|
2022-02-01 07:40:15 -08:00
|
|
|
return prefix + escapeGlyphs(result.String())
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 04:33:36 -08:00
|
|
|
func (cfg *Config) Write() {
|
2022-02-02 04:27:07 -08:00
|
|
|
cfg.write(cfg.origin)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cfg *Config) Backup() {
|
|
|
|
cfg.write(cfg.origin + ".bak")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cfg *Config) write(destination string) {
|
2022-01-31 04:33:36 -08:00
|
|
|
content := cfg.Export(cfg.format)
|
2022-02-02 04:27:07 -08:00
|
|
|
f, err := os.OpenFile(destination, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
2022-01-31 04:33:36 -08:00
|
|
|
cfg.exitWithError(err)
|
|
|
|
_, err = f.WriteString(content)
|
|
|
|
cfg.exitWithError(err)
|
|
|
|
if err := f.Close(); err != nil {
|
|
|
|
cfg.exitWithError(err)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
}
|
2022-02-01 07:40:15 -08:00
|
|
|
|
|
|
|
func escapeGlyphs(s string) string {
|
|
|
|
var builder strings.Builder
|
|
|
|
for _, r := range s {
|
|
|
|
if r < 0x1000 {
|
|
|
|
builder.WriteRune(r)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
quoted := fmt.Sprintf("\\u%04x", r)
|
|
|
|
builder.WriteString(quoted)
|
|
|
|
}
|
|
|
|
return builder.String()
|
|
|
|
}
|