aboutsummaryrefslogtreecommitdiff
path: root/gui/internal/model/testrule.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-16 23:31:44 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-16 23:31:44 +0200
commit9db67b201b80e9b7f824989df8517cefc587036d (patch)
tree18fba03617ae97e6a0eadeeb751eda97165f6123 /gui/internal/model/testrule.go
parent168fae0f72c3ca5ff9b307a42fb75173e58b5b17 (diff)
downloadkrino-9db67b201b80e9b7f824989df8517cefc587036d.tar.gz
krino-9db67b201b80e9b7f824989df8517cefc587036d.zip
gui: line numbers, a Check button, an operator for age and size, and Test rule
Diffstat (limited to 'gui/internal/model/testrule.go')
-rw-r--r--gui/internal/model/testrule.go75
1 files changed, 75 insertions, 0 deletions
diff --git a/gui/internal/model/testrule.go b/gui/internal/model/testrule.go
new file mode 100644
index 0000000..3cf0437
--- /dev/null
+++ b/gui/internal/model/testrule.go
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package model
+
+import (
+ "context"
+ "fmt"
+
+ "krino/internal/engine"
+ "krino/internal/plan"
+)
+
+// RuleHit is one file a rule would act on, and what it would do to it.
+type RuleHit struct {
+ Rel string
+ Steps []plan.Step
+}
+
+// RuleHits is the answer to "which files would this rule take?".
+type RuleHits struct {
+ Rule string
+ Files []RuleHit
+ Scanned int
+}
+
+// TestRule plans the directory with the unsaved text and reports the files
+// the named rule would act on. It reads only: no lock is taken - the file
+// the Plan tab is looking at is none of its business - and nothing is
+// written or moved. Content extraction makes it as slow as a scan, so
+// callers run it off the main loop.
+func (r *Rules) TestRule(ctx context.Context, name string) (*RuleHits, error) {
+ e, diags := r.load()
+ if len(diags) > 0 {
+ return nil, fmt.Errorf("%s", diags[0])
+ }
+ var dir *engine.Dir
+ for _, d := range e.Dirs {
+ if d.Name == r.Name {
+ dir = d
+ break
+ }
+ }
+ if dir == nil {
+ return nil, fmt.Errorf("model: %s is not in the configuration", r.Name)
+ }
+ found := false
+ for _, rule := range dir.Rules {
+ if rule.Conf.Name == name {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return nil, fmt.Errorf("model: no rule called %q in %s", name, r.Name)
+ }
+ dp, err := e.Plan(ctx, dir, plan.NewClaims())
+ if err != nil {
+ return nil, err
+ }
+ hits := &RuleHits{Rule: name}
+ res := dp.Result
+ hits.Scanned = len(res.Matched) + len(res.Unmatched) + len(res.Skipped)
+ for _, c := range dp.Chains {
+ var steps []plan.Step
+ for _, s := range c.Steps {
+ if s.Rule == name {
+ steps = append(steps, s)
+ }
+ }
+ if len(steps) > 0 {
+ hits.Files = append(hits.Files, RuleHit{Rel: c.File.Rel, Steps: steps})
+ }
+ }
+ return hits, nil
+}