Standardize config fetching

This commit is contained in:
2026-05-03 14:55:06 +03:00
parent 18462d1df9
commit 811a8f7ee9
7 changed files with 118 additions and 135 deletions
+15 -42
View File
@@ -3,8 +3,6 @@ package main
import (
"log"
"os"
"path/filepath"
"runtime"
"gopkg.in/yaml.v3"
)
@@ -21,7 +19,7 @@ type TyperConfig struct {
var Config TyperConfig
func readConfig() {
func readMainConfig() {
Config = TyperConfig{
SelectedStyle: "default",
FallbackStyle: "default-fallback",
@@ -32,49 +30,24 @@ func readConfig() {
TabIndentation: 4,
}
homeDir, err := os.UserHomeDir()
// Get main config path
mainConfigPath := GetConfigPath("config.yml")
// Ensure config exists at path
if mainConfigPath == "" {
log.Fatalf("config.yml not found in any config directory")
}
// Read config file
data, err := os.ReadFile(mainConfigPath)
if err != nil {
log.Fatalf("Could not get home directory: %s", err)
log.Fatalf("Could not read config.yml: %s", err)
}
execPath, err := os.Executable()
// Unmarshal contents into struct
err = yaml.Unmarshal(data, &Config)
if err != nil {
log.Fatalf("Could not get path to executable: %s", err)
}
configPaths := make([]string, 0)
switch runtime.GOOS {
case "windows":
configPaths = append(configPaths, filepath.Join(homeDir, "AppData/Roaming/Typer/config.yml"))
configPaths = append(configPaths, filepath.Join(filepath.Dir(execPath), "etc/typer/config.yml"))
case "darwin":
configPaths = append(configPaths, filepath.Join(homeDir, "Library/Typer/config.yml"))
configPaths = append(configPaths, "/Library/Typer/config.yml")
configPaths = append(configPaths, filepath.Join(sysconfdir, "typer/config.yml"))
default:
configPaths = append(configPaths, filepath.Join(homeDir, ".config/typer/config.yml"))
configPaths = append(configPaths, filepath.Join(sysconfdir, "typer/config.yml"))
}
for _, configPath := range configPaths {
// Ensure config exists at path
if _, err := os.Stat(configPath); err != nil {
continue
}
// Read config file
data, err := os.ReadFile(configPath)
if err != nil {
log.Fatalf("Could not read config.yml: %s", err)
}
// Unmarshal contents into struct
err = yaml.Unmarshal(data, &Config)
if err != nil {
log.Fatalf("Could not unmarshal config.yml: %s", err)
}
break
log.Fatalf("Could not unmarshal config.yml: %s", err)
}
// Validate config options
+1
View File
@@ -9,6 +9,7 @@ require (
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.10 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
+2
View File
@@ -11,6 +11,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+15 -42
View File
@@ -3,8 +3,6 @@ package main
import (
"log"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/gdamore/tcell/v2"
@@ -23,54 +21,29 @@ type Keybinding struct {
var Keybindings TyperKeybindings
func readKeybindings() {
func readKeybindingsConfig() {
Keybindings = TyperKeybindings{
Keybindings: make([]Keybinding, 0),
}
homeDir, err := os.UserHomeDir()
// Get keybindings config path
keybindingsConfigPath := GetConfigPath("keybindings.yml")
// Ensure config exists at path
if keybindingsConfigPath == "" {
log.Fatalf("keybindings.yml not found in any config directory")
}
// Read config file
data, err := os.ReadFile(keybindingsConfigPath)
if err != nil {
log.Fatalf("Could not get home directory: %s", err)
log.Fatalf("Could not read keybindings.yml: %s", err)
}
execPath, err := os.Executable()
// Unmarshal contents into struct
err = yaml.Unmarshal(data, &Keybindings)
if err != nil {
log.Fatalf("Could not get path to executable: %s", err)
}
configPaths := make([]string, 0)
switch runtime.GOOS {
case "windows":
configPaths = append(configPaths, filepath.Join(homeDir, "AppData/Roaming/Typer/keybindings.yml"))
configPaths = append(configPaths, filepath.Join(filepath.Dir(execPath), "etc/typer/keybindings.yml"))
case "darwin":
configPaths = append(configPaths, filepath.Join(homeDir, "Library/Typer/keybindings.yml"))
configPaths = append(configPaths, "/Library/Typer/keybindings.yml")
configPaths = append(configPaths, filepath.Join(sysconfdir, "typer/keybindings.yml"))
default:
configPaths = append(configPaths, filepath.Join(homeDir, ".config/typer/keybindings.yml"))
configPaths = append(configPaths, filepath.Join(sysconfdir, "typer/keybindings.yml"))
}
for _, configPath := range configPaths {
// Ensure config exists at path
if _, err := os.Stat(configPath); err != nil {
continue
}
// Read config file
data, err := os.ReadFile(configPath)
if err != nil {
log.Fatalf("Could not read keybindings.yml: %s", err)
}
// Unmarshal contents into struct
err = yaml.Unmarshal(data, &Keybindings)
if err != nil {
log.Fatalf("Could not unmarshal keybindings.yml: %s", err)
}
break
log.Fatalf("Could not unmarshal keybindings.yml: %s", err)
}
}
+18 -8
View File
@@ -2,19 +2,25 @@ package main
import (
"log"
"os"
flag "github.com/spf13/pflag"
)
var sysconfdir = "/etc/"
var configDirFlag = flag.StringP("config", "c", "", "Path to config directory")
func main() {
// Read config
readConfig()
// Read flags
readFlags()
// Read key bindings
readKeybindings()
// Read main config
readMainConfig()
// Read styles
// Read keybindings config
readKeybindingsConfig()
// Read styles directory
readStyles()
// Initialize commands
@@ -25,8 +31,8 @@ func main() {
log.Fatalf("Failed to create window: %v", err)
}
if len(os.Args) > 1 {
for i, file := range os.Args[1:] {
if flag.NArg() > 0 {
for i, file := range flag.Args() {
b, err := CreateFileBuffer(file, true)
if err != nil {
window.PrintMessage("Could not open file: " + file)
@@ -48,3 +54,7 @@ func main() {
window.screen.Fini()
window.screen = nil
}
func readFlags() {
flag.Parse()
}
+18 -42
View File
@@ -6,7 +6,6 @@ import (
"os"
"path/filepath"
"reflect"
"runtime"
"slices"
"strconv"
"strings"
@@ -73,54 +72,31 @@ var AvailableStyles = make(map[string]TyperStyle)
var CurrentStyle = FallbackStyle
func readStyles() {
homeDir, err := os.UserHomeDir()
// Get styles directory path
stylesDirPath := GetConfigPath("styles")
// Ensure directory exists at path
if stat, err := os.Stat(stylesDirPath); stylesDirPath == "" || err != nil || !stat.IsDir() {
return
}
// Get directory entries
entries, err := os.ReadDir(stylesDirPath)
if err != nil {
log.Fatalf("Could not get home directory: %s", err)
log.Fatalf("Could not read user style directory: %s", err)
}
execPath, err := os.Executable()
if err != nil {
log.Fatalf("Could not get path to executable: %s", err)
}
// Read entries in directory
for _, entry := range entries {
entryPath := filepath.Join(stylesDirPath, entry.Name())
stylesPaths := make([]string, 0)
switch runtime.GOOS {
case "windows":
stylesPaths = append(stylesPaths, filepath.Join(homeDir, "AppData/Roaming/Typer/styles"))
stylesPaths = append(stylesPaths, filepath.Join(filepath.Dir(execPath), "config/styles"))
case "darwin":
stylesPaths = append(stylesPaths, filepath.Join(homeDir, "Library/Typer/styles"))
stylesPaths = append(stylesPaths, "/Library/Typer/styles")
stylesPaths = append(stylesPaths, filepath.Join(sysconfdir, "typer/styles"))
default:
stylesPaths = append(stylesPaths, filepath.Join(homeDir, ".config/typer/styles"))
stylesPaths = append(stylesPaths, filepath.Join(sysconfdir, "typer/styles"))
}
for _, stylesPath := range stylesPaths {
// Ensure directory exists at path
if stat, err := os.Stat(stylesPath); err != nil || !stat.IsDir() {
continue
}
// Get directory entries
entries, err := os.ReadDir(stylesPath)
style, err := readStyleYamlFile(entryPath)
if err != nil {
log.Fatalf("Could not read user style directory: %s", err)
log.Fatalf("Could not read style file (%s): %s", entryPath, err)
}
// Read entries in directory
for _, entry := range entries {
entryPath := filepath.Join(stylesPath, entry.Name())
style, err := readStyleYamlFile(entryPath)
if err != nil {
log.Fatalf("Could not read style file (%s): %s", entryPath, err)
}
if _, ok := AvailableStyles[style.Name]; !ok {
AvailableStyles[style.Name] = style
}
if _, ok := AvailableStyles[style.Name]; !ok {
AvailableStyles[style.Name] = style
}
}
}
+49 -1
View File
@@ -1,6 +1,54 @@
package main
import "github.com/gdamore/tcell/v2"
import (
"log"
"os"
"path"
"path/filepath"
"runtime"
"github.com/gdamore/tcell/v2"
)
func GetConfigPath(relativeConfigPath string) string {
homeDir, err := os.UserHomeDir()
if err != nil {
log.Fatalf("Could not get home directory: %s", err)
}
execPath, err := os.Executable()
if err != nil {
log.Fatalf("Could not get path to executable: %s", err)
}
paths := make([]string, 0)
if *configDirFlag != "" {
paths = append(paths, path.Join(*configDirFlag, relativeConfigPath))
}
switch runtime.GOOS {
case "windows":
paths = append(paths, filepath.Join(homeDir, "AppData/Roaming/Typer", relativeConfigPath))
paths = append(paths, "C:/ProgramData/Typer", relativeConfigPath)
case "darwin":
paths = append(paths, filepath.Join(homeDir, "Library/Typer", relativeConfigPath))
paths = append(paths, filepath.Join(homeDir, "Library/typer", relativeConfigPath))
paths = append(paths, filepath.Join(sysconfdir, "Typer", relativeConfigPath))
paths = append(paths, filepath.Join(sysconfdir, "typer", relativeConfigPath))
default:
paths = append(paths, filepath.Join(homeDir, ".config/typer", relativeConfigPath))
paths = append(paths, filepath.Join(sysconfdir, "typer", relativeConfigPath))
}
paths = append(paths, filepath.Join(filepath.Dir(execPath), "config", relativeConfigPath))
for _, p := range paths {
// Return true if path exists
if _, err := os.Stat(p); err == nil {
return p
}
}
return ""
}
func drawText(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) {
row := y1