diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-16 01:02:33 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-16 01:02:33 +0200 |
| commit | be4b1275c76b9cad984dfafaa8023db94eb3eecf (patch) | |
| tree | 2a4db9266515d65f313bc26fb0ee5db14625b736 /internal/config/print.go | |
| parent | 40ecbfae85c4c76a8ed944a91f8c000b4ec55fc5 (diff) | |
| download | krino-be4b1275c76b9cad984dfafaa8023db94eb3eecf.tar.gz krino-be4b1275c76b9cad984dfafaa8023db94eb3eecf.zip | |
config prints and splices one form
Diffstat (limited to 'internal/config/print.go')
| -rw-r--r-- | internal/config/print.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/internal/config/print.go b/internal/config/print.go new file mode 100644 index 0000000..5c3d467 --- /dev/null +++ b/internal/config/print.go @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package config + +import ( + "strings" + + "krino/internal/sexp" +) + +// PrintRule renders a rule the way krino.conf(5) and the examples write +// one: the name on the first line, then each item on its own line indented +// two spaces, conditions inside (when ...) aligned under the first, and the +// closing paren on the last line. A GUI that edits a rule through a form +// writes the result back with this and Splice, leaving the rest of the file +// untouched (GUI design ยง5.1). +// +// What it prints comes from the parsed rule, so anything the parser dropped +// - comments inside the form, the writer's own line breaks - is not in the +// output; Splice's caller warns about that before replacing a form that +// holds comments. +func PrintRule(r *Rule) string { + var b strings.Builder + b.WriteString("(rule " + sexp.Quote(r.Name) + "\n") + if r.HasWhen { + b.WriteString(" (when ") + for i, c := range r.When { + if i > 0 { + b.WriteString("\n ") + } + b.WriteString(printNode(c)) + } + b.WriteString(")\n") + } + for _, line := range printSettings(r.Settings) { + b.WriteString(" " + line + "\n") + } + for _, a := range r.Actions { + b.WriteString(" " + printAction(a) + "\n") + } + if r.Stop { + b.WriteString(" (stop)\n") + } + // The closing paren belongs to the last line written, whichever it was. + out := strings.TrimRight(b.String(), "\n") + return out + ")\n" +} + +// PrintExclude renders an (exclude ...) form on one line. +func PrintExclude(x *Exclude) string { + var b strings.Builder + b.WriteString("(exclude") + for _, c := range x.When { + b.WriteString(" " + printNode(c)) + } + b.WriteString(")\n") + return b.String() +} + +// Splice replaces the bytes of the form between start and end - a form's +// Pos and End - with text, and returns the new file contents. Every other +// byte of src, comments and layout included, is kept exactly. +func Splice(src []byte, start, end sexp.Pos, text string) []byte { + out := make([]byte, 0, len(src)-(end.Offset-start.Offset)+len(text)) + out = append(out, src[:start.Offset]...) + out = append(out, text...) + return append(out, src[end.Offset:]...) +} + +// printAction renders one action form. +func printAction(a Action) string { + switch a.Kind { + case Delete: + return "(delete)" + case DeletePermanent: + return "(delete permanent)" + } + return "(" + a.Kind.String() + " " + sexp.Quote(a.Arg) + ")" +} + +// printSettings renders the settings a rule may carry (case, fold, +// on-conflict), in that order, leaving out those it does not set. +func printSettings(s Settings) []string { + var out []string + if s.Case != nil { + out = append(out, "(case "+s.Case.String()+")") + } + if s.Fold != nil { + word := "no" + if *s.Fold { + word = "yes" + } + out = append(out, "(fold "+word+")") + } + if s.OnConflict != nil { + out = append(out, "(on-conflict "+s.OnConflict.String()+")") + } + return out +} + +// printNode renders one condition node: a symbol as written, a string +// quoted, a list as its head and arguments separated by single spaces. +func printNode(n *sexp.Node) string { + switch n.Kind { + case sexp.String: + return sexp.Quote(n.Text) + case sexp.Symbol: + return n.Text + } + parts := make([]string, 0, len(n.Children)) + for _, c := range n.Children { + parts = append(parts, printNode(c)) + } + return "(" + strings.Join(parts, " ") + ")" +} |
