1
0

support initial state

This commit is contained in:
Arpad Ryszka 2025-12-06 00:57:43 +01:00
parent 3b1b460e6a
commit 33e2961b64
3 changed files with 52 additions and 5 deletions

22
lib.go
View File

@ -23,6 +23,7 @@ type Editor interface {
type editorFunc[S any] struct { type editorFunc[S any] struct {
edit func(rune, S) ([]rune, S) edit func(rune, S) ([]rune, S)
releaseState func(S) []rune releaseState func(S) []rune
init S
} }
// Writer implements the io.Writer interface, passing the input to every editor in the configured sequence, and // 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 err error
} }
func (e editorFunc[S]) initialize() any {
return e.init
}
func (e editorFunc[S]) Edit(r rune, state any) ([]rune, any) { func (e editorFunc[S]) Edit(r rune, state any) ([]rune, any) {
s, _ := state.(S) s, _ := state.(S)
return e.edit(r, s) return e.edit(r, s)
@ -44,8 +49,9 @@ func (e editorFunc[S]) ReleaseState(state any) []rune {
return e.releaseState(s) return e.releaseState(s)
} }
// Func can be used to define an Editor providing only the edit and releaseState functions. // FuncInit can be used to define an Editor providing only the edit and releaseState functions, and the initial
func Func[S any](edit func(r rune, state S) ([]rune, S), releaseState func(S) []rune) Editor { // state.
func FuncInit[S any](edit func(r rune, state S) ([]rune, S), releaseState func(S) []rune, init S) Editor {
if edit == nil { if edit == nil {
edit = func(r rune, s S) ([]rune, S) { return []rune{r}, s } 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 } 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 // 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 initializes an editing writer. The editor instances will be called in the order they are passed in to
// New. // New.
func New(out io.Writer, e ...Editor) *Writer { func New(out io.Writer, e ...Editor) *Writer {
seq := sequence(e...)
return &Writer{ return &Writer{
out: out, out: out,
editor: sequence(e...), editor: seq,
state: seq.(interface{ initialize() any }).initialize(),
} }
} }

View File

@ -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())
}
}

View File

@ -57,8 +57,16 @@ func sequenceRelease(e []Editor) func([]any) []rune {
} }
func sequence(e ...Editor) Editor { 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), sequenceEdit(e),
sequenceRelease(e), sequenceRelease(e),
init,
) )
} }