package config import ( "fmt" "os" "strings" "github.com/BurntSushi/toml" ) type FocusBehaviour string const ( FocusFirstNonCached FocusBehaviour = "default" FocusNone FocusBehaviour = "no-focus" FocusEnvironment FocusBehaviour = "environment" FocusUsername FocusBehaviour = "username" FocusPassword FocusBehaviour = "password" ) type ShellLoginFlag string const ( ShellLoginNone ShellLoginFlag = "none" ShellLoginShort ShellLoginFlag = "short" ShellLoginLong ShellLoginFlag = "long" ) type BackgroundStyle struct { Color string `toml:"color"` ShowBorder bool `toml:"show_border"` BorderColor string `toml:"border_color"` } type BackgroundConfig struct { ShowBackground bool `toml:"show_background"` Style BackgroundStyle `toml:"style"` } type PowerControl struct { Hint string `toml:"hint"` HintColor string `toml:"hint_color"` HintModifiers string `toml:"hint_modifiers"` Key string `toml:"key"` Cmd string `toml:"cmd"` } type PowerControlConfig struct { HintMargin uint16 `toml:"hint_margin"` BaseEntries []PowerControl `toml:"base_entries"` Entries []PowerControl `toml:"entries"` } type SwitcherConfig struct { SwitcherVisibility string `toml:"switcher_visibility"` ToggleHint string `toml:"toggle_hint"` ToggleHintColor string `toml:"toggle_hint_color"` ToggleHintModifiers string `toml:"toggle_hint_modifiers"` IncludeTTYShell bool `toml:"include_tty_shell"` Remember bool `toml:"remember"` ShowMovers bool `toml:"show_movers"` MoverColor string `toml:"mover_color"` MoverColorFocused string `toml:"mover_color_focused"` MoverModifiers string `toml:"mover_modifiers"` MoverModifiersFocused string `toml:"mover_modifiers_focused"` LeftMover string `toml:"left_mover"` RightMover string `toml:"right_mover"` MoverMargin uint16 `toml:"mover_margin"` ShowNeighbours bool `toml:"show_neighbours"` NeighbourColor string `toml:"neighbour_color"` NeighbourColorFocused string `toml:"neighbour_color_focused"` NeighbourModifiers string `toml:"neighbour_modifiers"` NeighbourModifiersFocused string `toml:"neighbour_modifiers_focused"` NeighbourMargin uint16 `toml:"neighbour_margin"` SelectedColor string `toml:"selected_color"` SelectedColorFocused string `toml:"selected_color_focused"` SelectedModifiers string `toml:"selected_modifiers"` SelectedModifiersFocused string `toml:"selected_modifiers_focused"` MaxDisplayLength uint16 `toml:"max_display_length"` NoEnvsText string `toml:"no_envs_text"` NoEnvsColor string `toml:"no_envs_color"` NoEnvsColorFocused string `toml:"no_envs_color_focused"` NoEnvsModifiers string `toml:"no_envs_modifiers"` NoEnvsModifiersFocused string `toml:"no_envs_modifiers_focused"` } type InputFieldStyle struct { ShowTitle bool `toml:"show_title"` Title string `toml:"title"` ShowBorder bool `toml:"show_border"` TitleColor string `toml:"title_color"` TitleColorFocused string `toml:"title_color_focused"` ContentColor string `toml:"content_color"` ContentColorFocused string `toml:"content_color_focused"` BorderColor string `toml:"border_color"` BorderColorFocused string `toml:"border_color_focused"` UseMaxWidth bool `toml:"use_max_width"` MaxWidth uint16 `toml:"max_width"` } type UsernameFieldConfig struct { Remember bool `toml:"remember"` Style InputFieldStyle `toml:"style"` } type PasswordFieldConfig struct { ReplacementChar string `toml:"content_replacement_character"` Style InputFieldStyle `toml:"style"` } type X11Config struct { Display string `toml:"x11_display"` ServerTimeoutSecs uint16 `toml:"xserver_timeout_secs"` ServerLogPath string `toml:"xserver_log_path"` ServerPath string `toml:"xserver_path"` XauthPath string `toml:"xauth_path"` ScriptsPath string `toml:"scripts_path"` SetupPath string `toml:"xsetup_path"` SessionsPath string `toml:"xsessions_path"` } type WaylandConfig struct { ScriptsPath string `toml:"scripts_path"` SessionsPath string `toml:"wayland_sessions_path"` } type Config struct { TTY uint8 `toml:"tty"` MainLogPath string `toml:"main_log_path"` ClientLogPath string `toml:"client_log_path"` CachePath string `toml:"cache_path"` DoLog bool `toml:"do_log"` PAMService string `toml:"pam_service"` SystemShell string `toml:"system_shell"` InitialPath string `toml:"initial_path"` ShellLoginFlag ShellLoginFlag `toml:"shell_login_flag"` FocusBehaviour FocusBehaviour `toml:"focus_behaviour"` Background BackgroundConfig `toml:"background"` PowerControls PowerControlConfig `toml:"power_controls"` Switcher SwitcherConfig `toml:"environment_switcher"` Username UsernameFieldConfig `toml:"username_field"` Password PasswordFieldConfig `toml:"password_field"` X11 X11Config `toml:"x11"` Wayland WaylandConfig `toml:"wayland"` } func Default() Config { var c Config if err := toml.Unmarshal([]byte(defaultTOML), &c); err != nil { panic("default config: " + err.Error()) } return c } func LoadPartial(filename string, vars map[string]string, dst *Config) error { raw, err := os.ReadFile(filename) if err != nil { return fmt.Errorf("read %s: %w", filename, err) } if vars != nil { raw = []byte(resolveVars(string(raw), vars)) } return toml.Unmarshal(raw, dst) } func LoadVariables(filename string) (map[string]string, error) { raw, err := os.ReadFile(filename) if err != nil { return nil, fmt.Errorf("read %s: %w", filename, err) } vars := make(map[string]string) var table map[string]any if err := toml.Unmarshal(raw, &table); err != nil { return nil, fmt.Errorf("parse %s: %w", filename, err) } for k, v := range table { vars[k] = fmt.Sprint(v) } return vars, nil } func resolveVars(in string, vars map[string]string) string { for k, v := range vars { in = strings.ReplaceAll(in, "$"+k, v) } return in } const defaultTOML = ` tty = 2 main_log_path = "/var/log/latchd.log" client_log_path = "/var/log/latchd.client.log" cache_path = "/var/cache/latchd" do_log = true pam_service = "latchd" system_shell = "/bin/sh" initial_path = "/usr/local/sbin:/usr/local/bin:/usr/bin" shell_login_flag = "short" focus_behaviour = "default" [background] show_background = true [background.style] color = "black" show_border = true border_color = "white" [power_controls] hint_margin = 2 entries = [] [[power_controls.base_entries]] hint = "Shutdown" hint_color = "dark gray" hint_modifiers = "" key = "F1" cmd = "systemctl poweroff -l" [[power_controls.base_entries]] hint = "Reboot" hint_color = "dark gray" hint_modifiers = "" key = "F2" cmd = "systemctl reboot -l" [environment_switcher] switcher_visibility = "visible" toggle_hint = "Switcher %key%" toggle_hint_color = "dark gray" toggle_hint_modifiers = "" include_tty_shell = false remember = true show_movers = true mover_color = "dark gray" mover_modifiers = "" mover_color_focused = "orange" mover_modifiers_focused = "bold" left_mover = "<" right_mover = ">" mover_margin = 1 show_neighbours = true neighbour_color = "dark gray" neighbour_modifiers = "" neighbour_color_focused = "gray" neighbour_modifiers_focused = "" neighbour_margin = 1 selected_color = "gray" selected_modifiers = "underlined" selected_color_focused = "white" selected_modifiers_focused = "bold" max_display_length = 8 no_envs_text = "No environments..." no_envs_color = "white" no_envs_modifiers = "" no_envs_color_focused = "red" no_envs_modifiers_focused = "" [username_field] remember = true [username_field.style] show_title = true title = "Login" title_color = "white" content_color = "white" title_color_focused = "orange" content_color_focused = "orange" show_border = true border_color = "white" border_color_focused = "orange" use_max_width = true max_width = 48 [password_field] content_replacement_character = "*" [password_field.style] show_title = true title = "Password" title_color = "white" content_color = "white" title_color_focused = "orange" content_color_focused = "orange" show_border = true border_color = "white" border_color_focused = "orange" use_max_width = true max_width = 48 [x11] x11_display = ":1" xserver_timeout_secs = 60 xserver_log_path = "/var/log/latchd.xorg.log" xserver_path = "/usr/bin/X" xauth_path = "/usr/bin/xauth" scripts_path = "/etc/latchd/wms" xsetup_path = "/etc/latchd/xsetup.sh" xsessions_path = "/usr/share/xsessions" [wayland] scripts_path = "/etc/latchd/wayland" wayland_sessions_path = "/usr/share/wayland-sessions" `