Documentation
¶
Overview ¶
Copyright (C) 2026 DmShAl (Shepeta Dmitry) SPDX-License-Identifier: GPL-3.0-or-later
Package server is the persistent HTTP server (D3): dictionary registry, JSON API, resource streaming, and the per-dictionary feature flow (contains / full-text / media) with SSE progress (SPEC §6, D24).
Index ¶
- Constants
- func ArticleStylesheets(body string) []string
- func ConfigureLibrary(cfg config.Config) (string, error)
- func DictStyles(d dict.ResourceOpener, names []string) htmlref.Styles
- func FormatArticles(d dict.Dictionary, format, base string, rs []dict.Result)
- func HoldActiveProcs() func()
- func ParseArticleFormat(s string) (string, error)
- func RecoverLibrary(cfg config.Config) ([]store.Adopted, error)
- func Reveal(path string) error
- func RewriteEntryHTML(html, dictID string) string
- func RewriteEntryHTMLMarked(html, dictID string, hl *hilite.Terms) string
- func RewriteFavouriteHTML(html, dictID string, assets map[string]string) string
- func RewriteFavouriteHTMLMarked(html, dictID string, assets map[string]string, hl *hilite.Terms) string
- func SetActiveProcs(n int)
- func SetBusyObserver(fn func(bool))
- func SetMemoryLimit(n int64)
- type Builtin
- type ConfigInfo
- type DictPref
- type DictionaryGroup
- type FirstRunMigration
- type Option
- type Power
- type Prefs
- func (p *Prefs) DisplayTitle(id string) string
- func (p *Prefs) Language() string
- func (p *Prefs) Off(id, path string) bool
- func (p *Prefs) Replace(dicts []DictPref) error
- func (p *Prefs) ResolvedLanguage(acceptLanguage string) string
- func (p *Prefs) Snapshot() (dicts []DictPref, exists bool)
- func (p *Prefs) UI() *UIPrefs
- type Registry
- func (r *Registry) AddBuiltin(b Builtin)
- func (r *Registry) Count() int
- func (r *Registry) Counts() (fromFolder, fromLibrary int)
- func (r *Registry) Dirs() []string
- func (r *Registry) IsBuiltin(path string) bool
- func (r *Registry) RefreshPrefs()
- func (r *Registry) Remove(id string, dropPrepared, dropSource bool) (removal, error)
- func (r *Registry) RemoveBuiltin(id string) bool
- func (r *Registry) Rescan() error
- func (r *Registry) ResolveOrphans(del, keep []string) orphanReport
- func (r *Registry) Roots() []Root
- func (r *Registry) SetDirs(dirs []string) error
- func (r *Registry) SetDirsDeferred(dirs []string) error
- func (r *Registry) SetPower(p Power)
- func (r *Registry) SetPreviewBudget(bytes int64)
- func (r *Registry) SetUseCached(on bool) error
- func (r *Registry) SourcePaths() []string
- func (r *Registry) UILanguageChoice() string
- func (r *Registry) UseCached() bool
- func (r *Registry) UserCount() int
- func (r *Registry) Warm()
- type ReindexStatus
- type Root
- type Runtime
- type SearchError
- type SearchErrorKind
- type SearchEvent
- type SearchRequest
- type SearchSlot
- type Server
- func (s *Server) ConfigSnapshot(local bool, host string) ConfigInfo
- func (s *Server) DemandDictionary(id string, explicit bool, priority ...bool) (bool, error)
- func (s *Server) DesktopArticleFindNavigation(ctx context.Context, query string) (any, error)
- func (s *Server) DesktopFolderSetup(argument string) (any, error)
- func (s *Server) DesktopJSON(baseURL, method, argument string) (any, error)
- func (s *Server) DesktopJSONContext(ctx context.Context, baseURL, method, argument string) (any, error)
- func (s *Server) DesktopMediaStream(rawURL string, requestHeaders map[string]string) (io.ReadCloser, int, string, bool)
- func (s *Server) DesktopResource(method, rawURL string, requestHeaders map[string]string, ...) (body []byte, status int, headers string, handled bool, spilled bool)
- func (s *Server) DesktopSearch(ctx context.Context, baseURL, query string, emit func([]byte)) error
- func (s *Server) DesktopSetup(argument string) (any, error)
- func (s *Server) DesktopStream(ctx context.Context, baseURL, method, query string, emit func([]byte)) error
- func (s *Server) InstallDesktopBackgrounds()
- func (s *Server) PrefsSnapshot() map[string]any
- func (s *Server) PromoteDictionary(id string) (bool, error)
- func (s *Server) RefreshMigratedUserFiles()
- func (s *Server) SavePrefs(body io.Reader) (map[string]any, error)
- func (s *Server) Search(parent context.Context, request SearchRequest, emit func(SearchEvent) error) error
- func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Server) StartReindex() (ReindexStatus, bool, error)
- func (s *Server) StopReindex() ReindexStatus
- func (s *Server) UseUserGroups()
- type UIPrefs
- type UserDir
Constants ¶
const ( FontSizeMin = 11 FontSizeMax = 32 // SearchThreadsMax bounds the configurable search fan-out. It is set well // past any sane device so the field cannot express a value the app would // then refuse; the per-search memory budget, not this, is what actually // keeps a wide fan-out honest. SearchThreadsMax = 256 )
Article text-size bounds. The ceiling is deliberately past what the layout was drawn for: a reader who needs 32px needs it more than the design needs to stay pretty, and nothing in the article surface loses text when it grows — it only gets taller.
const ( SettingsFile = "settings.json" SearchHistoryFile = "history.json" )
const (
// GroupsFileName is the file, beside wudict.toml.
GroupsFileName = "groups.ini"
)
const ServerHeader = "wudict"
ServerHeader is the value wudict answers with (plus its version), and the token a second launch looks for.
const StateFile = "state.json"
StateFile holds the part of the UI that describes the COLLECTION rather than the browser looking at it: which dictionaries are searched, in what order, and how big their text is set (see UIPrefs). Everything that describes the browser instead - theme, wide mode, the last dictionary picked in the dropdown - stays in localStorage, where it belongs.
The split is not cosmetic. localStorage is keyed by origin, so scheme://host:port is part of the identity: changing SERVER_PORT, reaching the same server as 127.0.0.1 instead of localhost, or opening it from a phone each hands the user a blank slate. Curating a hundred dictionaries and losing it to a port change is not a preference that survived, it is a preference that was never stored. The server, which owns the dictionaries, owns the answer to "which of them do I search".
It lives beside the wudict.toml in effect rather than at a hardcoded path, so a portable install (D32) keeps its state on the same stick as its config, and --config points both at once. It is deliberately NOT inside the library folders: D20 defines those as individually transferable units, and "which dictionaries are enabled" is a fact about the set, not about any member.
const ( // StyleDirName is the folder, beside the config file in effect, that holds // the two files. The CLI resolves the parent (see userDir), the same way // it resolves StateFile, so a portable install (D32) keeps its styling on // the same stick as its config. StyleDirName = "style" )
Global user styling: two CSS files the user owns, applied to everything.
D59 already lets a user replace a file a dictionary ships (<library folder>/res/<name>). That is per-dictionary and whole-file, and it cannot express either of the two things people actually ask for: "this dictionary's desktop side padding wastes half my phone screen" (one rule, but res/ demands a copy of the whole stylesheet, which then goes stale) and "give me sepia" (the chrome is not a dictionary resource at all). So this is the complementary layer: ADDITIVE, GLOBAL, and ordered last so it wins.
Two files rather than one, because a single box leaks in the damaging direction: body{}, p{}, a{}, table{} and div{} are exactly what someone styling articles writes, and every one of them would also hit the chrome. Two boxes make that structurally impossible, and the split is one sentence: app.css is colours and the app's own layout, article.css is what dictionaries render. They do not fragment the "sepia everywhere" case, because :root custom properties set in app.css already inherit into every shadow root and are carried into iframes by the existing bridge - so tokens are written once, in app.css, and reach all three surfaces.
Files on disk beside the wudict.toml in effect, not a blob in state.json: CSS is multi-line and users will want a real editor, a diff and a backup, and the res/ precedent is already "a file on disk, served no-cache, an edit lands on reload". state.json is for settings; this is a document.
Variables ¶
This section is empty.
Functions ¶
func ArticleStylesheets ¶
ArticleStylesheets lists the resources an article - as stored - links as stylesheets, as `clean` finds them for the server (cleanPolicy); DictStyles reads them into the display table. A dictionary links its stylesheet from every article, so a caller that walks all of them - `wudict dump -format md` - asks until one does, and opens the dictionary only then.
func ConfigureLibrary ¶
ConfigureLibrary selects the prepared database and protects it from being scanned as a source dictionary folder. It must precede NewRuntime.
func DictStyles ¶
func DictStyles(d dict.ResourceOpener, names []string) htmlref.Styles
DictStyles is the display table of d's stylesheets names.
func FormatArticles ¶
func FormatArticles(d dict.Dictionary, format, base string, rs []dict.Result)
FormatArticles applies the /api/search reduction (D61) to results looked up outside the server, in place. `wudict lookup -format clean` and `GET /api/search?format=clean` then produce the same bytes because they are the same code - a second implementation of "clean" would diverge on the first dictionary that stresses either one.
The pipeline is the handler's, in the handler's order: rewrite the dictionary's internal references first so they are named, derive the dictionary's own display table from the stylesheets the first article links, then reduce. base is prepended to wudict's root-absolute refs (/res/…); "" leaves them as they are, which is the honest answer when no server is running to serve them.
`raw` leaves the bodies as stored except for cross-references, which take their canonical spelling (htmlref.CanonLinks): wudict never emits `bword:`.
func HoldActiveProcs ¶
func HoldActiveProcs() func()
HoldActiveProcs marks user-waited work as running and returns the release. Safe to nest; parallelism is restored when the last holder releases.
func ParseArticleFormat ¶
ParseArticleFormat validates a `format` name for a caller that is not an HTTP request - the CLI. Same three names, same error text, so `wudict lookup -format cleen` and `?format=cleen` are wrong in the same words.
func RecoverLibrary ¶
RecoverLibrary removes interrupted imports and adopts loose prepared databases before the registry discovers dictionaries.
func Reveal ¶
Reveal shows path in the platform file manager. Exported for the tray's "Open dictionary folder" item (D74), which drives the same action as /api/reveal without going through the mux.
func RewriteEntryHTML ¶
RewriteEntryHTML rewrites resource references inside one article's HTML so the browser fetches them from /res/{dictID}/….
The walk is a real HTML tokenizer (internal/htmlref) rather than a set of regular expressions, which is what lets it see unquoted and malformed attributes - `<a href=plaintiff__gb_1.ogg">` is ordinary in repacked dictionaries - and what keeps it from rewriting `src="…"` written inside a <script> string or inside prose.
The result is a root-absolute URL (/res/{dictID}/…). wudict is served at the site root by design, so an absolute /res/ path resolves to the same origin-rooted URL in EVERY rendering context - the main page, a Shadow-DOM article, and (critically) a srcdoc iframe, whose base URL differs and inside which third-party dictionary scripts re-resolve relative refs against the wrong base. Absolute refs are context-insensitive, which removes the whole class of doubled res/{d}/res/{d}/… bugs.
Left untouched: fragments (#), query-only (?), protocol-relative (//), real schemes (http:, https:, data:, entry:, d:, x:, …), cross-reference links (see isResourceRef), and anything already under /res/{dictID}/ - the function is idempotent and can never produce a doubled URL. The one scheme rewritten is a lookup link: `bword:` → `entry://`, `entry://@` → `entry:@` (htmlref.CanonRef).
<base> is dropped: in dictionary HTML it is a scraping leftover, and left in place it would re-root every relative reference in the article.
func RewriteEntryHTMLMarked ¶
RewriteEntryHTMLMarked is RewriteEntryHTML with full-text terms wrapped in <mark class="wu-hl" data-wu-match="N"> (internal/hilite). hl may be nil, which is plain RewriteEntryHTML.
The marking costs no pass of its own: it rides the tokenizer walk this function does anyway, as the Rewriter's Text hook. That fusion is the whole design - a separate highlighting pass would double the parse of every article in a full-text fan-out, and a client-side one would pay for a DOM walk and a layout invalidation per article on top of that.
This path paints one query TERM per mark. The phrase and near readings are painted per occurrence by markArticleFindHTML instead, because an occurrence can span markup and a tokenizer hook sees one text node at a time.
The one thing marking cannot share is the fast path above. That test asks "has this article any rewritable reference", and an article of pure prose - which is precisely what a full-text search finds - answers no while still being full of matches to mark. So the tokenizer runs unconditionally here, on the cheapest documents there are.
func RewriteFavouriteHTML ¶
RewriteFavouriteHTML maps the original relative resource names in a saved article to the tokens recorded for that snapshot. The stored article bytes remain unchanged; references without copied bytes stay as their source spelling, matching the snapshot's provenance-only cross references.
func RewriteFavouriteHTMLMarked ¶
func RewriteFavouriteHTMLMarked(html, dictID string, assets map[string]string, hl *hilite.Terms) string
RewriteFavouriteHTMLMarked maps a saved article's copied resources while marking full-text matches in the same tokenizer pass.
func SetActiveProcs ¶
func SetActiveProcs(n int)
SetActiveProcs stores the active CPU ceiling and immediately reapplies the current power and thermal state. Android refreshes it at indexing boundaries.
func SetBusyObserver ¶
func SetBusyObserver(fn func(bool))
SetBusyObserver delivers foreground-work state to an in-process platform shell. The callback is invoked after releasing the observer lock.
func SetMemoryLimit ¶
func SetMemoryLimit(n int64)
SetMemoryLimit installs the soft heap ceiling (config MEMORY_LIMIT) and arms the pressure-driven eviction that makes it safe.
Types ¶
type Builtin ¶
Builtin is a dictionary the app ships: the wudict howto (internal/howto). It is listed after every folder is scanned, while its file exists, under a fixed ID so links to it work on every machine, and it stands down when a dictionary folder holds a file of the same name - the user's own copy, which is then the one listed. Removing it deletes its file, so it is no longer listed; the caller records the removal so it is not written back.
type ConfigInfo ¶
type ConfigInfo struct {
IndexDefaults indexOptions `json:"indexDefaults"`
IndexConcurrency int `json:"indexConcurrency"`
Roots []Root `json:"roots"`
LibDir string `json:"libDir"`
Prepared int `json:"prepared"`
UseCached bool `json:"useCached"`
ConfigPath string `json:"configPath"`
Total int `json:"total"`
// HowtoRemoved: the user removed the built-in wudict howto; the setup
// page offers it back.
HowtoRemoved bool `json:"howtoRemoved,omitempty"`
// DictDirOrigin is "flag", "env", "file" or "default"; DictDirEditable is
// false when a flag or environment variable outranks the config file, so
// the UI can say that saving here will not take effect rather than
// silently doing nothing on the next launch.
DictDirOrigin string `json:"dictDirOrigin"`
DictDirEditable bool `json:"dictDirEditable"`
// ConfigProblems are lines of wudict.toml that set nothing - a typo'd key
// is otherwise silent - as config.Config.Problems words them.
ConfigProblems []string `json:"configProblems,omitempty"`
// Effective is what every tunable config key currently resolves to, and
// which layer supplied it (config.Tunables). A platform shell overrides
// these for the device it runs on by writing the flag or environment layer
// (D101); it reads them back here because several of the defaults are
// computed from the device itself and Go is the only place that knows the
// formula (internal/config/tuning.go).
Effective map[string]config.Setting `json:"effective,omitempty"`
// RevealLabel is the platform's own name for "show this in the file
// manager" - the phrase a user of that OS already recognises.
RevealLabel string `json:"revealLabel"`
CanReveal bool `json:"canReveal"`
// CanDelete says this caller may remove a dictionary (D63 amended). True
// from the machine running wudict, whatever platform that is - the user at
// the keyboard owns those files, and managing a library includes throwing
// part of it away. From a remote browser it follows ALLOW_REMOTE_DELETE,
// which defaults to OFF. It is not CanReveal's complement: that would
// withhold the control from precisely the user who owns the files and hand
// it to every browser on the LAN.
CanDelete bool `json:"canDelete"`
CanExit bool `json:"canExit"`
// SystemLogHasErrors tells the panel whether a retained System Log has an
// error or crash record.
SystemLogHasErrors bool `json:"systemLogHasErrors"`
// PathAliases shorten the prefix that is identical on every row and
// therefore carries no information: {prefix, label} pairs, first match
// wins. On a desktop that is one entry, the home directory shown as "~"
// (D48). DISPLAY ONLY: the clipboard and /api/reveal keep the absolute
// path, which is what a user pasting into a script - or the file manager -
// needs. A label is a NAME, not a path: "~" is one only where a shell
// would accept it, which is why the platform decides (see pathAliases).
PathAliases [][2]string `json:"pathAliases,omitempty"`
}
ConfigInfo is what the panel's "Folders & configuration" section shows: the folders being scanned, where prepared dictionaries live, which config file is in effect - and, for each, WHICH layer set it. Everything here is otherwise visible only on the terminal at startup, which a user who opened the app in a browser never sees.
type DictPref ¶
type DictPref struct {
Groups []string `json:"groups,omitempty"` // user group IDs; independent of Off
ID string `json:"id"`
Path string `json:"path"`
Name string `json:"name,omitempty"` // display name, for a readable file
Title *string `json:"title,omitempty"` // optional user-facing label; nil restores the dictionary's own name
Off bool `json:"off,omitempty"` // excluded from "All dictionaries"
Pinned *bool `json:"pinned,omitempty"` // fixed at the top when All Dictionaries is sorted
}
DictPref is one dictionary's remembered state. The path is what makes this survivable: ids are sha256(path)[:12] (see pathID), so moving a dictionary folder changes every id at once. Recording the path - and, through it, the file name - lets the state be re-attached instead of silently reset.
type DictionaryGroup ¶
type DictionaryGroup struct {
ID string `json:"id"`
Name string `json:"name"`
Order []groupOrder `json:"order,omitempty"` // member IDs and their pin state; independent of global order
Filter *groupFilter `json:"filter,omitempty"`
SelectedFilter *groupFilter `json:"selectedFilter,omitempty"` // retained when the link is switched off
// False sorts unpinned members alphabetically; true preserves manual order
// and appends new members alphabetically. Nil is a legacy group whose mode
// is inferred from its saved order before new members are merged.
CustomOrder *bool `json:"customOrder,omitempty"`
}
DictionaryGroup is collection metadata in state.json. Membership is stored on DictPref so the existing identity repair also repairs group membership.
type FirstRunMigration ¶
FirstRunMigration describes an optional host-provided migration offered on the setup page before the user chooses dictionary folders.
type Option ¶
type Option func(*Registry)
Option configures a Registry at construction. Prefs must be in place BEFORE the first Warm, which is why this is an option and not a setter - a warm-up that pre-opened everything and only then learned what to skip would have already paid the memory it was told to save.
func WithBuiltin ¶
WithBuiltin lists the app's own dictionaries alongside the user's.
func WithComparisons ¶
WithComparisons is retained as a no-op for upstream call-site compatibility.
type Power ¶
type Power int32
Power is how much this process may spend right now. It exists because a desktop server and a phone are the same program in two utterly different situations: on a desktop "idle" costs nothing anyone notices, while on a phone a background process that keeps a core awake is a battery complaint, a thermal event, and eventually a kill by the platform's low-memory daemon.
The Go side does not detect any of this - it cannot: the signals are Android's (onStop, onTrimMemory, thermal status, power-save mode) and live in the JVM the server was exec'd away from (D52). The shell reports them through POST /api/power and the server obeys. Everything here is therefore platform-neutral: a desktop simply never leaves PowerActive.
const ( // PowerActive: someone is looking at the screen. Normal behaviour. PowerActive Power = iota // PowerBackground: the app is not visible. Nothing new is indexed and // every reopenable handle is dropped - but prepared databases stay open, // because they cost ~nothing and returning must be instant. PowerBackground // PowerRestricted: Android reports critical memory pressure. Everything // closes, including prepared databases; the process keeps only its listener. PowerRestricted // PowerSaving: Android's battery saver is enabled. User-requested work is // permitted at a reduced CPU ceiling even while the screen remains visible. PowerSaving // PowerThermalModerate and PowerThermalSevere carry Android's thermal // severity separately so active indexing can be throttled immediately. PowerThermalModerate PowerThermalSevere )
func CurrentPower ¶
func CurrentPower() Power
CurrentPower reports the state the shell last set (PowerActive everywhere that never sets one).
func ParsePower ¶
ParsePower reads a state name from the wire.
type Prefs ¶
type Prefs struct {
// contains filtered or unexported fields
}
Prefs is the state file (state.json), an ownedFile (ownedfile.go): read bounded and re-read when it changes on disk, so a hand edit made while the app runs is adopted - including by the next save, which re-reads first and so builds on it instead of writing it away. A Prefs with an empty path is in-memory only: it answers questions and forgets on exit, which is what tests and a home-less environment need.
func LoadPrefs ¶
LoadPrefs reads the state file. It never fails: a missing file is the normal first run, and an unreadable or corrupt one must not stop the app from serving dictionaries - the worst case is that the user re-curates a list.
func (*Prefs) DisplayTitle ¶
DisplayTitle returns a dictionary's optional user-facing label. Dictionary identity and its own metadata name remain unchanged.
func (*Prefs) Off ¶
Off reports whether this dictionary is excluded from "All dictionaries". It matches on id first and path second, so a record written before a move still speaks for the dictionary it was written about.
func (*Prefs) Replace ¶
Replace stores a new list and writes it, atomically (fsx.WriteAtomic): a crash mid-save leaves the previous state intact rather than a truncated file that reads as "nothing was ever configured".
func (*Prefs) ResolvedLanguage ¶
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry tracks all dictionaries: the foreign-format sources found under the dictionary folder and - only when the user has opted in (USE_CACHED) - the prepared dictionaries in the library (the db dir).
The library is NOT a discovery root by default. It is the app's private working area, and treating it as a dictionary folder is what let a media.db masquerade as a dictionary and kept the first-run setup page hidden behind a non-empty registry. Opting in is a deliberate, remembered choice made on the setup page ("Use these dictionaries").
func NewRegistry ¶
func (*Registry) AddBuiltin ¶
AddBuiltin lists one more of the app's own dictionaries (a restored guide); the next Rescan picks it up.
func (*Registry) Counts ¶
Counts reports how many dictionaries came from the dictionary folder and how many from the library, so the startup summary can describe each folder by what it actually contributed instead of showing one blended total.
func (*Registry) IsBuiltin ¶
IsBuiltin reports whether path is the source of a dictionary the app ships.
func (*Registry) RefreshPrefs ¶
func (r *Registry) RefreshPrefs()
RefreshPrefs invalidates the cached state after a host migration copies it into the active user folder.
func (*Registry) Remove ¶
Remove deletes a dictionary's prepared folder, its original files, or both, and rescans so the registry reflects what is actually on disk.
dropPrepared+dropSource is "remove this dictionary". dropPrepared alone frees the indexes and leaves a dictionary that will be re-indexed on next use. dropSource alone is the Android-shaped case - reclaim the imported original and keep the prepared dictionary, which D24 §4 already governs: the source is the safety net, so it may only be cut once the media that would be lost with it has been packed.
func (*Registry) RemoveBuiltin ¶
func (*Registry) ResolveOrphans ¶
ResolveOrphans deletes and keeps the named orphans and reports each outcome. A folder named twice, or in both lists, is refused rather than guessed at. A failure is reported per folder and never stops the others.
func (*Registry) SetDirs ¶
SetDirs re-points the registry at new dictionary folders and rescans (used by the first-run setup flow - no restart needed).
func (*Registry) SetDirsDeferred ¶
SetDirsDeferred updates the discovered folder list without starting index preparation. The folder editor uses this when it needs to show imported paths for review before the user chooses Use these folders.
func (*Registry) SetPower ¶
SetPower moves the process between power states, applying the consequences immediately: the parallelism, the open handles, and (via CurrentPower) the background indexer's willingness to start anything.
func (*Registry) SetPreviewBudget ¶
SetPreviewBudget sets how much memory unprepared ("preview") dictionaries may hold open (config PREVIEW_MEMORY; 0 = unlimited).
func (*Registry) SetUseCached ¶
SetUseCached opts the library in or out and rescans (setup flow - no restart needed).
func (*Registry) SourcePaths ¶
SourcePaths lists the path of every dictionary the user has, in every configured folder - not the ones the app ships. What an import checks "already installed" against beyond its own folder (intake.Manager.Library).
func (*Registry) UILanguageChoice ¶
UILanguageChoice returns the saved interface-language choice for native UI.
func (*Registry) UserCount ¶
UserCount counts user dictionaries by source, excluding builtins and treating cached receipts as the same source dictionary.
func (*Registry) Warm ¶
func (r *Registry) Warm()
Warm pre-opens dictionaries in the background so the first search does not pay the open cost. It opens only the ones that are PREPARED - a SQLite handle costing a few MB - and deliberately leaves unprepared ones alone: opening those builds an in-memory headword index (measured 300–500 B per headword), and doing it for a whole library costs several GB of resident memory for dictionaries nobody has searched yet (docs.local/PERF.md M2). An unprepared dictionary stays closed until its queued or explicit index operation opens it.
Disabled dictionaries are skipped. Turning one off is the user asking us to stop spending on it, and a few MB of SQLite handle each is exactly the kind of spending they meant; opening them anyway would make the switch a decoration. One that is turned back on opens on its next search.
Not on a phone, and not while the app is away (warmEnabled, CurrentPower): pre-opening is a bet that the user is about to search, paid in file descriptors, SQLite page caches and - worst on Android - a burst of I/O during the exact seconds the platform is measuring the app's launch cost. The bet is good on a desktop that just started a long-lived server; it is a bad one on a device that may be resuming an activity for a screen rotation.
type ReindexStatus ¶
type ReindexStatus struct {
Running bool `json:"running"`
// Active dictionaries being processed now (bounded by logical processors).
Active int `json:"active"`
ActiveDicts []string `json:"activeDicts,omitempty"`
BusyProgress []dictionaryWorkProgress `json:"busyProgress,omitempty"`
// Done of Total dictionaries finished (failed ones included).
Done int `json:"done"`
Total int `json:"total"`
// Current is the dictionary being rebuilt, with its own entry progress.
Current string `json:"current,omitempty"`
CurrentDone int `json:"currentDone,omitempty"`
CurrentTotal int `json:"currentTotal,omitempty"`
// Failed names each dictionary that could not be rebuilt, with why.
Failed []string `json:"failed,omitempty"`
// Canceled: the user stopped the job; what finished stays finished.
Canceled bool `json:"canceled,omitempty"`
}
ReindexStatus is the job as the page - and `wudict reindex`, handing off to a running server - polls it. The zero value is "nothing has run": Total 0 and not Running.
type Root ¶
type Root struct {
Path string `json:"path"`
Count int `json:"count"` // dictionaries this folder was the first to offer
Total int `json:"total"` // everything it holds (Total > Count ⇒ overlap)
Exists bool `json:"exists"`
}
Root is one dictionary folder and what it contributed. A folder that is missing (an unmounted drive, a deleted path) is reported, never fatal: the other folders must keep working.
type Runtime ¶
Runtime is the application state shared by the HTTP adapter and native platform bridges. It owns one registry and one Server for the lifetime of the application process.
func NewRuntime ¶
NewRuntime creates the application services without starting a listener. Callers may expose Server through HTTP, a native bridge, or both; those transports must share this Runtime rather than opening a second registry. ConfigureLibrary and RecoverLibrary run first, in that order.
type SearchError ¶
type SearchError struct {
Kind SearchErrorKind
Message string
}
SearchError reports lookup validation without imposing HTTP status codes.
func (*SearchError) Error ¶
func (e *SearchError) Error() string
type SearchErrorKind ¶
type SearchErrorKind string
const ( SearchInvalidRequest SearchErrorKind = "invalid_request" SearchDictionaryNotFound SearchErrorKind = "dictionary_not_found" )
type SearchEvent ¶
type SearchEvent struct {
T string `json:"t"`
Slots []SearchSlot `json:"slots,omitempty"`
I int `json:"i"`
Dict string `json:"dict,omitempty"`
Name string `json:"name,omitempty"`
Results []dict.Result `json:"results,omitempty"`
Skipped bool `json:"skipped,omitempty"`
Error string `json:"error,omitempty"`
// Rung says which reading of a full-text query this dictionary answered:
// "phrase" (the words adjacent, in order), "near" (within the configured
// window, ten tokens by default, any order) or "words" (anywhere in the
// article). Absent in every other mode.
//
// It is reported because the relaxation is silent otherwise, and a search
// tool that quietly answers a weaker question than the one asked is lying
// about its result. The UI says so only when the answer is NOT the phrase -
// the precise reading needs no announcement (D102).
Rung string `json:"rung,omitempty"`
// OneReading says the dictionary has a single reading and never tried
// another, so Rung is not a relaxation and must not be announced as one
// (an archive answering from its own index - see search.Hit.OneReading).
OneReading bool `json:"oneReading,omitempty"`
// NeedsIndex says this dictionary would have to read article texts to
// answer the reading, and declined to (search.Hit.NeedsIndex). What the
// reader gets instead is an offer to build our index for it: the same
// reading, answered from positions.
NeedsIndex bool `json:"needsIndex,omitempty"`
Term string `json:"term,omitempty"`
CacheID string `json:"cacheID,omitempty"`
Total int `json:"total,omitempty"`
Complete bool `json:"complete,omitempty"`
Start int `json:"start,omitempty"`
HasNext bool `json:"hasNext,omitempty"`
// Legacy morphology event fields retained for decoding older streams.
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
Lang string `json:"lang,omitempty"`
}
SearchEvent is one progressively delivered search result event:
{"t":"begin","slots":[{dict,name}…]} ordered slot layout
{"t":"hit","i":N,dict,name,results…} one dictionary's results
{"t":"end"} all dictionaries done
type SearchRequest ¶
type SearchRequest struct {
Query string `json:"q"`
Mode string `json:"mode,omitempty"`
Format string `json:"format,omitempty"`
Dictionary string `json:"dict,omitempty"`
Limit int `json:"n,omitempty"`
Highlight bool `json:"hl,omitempty"`
Suggestions bool `json:"suggest,omitempty"`
IgnoreDiacritics bool `json:"ignoreDiacritics,omitempty"`
Origin string `json:"-"`
CacheAction string `json:"cacheAction,omitempty"`
CacheID string `json:"cacheID,omitempty"`
ReturnCacheID string `json:"returnCacheID,omitempty"`
ReturnCacheStorage string `json:"returnCacheStorage,omitempty"`
CacheCount int `json:"cacheCount,omitempty"`
CacheOrder int `json:"cacheOrder,omitempty"`
Start int `json:"start,omitempty"`
Size int `json:"size,omitempty"`
Rung string `json:"rung,omitempty"`
PageCacheDiagnostics bool `json:"pageCacheDiagnostics,omitempty"`
SearchDiagnostics bool `json:"searchDiagnostics,omitempty"`
Transport string `json:"-"`
// contains filtered or unexported fields
}
SearchRequest contains lookup parameters independent of either transport. An empty Dictionary or "all" selects the library; a comma-separated list retains its caller's slot order. Origin is supplied by the host for clean article resource links, never read from the desktop JSON payload.
type SearchSlot ¶
SearchSlot names one dictionary in the result layout (begin message).
type Server ¶
type Server struct {
// ConfigPath, when set, is where the first-run setup flow persists
// DICT_DIR. In-memory state is updated regardless, so setup works
// even when the folder came from a CLI flag or the file is read-only.
ConfigPath string
// User is the folder beside the wudict.toml in effect, holding what the
// user owns besides it (userdir.go). Empty: none of it can be saved.
User UserDir
// Version identifies this build in the Server response header. A second
// launch uses that header to recognise an already-running wudict on
// the port - without it, "the port is busy" says nothing about WHO holds
// it, and sending the user's browser to an unknown local service would be
// worse than an error message.
Version string
// DesktopExit asks the owning desktop process to stop its HTTP server and
// tray. Nil for Android, tests, and hosts without a desktop Exit action.
DesktopExit func()
// AutoIndex is retained for compatibility with the shared UI API; the
// DictShelf host leaves it disabled and prepares indexes only on explicit action.
AutoIndex bool
// First-run Windows data migration is offered in the folder dialog after it
// has loaded. The host supplies filesystem operations; other platforms leave
// these callbacks nil.
FirstRunMigrationStatus func() FirstRunMigration
ApplyFirstRunMigration func(string) error
// DictDirOrigin / DictDirEditable describe where the dictionary folders
// came from (config layering), so the UI can warn that a flag or an
// environment variable will override anything saved to the file.
DictDirOrigin string
DictDirEditable bool
// ConfigProblems are the config file's lines that set nothing
// (config.Config.Problems), shown in the folder dialog.
ConfigProblems []string
// Effective is every tunable key's resolved value and origin, published by
// /api/config for shells that override them per device (D101).
Effective map[string]config.Setting
// Speexdec is the path to the external speexdec binary. It is used when
// UseExternalSpeex is set, or as a fallback when the in-process decoder is
// not compiled in (CGO_ENABLED=0) or fails on a given file.
Speexdec string
// UseExternalSpeex forces the external speexdec binary even when the
// in-process (cgo) libspeex decoder is available (config SPEEX_BACKEND).
UseExternalSpeex bool
// BrowserExtensions optionally pins which extension origins may read the
// client API cross-origin (config BROWSER_EXTENSIONS). Empty = any
// chrome-extension:// or moz-extension:// origin, which is what Firefox
// forces anyway: its moz-extension UUID is regenerated per install, so
// there is no stable id to list. See cors.go (D69).
BrowserExtensions []string
// AllowRemoteDelete lets a browser on another machine delete a dictionary
// (config ALLOW_REMOTE_DELETE). Loopback may regardless; this is only
// about the remote caller. New() sets it false, matching the config
// default, so a Server built directly in a test behaves like a real one.
AllowRemoteDelete bool
// Morph lemmatizes a word when a search finds nothing anywhere, so an
// inflected form still reaches its entry (O3, config MORPH_CACHE). Nil -
// which is what a Server built directly in a test has - is disabled, and
// every call site goes through Cache.Enabled.
Morph *morph.Cache
// WebOrigins lists http(s) page origins allowed to read the same three
// endpoints cross-origin (config WEB_ORIGINS). Empty - the default - means
// none: a web page gets nothing here. A single "*" allows any origin. See
// cors.go (D69).
WebOrigins []string
// TrustedHosts lists DNS names, beyond "localhost", that may appear in a
// request's Host header (config TRUSTED_HOSTS). Empty - the default -
// means none: every legitimate client addresses this server by IP, so the
// only thing a name buys is DNS rebinding. See host.go. A single "*"
// disables the check, for a reverse proxy whose name we cannot know.
TrustedHosts []string
// AuthToken, when set, is the capability token every route outside
// authFree must present (auth.go). Empty means the server is open, which
// is the right default for a loopback bind and the wrong one for any
// other; the CLI resolves which case this is (config.AuthRequired).
AuthToken string
// LemmaDir is where /api/lemmas installs lemma files (config LEMMA_DIR) -
// the same folder Morph indexes, which is what makes an install visible to
// the next search without a restart.
LemmaDir string
// LemmaURL is the catalogue those installs come from (config LEMMA_URL).
// It is server state and never a request parameter: a client-chosen URL
// would turn this endpoint into a fetcher for whatever address the machine
// running wudict can reach.
LemmaURL string
// ImportKeep (config IMPORT_KEEP) decides what becomes of the archive an
// import came from: "ask" leaves the question to the page, "keep" and
// "delete" answer it. A FAILED import always keeps it, whatever this
// says - see intake.Manager.Confirm.
ImportKeep string
// ImportURLHosts (config IMPORT_URL_HOSTS) optionally restricts which
// sites this server will fetch an archive from. Empty - the default - is
// any site: the link came from the person using the app, who found the
// dictionary somewhere no list was ever going to enumerate (D139). It
// earns its keep on a wudict other people can reach, where the caller
// and the owner are no longer the same person.
//
// ImportInsecure (IMPORT_INSECURE) is a different question and is NOT
// opened by the above: it lifts the two refusals that protect the machine
// this runs on - plain http, and an address on the local network. Both
// are server state for the same reason LemmaURL is: policy a request
// could widen is not policy.
ImportURLHosts []string
ImportInsecure bool
// contains filtered or unexported fields
}
Server exposes the registry over HTTP.
func (*Server) ConfigSnapshot ¶
func (s *Server) ConfigSnapshot(local bool, host string) ConfigInfo
ConfigSnapshot returns the configuration view for an already-authorized transport. HTTP derives locality and host from the request; a native desktop bridge supplies its known local connection.
func (*Server) DemandDictionary ¶
DemandDictionary starts or prioritizes preparation of a dictionary's headword index when an explicit action needs it.
func (*Server) DesktopArticleFindNavigation ¶
DesktopArticleFindNavigation makes the same navigation operation available to WebViews whose secure origin has no HTTP API fallback.
func (*Server) DesktopFolderSetup ¶
func (*Server) DesktopJSON ¶
DesktopJSON dispatches explicitly supported JSON operations for the desktop bridge. It calls shared server methods directly; browser HTTP routes remain available and delegate to the same operations where they overlap.
func (*Server) DesktopJSONContext ¶
func (s *Server) DesktopJSONContext(ctx context.Context, baseURL, method, argument string) (any, error)
DesktopJSONContext is the cancellable form used by the Windows bridge for JSON requests that may scan dictionary headwords.
func (*Server) DesktopMediaStream ¶
func (s *Server) DesktopMediaStream(rawURL string, requestHeaders map[string]string) (io.ReadCloser, int, string, bool)
DesktopMediaStream serves a resource through an in-process pipe. The caller receives headers before the body is copied, so even a multi-gigabyte open range can start playing without first materializing the entire response.
func (*Server) DesktopResource ¶
func (s *Server) DesktopResource(method, rawURL string, requestHeaders map[string]string, spill func() (io.WriteSeeker, error)) (body []byte, status int, headers string, handled bool, spilled bool)
DesktopResource adapts GET requests from the in-process WebView to Go operations. Mutating operations use the native bridge rather than HTTP.
func (*Server) DesktopSearch ¶
DesktopSearch accepts a legacy query string and calls the shared search operation directly. WebView2 uses the typed JSON request via DesktopStream.
func (*Server) DesktopSetup ¶
DesktopSetup exposes the setup page's migration actions to the Windows WebView bridge, with the same host callbacks as the HTTP adapter.
func (*Server) DesktopStream ¶
func (s *Server) DesktopStream(ctx context.Context, baseURL, method, query string, emit func([]byte)) error
DesktopStream dispatches desktop streams. Search, dictionary listing, ingest and rescan index work call their shared Go operations directly. An ordinary folder rescan likewise refreshes through the registry and then streams rows.
func (*Server) InstallDesktopBackgrounds ¶
func (s *Server) InstallDesktopBackgrounds()
func (*Server) PrefsSnapshot ¶
PrefsSnapshot returns the enabled set and order, healed against the dictionaries that exist right now. "exists" is false on a first run, which is the client's cue to adopt whatever an older build left in localStorage (once) instead of starting the user over. The desktop bridge and HTTP route share this method so both transports see the same state.
func (*Server) PromoteDictionary ¶
PromoteDictionary raises a dictionary that is already waiting in the running index queue to the front of it, and does nothing else. It is what Browse asks for when a reader arrives at a dictionary that has no index yet: the words they asked for are worth taking next instead of last, but opening a page must not begin indexing, which is why a dictionary that is not in the queue is left exactly as it was. `true` means the dictionary is in the queue (or already being indexed under it).
func (*Server) RefreshMigratedUserFiles ¶
func (s *Server) RefreshMigratedUserFiles()
RefreshMigratedUserFiles makes copied state, group rules and styles visible immediately without restarting the desktop server.
func (*Server) SavePrefs ¶
SavePrefs applies the /api/prefs update and returns its response snapshot. HTTP and the Windows WebView bridge share this path so writes have identical validation, merge and persistence behavior regardless of transport.
func (*Server) Search ¶
func (s *Server) Search(parent context.Context, request SearchRequest, emit func(SearchEvent) error) error
Search runs one lookup and serializes progressive events to emit. Both the HTTP adapter and the native bridge use this method without a listener. An emitter error stops delivery and cancels outstanding dictionary queries. Validation/emitter errors are returned; dictionary failures and cancellation are reported in hit events, retaining the progressive protocol's end event.
func (*Server) StartReindex ¶
func (s *Server) StartReindex() (ReindexStatus, bool, error)
func (*Server) StopReindex ¶
func (s *Server) StopReindex() ReindexStatus
func (*Server) UseUserGroups ¶
func (s *Server) UseUserGroups()
UseUserGroups selects the fork's membership picker at server startup. Upstream's rules editor and API stay available for synchronization, but its rules are separate editor filters; diagnostics do not enter the fork picker.
type UIPrefs ¶
type UIPrefs struct {
UpdateChannel string `json:"updateChannel,omitempty"` // release, prerelease or beta; Windows and Android default to beta
UpdateNotificationsOff bool `json:"updateNotificationsOff,omitempty"` // notifications are on unless disabled
ResultCacheLimitGB int `json:"resultCacheLimitGB,omitempty"`
ResultCacheNoLimit bool `json:"resultCacheNoLimit,omitempty"`
// CountAllResultsInBackground controls the background pass that counts
// every match after the initial results. A new profile and the first launch
// of each app version enable it; an explicit later choice is saved here.
CountAllResultsInBackground *bool `json:"countAllResultsInBackground,omitempty"`
// SkipBackgroundResultCount is the legacy opt-out key. Keep reading it for
// older state files; CountAllResultsInBackground takes precedence.
SkipBackgroundResultCount bool `json:"skipBackgroundResultCount,omitempty"`
SearchReturnCache string `json:"searchReturnCache,omitempty"`
CombinedDictionaryLimit int `json:"combinedDictionaryLimit,omitempty"`
// SearchThreads caps how many dictionaries a search touches at once: the
// server fan-out, and the Wildcards list build the page drives itself. 0 is
// automatic - the fan-out the app chose for the platform - and a positive
// value is the reader overriding it to measure.
SearchThreads int `json:"searchThreads,omitempty"`
// NearWords is the "near" reading's window: how many words may stand between
// the words of a query, for both a prepared dictionary and an archive. 0
// means the reader never chose one, and ftsq.NearDefault applies. It is an
// instruction to the search path (unlike HL off, which is UI state): the
// server resolves it with ftsq.ResolveNear and hands it to internal/search,
// and the page shows the same resolved number in the mode's hint.
NearWords int `json:"nearWords,omitempty"`
// Suggestion limits apply to headword suggestions in the main search field.
SuggestionPerDictionary int `json:"suggestionPerDictionary,omitempty"`
SuggestionListLimit int `json:"suggestionListLimit,omitempty"`
DictIconsOff bool `json:"dictIconsOff,omitempty"`
FontSize int `json:"fontSize,omitempty"` // article text, px; 0 = the default
// FontWeight is the article text's weight, in CSS units. 0 is the zero
// value AND the default (400), which is the same bargain as FontSize: a
// half-written state.json gets the default rather than a wrong value.
// Server state and not localStorage, for the reason the size is not - a
// reader who needs 500 needs it on the phone that reaches this server too.
FontWeight int `json:"fontWeight,omitempty"`
FontFamily string `json:"fontFamily,omitempty"` // system, charis, gentium or quivira
// HLOff turns OFF marking of full-text matches inside articles. It is
// negating for the same reason DictPref.Off is: the default is on, and a
// default that is the zero value is a default a hand-written or
// half-written state.json cannot get wrong. An absent key is the feature
// working, never the feature silently missing.
//
// It is remembered state for the UI, not an instruction to the server: the
// search path never reads it. The SPA turns it into ?hl= on the request,
// which is what keeps an API client that never saw this file from
// inheriting a preference set in somebody's browser.
HLOff bool `json:"hlOff,omitempty"`
// Also fold [ex] zones when the Examples Hide layer is enabled.
HideUnmarkedExamples *bool `json:"hideUnmarkedExamples,omitempty"`
// ExampleBackgroundOff opts out of the default background tint on examples.
ExampleBackgroundOff bool `json:"exampleBackgroundOff,omitempty"`
FadeExampleText bool `json:"fadeExampleText,omitempty"`
// FastFirst expands whichever dictionary answers first, instead of the
// first dictionary in the user's own order that has a result (D73, D142;
// default flipped in D144).
//
// Spelled as the opt-OUT, the way HLOff is, because the default is now the
// reader's own order: the list they arranged is the answer to "which of
// these do I want", and a race winner is not that answer. So an absent key
// is the default strategy, which is the rule both flags obey - a
// half-written state.json must not be able to invent a setting the user
// never made.
//
// Like HLOff it is remembered state for the UI and not an instruction to
// the server: /api/search knows nothing about it, because which section a
// reader unfolds is a property of the reader, not of the answer.
FastFirst bool `json:"fastFirst,omitempty"`
// OpenN is how many sections open by themselves under the reader's own
// order: the first OpenN dictionaries in that order that have a result.
// 0 (absent) and 1 are both the default, one; there is no upper limit,
// because the reader may trade speed for it. OpenAll opens every one that
// has a result. The page's menu sets these and FastFirst together, and
// FastFirst, which opens a single section, wins if a hand edit sets both.
// Remembered state for the UI, like FastFirst: the server never reads it.
OpenN int `json:"openN,omitempty"`
OpenAll bool `json:"openAll,omitempty"`
// SpeakOff turns OFF the read-aloud button that appears over a text
// selection in an article. Negated like HLOff: the feature is on unless
// the person said otherwise. Which VOICE reads is not here - the voices
// are whatever the device in front of them has installed, so that choice
// stays in that browser's localStorage.
SpeakOff bool `json:"speakOff,omitempty"`
// GroupsOff lists the picker sections the person has hidden, by facet id:
// "lang", "pair", or a groups.ini section lower-cased (internal/facet).
// Negated for the same reason as the flags above: every section the
// library supports is shown unless the person said otherwise, and a facet
// added tomorrow appears without a migration. Ids are kept opaque here - the server never groups anything,
// and an id no facet uses any more simply hides nothing.
GroupsOff []string `json:"groupsOff,omitempty"`
// False sorts the unpinned All Dictionaries tail alphabetically; true
// preserves manual order and appends new dictionaries alphabetically. Nil
// marks older state, whose mode the page infers from its saved order.
CustomOrder *bool `json:"customOrder,omitempty"`
// Full opens an article's secondary zone (DSL [*], wu-sec: examples and
// links to sub-entries) shown instead of hidden. Spelled positively, like
// SortMine: the brief view is Lingvo's own default, so the zero value
// keeps it. It is the reader's last choice on a section's switch, and
// sets how the next section opens; the server never reads it.
Full bool `json:"full,omitempty"`
// Mode is the search mode the reader last picked: "exact", "contains" or
// "fts". Empty is prefix, the default, so an absent key keeps it. It is the
// reader's habit, and which modes answer at all is a fact about this
// server's library, so it lives here and not in the browser. The page
// writes it only when the reader picks a mode, never when a link or the
// history sets one; the server never reads it.
Mode string `json:"mode,omitempty"`
}
UIPrefs is the part of the reading experience that belongs to the PERSON rather than to the browser in front of them. The split at the top of this file sends theme and wide mode to localStorage because they are per-device view choices; text size is not one. A reader who needs 24px needs it on the phone that reaches this same server too, and localStorage — keyed by origin — would hand them 15px there, and again the first time SERVER_PORT changes.
type UserDir ¶
type UserDir string
UserDir is the folder beside the wudict.toml in effect: everything the user owns besides that file lives in it, at names derived here and nowhere else. One value, so a portable install (D32) and --config move all of it at once. Empty is "no such folder": each path is then empty, and what lives there cannot be saved.
Source Files
¶
- about.go
- articleformat.go
- articlestyle.go
- auth.go
- backgrounds_other.go
- browse.go
- browse_diagnostic.go
- browse_find_diagnostic.go
- browse_memory.go
- browse_memory_other.go
- clear_database.go
- cors.go
- demand.go
- desktop_assets.go
- desktop_resource.go
- desktop_resource_stream.go
- desktop_search.go
- dictionary_icon.go
- dictrows.go
- dmsh_article_find_bridge.go
- dmsh_article_find_match.go
- dmsh_article_find_navigation.go
- dmsh_article_fonts.go
- dmsh_article_mark.go
- dmsh_article_page_cache.go
- dmsh_article_result_cache.go
- dmsh_browse_result_cache.go
- dmsh_busy_observer.go
- dmsh_desktop_snapshots.go
- dmsh_dictionary_list.go
- dmsh_estimate.go
- dmsh_groups.go
- dmsh_headword_export.go
- dmsh_index_parallelism.go
- dmsh_merged_from_wildcard.go
- dmsh_own_index.go
- dmsh_portable.go
- dmsh_prefs.go
- dmsh_runtime_library.go
- dmsh_search_open.go
- dmsh_search_return_cache.go
- dmsh_search_service.go
- dmsh_search_transport.go
- dmsh_stats.go
- dsl_defaults.go
- dsl_migration.go
- dsl_modes.go
- exit.go
- explorer_other.go
- favourites.go
- favourites_export.go
- first_run_migration.go
- folders.go
- foreground_other.go
- gd_assets.go
- groups.go
- hidewindow_other.go
- host.go
- howto.go
- i18n.go
- index_work.go
- indexlog.go
- intake.go
- jobs.go
- lemmas.go
- looks.go
- merged_browse.go
- near_words.go
- openapi.go
- orphans.go
- ownedfile.go
- power.go
- prefs.go
- presets.go
- registry.go
- registry_other.go
- reindex.go
- remove.go
- rescan_indexes.go
- resource_source.go
- result_cache_policy.go
- rewrite.go
- routes.go
- runtime.go
- search_threads.go
- server.go
- setup_work.go
- stream.go
- style.go
- system_version_other.go
- userdir.go
- userfiles.go
- userstorage.go
- webasset.go
- wildcard_cache.go
- wildcard_cached_find.go
- wildcard_group_find.go
- wildcard_simple_cache.go
- work_guard.go