Documentation
¶
Overview ¶
Package webui owns the web UI's Go side: compose windows, their bound service and the theme variables.
Index ¶
- Constants
- Variables
- func ThemeVars(t theme.Tokens) map[string]string
- type Account
- type Approval
- type AttachResult
- type Attachment
- type BodyChange
- type Change
- type Citation
- type Compose
- type ComposeEdit
- type ComposePage
- func (p *ComposePage) AddAttachments(ctx context.Context, revision int64) (AttachResult, error)
- func (p *ComposePage) Ask(ctx context.Context, input string, quoted []int64) (int64, error)
- func (p *ComposePage) Closed(ctx context.Context, gen int, saved bool) error
- func (p *ComposePage) Decide(ctx context.Context, approval int64, accept bool) (BodyChange, error)
- func (p *ComposePage) DecideAll(ctx context.Context, run int64, accept bool) (BodyChange, error)
- func (p *ComposePage) Finish(ctx context.Context, approval int64, decisions []int) (BodyChange, error)
- func (p *ComposePage) Follow(ctx context.Context) (WitHistory, error)
- func (p *ComposePage) Latest(ctx context.Context) (ComposeState, error)
- func (p *ComposePage) Load(ctx context.Context) (ComposeState, error)
- func (p *ComposePage) OpenLink(ctx context.Context, link string) error
- func (p *ComposePage) OpenModels(ctx context.Context) error
- func (p *ComposePage) RemoveAttachment(ctx context.Context, id, revision int64) (Change, error)
- func (p *ComposePage) Review(ctx context.Context, approval int64) (Review, error)
- func (p *ComposePage) Rewrite(ctx context.Context, revision int64, text string, start, end int, ...) (RunStart, error)
- func (p *ComposePage) Save(ctx context.Context, e ComposeEdit) (SaveResult, error)
- func (p *ComposePage) SearchMail(ctx context.Context, query string) ([]MailHit, error)
- func (p *ComposePage) Send(ctx context.Context, revision int64, digest string) (SendResult, error)
- func (p *ComposePage) SetAccount(ctx context.Context, id, revision int64) (Change, error)
- func (p *ComposePage) Skill(ctx context.Context, id, language string) (int64, error)
- func (p *ComposePage) Stop(ctx context.Context, run int64) error
- func (p *ComposePage) Undo(ctx context.Context) (BodyChange, error)
- func (p *ComposePage) WitInfo(ctx context.Context) (WitInfo, error)
- type ComposeState
- type Language
- type MailHit
- type PageDeps
- type Pages
- type Reader
- func (r *Reader) Allow(message int64)
- func (r *Reader) Bind(key any, message int64)
- func (r *Reader) Bound(key any) (message int64, ok bool)
- func (r *Reader) ImageHandler() http.Handler
- func (r *Reader) SetService(svc *core.Service)
- func (r *Reader) Translate(message int64, texts map[string]string)
- func (r *Reader) Unbind(key any)
- type ReaderBody
- type ReaderDeps
- type ReaderPage
- func (p *ReaderPage) Height(ctx context.Context, px int) error
- func (p *ReaderPage) Load(ctx context.Context) (ReaderBody, error)
- func (p *ReaderPage) Navigate(ctx context.Context, dir int) error
- func (p *ReaderPage) OpenLink(ctx context.Context, link string) error
- func (p *ReaderPage) Search(ctx context.Context) error
- func (p *ReaderPage) Wheel(ctx context.Context, dy float64) error
- type Review
- type ReviewBlock
- type ReviewOp
- type ReviewToken
- type RunStart
- type SaveResult
- type SendResult
- type SendWarning
- type Signature
- type SignaturePage
- func (p *SignaturePage) Load(ctx context.Context, account int64) (string, error)
- func (p *SignaturePage) PickImage(ctx context.Context) (string, error)
- func (p *SignaturePage) Save(ctx context.Context, account int64, html string) error
- func (p *SignaturePage) Saved(ctx context.Context, token int64, ok bool) error
- func (p *SignaturePage) State(ctx context.Context) (SignatureState, error)
- type SignatureState
- type Skill
- type Target
- type Theme
- type Window
- type Windows
- func (ws *Windows) CloseAll(done func(ok bool))
- func (ws *Windows) CloseDraft(draftID int64)
- func (ws *Windows) Closed(winID int)
- func (ws *Windows) Count() int
- func (ws *Windows) Done(winID int)
- func (ws *Windows) IsOpen(draftID int64) bool
- func (ws *Windows) Open(draftID int64)
- func (ws *Windows) RequestClose(winID int)
- type Wit
- type WitCall
- type WitEvent
- type WitHistory
- type WitInfo
- type WitMessage
- type WitOpenMsg
- type WitPage
- func (p *WitPage) Ask(ctx context.Context, conv int64, input string, quoted []int64) (RunStart, error)
- func (p *WitPage) Decide(ctx context.Context, approval int64, accept bool) error
- func (p *WitPage) DecideAll(ctx context.Context, run int64, accept bool) error
- func (p *WitPage) DecideSession(ctx context.Context, approval int64) error
- func (p *WitPage) Follow(ctx context.Context, conv int64) (WitHistory, error)
- func (p *WitPage) Load(ctx context.Context) (WitPageState, error)
- func (p *WitPage) Navigate(ctx context.Context, dir int) error
- func (p *WitPage) OpenCited(ctx context.Context, message int64) error
- func (p *WitPage) OpenLink(ctx context.Context, link string) error
- func (p *WitPage) OpenModels(ctx context.Context) error
- func (p *WitPage) SearchMail(ctx context.Context, query string) ([]MailHit, error)
- func (p *WitPage) Stop(ctx context.Context, run int64) error
- type WitPageDeps
- type WitPageState
- type WitResult
Constants ¶
const ImageScheme = "godwit-img"
ImageScheme is the URL scheme of a message's remote images in its body, served by ImageHandler: godwit-img://m<message>/<token>.
Variables ¶
var ( // ErrNoDraft is returned to a window that has no draft attached. ErrNoDraft = errors.New("this window has no draft") // ErrNotReady is returned before the data is open. ErrNotReady = errors.New("the data is not open yet") // ErrNoRevision is returned for a save without the revision it edits; // core skips the conflict check for revision 0 (core/compose.go SaveDraft). ErrNoRevision = errors.New("a save needs the revision it edits") // ErrNoPicker is returned for attaching files when there is no file dialog. ErrNoPicker = errors.New("no file dialog") )
var ( // ErrBadHeight is returned for a negative or absurd height. ErrBadHeight = errors.New("the height is out of range") // ErrBadWheel is returned for a wheel delta that is not a number. ErrBadWheel = errors.New("the wheel delta is not a number") )
var ( // SignatureAccount tells the signature page which account to show: it // saves the shown one's pending edit first. SignatureAccount = mygo.NewEvent[int64]("signatureAccount") // SignatureFlush asks the signature page to save now; it answers with // SignaturePage.Saved and the same token. SignatureFlush = mygo.NewEvent[int64]("signatureFlush") )
var ( // Closing tells a compose page its window is closing: it flushes its // input and calls ComposePage.Closed with the payload, the close // attempt, so an answer to an earlier attempt counts for nothing. Closing = mygo.NewEvent[int]("closing") // ThemeChanged carries the theme to every page when the settings change. ThemeChanged = mygo.NewEvent[Theme]("theme") )
var ( // ErrBadDecisions is returned for decisions that are not one 1 (accept) // or -1 (reject) per change of an inline review. ErrBadDecisions = errors.New("one decision, 1 or -1, per change of an inline review") // ErrBadSelection is returned for an empty selection or one outside the text. ErrBadSelection = errors.New("the selection is empty or outside the text") // ErrBadLink is returned for a link that is not http, https or mailto. ErrBadLink = errors.New("only http, https and mailto links open") )
var ( // WitOpen tells the Wit page the route's conversation changed. WitOpen = mygo.NewEvent[WitOpenMsg]("witOpen") // WitState tells the Wit page its model label, copy or theme changed // (the settings did); the conversation and its stream stay. WitState = mygo.NewEvent[WitPageState]("witState") // WitAsk hands the Wit page a question native collected (a search that // found nothing): the page asks it once, in the conversation it shows. WitAsk = mygo.NewEvent[string]("witAsk") )
var ErrBadDirection = errors.New("navigate goes back (-1) or forward (1)")
ErrBadDirection is returned for a Navigate that is not -1 or 1.
var ErrNotAsk = errors.New("the Wit page acts on its ask conversation only")
ErrNotAsk is returned to the Wit page for a conversation that is not an ask one, or an approval or run not of the ask conversation it follows.
var ErrSignatureAccountGone = errors.New("signature account gone")
ErrSignatureAccountGone is final: the saver (saver.ts) drops the pending edit.
var ErrSignatureTooLarge = errors.New("the signature is too large")
ErrSignatureTooLarge is returned for a signature over maxSignatureBytes.
var ErrWrongPage = errors.New("this page may not call that")
ErrWrongPage is returned to a caller that is not a registered page of the role a method serves: a window, another role's page, or none.
var ReaderReload = mygo.NewEvent[ReaderBody]("readerBody")
ReaderReload tells a reader page its body changed (加载图片, a retry).
var WitStream = mygo.NewEvent[WitEvent]("wit")
WitStream carries Wit events to the window or page following them only (a Target). Each follows one conversation at a time: a run or Follow in another conversation replaces what it followed.
Functions ¶
func ThemeVars ¶
ThemeVars maps tokens to shadcn's CSS variables, plus Wit's review marks (--ins-* and --del-*), the warning colours (--warning-*) and the floating input's shadow (--shadow-float: ShadowFloat in the light appearance, the FloatInset inner edge in the dark), the window material's colour (--window) and a card's shadow (--shadow-xs: ShadowXs, black in both). --radius is Radius.Lg; styles.css derives sm…4xl from it by fixed offsets, landing on the native 4/6/8/12/16/24/32.
Types ¶
type Account ¶
type Account struct {
// ID and Email identify the account.
ID int64 `json:"id"`
Email string `json:"email"`
}
Account is a sender the page can pick.
type Approval ¶
type Approval struct {
ID int64 `json:"id"`
Run int64 `json:"run"`
// CallID is the tool call it answers ("skill" for a skill's edit).
CallID string `json:"callId"`
Tool string `json:"tool"`
Summary string `json:"summary"`
// State is pending, executing, done, failed, rejected or stale.
State string `json:"state"`
Error string `json:"error"`
Destinations []string `json:"destinations"`
// Args is the call's arguments, JSON text ("" for none).
Args string `json:"args"`
// SessionAllow: 本次对话都允许 can decide it (WitPage.DecideSession).
SessionAllow bool `json:"sessionAllow"`
}
Approval is a call waiting for the user, or decided.
type AttachResult ¶
type AttachResult struct {
Change
// TooLarge are the files over the size limit; Failed those that failed
// for another reason (logged).
TooLarge []string `json:"tooLarge"`
Failed []string `json:"failed"`
}
AttachResult is the outcome of adding files: a partial success is no error.
type Attachment ¶
type Attachment struct {
// ID names it to RemoveAttachment; Size is in bytes.
ID int64 `json:"id"`
Filename string `json:"filename"`
Size int `json:"size"`
}
Attachment is a file attached to the draft.
type BodyChange ¶
BodyChange is the draft after a Wit action, read again: Body is its editable HTML as stored, which the page adopts with the Change at once.
type Change ¶
type Change struct {
// Revision and Attachments are the draft's after the change.
Revision int64 `json:"revision"`
Attachments []Attachment `json:"attachments"`
// Conflict means the draft changed elsewhere: nothing was done.
Conflict bool `json:"conflict"`
// Signature is the draft's signature as plain text, SignatureImages its
// images as data: URLs.
Signature string `json:"signature"`
SignatureImages []string `json:"signatureImages"`
// UpdatedAt is when the draft was last stored, in Unix milliseconds.
UpdatedAt int64 `json:"updatedAt"`
}
Change is the outcome of an account switch or an attachment change.
type Citation ¶
type Citation struct {
N int `json:"n"`
MessageID int64 `json:"messageId"`
Subject string `json:"subject"`
From string `json:"from"`
// Date is in Unix milliseconds, 0 for none.
Date int64 `json:"date"`
// Suspect means it seems to hold instructions (wit.suspect).
Suspect bool `json:"suspect"`
// Quote is the suspect text from where it starts, at most 40 runes; mail text, shown as plain text.
Quote string `json:"quote"`
}
Citation is a message Wit read, numbered N from 1 in the conversation (core.Citation.N).
type Compose ¶
type Compose struct {
// contains filtered or unexported fields
}
Compose keeps each compose window's session: its draft and the parts of the draft the page does not edit. It is not bound: pages reach it only through ComposePage.
func NewCompose ¶
func NewCompose() *Compose
NewCompose is a Compose with no windows; SetService opens it up.
func (*Compose) Detach ¶
Detach forgets window winID's draft: new calls from it get ErrNoDraft; one already in progress finishes. Its Wit events stop.
func (*Compose) OnClosed ¶
OnClosed sets the hook that hears the page's final flush: gen is the close attempt it answers (the Closing event's payload), saved whether it succeeded.
func (*Compose) OnDone ¶
OnDone sets the hook told that window winID's draft was sent or discarded: the window can close without asking.
func (*Compose) Release ¶
Release lets go of closed window winID: new calls from it get ErrNoDraft, the call in progress finishes first, then its draft is deleted if it is empty (core DeleteDraftIfEmpty, on the revision checked). Its Wit events stop; a run goes on.
func (*Compose) SetService ¶
SetService gives Compose the service, once the data is open.
type ComposeEdit ¶
type ComposeEdit struct {
// To, Cc, Bcc, ReplyTo, Subject and Body (HTML) are the edited fields, as
// in ComposeState; Revision is the one they were made against.
To []string `json:"to"`
Cc []string `json:"cc"`
Bcc []string `json:"bcc"`
ReplyTo string `json:"replyTo"`
Subject string `json:"subject"`
Body string `json:"body"`
Revision int64 `json:"revision"`
}
ComposeEdit is what the page saves: the fields it edits, and the revision they were made against.
type ComposePage ¶
type ComposePage struct {
// contains filtered or unexported fields
}
ComposePage is what compose pages call (mygo.Bind); every method acts on the calling window's draft only.
func NewComposePage ¶
func NewComposePage(c *Compose, d PageDeps) *ComposePage
NewComposePage is the bound facade of c.
func (*ComposePage) AddAttachments ¶
func (p *ComposePage) AddAttachments(ctx context.Context, revision int64) (AttachResult, error)
AddAttachments asks for files in a dialog on the calling window and adds each to its draft, if the draft is at revision (else Conflict, without the dialog). A file over the limit or failing is reported, not an error; a write from elsewhere stops the adding with Conflict, the files added so far in Attachments.
The dialog runs without the session lock: Release does not wait for it (AppKit gives no promise a sheet on a closed window ever ends), and once the window is released the files are dropped (ErrNoDraft).
func (*ComposePage) Ask ¶
Ask asks Wit about the calling window's draft, with the mail the user quoted (message IDs; core AssistWith), and returns the run's ID; its events go to the window on WitStream.
func (*ComposePage) Closed ¶
Closed is the page's final flush for the close attempt gen, the payload of the Closing event it answers: saved reports whether it succeeded.
func (*ComposePage) Decide ¶
func (p *ComposePage) Decide(ctx context.Context, approval int64, accept bool) (BodyChange, error)
Decide accepts or rejects approval, any pending one of the calling window's draft (a draft edit or a tool's call). The window follows its conversation first, so the run it resumes streams on WitStream. A draft changed since the edit was proposed is Conflict.
func (*ComposePage) DecideAll ¶
func (p *ComposePage) DecideAll(ctx context.Context, run int64, accept bool) (BodyChange, error)
DecideAll accepts or rejects every pending approval of run, one of the calling window's draft (core ResolveAll; 全部允许). As Decide.
func (*ComposePage) Finish ¶
func (p *ComposePage) Finish(ctx context.Context, approval int64, decisions []int) (BodyChange, error)
Finish settles approval, an inline draft edit, with a decision per change (Review.Changes; 1 accepts, -1 rejects): all accepted or all rejected decides it; a mix applies the text the decisions make. As Decide.
func (*ComposePage) Follow ¶
func (p *ComposePage) Follow(ctx context.Context) (WitHistory, error)
Follow makes the calling window follow its draft's conversation (a run going on, else an edit waiting, else the Assist one) and returns its history as read after subscribing. Events that come during the reads are held back and sent after: a run seen ending meanwhile shows as ended, read again. A run that ends later shows as Running: its end reaches the window after the reply, on the subscription, which goes on.
func (*ComposePage) Latest ¶
func (p *ComposePage) Latest(ctx context.Context) (ComposeState, error)
Latest is the draft as stored now, as Load, for resolving a conflict: its quote and signature become the ones saves keep.
func (*ComposePage) Load ¶
func (p *ComposePage) Load(ctx context.Context) (ComposeState, error)
Load is the calling window's draft, with the accounts, the theme and the page's copy.
func (*ComposePage) OpenLink ¶
func (p *ComposePage) OpenLink(ctx context.Context, link string) error
OpenLink opens a link from Wit's answer: an http or https one in the browser; a mailto one as a new draft to its addresses, from the calling window's account, in a compose window. Any other is ErrBadLink.
func (*ComposePage) OpenModels ¶
func (p *ComposePage) OpenModels(ctx context.Context) error
OpenModels opens the model settings (the input's model chip).
func (*ComposePage) RemoveAttachment ¶
RemoveAttachment removes attachment id from the calling window's draft, if the draft is at revision (else Conflict).
func (*ComposePage) Review ¶
Review is approval, a draft edit of the calling window's draft waiting for a decision, as the page reviews it.
func (*ComposePage) Rewrite ¶
func (p *ComposePage) Rewrite(ctx context.Context, revision int64, text string, start, end int, instruction string) (RunStart, error)
Rewrite rewrites [start, end) of the calling window's draft as instruction says (⌘K, core RewriteSelection). The page saved revision and sends its text and the selection in it in UTF-16 offsets (the plainText contract); a draft not at revision, or with another text, is Conflict. The run's events go to the window on WitStream.
func (*ComposePage) Save ¶
func (p *ComposePage) Save(ctx context.Context, e ComposeEdit) (SaveResult, error)
Save stores the edit in the calling window's draft, keeping its quote and signature. A draft changed elsewhere is a Conflict, not an error.
func (*ComposePage) SearchMail ¶
SearchMail is the quote picker's search (core Search, every account).
func (*ComposePage) Send ¶
func (p *ComposePage) Send(ctx context.Context, revision int64, digest string) (SendResult, error)
Send sends exactly revision of the calling window's draft, else Conflict. digest, from an earlier SendResult's warnings, sends despite them. Once sent, the window closes (OnDone).
func (*ComposePage) SetAccount ¶
SetAccount moves the calling window's draft to account id, whose signature replaces the old one; revision must be the stored one, else Conflict.
func (*ComposePage) Skill ¶
Skill runs skill id on the calling window's draft (core AssistSkill); translate-draft writes in language ("" for the reading language). It returns the run's ID; its events go to the window on WitStream.
func (*ComposePage) Stop ¶
func (p *ComposePage) Stop(ctx context.Context, run int64) error
Stop cancels run, which must be one of the calling window's draft.
func (*ComposePage) Undo ¶
func (p *ComposePage) Undo(ctx context.Context) (BodyChange, error)
Undo takes back the latest edit Wit applied to the calling window's draft (core UndoLastAssist).
type ComposeState ¶
type ComposeState struct {
// DraftID is the window's draft; Accounts are the senders to pick from.
DraftID int64 `json:"draftId"`
Accounts []Account `json:"accounts"`
// From is the sending account's ID.
From int64 `json:"from"`
// To, Cc, Bcc, ReplyTo and Subject are the header fields as stored.
To []string `json:"to"`
Cc []string `json:"cc"`
Bcc []string `json:"bcc"`
ReplyTo string `json:"replyTo"`
Subject string `json:"subject"`
// Body is the editable part as sanitized HTML.
Body string `json:"body"`
// Quote and Signature are read-only plain text; SignatureImages are the
// signature's images as data: URLs, shown after its text.
Quote string `json:"quote"`
Signature string `json:"signature"`
SignatureImages []string `json:"signatureImages"`
// Attachments are the draft's files.
Attachments []Attachment `json:"attachments"`
// Revision is what the next save must pass; Theme styles the page.
Revision int64 `json:"revision"`
Theme Theme `json:"theme"`
// UpdatedAt is when the draft was last stored, in Unix milliseconds.
UpdatedAt int64 `json:"updatedAt"`
// Locale selects the shared catalog bundled with the page.
Locale string `json:"locale"`
// Wit is what the Wit panel offers, as WitInfo.
Wit WitInfo `json:"wit"`
}
ComposeState is what a compose page shows when it opens.
type MailHit ¶
type MailHit struct {
ID int64 `json:"id"`
Subject string `json:"subject"`
From string `json:"from"`
// Date is in Unix milliseconds; 0 for none.
Date int64 `json:"date"`
}
MailHit is a message the quote picker offers.
type PageDeps ¶
type PageDeps struct {
// WinOf names the calling window (mygo.CallerWindow(ctx).ID() in production).
WinOf func(context.Context) (int, bool)
// PickFiles asks for files to attach, in a dialog on window winID; none
// picked is no error.
PickFiles func(ctx context.Context, winID int) ([]string, error)
// Emit sends a Wit event to a window or page (WitStream.Emit or
// EmitPage in production).
Emit func(t Target, ev WitEvent)
// OpenURL opens an http(s) link in the browser; OpenCompose opens draft
// id in a compose window.
OpenURL func(url string) error
OpenCompose func(draftID int64)
// OpenModels opens the model settings in the main window.
OpenModels func()
}
PageDeps is what ComposePage needs from the platform.
type Pages ¶
type Pages struct {
// contains filtered or unexported fields
}
Pages keeps the embedded pages and their roles. A page is known by an opaque key (its *mygo.Page in production) and gets an ID of its own.
func NewPages ¶
NewPages is a registry with no pages; pageOf is the calling page's key (mygo.CallerPage(ctx) in production).
func (*Pages) Caller ¶
Caller is the calling page's ID, if it is a registered page of role; else ErrWrongPage.
func (*Pages) Register ¶
Register makes the page with key one of role and returns its ID, new on every call; Unregister it when the page is destroyed.
func (*Pages) Unregister ¶
Unregister forgets the page with key: its calls get ErrWrongPage.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader keeps the reader pages (role "reader"), each bound to a message: its body, version and images. It is not bound: the pages reach it only through ReaderPage; native calls Bind, Unbind and Allow.
func NewReader ¶
func NewReader(pages *Pages, d ReaderDeps) *Reader
NewReader keeps the reader pages of pages; SetService opens it up.
func (*Reader) Allow ¶
Allow lets message's remote images load (加载图片), or loads its body again (a retry): its pages get the new body, with Remote, by Emit. A message no page shows is left alone. It returns at once: the body is read on a goroutine.
func (*Reader) Bind ¶
Bind makes the page with key (registered as "reader") show message; a page shows one message at a time.
func (*Reader) ImageHandler ¶
ImageHandler is the image proxy the pages load remote images from. It serves the image of a token of a message a page shows and whose images may load (Remote), from the cache: downloaded once through core's client (public hosts only, no cookies, no Referer), kept on disk, shared by messages.
func (*Reader) SetService ¶
SetService gives the pages the service, once the data is open.
type ReaderBody ¶
type ReaderBody struct {
Message int64 `json:"message"`
// Version orders the bodies of a page: it applies only a newer one, so
// a Load that resolves after a ReaderReload is dropped.
Version int64 `json:"version"`
// HTML is the sanitized body (remote images kept when Remote), its
// inline images within the message's budget and its structure within
// the limits; "" when the mail has no HTML, which Plain then holds.
HTML string `json:"html"`
Plain string `json:"plain"`
// Remote is that the message's remote images may load (the setting, or
// the user's 加载图片): HTML holds them as godwit-img: URLs, which the
// image proxy (ImageHandler) serves.
Remote bool `json:"remote"`
// Blocked is the remote images left out while not Remote.
Blocked int `json:"blocked"`
// Cut is that the body is only its start: the Service kept only that,
// or the limits cut it.
Cut bool `json:"cut"`
Theme Theme `json:"theme"`
Locale string `json:"locale"`
}
ReaderBody is a message's body as the reader page shows it.
type ReaderDeps ¶
type ReaderDeps struct {
// Emit sends a body to the page with key page (ReaderReload.EmitPage,
// which only queues it). It runs with the Reader's lock held, so the
// page is bound to b's message as it is sent: it must not block or call
// back into the Reader.
Emit func(page any, b ReaderBody)
// OnHeight is the height of message's body in page, in CSS pixels.
OnHeight func(page any, message int64, px int)
// OnWheel is a wheel delta page's body did not use: the reader scrolls.
OnWheel func(page any, dy float64)
// OnLink opens a link of page's body (the native confirmation; mailto
// composes).
OnLink func(page any, url string)
OnNavigate func(page any, dir int)
// OnSearch opens the mail list's search, as ⌘F does natively.
OnSearch func(page any)
// OnBuilt is told, for each page bound to b.Message, each body built
// as the message's current version: native shows the truncated notice
// by b.Cut and hides the remote-image notice once b.Remote. It runs
// with the Reader's lock held, as Emit does (so a page is told the
// bodies in their versions' order): it must not block or call back.
OnBuilt func(page any, b ReaderBody)
// OnFailed is told, for each page bound to message, that the body
// Allow read failed: native offers 加载图片 again. Under the lock too.
OnFailed func(page any, message int64, err error)
}
ReaderDeps is what Reader needs from the platform. The callbacks post to the UI thread themselves. Each names the page (its key) it is about, bound as the call was made: by the time the post runs the page may be closed or rebound, which the UI thread checks.
type ReaderPage ¶
type ReaderPage struct {
// contains filtered or unexported fields
}
ReaderPage is what a reader page (role "reader", one per expanded message) calls (mygo.Bind). Each acts on the caller's own message.
func NewReaderPage ¶
func NewReaderPage(r *Reader) *ReaderPage
NewReaderPage is the bound facade of r.
func (*ReaderPage) Height ¶
func (p *ReaderPage) Height(ctx context.Context, px int) error
Height is the body's height in CSS pixels, for the native layout.
func (*ReaderPage) Load ¶
func (p *ReaderPage) Load(ctx context.Context) (ReaderBody, error)
Load is the caller's message's body, as of its version.
func (*ReaderPage) Navigate ¶
func (p *ReaderPage) Navigate(ctx context.Context, dir int) error
Navigate goes back (-1) or forward (1), as ⌘[ and ⌘] do natively.
func (*ReaderPage) OpenLink ¶
func (p *ReaderPage) OpenLink(ctx context.Context, link string) error
OpenLink opens a link of the body (its data-href) natively: an http or https one after the confirmation, a mailto one in a compose window. Any other is ErrBadLink.
type Review ¶
type Review struct {
Approval int64 `json:"approval"`
Tool string `json:"tool"`
// Inline means the changes are shown and decided word by word (Finish);
// else it is a rewrite, decided as a whole (Decide).
Inline bool `json:"inline"`
// Ratio is the share of words changed; Exact means the diff completed
// within its budget, so Ratio is known (else wit.compose.rewrite_plain).
Ratio float64 `json:"ratio"`
Exact bool `json:"exact"`
// Blocks are the new text with the changes marked, when the block shapes are kept (Inline); Changes
// is how many changes they hold, the length Finish wants.
Blocks []ReviewBlock `json:"blocks"`
Changes int `json:"changes"`
// Old and New are the editable HTML before and after, for the compare.
Old string `json:"old"`
New string `json:"new"`
}
Review is a pending draft edit as the compose page reviews it.
type ReviewBlock ¶
type ReviewBlock struct {
// Kind is paragraph, heading, quote, listItem or pre; Level and Ordered
// as in the editor (heading level, quote or list depth; an <ol> item).
Kind string `json:"kind"`
Level int `json:"level"`
Ordered bool `json:"ordered"`
// Added and Removed mark a whole block added or removed: change Whole
// (else -1), even when it is empty.
Added bool `json:"added"`
Removed bool `json:"removed"`
Whole int `json:"whole"`
Ops []ReviewOp `json:"ops"`
}
ReviewBlock is a block of the review.
type ReviewOp ¶
type ReviewOp struct {
// Kind is same, del or ins; Change the change it belongs to, -1 for same.
Kind string `json:"kind"`
Change int `json:"change"`
Tokens []ReviewToken `json:"tokens"`
// Link, on the last op of a change of only a link's address, is the new
// address (wit.compose.link).
Link string `json:"link"`
}
ReviewOp is a run of words kept, deleted or inserted.
type ReviewToken ¶
type ReviewToken struct {
Text string `json:"text"`
Bold bool `json:"bold"`
Italic bool `json:"italic"`
Href string `json:"href"`
}
ReviewToken is text in one style.
type RunStart ¶
type RunStart struct {
Run int64 `json:"run"`
Conversation int64 `json:"conversation"`
Revision int64 `json:"revision"`
Conflict bool `json:"conflict"`
}
RunStart is a ⌘K run started, or Conflict: the draft is not at the revision, or its text is not the text the page sent. Revision is the draft's stored revision. For WitPage.Ask, Conversation is the run's conversation (made for a new one).
type SaveResult ¶
type SaveResult struct {
// Revision is the draft's new revision, to pass to the next save.
Revision int64 `json:"revision"`
// Conflict means the draft changed elsewhere: nothing was saved.
Conflict bool `json:"conflict"`
}
SaveResult is the outcome of a save.
type SendResult ¶
type SendResult struct {
// Sent means it is in the outbox and the window closes.
Sent bool `json:"sent"`
// Conflict means the draft is not at the revision sent: nothing was sent.
Conflict bool `json:"conflict"`
// Warnings, with Digest, need the user's go-ahead: Send again with Digest.
Warnings []SendWarning `json:"warnings"`
Digest string `json:"digest"`
// Blocked is the plugin that refused the draft, and its message.
Blocked *SendWarning `json:"blocked"`
}
SendResult is the outcome of a send.
type SendWarning ¶
type SendWarning struct {
// Plugin is its name; Message what it said.
Plugin string `json:"plugin"`
Message string `json:"message"`
}
SendWarning is a plugin's word about the draft.
type Signature ¶
type Signature struct {
// contains filtered or unexported fields
}
Signature keeps the signature page's state (role "signature", embedded in the account settings): the account native shows and the flushes waiting for the page. It is not bound: the page reaches it only through SignaturePage.
func NewSignature ¶
NewSignature is the signature page's state; SetService opens it up. pick asks for one image file, in a dialog on the calling page's window: its path, "" for none.
func (*Signature) Close ¶
func (s *Signature) Close()
Close forgets the page (its view closing): the flushes waiting get no answer, and later ones answer at once until a page runs again.
func (*Signature) Flush ¶
Flush asks the page to save now through emit (SignatureFlush); done hears its answer, once, on the page's goroutine. A page that never ran holds no edit: done(true) at once.
func (*Signature) SetService ¶
SetService gives the page the service, once the data is open.
type SignaturePage ¶
type SignaturePage struct {
// contains filtered or unexported fields
}
SignaturePage is what the signature page calls (mygo.Bind).
func NewSignaturePage ¶
func NewSignaturePage(s *Signature) *SignaturePage
NewSignaturePage is the bound facade of s.
func (*SignaturePage) Load ¶
Load is account's signature as the editor's HTML: sanitized, a plain one escaped into a paragraph, its images as data: URLs.
func (*SignaturePage) PickImage ¶
func (p *SignaturePage) PickImage(ctx context.Context) (string, error)
PickImage asks for an image to insert and returns it as a data: URL, "" for none picked: a png, jpeg, gif or webp (by its content) of at most 512 KB, else core.ErrSignatureImage.
func (*SignaturePage) Save ¶
Save stores html as account's signature, marked as editor HTML ("" for none); drafts sanitize it as they take it. Its data: images become the account's signature images (core.ErrSignatureImage, ErrSignatureImageCount).
func (*SignaturePage) Saved ¶
Saved answers the flush token: ok is whether the page's save succeeded.
func (*SignaturePage) State ¶
func (p *SignaturePage) State(ctx context.Context) (SignatureState, error)
State is the account shown, the locale and the theme.
type SignatureState ¶
type SignatureState struct {
Account int64 `json:"account"`
Locale string `json:"locale"`
Theme Theme `json:"theme"`
}
SignatureState is what the signature page needs besides a signature: the account shown (0 before native showed one), its locale and theme.
type Skill ¶
type Skill struct {
ID string `json:"id"`
Label string `json:"label"`
// Hint is what the skill changes, shown beside its label.
Hint string `json:"hint"`
}
Skill is a 调整 menu item.
type Target ¶
Target is where Wit events go: a window or a registered page. Exactly one is set; page IDs come from Pages.Register.
type Theme ¶
type Theme struct {
// Mode is the user's choice: "system", "light" or "dark".
Mode string `json:"mode"`
// Light and Dark map CSS variable names to values for each appearance.
Light map[string]string `json:"light"`
Dark map[string]string `json:"dark"`
// FontSize is the interface font size in CSS pixels.
FontSize float32 `json:"fontSize"`
// BodyFontSize is the mail body font size in CSS pixels (the reader's).
BodyFontSize float32 `json:"bodyFontSize"`
}
Theme is what a web page needs to look like the native UI: the CSS variables of both appearances (the page picks by Mode, following the system's for "system"), the interface font size and the mail body's.
type Window ¶
type Window interface {
ID() int
Focus()
// Destroy closes the window without asking again.
Destroy()
// EmitClosing tells the page to flush and call Closed with gen.
EmitClosing(gen int)
}
Window is one compose window, as Windows drives it.
type Windows ¶
type Windows struct {
// OnChange, when set (before any window opens), is called after a window
// registers and after a closed window's release, the empty-draft delete
// included: IsOpen has changed. Never under mu.
OnChange func()
// contains filtered or unexported fields
}
Windows opens one compose window per draft and lets none close or quit with input unsaved: a window closes once its page reports its last input saved, or the user chose to close it anyway. No timeout closes one.
func NewWindows ¶
NewWindows opens windows with newWindow. ask shows 「有修改没有保存」 for a window whose last input could not be saved: true closes it anyway. Windows hears the pages' final flush through c.OnClosed.
func (*Windows) CloseAll ¶
CloseAll closes every window as RequestClose does, for quitting; done reports, once every one has gone or been kept, whether all went. A CloseAll while one is in progress joins it: only the first done runs.
func (*Windows) CloseDraft ¶
CloseDraft destroys draftID's window, if one is open, as Done: the draft was deleted elsewhere.
func (*Windows) Closed ¶
Closed is told when window winID went, on mygo's main thread: it returns at once, and its page's session is released (Compose.Release, which waits for a call in progress and deletes an empty draft) on another goroutine. The window counts as open, and a CloseAll waits for it, until that release is done, so a quit never exits in the middle of it.
func (*Windows) Done ¶
Done destroys window winID now, without a flush or a question: its draft was sent or discarded. A close or quit waiting for it settles once it has gone.
func (*Windows) Open ¶
Open shows draftID's window, opening it unless it is open already. While the draft's closed window is still being released, the Open waits for that: it opens then, unless the release deleted the draft as empty. While the window is being made, the Open joins that: it is focused once made.
func (*Windows) RequestClose ¶
RequestClose starts closing window winID, from its OnClose (always prevented): the page flushes, then the window closes once the page reports saved, or asks on a failed save or after 5 s without an answer. A window already closing goes on as it was: one flush, one question.
type Wit ¶
type Wit struct {
// contains filtered or unexported fields
}
Wit keeps the Wit page's state: the route's conversation as a versioned snapshot and the page's subscription. It is not bound: the page reaches it only through WitPage; native calls SetConversation and SettingsChanged.
func NewWit ¶
func NewWit(pages *Pages, d WitPageDeps) *Wit
NewWit is the Wit page's state for the pages of role "wit"; SetService opens it up.
func (*Wit) Handoff ¶
Handoff gives the page a question to ask (WitAsk): the page starts the run through WitPage.Ask, so it follows it and Stop works. Native navigates to a new conversation first.
func (*Wit) SetConversation ¶
SetConversation is the route's conversation (0: a new one), as native navigates: a new snapshot version, sent to the page (WitOpen) and returned.
func (*Wit) SetCreated ¶
SetCreated is SetConversation for native taking the conversation the page's Ask made (ConversationCreated): WitOpen says Created, so the page's first question goes on in it.
func (*Wit) SetService ¶
SetService gives the page the service, once the data is open.
func (*Wit) SettingsChanged ¶
SettingsChanged sends the page its state for st (WitState).
type WitEvent ¶
type WitEvent struct {
// Conversation and Run are the conversation and the run it belongs to.
Conversation int64 `json:"conversation"`
Run int64 `json:"run"`
// Kind is context, text, tool_call, tool_result, interrupted, done or error.
Kind string `json:"kind"`
// Text is a text delta.
Text string `json:"text"`
// Call is a tool_call's call; Result a tool_result's result.
Call *WitCall `json:"call"`
Result *WitResult `json:"result"`
// Interrupts are the calls an interrupt waits on; a skill's has ID
// "skill" and no tool_call before it.
Interrupts []WitCall `json:"interrupts"`
// Citations are the mail shown to the model (N is 0: the page numbers
// them after the history's); Approvals an interrupt's, in call order.
Citations []Citation `json:"citations"`
Approvals []Approval `json:"approvals"`
// Error is an error's i18n key; "" for a stop.
Error string `json:"error"`
}
WitEvent is one event of a Wit run, as core.WitEvent.
type WitHistory ¶
type WitHistory struct {
// Conversation is 0 when the draft has none yet.
Conversation int64 `json:"conversation"`
Messages []WitMessage `json:"messages"`
// Running is the run going on (not one waiting for a decision), else 0.
Running int64 `json:"running"`
// Approvals are every approval of the conversation, in any state.
Approvals []Approval `json:"approvals"`
}
WitHistory is a conversation as the Wit panel shows it.
type WitInfo ¶
type WitInfo struct {
// Enabled means the panel shows: a model is configured, or a plugin translates.
Enabled bool `json:"enabled"`
// TranslateOnly: no model, but a plugin translates. The panel offers its
// 翻译 menu alone: no input, no 调整, no chips.
TranslateOnly bool `json:"translateOnly"`
// Skills are the 调整 menu's; Languages the 翻译 menu's, the reading
// language first.
Skills []Skill `json:"skills"`
Languages []Language `json:"languages"`
// Chips name what Wit knows of the draft.
Chips []string `json:"chips"`
// Model is the default model's label, as the input's chip.
Model string `json:"model"`
}
WitInfo is what the Wit panel offers for the draft.
type WitMessage ¶
type WitMessage struct {
ID string `json:"id"`
// Role is user or assistant; an answer's Text is Markdown.
Role string `json:"role"`
Text string `json:"text"`
Calls []WitCall `json:"calls"`
Results []WitResult `json:"results"`
Citations []Citation `json:"citations"`
// Runs are the runs that added it (a question: the run it started).
Runs []int64 `json:"runs"`
}
WitMessage is a question, or the answer to one: everything the model said and called up to the next question.
type WitOpenMsg ¶
type WitOpenMsg struct {
Conversation int64 `json:"conversation"`
Version int64 `json:"version"`
Created bool `json:"created"`
}
WitOpenMsg tells the Wit page to show Conversation (0: a new one), the snapshot at Version. Created marks native taking the conversation the page's Ask made (SetCreated): the page's first question goes on in it, no switch.
type WitPage ¶
type WitPage struct {
// contains filtered or unexported fields
}
WitPage is what the Wit page (role "wit", embedded in the main window) calls (mygo.Bind). It acts on ask conversations only.
func (*WitPage) Ask ¶
func (p *WitPage) Ask(ctx context.Context, conv int64, input string, quoted []int64) (RunStart, error)
Ask asks input in conv, an ask conversation, with the mail the user quoted (message IDs; core AskWith); conv 0 makes one first, which ConversationCreated hears of. The page follows conv from before the run starts, unless a newer selection came meanwhile. Only Stop cancels the run: a page reload does not.
func (*WitPage) Decide ¶
Decide accepts or rejects approval, one of the conversation the page follows: the run it resumes streams on that subscription.
func (*WitPage) DecideAll ¶
DecideAll accepts or rejects every pending approval of run, one of the conversation the page follows (全部允许). As Decide.
func (*WitPage) DecideSession ¶
DecideSession accepts approval and allows its tool for the rest of the conversation (本次对话都允许; core ResolveApprovalForConversation). As Decide.
func (*WitPage) Follow ¶
Follow makes the page follow conv, an ask conversation (0: none), and returns its history as read after subscribing (follow.read). The newest selection wins: an older Follow or Ask no longer subscribes.
func (*WitPage) Load ¶
func (p *WitPage) Load(ctx context.Context) (WitPageState, error)
Load is the page's state: the snapshot, the model, the copy and the theme.
func (*WitPage) OpenLink ¶
OpenLink opens a link from Wit's answer: an http or https one in the browser; a mailto one as a new draft to its addresses, from the default account, in a compose window. Any other is ErrBadLink.
func (*WitPage) OpenModels ¶
OpenModels opens the model settings.
func (*WitPage) SearchMail ¶
SearchMail is the quote picker's search (core Search, every account).
type WitPageDeps ¶
type WitPageDeps struct {
// Emit sends a Wit event to the page (WitStream.EmitPage in production).
Emit func(t Target, ev WitEvent)
// Open and State send WitOpen and WitState to the page.
Open func(WitOpenMsg)
State func(WitPageState)
// Ask sends WitAsk to the page.
Ask func(query string)
// OpenMessage opens message id in the reader; OpenModels the model
// settings; Navigate goes back (-1) or forward (1).
OpenMessage func(id int64)
OpenModels func()
// ConversationCreated is told Ask made conversation id, asked under
// snapshot version.
ConversationCreated func(id, version int64)
// OpenURL opens an http(s) link in the browser; OpenCompose opens draft
// id in a compose window.
OpenURL func(url string) error
OpenCompose func(draftID int64)
}
WitPageDeps is what WitPage needs from the platform. The native callbacks post to the UI thread.
type WitPageState ¶
type WitPageState struct {
// Conversation is the route's (0: a new one) as of Version, the
// snapshot's: the page applies only newer ones (WitOpen).
Conversation int64 `json:"conversation"`
Version int64 `json:"version"`
// Model is the default model's label; "" for none.
Model string `json:"model"`
Locale string `json:"locale"`
Theme Theme `json:"theme"`
}
WitPageState is what the Wit page shows besides the conversation.