diff --git a/env.go b/env.go new file mode 100644 index 0000000..b7f8066 --- /dev/null +++ b/env.go @@ -0,0 +1,37 @@ +package main + +import ( + "os" + "path/filepath" + "strings" +) + +// isReadonly reports whether the editor should open in read-only mode. +func isReadonly() bool { + return os.Getenv("READONLY") == "true" +} + +// fixedPitchEnabled reports whether the user opted into a monospace +// (programmer) font. The value comes from the TINY_ENCRYPT_ENABLE_FIXED_PITCH +// environment variable; when that is unset it falls back to the file at +// ~/.config/envs/TINY_ENCRYPT_ENABLE_FIXED_PITCH (content trimmed). The values +// true/on/yes/1 are accepted, case-insensitively. +func fixedPitchEnabled() bool { + v := os.Getenv("TINY_ENCRYPT_ENABLE_FIXED_PITCH") + if v == "" { + home, err := os.UserHomeDir() + if err != nil { + return false + } + data, err := os.ReadFile(filepath.Join(home, ".config", "envs", "TINY_ENCRYPT_ENABLE_FIXED_PITCH")) + if err != nil { + return false + } + v = strings.TrimSpace(string(data)) + } + switch strings.ToLower(v) { + case "true", "on", "yes", "1": + return true + } + return false +} diff --git a/main.go b/main.go index 20f3e73..3990075 100644 --- a/main.go +++ b/main.go @@ -4,12 +4,9 @@ import ( "crypto/aes" "crypto/cipher" "encoding/hex" - "encoding/json" "fmt" "image/color" "os" - "path/filepath" - "strings" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" @@ -24,11 +21,6 @@ const ( Title = "Secure Editor" AlgorithmAes256Gcm = "aes-256-gcm" - DefaultWindowWidth = 800.0 - DefaultWindowHeight = 600.0 - - ConfigFileName = "secure-editor-go-config.json" - // Exit codes: // 0 -> file was saved and the editor exited // 2 -> editor closed without saving @@ -86,106 +78,6 @@ func showErrorMessage(err error, parent fyne.Window) { dialog.ShowError(err, parent) } -func isReadonly() bool { - return os.Getenv("READONLY") == "true" -} - -// fixedPitchEnabled reports whether the user opted into a monospace -// (programmer) font. The value comes from the TINY_ENCRYPT_ENABLE_FIXED_PITCH -// environment variable; when that is unset it falls back to the file at -// ~/.config/envs/TINY_ENCRYPT_ENABLE_FIXED_PITCH (content trimmed). The values -// true/on/yes/1 are accepted, case-insensitively. -func fixedPitchEnabled() bool { - v := os.Getenv("TINY_ENCRYPT_ENABLE_FIXED_PITCH") - if v == "" { - home, err := os.UserHomeDir() - if err != nil { - return false - } - data, err := os.ReadFile(filepath.Join(home, ".config", "envs", "TINY_ENCRYPT_ENABLE_FIXED_PITCH")) - if err != nil { - return false - } - v = strings.TrimSpace(string(data)) - } - switch strings.ToLower(v) { - case "true", "on", "yes", "1": - return true - } - return false -} - -// windowConfig is persisted to ~/.cache/secure-editor-go-config.json so the -// editor remembers its window size across runs. -type windowConfig struct { - Width float32 `json:"width"` - Height float32 `json:"height"` -} - -func configPath() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", err - } - return filepath.Join(home, ".cache", ConfigFileName), nil -} - -func defaultConfig() windowConfig { - return windowConfig{Width: DefaultWindowWidth, Height: DefaultWindowHeight} -} - -func loadConfig() windowConfig { - p, err := configPath() - if err != nil { - return defaultConfig() - } - data, err := os.ReadFile(p) - if err != nil { - return defaultConfig() - } - var c windowConfig - if err := json.Unmarshal(data, &c); err != nil { - return defaultConfig() - } - if c.Width <= 0 || c.Height <= 0 { - return defaultConfig() - } - return c -} - -func saveConfig(size fyne.Size) { - p, err := configPath() - if err != nil { - return - } - if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil { - return - } - c := windowConfig{Width: size.Width, Height: size.Height} - data, err := json.MarshalIndent(c, "", " ") - if err != nil { - return - } - _ = os.WriteFile(p, data, 0644) -} - -// clampToScreen shrinks size so it never exceeds the visible desktop area. -// When the desktop size can't be determined it returns size unchanged. -func clampToScreen(size fyne.Size) fyne.Size { - sw, sh := desktopSize() - if sw <= 0 || sh <= 0 { - return size - } - w, h := size.Width, size.Height - if w > sw { - w = sw - } - if h > sh { - h = sh - } - return fyne.NewSize(w, h) -} - // lightEditorTheme forces a light variant with a pure white input background // so the editable text area reads as a white editing surface regardless of // the system appearance setting. Readonly mode keeps the default theme (grey). diff --git a/window.go b/window.go new file mode 100644 index 0000000..34d52ca --- /dev/null +++ b/window.go @@ -0,0 +1,87 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + + "fyne.io/fyne/v2" +) + +const ( + DefaultWindowWidth = 800.0 + DefaultWindowHeight = 600.0 + + ConfigFileName = "secure-editor-go-config.json" +) + +// windowConfig is persisted to ~/.cache/secure-editor-go-config.json so the +// editor remembers its window size across runs. +type windowConfig struct { + Width float32 `json:"width"` + Height float32 `json:"height"` +} + +func configPath() (string, error) { + home, err := os.UserHomeDir() + if err != nil { + return "", err + } + return filepath.Join(home, ".cache", ConfigFileName), nil +} + +func defaultConfig() windowConfig { + return windowConfig{Width: DefaultWindowWidth, Height: DefaultWindowHeight} +} + +func loadConfig() windowConfig { + p, err := configPath() + if err != nil { + return defaultConfig() + } + data, err := os.ReadFile(p) + if err != nil { + return defaultConfig() + } + var c windowConfig + if err := json.Unmarshal(data, &c); err != nil { + return defaultConfig() + } + if c.Width <= 0 || c.Height <= 0 { + return defaultConfig() + } + return c +} + +func saveConfig(size fyne.Size) { + p, err := configPath() + if err != nil { + return + } + if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil { + return + } + c := windowConfig{Width: size.Width, Height: size.Height} + data, err := json.MarshalIndent(c, "", " ") + if err != nil { + return + } + _ = os.WriteFile(p, data, 0644) +} + +// clampToScreen shrinks size so it never exceeds the visible desktop area. +// When the desktop size can't be determined it returns size unchanged. +func clampToScreen(size fyne.Size) fyne.Size { + sw, sh := desktopSize() + if sw <= 0 || sh <= 0 { + return size + } + w, h := size.Width, size.Height + if w > sw { + w = sw + } + if h > sh { + h = sh + } + return fyne.NewSize(w, h) +}