From b4b0adb8c934be3645ae8885d51d48ed47f5cce9 Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Fri, 27 Jan 2023 14:29:22 +0100 Subject: [PATCH] feat: migrate v3 Nerd Font glyphs --- .vscode/launch.json | 22 +++++++++--- src/cli/config_migrate.go | 5 +-- src/cli/config_migrate_glyphs.go | 60 +++++++++++++++++++++++++++++++ src/engine/config.go | 24 +++++++++---- src/engine/config_test.go | 2 +- src/engine/migrate_glyphs.go | 52 +++++++++++++++++++++++++++ src/engine/migrate_glyphs_test.go | 12 +++++++ website/docs/faq.mdx | 14 ++++++++ 8 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 src/cli/config_migrate_glyphs.go create mode 100644 src/engine/migrate_glyphs.go create mode 100644 src/engine/migrate_glyphs_test.go diff --git a/.vscode/launch.json b/.vscode/launch.json index e793e955ea58..736ce94eaaae 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Debug Prompt", + "name": "Primary", "type": "go", "request": "launch", "mode": "debug", @@ -16,7 +16,7 @@ ] }, { - "name": "Debug Tooltip", + "name": "Tooltip", "type": "go", "request": "launch", "mode": "debug", @@ -30,7 +30,7 @@ ] }, { - "name": "Debug Transient", + "name": "Transient", "type": "go", "request": "launch", "mode": "debug", @@ -54,7 +54,7 @@ ] }, { - "name": "Print debug", + "name": "Debug", "type": "go", "request": "launch", "mode": "debug", @@ -65,7 +65,7 @@ ] }, { - "name": "Print init", + "name": "Init", "type": "go", "request": "launch", "mode": "debug", @@ -100,6 +100,18 @@ "migrate" ] }, + { + "name": "Migrate glyphs", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceRoot}/src", + "args": [ + "config", + "migrate", + "glyphs" + ] + }, { "name": "Get value", "type": "go", diff --git a/src/cli/config_migrate.go b/src/cli/config_migrate.go index e0c6be78a998..ed71cc4846fa 100644 --- a/src/cli/config_migrate.go +++ b/src/cli/config_migrate.go @@ -30,11 +30,12 @@ Migrates the ~/myconfig.omp.json config file and prints the result to stdout. > oh-my-posh config migrate --config ~/myconfig.omp.json --format toml -Migrates the ~/myconfig.omp.json config file to toml and prints the result to stdout. +Migrates the ~/myconfig.omp.json config file to TOML and prints the result to stdout. > oh-my-posh config migrate --config ~/myconfig.omp.json --format toml --write -Migrates the ~/myconfig.omp.json config file to toml and writes the result to your config file. +Migrates the ~/myconfig.omp.json config file to TOML and writes the result to your config file. + A backup of the current config can be found at ~/myconfig.omp.json.bak.`, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { diff --git a/src/cli/config_migrate_glyphs.go b/src/cli/config_migrate_glyphs.go new file mode 100644 index 000000000000..4ea37ec1c70e --- /dev/null +++ b/src/cli/config_migrate_glyphs.go @@ -0,0 +1,60 @@ +package cli + +import ( + "fmt" + + "github.com/jandedobbeleer/oh-my-posh/src/engine" + "github.com/jandedobbeleer/oh-my-posh/src/platform" + + "github.com/spf13/cobra" +) + +// migrateCmd represents the migrate command +var migrateGlyphsCmd = &cobra.Command{ + Use: "glyphs", + Short: "Migrate the nerd font glyphs in your config", + Long: `Migrate the nerd font glyphs in your config. + +You can choose to print the output to stdout, or migrate your config in the format of your choice. + +Example usage + +> oh-my-posh config migrate glyphs --config ~/myconfig.omp.json + +Migrates the ~/myconfig.omp.json config file's glyphs and prints the result to stdout. + +> oh-my-posh config migrate glyphs --config ~/myconfig.omp.json --format toml + +Migrates the ~/myconfig.omp.json config file's glyphs and prints the result to stdout in a TOML format. + +> oh-my-posh config migrate glyphs --config ~/myconfig.omp.json --format toml --write + +Migrates the ~/myconfig.omp.json config file's glyphs and writes the result to your config file in a TOML format. + +A backup of the current config can be found at ~/myconfig.omp.json.bak.`, + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + env := &platform.Shell{ + Version: cliVersion, + CmdFlags: &platform.Flags{ + Config: config, + }, + } + env.Init() + defer env.Close() + cfg := engine.LoadConfig(env) + cfg.MigrateGlyphs = true + if write { + cfg.Backup() + cfg.Write(format) + return + } + fmt.Print(cfg.Export(format)) + }, +} + +func init() { //nolint:gochecknoinits + migrateGlyphsCmd.Flags().BoolVarP(&write, "write", "w", false, "write the migrated config back to the config file") + migrateGlyphsCmd.Flags().StringVarP(&format, "format", "f", "json", "the config format to migrate to") + migrateCmd.AddCommand(migrateGlyphsCmd) +} diff --git a/src/engine/config.go b/src/engine/config.go index d53ea1f4fa11..fb0cbc4f1f0f 100644 --- a/src/engine/config.go +++ b/src/engine/config.go @@ -53,7 +53,8 @@ type Config struct { // Deprecated OSC99 bool `json:"osc99,omitempty"` - Output string `json:"-"` + Output string `json:"-"` + MigrateGlyphs bool `json:"-"` format string origin string @@ -177,7 +178,7 @@ func (cfg *Config) Export(format string) string { _ = jsonEncoder.Encode(cfg) prefix := "{\n \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\"," data := strings.Replace(result.String(), "{", prefix, 1) - return escapeGlyphs(data) + return escapeGlyphs(data, cfg.MigrateGlyphs) } _, _ = config.DumpTo(&result, cfg.format) @@ -187,14 +188,14 @@ func (cfg *Config) Export(format string) string { return prefix + result.String() case TOML: prefix := "#:schema https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\n\n" - return prefix + escapeGlyphs(result.String()) + return prefix + escapeGlyphs(result.String(), cfg.MigrateGlyphs) default: return result.String() } } func (cfg *Config) BackupAndMigrate(env platform.Environment) { - cfg.backup() + cfg.Backup() cfg.Migrate(env) cfg.Write(cfg.format) } @@ -216,7 +217,7 @@ func (cfg *Config) Write(format string) { _ = f.Close() } -func (cfg *Config) backup() { +func (cfg *Config) Backup() { dst := cfg.origin + ".bak" source, err := os.Open(cfg.origin) if err != nil { @@ -234,7 +235,7 @@ func (cfg *Config) backup() { } } -func escapeGlyphs(s string) string { +func escapeGlyphs(s string, migrate bool) string { shouldExclude := func(r rune) bool { if r < 0x1000 { // Basic Multilingual Plane return true @@ -266,6 +267,11 @@ func escapeGlyphs(s string) string { return false } + var cp codePoints + if migrate { + cp = getGlyphCodePoints() + } + var builder strings.Builder for _, r := range s { // exclude regular characters and emojis @@ -274,6 +280,12 @@ func escapeGlyphs(s string) string { continue } + if migrate { + if val, OK := cp[int(r)]; OK { + r = rune(val) + } + } + if r > 0x10000 { // calculate surrogate pairs one := 0xd800 + (((r - 0x10000) >> 10) & 0x3ff) diff --git a/src/engine/config_test.go b/src/engine/config_test.go index fd69d02f7e7f..1e4f1da530a9 100644 --- a/src/engine/config_test.go +++ b/src/engine/config_test.go @@ -57,7 +57,7 @@ func TestEscapeGlyphs(t *testing.T) { {Input: "🏚", Expected: "🏚"}, } for _, tc := range cases { - assert.Equal(t, tc.Expected, escapeGlyphs(tc.Input), tc.Input) + assert.Equal(t, tc.Expected, escapeGlyphs(tc.Input, false), tc.Input) } } diff --git a/src/engine/migrate_glyphs.go b/src/engine/migrate_glyphs.go new file mode 100644 index 000000000000..3ab4dcb589c4 --- /dev/null +++ b/src/engine/migrate_glyphs.go @@ -0,0 +1,52 @@ +package engine + +import ( + "context" + "encoding/csv" + "net/http" + "strconv" + "time" +) + +type codePoints map[int]int + +func getGlyphCodePoints() codePoints { + var codePoints = make(codePoints) + + client := &http.Client{} + ctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) + defer cncl() + + request, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://ohmyposh.dev/codepoints.csv", nil) + if err != nil { + return codePoints + } + + response, err := client.Do(request) + if err != nil { + return codePoints + } + + defer response.Body.Close() + + lines, err := csv.NewReader(response.Body).ReadAll() + if err != nil { + return codePoints + } + + for _, line := range lines { + if len(line) < 2 { + continue + } + oldGlyph, err := strconv.ParseUint(line[0], 16, 32) + if err != nil { + continue + } + newGlyph, err := strconv.ParseUint(line[1], 16, 32) + if err != nil { + continue + } + codePoints[int(oldGlyph)] = int(newGlyph) + } + return codePoints +} diff --git a/src/engine/migrate_glyphs_test.go b/src/engine/migrate_glyphs_test.go new file mode 100644 index 000000000000..ef6b63505871 --- /dev/null +++ b/src/engine/migrate_glyphs_test.go @@ -0,0 +1,12 @@ +package engine + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetCodePoints(t *testing.T) { + codepoints := getGlyphCodePoints() + assert.Equal(t, 1939, len(codepoints)) +} diff --git a/website/docs/faq.mdx b/website/docs/faq.mdx index 2f6efdb814eb..b740502ce370 100644 --- a/website/docs/faq.mdx +++ b/website/docs/faq.mdx @@ -223,6 +223,20 @@ setopt appendhistory You should update fish to v3.4.0 or higher. Fish supports `$(...)` and `"$(...)"` since v3.4.0, as described in its [changelog][fish-changelog]. +### After updating my Nerd Font to a newer version, the prompt displays unknown characters + +Nerd Fonts moved the icons to a different location in the font for v3. +This can cause the prompt to display unknown characters. There's a built-in migration in Oh My Posh to fix this. + +To migrate, run the following command: + +```bash +oh-my-posh config migrate glyphs --write +``` + +This will update your configuration file to use the new glyph locations. Do know they might look different, as they also +updated the icons themselves. A backup of the current config can be found in the same location with a `.bak` extension. + [exclusion]: https://support.microsoft.com/en-us/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26 [arch-terminfo]: https://wiki.archlinux.org/title/Bash/Prompt_customization#Terminfo_escape_sequences [ps-ansi-docs]: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_ansi_terminals?view=powershell-7.2