From 85d65ebe0adf1b156324a3a4c220e415a79ba9ce Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 16 Sep 2026 14:13:26 +0200 Subject: gui: Rules tab - the file as text, checked as you type, tested and saved --- gui/internal/ui/window.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'gui/internal/ui/window.go') diff --git a/gui/internal/ui/window.go b/gui/internal/ui/window.go index c42a7e8..2453444 100644 --- a/gui/internal/ui/window.go +++ b/gui/internal/ui/window.go @@ -27,6 +27,7 @@ type Window struct { plan *planView history *historyView + rules *rulesView status *gtk.Label } @@ -44,7 +45,8 @@ func NewWindow(app *gtk.Application, e *engine.Engine) *Window { notebook.AppendPage(w.plan.root, gtk.NewLabel("Plan")) w.history = newHistoryView(w) notebook.AppendPage(w.history.root, gtk.NewLabel("History & undo")) - notebook.AppendPage(placeholder("The rules editor arrives with a later milestone."), gtk.NewLabel("Rules")) + w.rules = newRulesView(w) + notebook.AppendPage(w.rules.root, gtk.NewLabel("Rules")) // The log is read when the tab is first opened, not at start-up: a // window that only sorts never reads it. loaded := false @@ -81,6 +83,21 @@ func NewWindow(app *gtk.Application, e *engine.Engine) *Window { // Show puts the window on screen. func (w *Window) Show() { w.win.Show() } +// reloadEngine re-reads the configuration, after the rules editor saves, so +// every tab works from the rules the user just wrote. An open plan came +// from the old ones, so it is closed and its lock released. +func (w *Window) reloadEngine() error { + e, diags := engine.Load(w.engine.MainFile) + if len(diags) > 0 { + return diags[0] + } + e.CacheDir = w.engine.CacheDir + w.plan.closeTab() + w.history.closeTab() + w.engine = e + return nil +} + // dirRoot is the path of the configured directory called name, or "" if // the configuration no longer has one - a log entry can outlive its // directory. @@ -126,6 +143,18 @@ func escape(s string) string { return b.String() } +// escapeText is escape for text shown in a pane rather than on one line: +// line breaks are the layout, so they are kept, and every other control or +// bidirectional character is still written as an escape. +func escapeText(s string) string { + var b strings.Builder + for _, line := range strings.Split(s, "\n") { + b.WriteString(escape(line)) + b.WriteString("\n") + } + return strings.TrimSuffix(b.String(), "\n") +} + // runInBackground runs work off the main loop and hands its result back to // the GTK thread with done. GTK may only be touched from the main loop. func runInBackground(work func(context.Context) error, done func(error)) context.CancelFunc { -- cgit v1.3