detached 711511a

merge(core): integrate v0.2.0 and v0.2.1

commit
711511a7ee699a9ff7b6454b79bde30eae86f097
author
brice · · 2026-08-18 18:44 UTC
merge of
d5196eb + 7bd1a3c · diff against the first parent
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
21 files · +135 -93
M .github/workflows/ci.yml +5 -1
@@ -46,7 +46,11 @@ jobs:
4646 echo 'the ANSI package must consume the core model'
4747 exit 1
4848 fi
49- - name: Fuzz smoke
49+ - name: VT fuzz smoke
50+ run: go test . -run '^$' -fuzz FuzzVTInputDoesNotPanic -fuzztime=10s
51+ - name: ANSI fuzz smoke
52+ run: go test . -run '^$' -fuzz FuzzANSIRenderingDoesNotPanic -fuzztime=10s
53+ - name: VTH3 fuzz smoke
5054 run: go test . -run '^$' -fuzz FuzzHistoryPreflightMatchesUnmarshal -fuzztime=10s
5155 - name: Benchmark smoke
5256 run: go test ./... -run '^$' -bench='(VT|History|Snapshot|ANSI)' -benchmem -benchtime=1x
@@ -46,7 +46,11 @@ jobs:
46 echo 'the ANSI package must consume the core model'46 echo 'the ANSI package must consume the core model'
47 exit 147 exit 1
48 fi48 fi
49- - name: Fuzz smoke49+ - name: VT fuzz smoke
50+ run: go test . -run '^$' -fuzz FuzzVTInputDoesNotPanic -fuzztime=10s
51+ - name: ANSI fuzz smoke
52+ run: go test . -run '^$' -fuzz FuzzANSIRenderingDoesNotPanic -fuzztime=10s
53+ - name: VTH3 fuzz smoke
50 run: go test . -run '^$' -fuzz FuzzHistoryPreflightMatchesUnmarshal -fuzztime=10s54 run: go test . -run '^$' -fuzz FuzzHistoryPreflightMatchesUnmarshal -fuzztime=10s
51 - name: Benchmark smoke55 - name: Benchmark smoke
52 run: go test ./... -run '^$' -bench='(VT|History|Snapshot|ANSI)' -benchmem -benchtime=1x56 run: go test ./... -run '^$' -bench='(VT|History|Snapshot|ANSI)' -benchmem -benchtime=1x
M ansi/cell.go +2 -2
@@ -4,6 +4,6 @@ import "github.com/bnema/vev-vt/core"
44
55 // Cell is an alias for the frontend-neutral core model. New code should import
66 // github.com/bnema/vev-vt/core when it needs the model directly.
7-type Cell = vtcore.Cell
7+type Cell = core.Cell
88
9-var BlankCell = vtcore.BlankCell
9+var BlankCell = core.BlankCell
@@ -4,6 +4,6 @@ import "github.com/bnema/vev-vt/core"
4 4
5 // Cell is an alias for the frontend-neutral core model. New code should import5 // Cell is an alias for the frontend-neutral core model. New code should import
6 // github.com/bnema/vev-vt/core when it needs the model directly.6 // github.com/bnema/vev-vt/core when it needs the model directly.
7-type Cell = vtcore.Cell7+type Cell = core.Cell
8 8
9-var BlankCell = vtcore.BlankCell9+var BlankCell = core.BlankCell
M ansi/consumer_external_test.go +4 -4
@@ -9,11 +9,11 @@ import (
99 )
1010
1111 func TestExternalANSIConsumesCoreFrameIndependently(t *testing.T) {
12- frame := vtcore.NewFrame(2, 1)
13- frame.Set(0, 0, vtcore.Cell{Rune: 'O', Style: vtcore.DefaultStyle()})
14- frame.Set(1, 0, vtcore.Cell{Rune: 'K', Style: vtcore.DefaultStyle()})
12+ frame := core.NewFrame(2, 1)
13+ frame.Set(0, 0, core.Cell{Rune: 'O', Style: core.DefaultStyle()})
14+ frame.Set(1, 0, core.Cell{Rune: 'K', Style: core.DefaultStyle()})
1515
16- output, err := ansi.New(ansi.Capabilities{}).Draw(frame, []vtcore.Damage{vtcore.FullRedraw()})
16+ output, err := ansi.New(ansi.Capabilities{}).Draw(frame, []core.Damage{core.FullRedraw()})
1717 if err != nil {
1818 t.Fatalf("Draw: %v", err)
1919 }
@@ -9,11 +9,11 @@ import (
9 )9 )
10 10
11 func TestExternalANSIConsumesCoreFrameIndependently(t *testing.T) {11 func TestExternalANSIConsumesCoreFrameIndependently(t *testing.T) {
12- frame := vtcore.NewFrame(2, 1)12+ frame := core.NewFrame(2, 1)
13- frame.Set(0, 0, vtcore.Cell{Rune: 'O', Style: vtcore.DefaultStyle()})13+ frame.Set(0, 0, core.Cell{Rune: 'O', Style: core.DefaultStyle()})
14- frame.Set(1, 0, vtcore.Cell{Rune: 'K', Style: vtcore.DefaultStyle()})14+ frame.Set(1, 0, core.Cell{Rune: 'K', Style: core.DefaultStyle()})
15 15
16- output, err := ansi.New(ansi.Capabilities{}).Draw(frame, []vtcore.Damage{vtcore.FullRedraw()})16+ output, err := ansi.New(ansi.Capabilities{}).Draw(frame, []core.Damage{core.FullRedraw()})
17 if err != nil {17 if err != nil {
18 t.Fatalf("Draw: %v", err)18 t.Fatalf("Draw: %v", err)
19 }19 }
M ansi/damage.go +7 -8
@@ -2,15 +2,14 @@ package ansi
22
33 import "github.com/bnema/vev-vt/core"
44
5-type DamageKind = vtcore.DamageKind
6-
7-type Damage = vtcore.Damage
5+type DamageKind = core.DamageKind
6+type Damage = core.Damage
87
98 const (
10- DamageText = vtcore.DamageText
11- DamageClear = vtcore.DamageClear
12- DamageScrollUp = vtcore.DamageScrollUp
13- DamageFullRedraw = vtcore.DamageFullRedraw
9+ DamageText = core.DamageText
10+ DamageClear = core.DamageClear
11+ DamageScrollUp = core.DamageScrollUp
12+ DamageFullRedraw = core.DamageFullRedraw
1413 )
1514
16-var FullRedraw = vtcore.FullRedraw
15+var FullRedraw = core.FullRedraw
@@ -2,15 +2,14 @@ package ansi
2 2
3 import "github.com/bnema/vev-vt/core"3 import "github.com/bnema/vev-vt/core"
4 4
5-type DamageKind = vtcore.DamageKind5+type DamageKind = core.DamageKind
6-6+type Damage = core.Damage
7-type Damage = vtcore.Damage
8 7
9 const (8 const (
10- DamageText = vtcore.DamageText9+ DamageText = core.DamageText
11- DamageClear = vtcore.DamageClear10+ DamageClear = core.DamageClear
12- DamageScrollUp = vtcore.DamageScrollUp11+ DamageScrollUp = core.DamageScrollUp
13- DamageFullRedraw = vtcore.DamageFullRedraw12+ DamageFullRedraw = core.DamageFullRedraw
14 )13 )
15 14
16-var FullRedraw = vtcore.FullRedraw15+var FullRedraw = core.FullRedraw
M ansi/doc.go +1 -1
@@ -3,5 +3,5 @@
33 //
44 // The package owns output planning, ANSI encoding, and a transactional renderer
55 // shadow. It does not own Cell, Style, RGB, Frame, Damage, or RuneWidth; those
6-// values are aliases of the core package and are owned by vtcore.
6+// values are aliases of the core package and are owned by core.
77 package ansi
@@ -3,5 +3,5 @@
3 //3 //
4 // The package owns output planning, ANSI encoding, and a transactional renderer4 // The package owns output planning, ANSI encoding, and a transactional renderer
5 // shadow. It does not own Cell, Style, RGB, Frame, Damage, or RuneWidth; those5 // shadow. It does not own Cell, Style, RGB, Frame, Damage, or RuneWidth; those
6-// values are aliases of the core package and are owned by vtcore.6+// values are aliases of the core package and are owned by core.
7 package ansi7 package ansi
M ansi/frame.go +2 -2
@@ -4,6 +4,6 @@ import "github.com/bnema/vev-vt/core"
44
55 // Frame is an alias for the frontend-neutral terminal grid. ANSI rendering
66 // consumes it but does not own its model or storage policy.
7-type Frame = vtcore.Frame
7+type Frame = core.Frame
88
9-var NewFrame = vtcore.NewFrame
9+var NewFrame = core.NewFrame
@@ -4,6 +4,6 @@ import "github.com/bnema/vev-vt/core"
4 4
5 // Frame is an alias for the frontend-neutral terminal grid. ANSI rendering5 // Frame is an alias for the frontend-neutral terminal grid. ANSI rendering
6 // consumes it but does not own its model or storage policy.6 // consumes it but does not own its model or storage policy.
7-type Frame = vtcore.Frame7+type Frame = core.Frame
8 8
9-var NewFrame = vtcore.NewFrame9+var NewFrame = core.NewFrame
M ansi/rune_width.go +1 -1
@@ -4,4 +4,4 @@ import "github.com/bnema/vev-vt/core"
44
55 // RuneWidth is the terminal cell width function from the frontend-neutral
66 // model package.
7-func RuneWidth(r rune) int { return vtcore.RuneWidth(r) }
7+func RuneWidth(r rune) int { return core.RuneWidth(r) }
@@ -4,4 +4,4 @@ import "github.com/bnema/vev-vt/core"
4 4
5 // RuneWidth is the terminal cell width function from the frontend-neutral5 // RuneWidth is the terminal cell width function from the frontend-neutral
6 // model package.6 // model package.
7-func RuneWidth(r rune) int { return vtcore.RuneWidth(r) }7+func RuneWidth(r rune) int { return core.RuneWidth(r) }
M ansi/style.go +15 -15
@@ -2,23 +2,23 @@ package ansi
22
33 import "github.com/bnema/vev-vt/core"
44
5-type RGB = vtcore.RGB
6-type StyleAttrs = vtcore.StyleAttrs
7-type UnderlineStyle = vtcore.UnderlineStyle
8-type Style = vtcore.Style
5+type RGB = core.RGB
6+type StyleAttrs = core.StyleAttrs
7+type UnderlineStyle = core.UnderlineStyle
8+type Style = core.Style
99
1010 const (
11- AttrDim = vtcore.AttrDim
12- AttrUnderline = vtcore.AttrUnderline
13- AttrBlink = vtcore.AttrBlink
14- AttrStrikethrough = vtcore.AttrStrikethrough
11+ AttrDim = core.AttrDim
12+ AttrUnderline = core.AttrUnderline
13+ AttrBlink = core.AttrBlink
14+ AttrStrikethrough = core.AttrStrikethrough
1515
16- UnderlineNone = vtcore.UnderlineNone
17- UnderlineSingle = vtcore.UnderlineSingle
18- UnderlineDouble = vtcore.UnderlineDouble
19- UnderlineCurly = vtcore.UnderlineCurly
20- UnderlineDotted = vtcore.UnderlineDotted
21- UnderlineDashed = vtcore.UnderlineDashed
16+ UnderlineNone = core.UnderlineNone
17+ UnderlineSingle = core.UnderlineSingle
18+ UnderlineDouble = core.UnderlineDouble
19+ UnderlineCurly = core.UnderlineCurly
20+ UnderlineDotted = core.UnderlineDotted
21+ UnderlineDashed = core.UnderlineDashed
2222 )
2323
24-var DefaultStyle = vtcore.DefaultStyle
24+var DefaultStyle = core.DefaultStyle
@@ -2,23 +2,23 @@ package ansi
2 2
3 import "github.com/bnema/vev-vt/core"3 import "github.com/bnema/vev-vt/core"
4 4
5-type RGB = vtcore.RGB5+type RGB = core.RGB
6-type StyleAttrs = vtcore.StyleAttrs6+type StyleAttrs = core.StyleAttrs
7-type UnderlineStyle = vtcore.UnderlineStyle7+type UnderlineStyle = core.UnderlineStyle
8-type Style = vtcore.Style8+type Style = core.Style
9 9
10 const (10 const (
11- AttrDim = vtcore.AttrDim11+ AttrDim = core.AttrDim
12- AttrUnderline = vtcore.AttrUnderline12+ AttrUnderline = core.AttrUnderline
13- AttrBlink = vtcore.AttrBlink13+ AttrBlink = core.AttrBlink
14- AttrStrikethrough = vtcore.AttrStrikethrough14+ AttrStrikethrough = core.AttrStrikethrough
15 15
16- UnderlineNone = vtcore.UnderlineNone16+ UnderlineNone = core.UnderlineNone
17- UnderlineSingle = vtcore.UnderlineSingle17+ UnderlineSingle = core.UnderlineSingle
18- UnderlineDouble = vtcore.UnderlineDouble18+ UnderlineDouble = core.UnderlineDouble
19- UnderlineCurly = vtcore.UnderlineCurly19+ UnderlineCurly = core.UnderlineCurly
20- UnderlineDotted = vtcore.UnderlineDotted20+ UnderlineDotted = core.UnderlineDotted
21- UnderlineDashed = vtcore.UnderlineDashed21+ UnderlineDashed = core.UnderlineDashed
22 )22 )
23 23
24-var DefaultStyle = vtcore.DefaultStyle24+var DefaultStyle = core.DefaultStyle
M core/cell.go +1 -1
@@ -1,4 +1,4 @@
1-package vtcore
1+package core
22
33 // Cell is a single terminal grid cell.
44 //
@@ -1,4 +1,4 @@
1-package vtcore1+package core
2 2
3 // Cell is a single terminal grid cell.3 // Cell is a single terminal grid cell.
4 //4 //
M core/damage.go +1 -1
@@ -1,4 +1,4 @@
1-package vtcore
1+package core
22
33 type DamageKind int
44
@@ -1,4 +1,4 @@
1-package vtcore1+package core
2 2
3 type DamageKind int3 type DamageKind int
4 4
M core/doc.go +1 -1
@@ -4,4 +4,4 @@
44 // Frame and other mutable values are single-owner. Frame.Row returns a backing
55 // slice that is valid until the next scroll or resize; Frame.Clone returns
66 // independent storage. The package has no frontend, transport, or vev policy.
7-package vtcore
7+package core
@@ -4,4 +4,4 @@
4 // Frame and other mutable values are single-owner. Frame.Row returns a backing4 // Frame and other mutable values are single-owner. Frame.Row returns a backing
5 // slice that is valid until the next scroll or resize; Frame.Clone returns5 // slice that is valid until the next scroll or resize; Frame.Clone returns
6 // independent storage. The package has no frontend, transport, or vev policy.6 // independent storage. The package has no frontend, transport, or vev policy.
7-package vtcore7+package core
M core/frame.go +1 -1
@@ -1,4 +1,4 @@
1-package vtcore
1+package core
22
33 import "fmt"
44
@@ -1,4 +1,4 @@
1-package vtcore1+package core
2 2
3 import "fmt"3 import "fmt"
4 4
M core/frame_test.go +1 -1
@@ -1,4 +1,4 @@
1-package vtcore
1+package core
22
33 import "testing"
44
@@ -1,4 +1,4 @@
1-package vtcore1+package core
2 2
3 import "testing"3 import "testing"
4 4
M core/rune_width.go +1 -1
@@ -1,4 +1,4 @@
1-package vtcore
1+package core
22
33 import "unicode"
44
@@ -1,4 +1,4 @@
1-package vtcore1+package core
2 2
3 import "unicode"3 import "unicode"
4 4
M core/style.go +1 -1
@@ -1,4 +1,4 @@
1-package vtcore
1+package core
22
33 type RGB struct {
44 R uint8
@@ -1,4 +1,4 @@
1-package vtcore1+package core
2 2
3 type RGB struct {3 type RGB struct {
4 R uint84 R uint8
M core_model.go +30 -22
@@ -5,32 +5,40 @@ import "github.com/bnema/vev-vt/core"
55 // The root package re-exports the frontend-neutral core model so screen,
66 // history, and renderer consumers share one cell/style/frame representation.
77 // The implementation and storage policy remain owned by the core package.
8-type Cell = vtcore.Cell
9-type RGB = vtcore.RGB
10-type StyleAttrs = vtcore.StyleAttrs
11-type UnderlineStyle = vtcore.UnderlineStyle
12-type Style = vtcore.Style
13-type Frame = vtcore.Frame
8+type Cell = core.Cell
9+type RGB = core.RGB
10+type StyleAttrs = core.StyleAttrs
11+type UnderlineStyle = core.UnderlineStyle
12+type Style = core.Style
13+type Frame = core.Frame
14+
15+type DamageKind = core.DamageKind
16+type Damage = core.Damage
1417
1518 const (
16- AttrDim = vtcore.AttrDim
17- AttrUnderline = vtcore.AttrUnderline
18- AttrBlink = vtcore.AttrBlink
19- AttrStrikethrough = vtcore.AttrStrikethrough
20-
21- UnderlineNone = vtcore.UnderlineNone
22- UnderlineSingle = vtcore.UnderlineSingle
23- UnderlineDouble = vtcore.UnderlineDouble
24- UnderlineCurly = vtcore.UnderlineCurly
25- UnderlineDotted = vtcore.UnderlineDotted
26- UnderlineDashed = vtcore.UnderlineDashed
19+ AttrDim = core.AttrDim
20+ AttrUnderline = core.AttrUnderline
21+ AttrBlink = core.AttrBlink
22+ AttrStrikethrough = core.AttrStrikethrough
23+
24+ UnderlineNone = core.UnderlineNone
25+ UnderlineSingle = core.UnderlineSingle
26+ UnderlineDouble = core.UnderlineDouble
27+ UnderlineCurly = core.UnderlineCurly
28+ UnderlineDotted = core.UnderlineDotted
29+ UnderlineDashed = core.UnderlineDashed
30+
31+ DamageText = core.DamageText
32+ DamageClear = core.DamageClear
33+ DamageScrollUp = core.DamageScrollUp
34+ DamageFullRedraw = core.DamageFullRedraw
2735 )
2836
2937 var (
30- BlankCell = vtcore.BlankCell
31- DefaultStyle = vtcore.DefaultStyle
32- FullRedraw = vtcore.FullRedraw
33- NewFrame = vtcore.NewFrame
38+ BlankCell = core.BlankCell
39+ DefaultStyle = core.DefaultStyle
40+ FullRedraw = core.FullRedraw
41+ NewFrame = core.NewFrame
3442 )
3543
36-func RuneWidth(r rune) int { return vtcore.RuneWidth(r) }
44+func RuneWidth(r rune) int { return core.RuneWidth(r) }
@@ -5,32 +5,40 @@ import "github.com/bnema/vev-vt/core"
5 // The root package re-exports the frontend-neutral core model so screen,5 // The root package re-exports the frontend-neutral core model so screen,
6 // history, and renderer consumers share one cell/style/frame representation.6 // history, and renderer consumers share one cell/style/frame representation.
7 // The implementation and storage policy remain owned by the core package.7 // The implementation and storage policy remain owned by the core package.
8-type Cell = vtcore.Cell8+type Cell = core.Cell
9-type RGB = vtcore.RGB9+type RGB = core.RGB
10-type StyleAttrs = vtcore.StyleAttrs10+type StyleAttrs = core.StyleAttrs
11-type UnderlineStyle = vtcore.UnderlineStyle11+type UnderlineStyle = core.UnderlineStyle
12-type Style = vtcore.Style12+type Style = core.Style
13-type Frame = vtcore.Frame13+type Frame = core.Frame
14+
15+type DamageKind = core.DamageKind
16+type Damage = core.Damage
14 17
15 const (18 const (
16- AttrDim = vtcore.AttrDim19+ AttrDim = core.AttrDim
17- AttrUnderline = vtcore.AttrUnderline20+ AttrUnderline = core.AttrUnderline
18- AttrBlink = vtcore.AttrBlink21+ AttrBlink = core.AttrBlink
19- AttrStrikethrough = vtcore.AttrStrikethrough22+ AttrStrikethrough = core.AttrStrikethrough
20-23+
21- UnderlineNone = vtcore.UnderlineNone24+ UnderlineNone = core.UnderlineNone
22- UnderlineSingle = vtcore.UnderlineSingle25+ UnderlineSingle = core.UnderlineSingle
23- UnderlineDouble = vtcore.UnderlineDouble26+ UnderlineDouble = core.UnderlineDouble
24- UnderlineCurly = vtcore.UnderlineCurly27+ UnderlineCurly = core.UnderlineCurly
25- UnderlineDotted = vtcore.UnderlineDotted28+ UnderlineDotted = core.UnderlineDotted
26- UnderlineDashed = vtcore.UnderlineDashed29+ UnderlineDashed = core.UnderlineDashed
30+
31+ DamageText = core.DamageText
32+ DamageClear = core.DamageClear
33+ DamageScrollUp = core.DamageScrollUp
34+ DamageFullRedraw = core.DamageFullRedraw
27 )35 )
28 36
29 var (37 var (
30- BlankCell = vtcore.BlankCell38+ BlankCell = core.BlankCell
31- DefaultStyle = vtcore.DefaultStyle39+ DefaultStyle = core.DefaultStyle
32- FullRedraw = vtcore.FullRedraw40+ FullRedraw = core.FullRedraw
33- NewFrame = vtcore.NewFrame41+ NewFrame = core.NewFrame
34 )42 )
35 43
36-func RuneWidth(r rune) int { return vtcore.RuneWidth(r) }44+func RuneWidth(r rune) int { return core.RuneWidth(r) }
D damage.go +0 -14
@@ -1,14 +0,0 @@
1-package vt
2-
3-import "github.com/bnema/vev-vt/core"
4-
5-type Damage = vtcore.Damage
6-
7-type DamageKind = vtcore.DamageKind
8-
9-const (
10- DamageText = vtcore.DamageText
11- DamageClear = vtcore.DamageClear
12- DamageScrollUp = vtcore.DamageScrollUp
13- DamageFullRedraw = vtcore.DamageFullRedraw
14-)
@@ -1,14 +0,0 @@
1-package vt
2-
3-import "github.com/bnema/vev-vt/core"
4-
5-type Damage = vtcore.Damage
6-
7-type DamageKind = vtcore.DamageKind
8-
9-const (
10- DamageText = vtcore.DamageText
11- DamageClear = vtcore.DamageClear
12- DamageScrollUp = vtcore.DamageScrollUp
13- DamageFullRedraw = vtcore.DamageFullRedraw
14-)
M extraction_contract_external_test.go +4 -4
@@ -4,7 +4,7 @@ import (
44 "reflect"
55 "testing"
66
7- "github.com/bnema/vev-vt"
7+ vt "github.com/bnema/vev-vt"
88 "github.com/bnema/vev-vt/core"
99 )
1010
@@ -101,7 +101,7 @@ func TestExternalSnapshotsAndHistoryRespectOwnershipContracts(t *testing.T) {
101101 snapshot := screen.Snapshot()
102102
103103 owned := snapshot.Row(0)
104- owned[0] = vtcore.Cell{Rune: 'X'}
104+ owned[0] = core.Cell{Rune: 'X'}
105105 if got := snapshot.Row(0)[0].Rune; got != 'A' {
106106 t.Fatalf("owned snapshot row mutation changed snapshot to %q", got)
107107 }
@@ -129,7 +129,7 @@ func TestExternalSnapshotsAndHistoryRespectOwnershipContracts(t *testing.T) {
129129 }
130130
131131 copyOfRow := before.Row(0)
132- copyOfRow[0] = vtcore.Cell{Rune: 'x'}
132+ copyOfRow[0] = core.Cell{Rune: 'x'}
133133 if got := before.Row(0)[0].Rune; got != 'a' {
134134 t.Fatalf("owned history row mutation changed view to %q", got)
135135 }
@@ -177,7 +177,7 @@ func TestExternalSingleOwnerUsageSerializesMutationAndCapture(t *testing.T) {
177177
178178 func appendHistoryRow(t *testing.T, history *vt.History, runeValue rune, id vt.RowID) {
179179 t.Helper()
180- if err := history.AppendWithID([]vtcore.Cell{{Rune: runeValue}}, vt.LineBound{End: 1}, id); err != nil {
180+ if err := history.AppendWithID([]core.Cell{{Rune: runeValue}}, vt.LineBound{End: 1}, id); err != nil {
181181 t.Fatalf("AppendWithID(%d): %v", id, err)
182182 }
183183 }
@@ -4,7 +4,7 @@ import (
4 "reflect"4 "reflect"
5 "testing"5 "testing"
6 6
7- "github.com/bnema/vev-vt"7+ vt "github.com/bnema/vev-vt"
8 "github.com/bnema/vev-vt/core"8 "github.com/bnema/vev-vt/core"
9 )9 )
10 10
@@ -101,7 +101,7 @@ func TestExternalSnapshotsAndHistoryRespectOwnershipContracts(t *testing.T) {
101 snapshot := screen.Snapshot()101 snapshot := screen.Snapshot()
102 102
103 owned := snapshot.Row(0)103 owned := snapshot.Row(0)
104- owned[0] = vtcore.Cell{Rune: 'X'}104+ owned[0] = core.Cell{Rune: 'X'}
105 if got := snapshot.Row(0)[0].Rune; got != 'A' {105 if got := snapshot.Row(0)[0].Rune; got != 'A' {
106 t.Fatalf("owned snapshot row mutation changed snapshot to %q", got)106 t.Fatalf("owned snapshot row mutation changed snapshot to %q", got)
107 }107 }
@@ -129,7 +129,7 @@ func TestExternalSnapshotsAndHistoryRespectOwnershipContracts(t *testing.T) {
129 }129 }
130 130
131 copyOfRow := before.Row(0)131 copyOfRow := before.Row(0)
132- copyOfRow[0] = vtcore.Cell{Rune: 'x'}132+ copyOfRow[0] = core.Cell{Rune: 'x'}
133 if got := before.Row(0)[0].Rune; got != 'a' {133 if got := before.Row(0)[0].Rune; got != 'a' {
134 t.Fatalf("owned history row mutation changed view to %q", got)134 t.Fatalf("owned history row mutation changed view to %q", got)
135 }135 }
@@ -177,7 +177,7 @@ func TestExternalSingleOwnerUsageSerializesMutationAndCapture(t *testing.T) {
177 177
178 func appendHistoryRow(t *testing.T, history *vt.History, runeValue rune, id vt.RowID) {178 func appendHistoryRow(t *testing.T, history *vt.History, runeValue rune, id vt.RowID) {
179 t.Helper()179 t.Helper()
180- if err := history.AppendWithID([]vtcore.Cell{{Rune: runeValue}}, vt.LineBound{End: 1}, id); err != nil {180+ if err := history.AppendWithID([]core.Cell{{Rune: runeValue}}, vt.LineBound{End: 1}, id); err != nil {
181 t.Fatalf("AppendWithID(%d): %v", id, err)181 t.Fatalf("AppendWithID(%d): %v", id, err)
182 }182 }
183 }183 }
M extraction_line_callback_external_test.go +4 -4
@@ -3,15 +3,15 @@ package vt_test
33 import (
44 "testing"
55
6- "github.com/bnema/vev-vt"
6+ vt "github.com/bnema/vev-vt"
77 "github.com/bnema/vev-vt/core"
88 )
99
1010 func TestExternalLineEvictionCallbackReceivesStableCopy(t *testing.T) {
1111 screen := vt.NewScreen(4, 3)
1212 inWrite := false
13- var evicted [][]vtcore.Cell
14- screen.OnLineEvicted = func(row []vtcore.Cell) {
13+ var evicted [][]core.Cell
14+ screen.OnLineEvicted = func(row []core.Cell) {
1515 if !inWrite {
1616 t.Error("line eviction callback ran after Write returned")
1717 }
@@ -25,7 +25,7 @@ func TestExternalLineEvictionCallbackReceivesStableCopy(t *testing.T) {
2525 if len(evicted) != 1 || len(evicted[0]) != 4 || evicted[0][0].Rune != 'A' {
2626 t.Fatalf("evicted rows = %#v, want one stable AAAA row", evicted)
2727 }
28- evicted[0][0] = vtcore.Cell{Rune: 'X'}
28+ evicted[0][0] = core.Cell{Rune: 'X'}
2929 if got := screen.Frame.At(0, 0).Rune; got != 'B' {
3030 t.Fatalf("mutating callback row changed live frame to %q", got)
3131 }
@@ -3,15 +3,15 @@ package vt_test
3 import (3 import (
4 "testing"4 "testing"
5 5
6- "github.com/bnema/vev-vt"6+ vt "github.com/bnema/vev-vt"
7 "github.com/bnema/vev-vt/core"7 "github.com/bnema/vev-vt/core"
8 )8 )
9 9
10 func TestExternalLineEvictionCallbackReceivesStableCopy(t *testing.T) {10 func TestExternalLineEvictionCallbackReceivesStableCopy(t *testing.T) {
11 screen := vt.NewScreen(4, 3)11 screen := vt.NewScreen(4, 3)
12 inWrite := false12 inWrite := false
13- var evicted [][]vtcore.Cell13+ var evicted [][]core.Cell
14- screen.OnLineEvicted = func(row []vtcore.Cell) {14+ screen.OnLineEvicted = func(row []core.Cell) {
15 if !inWrite {15 if !inWrite {
16 t.Error("line eviction callback ran after Write returned")16 t.Error("line eviction callback ran after Write returned")
17 }17 }
@@ -25,7 +25,7 @@ func TestExternalLineEvictionCallbackReceivesStableCopy(t *testing.T) {
25 if len(evicted) != 1 || len(evicted[0]) != 4 || evicted[0][0].Rune != 'A' {25 if len(evicted) != 1 || len(evicted[0]) != 4 || evicted[0][0].Rune != 'A' {
26 t.Fatalf("evicted rows = %#v, want one stable AAAA row", evicted)26 t.Fatalf("evicted rows = %#v, want one stable AAAA row", evicted)
27 }27 }
28- evicted[0][0] = vtcore.Cell{Rune: 'X'}28+ evicted[0][0] = core.Cell{Rune: 'X'}
29 if got := screen.Frame.At(0, 0).Rune; got != 'B' {29 if got := screen.Frame.At(0, 0).Rune; got != 'B' {
30 t.Fatalf("mutating callback row changed live frame to %q", got)30 t.Fatalf("mutating callback row changed live frame to %q", got)
31 }31 }
A fuzz_contract_test.go +45 -0
@@ -0,0 +1,45 @@
1+package vt_test
2+
3+import (
4+ "testing"
5+
6+ vt "github.com/bnema/vev-vt"
7+ "github.com/bnema/vev-vt/ansi"
8+ core "github.com/bnema/vev-vt/core"
9+)
10+
11+func FuzzVTInputDoesNotPanic(f *testing.F) {
12+ f.Add([]byte("hello\r\n"))
13+ f.Add([]byte("\x1b[2J\x1b[?1049h界\x1b[?1049l"))
14+ f.Add([]byte("\x1b]52;c;SGVsbG8=\a"))
15+ f.Add([]byte{0x1b, '[', '3', '1'})
16+
17+ f.Fuzz(func(t *testing.T, data []byte) {
18+ if len(data) > 4096 {
19+ data = data[:4096]
20+ }
21+ screen := vt.NewScreen(80, 24)
22+ screen.Write(data)
23+ _ = screen.Snapshot()
24+ })
25+}
26+
27+func FuzzANSIRenderingDoesNotPanic(f *testing.F) {
28+ f.Add([]byte("hello"))
29+ f.Add([]byte("界🙂"))
30+ f.Add([]byte{0, 1, 2, 0x1b, 0x7f, 0xff})
31+
32+ f.Fuzz(func(t *testing.T, data []byte) {
33+ if len(data) > 4096 {
34+ data = data[:4096]
35+ }
36+ frame := core.NewFrame(16, 2)
37+ for index, value := range data {
38+ cell := core.Cell{Rune: rune(value), Style: core.DefaultStyle()}
39+ frame.Set(index%frame.Width, (index/frame.Width)%frame.Height, cell)
40+ }
41+ if _, err := ansi.New(ansi.Capabilities{}).Draw(frame, []core.Damage{core.FullRedraw()}); err != nil {
42+ t.Fatalf("Draw: %v", err)
43+ }
44+ })
45+}
@@ -0,0 +1,45 @@
1+package vt_test
2+
3+import (
4+ "testing"
5+
6+ vt "github.com/bnema/vev-vt"
7+ "github.com/bnema/vev-vt/ansi"
8+ core "github.com/bnema/vev-vt/core"
9+)
10+
11+func FuzzVTInputDoesNotPanic(f *testing.F) {
12+ f.Add([]byte("hello\r\n"))
13+ f.Add([]byte("\x1b[2J\x1b[?1049h界\x1b[?1049l"))
14+ f.Add([]byte("\x1b]52;c;SGVsbG8=\a"))
15+ f.Add([]byte{0x1b, '[', '3', '1'})
16+
17+ f.Fuzz(func(t *testing.T, data []byte) {
18+ if len(data) > 4096 {
19+ data = data[:4096]
20+ }
21+ screen := vt.NewScreen(80, 24)
22+ screen.Write(data)
23+ _ = screen.Snapshot()
24+ })
25+}
26+
27+func FuzzANSIRenderingDoesNotPanic(f *testing.F) {
28+ f.Add([]byte("hello"))
29+ f.Add([]byte("界🙂"))
30+ f.Add([]byte{0, 1, 2, 0x1b, 0x7f, 0xff})
31+
32+ f.Fuzz(func(t *testing.T, data []byte) {
33+ if len(data) > 4096 {
34+ data = data[:4096]
35+ }
36+ frame := core.NewFrame(16, 2)
37+ for index, value := range data {
38+ cell := core.Cell{Rune: rune(value), Style: core.DefaultStyle()}
39+ frame.Set(index%frame.Width, (index/frame.Width)%frame.Height, cell)
40+ }
41+ if _, err := ansi.New(ansi.Capabilities{}).Draw(frame, []core.Damage{core.FullRedraw()}); err != nil {
42+ t.Fatalf("Draw: %v", err)
43+ }
44+ })
45+}
M history_vth3_golden_external_test.go +8 -8
@@ -6,7 +6,7 @@ import (
66 "encoding/hex"
77 "testing"
88
9- "github.com/bnema/vev-vt"
9+ vt "github.com/bnema/vev-vt"
1010 "github.com/bnema/vev-vt/core"
1111 )
1212
@@ -73,21 +73,21 @@ func TestExternalVTH3GoldenVectors(t *testing.T) {
7373 t.Fatalf("plain row = %#v", row)
7474 }
7575 case "all style fields":
76- wantStyle := vtcore.Style{
76+ wantStyle := core.Style{
7777 Bold: true,
7878 Italic: true,
7979 Inverse: true,
80- Attrs: vtcore.StyleAttrs(0x000f),
80+ Attrs: core.StyleAttrs(0x000f),
8181 Foreground: -7,
8282 Background: 257,
8383 HasForegroundRGB: true,
84- ForegroundRGB: vtcore.RGB{R: 1, G: 2, B: 3},
84+ ForegroundRGB: core.RGB{R: 1, G: 2, B: 3},
8585 HasBackgroundRGB: true,
86- BackgroundRGB: vtcore.RGB{R: 4, G: 5, B: 6},
87- UnderlineStyle: vtcore.UnderlineDashed,
86+ BackgroundRGB: core.RGB{R: 4, G: 5, B: 6},
87+ UnderlineStyle: core.UnderlineDashed,
8888 UnderlineColor: -9,
8989 HasUnderlineColorRGB: true,
90- UnderlineColorRGB: vtcore.RGB{R: 7, G: 8, B: 9},
90+ UnderlineColorRGB: core.RGB{R: 7, G: 8, B: 9},
9191 }
9292 if view.Len() != 1 || view.RowID(0) != 42 || view.Bound(0) != (vt.LineBound{End: 1, Soft: true}) || view.NextRowID() != 43 {
9393 t.Fatalf("styled view = len %d row %d bound %#v next %d", view.Len(), view.RowID(0), view.Bound(0), view.NextRowID())
@@ -128,7 +128,7 @@ func TestExternalVTH3RejectsMalformedVectors(t *testing.T) {
128128 {name: "zero next row ID", data: mutate(func(data []byte) { clear(data[9:17]) })},
129129 {name: "zero row ID", data: mutate(func(data []byte) { clear(data[rowIDOffset : rowIDOffset+8]) })},
130130 {name: "invalid rune", data: mutate(func(data []byte) { binary.BigEndian.PutUint32(data[cellOffset:], ^uint32(0)) })},
131- {name: "invalid underline style", data: mutate(func(data []byte) { data[cellOffset+29] = byte(vtcore.UnderlineDashed + 1) })},
131+ {name: "invalid underline style", data: mutate(func(data []byte) { data[cellOffset+29] = byte(core.UnderlineDashed + 1) })},
132132 {name: "bound exceeds row", data: mutate(func(data []byte) { binary.BigEndian.PutUint32(data[boundOffset:], 3) })},
133133 }
134134
@@ -6,7 +6,7 @@ import (
6 "encoding/hex"6 "encoding/hex"
7 "testing"7 "testing"
8 8
9- "github.com/bnema/vev-vt"9+ vt "github.com/bnema/vev-vt"
10 "github.com/bnema/vev-vt/core"10 "github.com/bnema/vev-vt/core"
11 )11 )
12 12
@@ -73,21 +73,21 @@ func TestExternalVTH3GoldenVectors(t *testing.T) {
73 t.Fatalf("plain row = %#v", row)73 t.Fatalf("plain row = %#v", row)
74 }74 }
75 case "all style fields":75 case "all style fields":
76- wantStyle := vtcore.Style{76+ wantStyle := core.Style{
77 Bold: true,77 Bold: true,
78 Italic: true,78 Italic: true,
79 Inverse: true,79 Inverse: true,
80- Attrs: vtcore.StyleAttrs(0x000f),80+ Attrs: core.StyleAttrs(0x000f),
81 Foreground: -7,81 Foreground: -7,
82 Background: 257,82 Background: 257,
83 HasForegroundRGB: true,83 HasForegroundRGB: true,
84- ForegroundRGB: vtcore.RGB{R: 1, G: 2, B: 3},84+ ForegroundRGB: core.RGB{R: 1, G: 2, B: 3},
85 HasBackgroundRGB: true,85 HasBackgroundRGB: true,
86- BackgroundRGB: vtcore.RGB{R: 4, G: 5, B: 6},86+ BackgroundRGB: core.RGB{R: 4, G: 5, B: 6},
87- UnderlineStyle: vtcore.UnderlineDashed,87+ UnderlineStyle: core.UnderlineDashed,
88 UnderlineColor: -9,88 UnderlineColor: -9,
89 HasUnderlineColorRGB: true,89 HasUnderlineColorRGB: true,
90- UnderlineColorRGB: vtcore.RGB{R: 7, G: 8, B: 9},90+ UnderlineColorRGB: core.RGB{R: 7, G: 8, B: 9},
91 }91 }
92 if view.Len() != 1 || view.RowID(0) != 42 || view.Bound(0) != (vt.LineBound{End: 1, Soft: true}) || view.NextRowID() != 43 {92 if view.Len() != 1 || view.RowID(0) != 42 || view.Bound(0) != (vt.LineBound{End: 1, Soft: true}) || view.NextRowID() != 43 {
93 t.Fatalf("styled view = len %d row %d bound %#v next %d", view.Len(), view.RowID(0), view.Bound(0), view.NextRowID())93 t.Fatalf("styled view = len %d row %d bound %#v next %d", view.Len(), view.RowID(0), view.Bound(0), view.NextRowID())
@@ -128,7 +128,7 @@ func TestExternalVTH3RejectsMalformedVectors(t *testing.T) {
128 {name: "zero next row ID", data: mutate(func(data []byte) { clear(data[9:17]) })},128 {name: "zero next row ID", data: mutate(func(data []byte) { clear(data[9:17]) })},
129 {name: "zero row ID", data: mutate(func(data []byte) { clear(data[rowIDOffset : rowIDOffset+8]) })},129 {name: "zero row ID", data: mutate(func(data []byte) { clear(data[rowIDOffset : rowIDOffset+8]) })},
130 {name: "invalid rune", data: mutate(func(data []byte) { binary.BigEndian.PutUint32(data[cellOffset:], ^uint32(0)) })},130 {name: "invalid rune", data: mutate(func(data []byte) { binary.BigEndian.PutUint32(data[cellOffset:], ^uint32(0)) })},
131- {name: "invalid underline style", data: mutate(func(data []byte) { data[cellOffset+29] = byte(vtcore.UnderlineDashed + 1) })},131+ {name: "invalid underline style", data: mutate(func(data []byte) { data[cellOffset+29] = byte(core.UnderlineDashed + 1) })},
132 {name: "bound exceeds row", data: mutate(func(data []byte) { binary.BigEndian.PutUint32(data[boundOffset:], 3) })},132 {name: "bound exceeds row", data: mutate(func(data []byte) { binary.BigEndian.PutUint32(data[boundOffset:], 3) })},
133 }133 }
134 134

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 13

↑↓ moveenter openesc close