aboutsummaryrefslogtreecommitdiff
path: root/gui/internal/ui/rules.go
diff options
context:
space:
mode:
Diffstat (limited to 'gui/internal/ui/rules.go')
-rw-r--r--gui/internal/ui/rules.go82
1 files changed, 75 insertions, 7 deletions
diff --git a/gui/internal/ui/rules.go b/gui/internal/ui/rules.go
index 939d77f..0a10996 100644
--- a/gui/internal/ui/rules.go
+++ b/gui/internal/ui/rules.go
@@ -27,13 +27,15 @@ type rulesView struct {
w *Window
root *gtk.Box
- dirs *gtk.DropDown
- names []string
- save *gtk.Button
- revert *gtk.Button
- reload *gtk.Button
+ dirs *gtk.DropDown
+ names []string
+ save *gtk.Button
+ revert *gtk.Button
+ reload *gtk.Button
+ checkNow *gtk.Button
view *gtk.TextView
+ nums *gtk.TextView
buf *gtk.TextBuffer
check *gtk.Label
diags *gtk.ListBox
@@ -46,6 +48,7 @@ type rulesView struct {
forms *formsView
rules *model.Rules
pending glib.SourceHandle
+ lines int
quiet bool // set while the view is being filled, so no check is armed
inSwap bool // set while a sub-tab switch is being handled
}
@@ -64,6 +67,7 @@ func newRulesView(w *Window) *rulesView {
r.save.AddCSSClass("suggested-action")
r.revert = gtk.NewButtonWithLabel("Revert")
r.reload = gtk.NewButtonWithLabel("Reload")
+ r.checkNow = gtk.NewButtonWithLabel("Check")
bar := gtk.NewBox(gtk.OrientationHorizontal, 6)
bar.SetMarginTop(6)
@@ -78,6 +82,7 @@ func newRulesView(w *Window) *rulesView {
r.check.SetEllipsize(pango.EllipsizeEnd)
r.check.SetMaxWidthChars(20)
bar.Append(r.check)
+ bar.Append(r.checkNow)
bar.Append(r.reload)
bar.Append(r.revert)
bar.Append(r.save)
@@ -88,8 +93,31 @@ func newRulesView(w *Window) *rulesView {
r.view.SetRightMargin(8)
r.view.SetTopMargin(6)
r.buf = r.view.Buffer()
+
+ // Line numbers: their own view beside the editor, in the same scrolled
+ // window so the two always line up. The editor does not wrap, so one
+ // line of text is one line on screen (his request, 2026-09-16).
+ r.nums = gtk.NewTextView()
+ r.nums.SetMonospace(true)
+ r.nums.SetEditable(false)
+ r.nums.SetCursorVisible(false)
+ r.nums.SetJustification(gtk.JustifyRight)
+ r.nums.SetLeftMargin(6)
+ r.nums.SetRightMargin(6)
+ r.nums.SetTopMargin(6)
+ r.nums.AddCSSClass("dim-label")
+ r.nums.SetCanFocus(false)
+ r.nums.SetVAlign(gtk.AlignStart)
+ r.nums.SetSizeRequest(46, -1)
+ r.view.SetVAlign(gtk.AlignStart)
+ editRow := gtk.NewBox(gtk.OrientationHorizontal, 0)
+ editRow.Append(r.nums)
+ editRow.Append(gtk.NewSeparator(gtk.OrientationVertical))
+ editRow.Append(r.view)
+ r.view.SetHExpand(true)
+
editScroll := gtk.NewScrolledWindow()
- editScroll.SetChild(r.view)
+ editScroll.SetChild(editRow)
editScroll.SetVExpand(true)
editScroll.SetHExpand(true)
@@ -182,6 +210,14 @@ func newRulesView(w *Window) *rulesView {
}
})
r.reload.ConnectClicked(func() { r.reloadFromDisk() })
+ r.checkNow.ConnectClicked(func() {
+ r.runCheck()
+ if len(r.rules.Diags) == 0 {
+ r.w.setStatus("check: no errors in %s", escape(xdg.Abbrev(r.rules.File)))
+ } else {
+ r.w.setStatus("check: %d problem(s); the list is under the editor", len(r.rules.Diags))
+ }
+ })
r.testGo.ConnectClicked(r.onTest)
r.testPath.ConnectActivate(r.onTest)
@@ -201,6 +237,12 @@ func (r *rulesView) formsOf() ([]model.Form, error) {
// setCheck writes one line in the bar where the check result goes.
func (r *rulesView) setCheck(text string) { r.check.SetText(escape(text)) }
+// showTestOutput writes in the pane on the right, where both Test on file
+// and Test rule report.
+func (r *rulesView) showTestOutput(text string) {
+ r.out.Buffer().SetText(escapeText(text))
+}
+
// showText brings the Text sub-tab forward.
func (r *rulesView) showText() {
r.inSwap = true
@@ -327,8 +369,34 @@ func (r *rulesView) runCheck() {
row.SetName(fmt.Sprintf("%d", line))
}
}
- r.save.SetSensitive(len(diags) == 0 && r.rules.Modified())
+ canSave := len(diags) == 0 && r.rules.Modified()
+ r.save.SetSensitive(canSave)
r.revert.SetSensitive(r.rules.Modified())
+ switch {
+ case canSave:
+ r.save.SetTooltipText("write " + xdg.Abbrev(r.rules.File) +
+ ", keeping the previous text as " + r.rules.Name + ".conf.bak")
+ case len(diags) > 0:
+ r.save.SetTooltipText("Save waits until the problems below are fixed")
+ r.check.SetText(r.check.Text() + " - Save waits until they are fixed")
+ default:
+ r.save.SetTooltipText("nothing to save: the file matches what is on disk")
+ }
+ r.updateLineNumbers()
+}
+
+// updateLineNumbers refills the gutter when the number of lines changes.
+func (r *rulesView) updateLineNumbers() {
+ n := r.buf.LineCount()
+ if n == r.lines {
+ return
+ }
+ r.lines = n
+ var b strings.Builder
+ for i := 1; i <= n; i++ {
+ fmt.Fprintf(&b, "%3d\n", i)
+ }
+ r.nums.Buffer().SetText(strings.TrimSuffix(b.String(), "\n"))
}
// goToLine puts the cursor on the line a diagnostic names, so clicking one