Files

88 lines
2.2 KiB
Go

// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
// Package spellcheck owns offline dictionary work and personal exceptions.
package spellcheck
/*
#cgo LDFLAGS: -ldl
#include "native.h"
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"unsafe"
)
// Dictionary is used only by the service's worker, including Close.
type Dictionary interface {
Check(string) (bool, error)
Suggest(string) ([]string, error)
Close()
}
type EnchantDictionary struct {
native *C.SpellDictionary
}
func open_dictionary(language string) (Dictionary, error) {
if language == "" {
return nil, fmt.Errorf("the session has no spelling language")
}
tag := C.CString(language)
defer C.free(unsafe.Pointer(tag))
var status C.int
native := C.spell_dictionary_open(tag, &status)
if native == nil {
switch status {
case 1:
return nil, fmt.Errorf("Enchant 2 could not be loaded")
case 2:
return nil, fmt.Errorf("Enchant 2 has an incompatible interface")
case 4:
return nil, fmt.Errorf("dictionary for %s is unavailable", language)
default:
return nil, fmt.Errorf("could not initialize Enchant")
}
}
return &EnchantDictionary{native: native}, nil
}
func (d *EnchantDictionary) Check(word string) (bool, error) {
value := C.CString(word)
defer C.free(unsafe.Pointer(value))
result := C.spell_dictionary_check(d.native, value, C.size_t(len(word)))
if result < 0 {
return false, fmt.Errorf("dictionary check failed")
}
return result == 0, nil
}
func (d *EnchantDictionary) Suggest(word string) ([]string, error) {
value := C.CString(word)
defer C.free(unsafe.Pointer(value))
var count C.size_t
list := C.spell_dictionary_suggest(d.native, value, C.size_t(len(word)), &count)
if list == nil {
return nil, nil
}
defer C.spell_dictionary_free_suggestions(d.native, list)
// Preserve provider ranking, with a bounded result set for the picker.
var suggestions []string
seen := make(map[string]bool)
for _, item := range unsafe.Slice(list, int(min(count, 128))) {
word := C.GoString(item)
if word != "" && !seen[word] {
seen[word] = true
suggestions = append(suggestions, word)
}
}
return suggestions, nil
}
func (d *EnchantDictionary) Close() {
C.spell_dictionary_close(d.native)
}