package spell import ( "bufio" "os" "path/filepath" "strings" ) // SetPersonalPath records where the hand-editable personal dictionary lives // (conventionally ~/.config/glint/dict.txt). It does not touch the file. func (d *Dict) SetPersonalPath(path string) { d.personalPath = path } // LoadPersonal reads the personal dictionary into memory, one word per line. // Blank lines and lines beginning with '#' are ignored. A missing file is not an // error — the personal dictionary simply starts empty. func (d *Dict) LoadPersonal() error { if d.personalPath == "" { return nil } f, err := os.Open(d.personalPath) if err != nil { if os.IsNotExist(err) { return nil } return err } defer func() { _ = f.Close() }() sc := bufio.NewScanner(f) for sc.Scan() { w := strings.TrimSpace(sc.Text()) if w == "" || strings.HasPrefix(w, "#") { continue } d.personal[strings.ToLower(w)] = struct{}{} } return sc.Err() } // Add inserts word into the in-memory personal set and appends it to dict.txt, // creating the file (and any missing parent directories) if needed. The word is // stored lowercased so membership stays case-insensitive. func (d *Dict) Add(word string) error { w := strings.ToLower(strings.TrimSpace(word)) if w == "" { return nil } if _, ok := d.personal[w]; !ok { d.personal[w] = struct{}{} } if d.personalPath == "" { return nil } if err := os.MkdirAll(filepath.Dir(d.personalPath), 0o755); err != nil { return err } f, err := os.OpenFile(d.personalPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return err } if _, err := f.WriteString(w + "\n"); err != nil { _ = f.Close() return err } return f.Close() }