From 33e2961b643452342790e33bcf635769567339ac Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Sat, 6 Dec 2025 00:57:43 +0100 Subject: [PATCH] support initial state --- lib.go | 22 ++++++++++++++++++---- lib_test.go | 25 +++++++++++++++++++++++++ sequence.go | 10 +++++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/lib.go b/lib.go index a3dbf84..774aa59 100644 --- a/lib.go +++ b/lib.go @@ -23,6 +23,7 @@ type Editor interface { type editorFunc[S any] struct { edit func(rune, S) ([]rune, S) releaseState func(S) []rune + init S } // Writer implements the io.Writer interface, passing the input to every editor in the configured sequence, and @@ -34,6 +35,10 @@ type Writer struct { err error } +func (e editorFunc[S]) initialize() any { + return e.init +} + func (e editorFunc[S]) Edit(r rune, state any) ([]rune, any) { s, _ := state.(S) return e.edit(r, s) @@ -44,8 +49,9 @@ func (e editorFunc[S]) ReleaseState(state any) []rune { return e.releaseState(s) } -// Func can be used to define an Editor providing only the edit and releaseState functions. -func Func[S any](edit func(r rune, state S) ([]rune, S), releaseState func(S) []rune) Editor { +// FuncInit can be used to define an Editor providing only the edit and releaseState functions, and the initial +// state. +func FuncInit[S any](edit func(r rune, state S) ([]rune, S), releaseState func(S) []rune, init S) Editor { if edit == nil { edit = func(r rune, s S) ([]rune, S) { return []rune{r}, s } } @@ -54,7 +60,13 @@ func Func[S any](edit func(r rune, state S) ([]rune, S), releaseState func(S) [] releaseState = func(S) []rune { return nil } } - return editorFunc[S]{edit: edit, releaseState: releaseState} + return editorFunc[S]{edit: edit, releaseState: releaseState, init: init} +} + +// Func can be used to define an Editor providing only the edit and releaseState functions. +func Func[S any](edit func(r rune, state S) ([]rune, S), releaseState func(S) []rune) Editor { + var s S + return FuncInit(edit, releaseState, s) } // Replace is a built-in editor for simple replace operations. The arguments are mapped such that the ones at @@ -96,9 +108,11 @@ func SingleLine() Editor { // New initializes an editing writer. The editor instances will be called in the order they are passed in to // New. func New(out io.Writer, e ...Editor) *Writer { + seq := sequence(e...) return &Writer{ out: out, - editor: sequence(e...), + editor: seq, + state: seq.(interface{ initialize() any }).initialize(), } } diff --git a/lib_test.go b/lib_test.go index 8e534c4..6eeccb2 100644 --- a/lib_test.go +++ b/lib_test.go @@ -181,3 +181,28 @@ func TestFlush(t *testing.T) { } }) } + +func TestInit(t *testing.T) { + edit := func(r rune, lineStart bool) ([]rune, bool) { + if r == '\n' { + return []rune{'\n'}, true + } + + if lineStart { + return append([]rune("> "), r), false + } + + return []rune{r}, false + } + + var b bytes.Buffer + e := textedit.FuncInit(edit, func(bool) []rune { return nil }, true) + w := textedit.New(&b, e) + if _, err := w.Write([]byte("quoted\nemail")); err != nil { + t.Fatal(err) + } + + if b.String() != "> quoted\n> email" { + t.Fatal(b.String()) + } +} diff --git a/sequence.go b/sequence.go index e70398f..cb59afd 100644 --- a/sequence.go +++ b/sequence.go @@ -57,8 +57,16 @@ func sequenceRelease(e []Editor) func([]any) []rune { } func sequence(e ...Editor) Editor { - return Func( + init := make([]any, len(e)) + for i, ei := range e { + if initializer, ok := ei.(interface{ initialize() any }); ok { + init[i] = initializer.initialize() + } + } + + return FuncInit( sequenceEdit(e), sequenceRelease(e), + init, ) }