From add62fbfa054d10e046fb4dc836a64e1e638ab5c Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Tue, 8 Sep 2026 22:03:41 +1000 Subject: [PATCH] Added map-lines and upgraded UCL --- .idea/dequoter.iml | 1 + app.go | 2 ++ frontend/wailsjs/go/main/App.d.ts | 2 ++ frontend/wailsjs/go/main/App.js | 4 +++ go.mod | 2 +- go.sum | 6 ++-- plugins.go | 51 +++++++++++++++++++++++++++++-- 7 files changed, 63 insertions(+), 5 deletions(-) diff --git a/.idea/dequoter.iml b/.idea/dequoter.iml index 5e764c4..9c408cc 100644 --- a/.idea/dequoter.iml +++ b/.idea/dequoter.iml @@ -1,6 +1,7 @@ + diff --git a/app.go b/app.go index e46d5b9..37d2bd1 100644 --- a/app.go +++ b/app.go @@ -32,6 +32,7 @@ type App struct { func newUCLInst(plugins *PluginFilters) *ucl.Inst { return ucl.New( ucl.WithModule(plugins.Module()), + ucl.WithModule(builtins.Bytes()), ucl.WithModule(builtins.CSV(nil)), ucl.WithModule(builtins.Fns()), ucl.WithModule(builtins.FS(nil)), @@ -41,6 +42,7 @@ func newUCLInst(plugins *PluginFilters) *ucl.Inst { ucl.WithModule(builtins.OS()), ucl.WithModule(builtins.Strs()), ucl.WithModule(builtins.Time()), + ucl.WithModule(builtins.URLs()), ) } diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 56c40cf..f44f801 100755 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -10,6 +10,8 @@ export function ProcessText(arg1:main.ProcessTextRequest):Promise; export function PromptUser(arg1:string,arg2:any):Promise; +export function ReloadPlugins():Promise; + export function SaveCurrentBuffer(arg1:string):Promise; export function TriggerTextProcess(arg1:string):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 144d9f3..78a313d 100755 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -18,6 +18,10 @@ export function PromptUser(arg1, arg2) { return window['go']['main']['App']['PromptUser'](arg1, arg2); } +export function ReloadPlugins() { + return window['go']['main']['App']['ReloadPlugins'](); +} + export function SaveCurrentBuffer(arg1) { return window['go']['main']['App']['SaveCurrentBuffer'](arg1); } diff --git a/go.mod b/go.mod index 9a8d136..d967a05 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 lmika.dev/pkg/modash v0.1.0 lmika.dev/pkg/progdoc v0.0.0-20260207235039-984257fb414b - ucl.lmika.dev v0.1.3 + ucl.lmika.dev v0.1.7 ) require ( diff --git a/go.sum b/go.sum index 04dd12d..94bf82c 100644 --- a/go.sum +++ b/go.sum @@ -796,5 +796,7 @@ lmika.dev/pkg/modash v0.1.0/go.mod h1:8NDl/yR1eCCEhip9FJlVuMNXIeaztQ0Ks/tizExFcT lmika.dev/pkg/progdoc v0.0.0-20260207235039-984257fb414b h1:uarBEkpjAnpzO98btsA6ZDw9oGnJX8zSb8gZnCFl+6Y= lmika.dev/pkg/progdoc v0.0.0-20260207235039-984257fb414b/go.mod h1:GefQ+wxW6L0p2TfB4fzoP7ihOgEt5Lb/1qgXhruVHos= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -ucl.lmika.dev v0.1.3 h1:Y2m+ORnLMA8boQmkXpW41VbkR3bwmnZjDLGVTYbZQic= -ucl.lmika.dev v0.1.3/go.mod h1:Hjl6Udph2yuOPcBSytz4SFJVt5MZbM5JyiSAyTMTbNU= +ucl.lmika.dev v0.1.6 h1:cZocpR/IQcy9nvE8u+SSLY7/PE9fd1HIVWhZr/m+U5M= +ucl.lmika.dev v0.1.6/go.mod h1:Hjl6Udph2yuOPcBSytz4SFJVt5MZbM5JyiSAyTMTbNU= +ucl.lmika.dev v0.1.7 h1:3yfvWOhBnWpQIm4NhKrUBh5PajB1wzUWzoPPa8ltaVo= +ucl.lmika.dev v0.1.7/go.mod h1:Hjl6Udph2yuOPcBSytz4SFJVt5MZbM5JyiSAyTMTbNU= diff --git a/plugins.go b/plugins.go index 86dc977..baaf476 100644 --- a/plugins.go +++ b/plugins.go @@ -1,6 +1,8 @@ package main import ( + "bufio" + "bytes" "context" "errors" "fmt" @@ -18,7 +20,6 @@ const pluginKeyPrefix = "plugin:" // PluginFilters is the registry of text filters defined by UCL plugin files. type PluginFilters struct { - inst *ucl.Inst filters map[string]TextProcessor errors []error } @@ -34,7 +35,8 @@ func (p *PluginFilters) Module() ucl.Module { return ucl.Module{ Name: "d", Builtins: map[string]ucl.BuiltinHandler{ - "filter": p.filterBuiltin, + "filter": p.filterBuiltin, + "map-lines": p.mapLinesBuiltin, }, } } @@ -78,6 +80,51 @@ func (p *PluginFilters) filterBuiltin(ctx context.Context, args ucl.CallArgs) (a return nil, nil } +// mapLinesBuiltin implements `d:map-lines INPUT PROC` which applies a transform for each line of the input. +func (p *PluginFilters) mapLinesBuiltin(ctx context.Context, args ucl.CallArgs) (any, error) { + var ( + input string + proc ucl.Invokable + ) + + if err := args.Bind(&input, &proc); err != nil { + return nil, fmt.Errorf("d:map-lines: expected INPUT and PROC: %w", err) + } + + var ( + dst bytes.Buffer + dstLine bytes.Buffer + ) + + scnr := bufio.NewScanner(strings.NewReader(input)) + isFirst := true + for scnr.Scan() { + dstLine.Reset() + line := scnr.Text() + + out, err := proc.Invoke(ctx, line) + if err != nil { + return TextFilterResponse{}, err + } else if out == nil { + continue + } else if strOut, ok := out.(fmt.Stringer); ok { + dstLine.WriteString(strOut.String()) + } else { + dstLine.WriteString(fmt.Sprint(out)) + } + + if isFirst { + isFirst = false + } else { + dst.WriteString("\n") + } + + dst.WriteString(dstLine.String()) + } + + return dst.String(), nil +} + // LoadDir evaluates every *.ucl file found under dir (recursively, in lexical order). Files // that fail to load are recorded in Errors() and skipped; loading continues with the rest. // A missing directory is not an error.