diff options
Diffstat (limited to 'gui/internal/ui/rules.go')
| -rw-r--r-- | gui/internal/ui/rules.go | 82 |
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 |
