From ab958436fa3de232212d5bca14bcd4636f29eefb Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sat, 24 Jan 2026 21:03:40 +0000 Subject: [PATCH 01/17] chore: initial primative def for gap buffer --- gap_buffer.v | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 gap_buffer.v diff --git a/gap_buffer.v b/gap_buffer.v new file mode 100644 index 00000000..6f055506 --- /dev/null +++ b/gap_buffer.v @@ -0,0 +1,28 @@ +module buffers + +pub struct GapBuffer { + data []rune + gap_start u32 + gap_size u32 +} + +const null_code_point = rune(0xfeff) +const initial_gap_size = 32 + +pub fn GapBuffer.new(content []rune) GapBuffer { + mut gb := GapBuffer{ + data: []rune{ len: content.len + initial_gap_size, init: null_code_point } + gap_start: 0 + gap_size: initial_gap_size + } + gb.insert(content) + return gb +} + +pub fn (mut g GapBuffer) insert(data []rune) { +} + +pub fn (g GapBuffer) content() string { + return g.data[g.gap_start + g.gap_size..].string() +} + From ac5cad671ad91b809d232846f82c510a400ef533 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sat, 24 Jan 2026 21:04:04 +0000 Subject: [PATCH 02/17] test: initial attempt to test gap buffer initialisation --- gap_buffer_test.v | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 gap_buffer_test.v diff --git a/gap_buffer_test.v b/gap_buffer_test.v new file mode 100644 index 00000000..8548e983 --- /dev/null +++ b/gap_buffer_test.v @@ -0,0 +1,15 @@ +module buffers + +@[assert_continues] +fn test_initialise_gap_buffer_with_contents() { + tests := { + '': ''.runes() + 'abc': 'abc'.runes() + } + + for k, v in tests { + gp := GapBuffer.new(v) + assert gp.content() == k + } +} + From 21f3b983ae2c627ce4c9c79578c3d1cbce7590bd Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sat, 24 Jan 2026 21:06:49 +0000 Subject: [PATCH 03/17] feat: insert text into gap buffer --- gap_buffer.v | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gap_buffer.v b/gap_buffer.v index 6f055506..7d4fadf7 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -1,6 +1,7 @@ module buffers pub struct GapBuffer { +mut: data []rune gap_start u32 gap_size u32 @@ -20,6 +21,9 @@ pub fn GapBuffer.new(content []rune) GapBuffer { } pub fn (mut g GapBuffer) insert(data []rune) { + for i, c in data { + g.data[int(g.gap_start + g.gap_size) + i] = c + } } pub fn (g GapBuffer) content() string { From 900efa5c49aa0e5bb8a2ffcc054710cf81b2f9c2 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sat, 24 Jan 2026 21:17:19 +0000 Subject: [PATCH 04/17] test: reproducably ensure gap present as intended --- gap_buffer.v | 4 ++++ gap_buffer_test.v | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/gap_buffer.v b/gap_buffer.v index 7d4fadf7..e6c28524 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -30,3 +30,7 @@ pub fn (g GapBuffer) content() string { return g.data[g.gap_start + g.gap_size..].string() } +pub fn (g GapBuffer) raw_content() []rune { + return g.data +} + diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 8548e983..3c3f70a8 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -10,6 +10,17 @@ fn test_initialise_gap_buffer_with_contents() { for k, v in tests { gp := GapBuffer.new(v) assert gp.content() == k + assert gp.raw_content().map(fn (c rune) rune { + return if c == null_code_point { `_` } else { c } + }).string() == 'iwejfijewoifjweif' } } +fn test_initialise_gap_buffer_with_no_contents() { + gb := GapBuffer.new(''.runes()) + assert gb.content() == '' + assert gb.raw_content().map(fn (c rune) rune { + return if c == null_code_point { `_` } else { c } + }).string() == `_`.repeat(initial_gap_size) +} + From 92aed28d15c9f1f5f3a4fb495def9a162800b6e3 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sat, 24 Jan 2026 21:23:56 +0000 Subject: [PATCH 05/17] feat: helper method to visualise data contents --- gap_buffer.v | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gap_buffer.v b/gap_buffer.v index e6c28524..821729b4 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -34,3 +34,7 @@ pub fn (g GapBuffer) raw_content() []rune { return g.data } +fn null_code_point_to_str(c rune) rune { + return if c == null_code_point { `_` } else { c } +} + From 8e508b9b96f8a0a8063796f3c2144bc402be9d89 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sat, 24 Jan 2026 21:24:42 +0000 Subject: [PATCH 06/17] test: ensure initialised gap buffer content loads correctly --- gap_buffer_test.v | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 3c3f70a8..9407ec0f 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -1,26 +1,14 @@ module buffers -@[assert_continues] -fn test_initialise_gap_buffer_with_contents() { - tests := { - '': ''.runes() - 'abc': 'abc'.runes() - } - - for k, v in tests { - gp := GapBuffer.new(v) - assert gp.content() == k - assert gp.raw_content().map(fn (c rune) rune { - return if c == null_code_point { `_` } else { c } - }).string() == 'iwejfijewoifjweif' - } -} - fn test_initialise_gap_buffer_with_no_contents() { gb := GapBuffer.new(''.runes()) assert gb.content() == '' - assert gb.raw_content().map(fn (c rune) rune { - return if c == null_code_point { `_` } else { c } - }).string() == `_`.repeat(initial_gap_size) + assert gb.raw_content().map(null_code_point_to_str).string() == `_`.repeat(initial_gap_size) +} + +fn test_initialise_gap_buffer_with_content() { + gb := GapBuffer.new('abcdef'.runes()) + assert gb.content() == 'abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == '${`_`.repeat(initial_gap_size)}abcdef' } From a46131b2dfb77d254a4a1c9035569a8a28eeb3e6 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sun, 25 Jan 2026 00:56:20 +0000 Subject: [PATCH 07/17] fix: adjust how gap space is tracked with explicit start and end --- gap_buffer.v | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/gap_buffer.v b/gap_buffer.v index 821729b4..5ff7e7fd 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -4,7 +4,7 @@ pub struct GapBuffer { mut: data []rune gap_start u32 - gap_size u32 + gap_end u32 } const null_code_point = rune(0xfeff) @@ -14,20 +14,27 @@ pub fn GapBuffer.new(content []rune) GapBuffer { mut gb := GapBuffer{ data: []rune{ len: content.len + initial_gap_size, init: null_code_point } gap_start: 0 - gap_size: initial_gap_size + gap_end: initial_gap_size } - gb.insert(content) + gb.initial_fill(content) return gb } -pub fn (mut g GapBuffer) insert(data []rune) { +pub fn (mut g GapBuffer) initial_fill(data []rune) { for i, c in data { - g.data[int(g.gap_start + g.gap_size) + i] = c + g.data[int(g.gap_end) + i] = c } } +pub fn (mut g GapBuffer) insert_char(data rune) { + g.data[g.gap_start] = data + g.gap_start += 1 +} + pub fn (g GapBuffer) content() string { - return g.data[g.gap_start + g.gap_size..].string() + pre_gap := g.data[..g.gap_start] + post_gap := g.data[g.gap_end..] + return pre_gap.string() + post_gap.string() } pub fn (g GapBuffer) raw_content() []rune { From ddef03db424fb9479d3b1b91148259950ac07056 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sun, 25 Jan 2026 00:56:52 +0000 Subject: [PATCH 08/17] test: ensure initial naive implementations for insertion work at least --- gap_buffer_test.v | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 9407ec0f..0f98ffe8 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -12,3 +12,18 @@ fn test_initialise_gap_buffer_with_content() { assert gb.raw_content().map(null_code_point_to_str).string() == '${`_`.repeat(initial_gap_size)}abcdef' } +fn test_insert_char_into_gap_buffer_with_no_existing_content() { + mut gb := GapBuffer.new(''.runes()) + gb.insert_char(`z`) + assert gb.content() == 'z' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(initial_gap_size - 1)}' +} + +fn test_insert_char_into_gap_buffer_with_existing_content() { + mut gb := GapBuffer.new('abcdef'.runes()) + gb.insert_char(`z`) + assert gb.content() == 'zabcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(initial_gap_size - 1)}abcdef' +} + + From 7271b7683a4eb18cd9ef147bcdb6210bafc5b149 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sun, 25 Jan 2026 22:39:46 +0000 Subject: [PATCH 09/17] feat: permit overriding/custom setting of gap buffers gap size --- gap_buffer.v | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/gap_buffer.v b/gap_buffer.v index 5ff7e7fd..549cff34 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -10,13 +10,19 @@ mut: const null_code_point = rune(0xfeff) const initial_gap_size = 32 -pub fn GapBuffer.new(content []rune) GapBuffer { +@[params] +pub struct GapBufferParams { + content []rune + gap_size u32 = initial_gap_size +} + +pub fn GapBuffer.new(opts GapBufferParams) GapBuffer { mut gb := GapBuffer{ - data: []rune{ len: content.len + initial_gap_size, init: null_code_point } + data: []rune{ len: opts.content.len + int(opts.gap_size), init: null_code_point } gap_start: 0 - gap_end: initial_gap_size + gap_end: opts.gap_size } - gb.initial_fill(content) + gb.initial_fill(opts.content) return gb } From b922ce6f0763d292d5929052af8d2238248ee353 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Sun, 25 Jan 2026 22:40:01 +0000 Subject: [PATCH 10/17] test: custom gap size param --- gap_buffer_test.v | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 0f98ffe8..93cd9f67 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -1,29 +1,36 @@ module buffers fn test_initialise_gap_buffer_with_no_contents() { - gb := GapBuffer.new(''.runes()) + gb := GapBuffer.new(content: ''.runes()) assert gb.content() == '' assert gb.raw_content().map(null_code_point_to_str).string() == `_`.repeat(initial_gap_size) } fn test_initialise_gap_buffer_with_content() { - gb := GapBuffer.new('abcdef'.runes()) + gb := GapBuffer.new(content: 'abcdef'.runes()) assert gb.content() == 'abcdef' assert gb.raw_content().map(null_code_point_to_str).string() == '${`_`.repeat(initial_gap_size)}abcdef' } fn test_insert_char_into_gap_buffer_with_no_existing_content() { - mut gb := GapBuffer.new(''.runes()) + mut gb := GapBuffer.new(content: ''.runes()) gb.insert_char(`z`) assert gb.content() == 'z' assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(initial_gap_size - 1)}' } fn test_insert_char_into_gap_buffer_with_existing_content() { - mut gb := GapBuffer.new('abcdef'.runes()) + mut gb := GapBuffer.new(content: 'abcdef'.runes()) gb.insert_char(`z`) assert gb.content() == 'zabcdef' assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(initial_gap_size - 1)}abcdef' } +fn test_insert_char_into_gap_buffer_with_existing_content_with_custom_gap_size() { + mut gb := GapBuffer.new(content: 'abcdef'.runes(), gap_size: 3) + gb.insert_char(`z`) + assert gb.content() == 'zabcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z__abcdef' +} + From 0e58dedac6a90284ac728ae27194aa77ac2b8dd5 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 01:35:08 +0000 Subject: [PATCH 11/17] feat: internally expand gap when necessary --- gap_buffer.v | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/gap_buffer.v b/gap_buffer.v index 549cff34..4c0527bd 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -1,6 +1,9 @@ module buffers +import arrays + pub struct GapBuffer { + initial_gap_size u32 mut: data []rune gap_start u32 @@ -8,16 +11,17 @@ mut: } const null_code_point = rune(0xfeff) -const initial_gap_size = 32 +const initial_gap_size = u32(32) @[params] pub struct GapBufferParams { - content []rune - gap_size u32 = initial_gap_size + content []rune + gap_size u32 = initial_gap_size } pub fn GapBuffer.new(opts GapBufferParams) GapBuffer { mut gb := GapBuffer{ + initial_gap_size: opts.gap_size data: []rune{ len: opts.content.len + int(opts.gap_size), init: null_code_point } gap_start: 0 gap_end: opts.gap_size @@ -26,13 +30,29 @@ pub fn GapBuffer.new(opts GapBufferParams) GapBuffer { return gb } -pub fn (mut g GapBuffer) initial_fill(data []rune) { +fn (mut g GapBuffer) initial_fill(data []rune) { for i, c in data { g.data[int(g.gap_end) + i] = c } } +fn (mut g GapBuffer) grow_gap() { + mut dest := []rune{ len: g.data.len + int(g.initial_gap_size), init: null_code_point } + arrays.copy(mut dest[..g.gap_start], g.data[..g.gap_start]) + gap_end := g.gap_start + g.initial_gap_size + arrays.copy(mut dest[gap_end..], g.data[g.gap_end..]) + g.gap_end = gap_end + g.data = dest +} + +fn (g GapBuffer) current_gap_size() u32 { + return u32(g.gap_end - g.gap_start) +} + pub fn (mut g GapBuffer) insert_char(data rune) { + if g.current_gap_size() == 0 { + g.grow_gap() + } g.data[g.gap_start] = data g.gap_start += 1 } From 72aff5b488346c581b144a05dc5efc939205170e Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 01:35:17 +0000 Subject: [PATCH 12/17] test: gap grows when empty --- gap_buffer_test.v | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 93cd9f67..863eda5d 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -3,27 +3,27 @@ module buffers fn test_initialise_gap_buffer_with_no_contents() { gb := GapBuffer.new(content: ''.runes()) assert gb.content() == '' - assert gb.raw_content().map(null_code_point_to_str).string() == `_`.repeat(initial_gap_size) + assert gb.raw_content().map(null_code_point_to_str).string() == `_`.repeat(int(initial_gap_size)) } fn test_initialise_gap_buffer_with_content() { gb := GapBuffer.new(content: 'abcdef'.runes()) assert gb.content() == 'abcdef' - assert gb.raw_content().map(null_code_point_to_str).string() == '${`_`.repeat(initial_gap_size)}abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == '${`_`.repeat(int(initial_gap_size))}abcdef' } fn test_insert_char_into_gap_buffer_with_no_existing_content() { mut gb := GapBuffer.new(content: ''.runes()) gb.insert_char(`z`) assert gb.content() == 'z' - assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(initial_gap_size - 1)}' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(int(initial_gap_size - 1))}' } fn test_insert_char_into_gap_buffer_with_existing_content() { mut gb := GapBuffer.new(content: 'abcdef'.runes()) gb.insert_char(`z`) assert gb.content() == 'zabcdef' - assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(initial_gap_size - 1)}abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z${`_`.repeat(int(initial_gap_size - 1))}abcdef' } fn test_insert_char_into_gap_buffer_with_existing_content_with_custom_gap_size() { @@ -33,4 +33,24 @@ fn test_insert_char_into_gap_buffer_with_existing_content_with_custom_gap_size() assert gb.raw_content().map(null_code_point_to_str).string() == 'z__abcdef' } +@[assert_continues] +fn test_insert_char_into_gap_buffer_with_existing_content_overflow_gap_grows_gap() { + mut gb := GapBuffer.new(content: 'abcdef'.runes(), gap_size: 3) + gb.insert_char(`z`) + assert gb.content() == 'zabcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z__abcdef' + + gb.insert_char(`1`) + assert gb.content() == 'z1abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z1_abcdef' + + gb.insert_char(`2`) + assert gb.content() == 'z12abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z12abcdef' + + gb.insert_char(`3`) + assert gb.content() == 'z123abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z123__abcdef' +} + From b6fd681aa008461b9f9041736afcbb81e7098267 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 15:59:47 +0000 Subject: [PATCH 13/17] test: gap grows consistently --- gap_buffer_test.v | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 863eda5d..a5eaf657 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -53,4 +53,35 @@ fn test_insert_char_into_gap_buffer_with_existing_content_overflow_gap_grows_gap assert gb.raw_content().map(null_code_point_to_str).string() == 'z123__abcdef' } +@[assert_continues] +fn test_insert_char_into_gap_buffer_with_existing_content_overflow_gap_grows_gap_consistently() { + mut gb := GapBuffer.new(content: 'abcdef'.runes(), gap_size: 3) + gb.insert_char(`z`) + assert gb.content() == 'zabcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z__abcdef' + + gb.insert_char(`1`) + assert gb.content() == 'z1abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z1_abcdef' + + gb.insert_char(`2`) + assert gb.content() == 'z12abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z12abcdef' + + gb.insert_char(`3`) + assert gb.content() == 'z123abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z123__abcdef' + + gb.insert_char(`4`) + assert gb.content() == 'z1234abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z1234_abcdef' + + gb.insert_char(`5`) + assert gb.content() == 'z12345abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z12345abcdef' + + gb.insert_char(`6`) + assert gb.content() == 'z123456abcdef' + assert gb.raw_content().map(null_code_point_to_str).string() == 'z123456__abcdef' +} From 7f74ff7aa83315bf8d782ba920940082eacecd81 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 18:24:08 +0000 Subject: [PATCH 14/17] feat: enable gap to move around to given pos --- gap_buffer.v | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/gap_buffer.v b/gap_buffer.v index 4c0527bd..89a7cc21 100644 --- a/gap_buffer.v +++ b/gap_buffer.v @@ -45,6 +45,31 @@ fn (mut g GapBuffer) grow_gap() { g.data = dest } +fn (mut g GapBuffer) move_gap(position int) { + if position == g.gap_start { + return + } + + if position > g.gap_start { + chars_to_move := position - int(g.gap_start) + for i in 0..chars_to_move { + g.data[int(g.gap_start) + i] = g.data[int(g.gap_end) + i] + g.data[int(g.gap_end) + i] = null_code_point + } + g.gap_start = u32(position) + g.gap_end += u32(chars_to_move) + return + } + + chars_to_move := int(g.gap_start) - position + for i := chars_to_move - 1; i >= 0; i-- { + g.data[int(g.gap_end) - chars_to_move + i] = g.data[position + i] + g.data[position + i] = null_code_point + } + g.gap_end -= u32(chars_to_move) + g.gap_start = u32(position) +} + fn (g GapBuffer) current_gap_size() u32 { return u32(g.gap_end - g.gap_start) } From 09561615da25481b53e7acca0fed177c0efa1ceb Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 18:24:27 +0000 Subject: [PATCH 15/17] test: move gap to index 1 and to middle --- gap_buffer_test.v | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index a5eaf657..14d2bdd9 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -85,3 +85,26 @@ fn test_insert_char_into_gap_buffer_with_existing_content_overflow_gap_grows_gap assert gb.raw_content().map(null_code_point_to_str).string() == 'z123456__abcdef' } +@[assert_continues] +fn test_move_gap_buffer_simplest_case() { + mut gb := GapBuffer.new(content: 'abcdefghijk'.runes(), gap_size: 3) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' + + gb.move_gap(1) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'a___bcdefghijk' +} + +@[assert_continues] +fn test_move_gap_buffer_to_middle() { + mut gb := GapBuffer.new(content: 'abcdefghijk'.runes(), gap_size: 3) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' + + gb.move_gap(5) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'abcde___fghijk' +} + + From 8cc0735042c9c66cecbe50f56767ed9d3772a046 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 18:29:07 +0000 Subject: [PATCH 16/17] test: gap buffer can move around seemlessly back and forth --- gap_buffer_test.v | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 14d2bdd9..2e7db874 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -107,4 +107,41 @@ fn test_move_gap_buffer_to_middle() { assert gb.raw_content().map(null_code_point_to_str).string() == 'abcde___fghijk' } +@[assert_continues] +fn test_move_gap_buffer_to_middle_and_back() { + mut gb := GapBuffer.new(content: 'abcdefghijk'.runes(), gap_size: 3) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' + + gb.move_gap(5) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'abcde___fghijk' + + gb.move_gap(0) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' +} + +@[assert_continues] +fn test_move_gap_buffer_to_middle_end_and_back() { + mut gb := GapBuffer.new(content: 'abcdefghijk'.runes(), gap_size: 3) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' + + gb.move_gap(5) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'abcde___fghijk' + + gb.move_gap(gb.content().runes().len) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'abcdefghijk___' + + gb.move_gap(5) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'abcde___fghijk' + + gb.move_gap(0) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' +} From a4cb0cf272b6696f830884554d972d4bda7666fa Mon Sep 17 00:00:00 2001 From: tauraamui Date: Mon, 26 Jan 2026 18:38:09 +0000 Subject: [PATCH 17/17] test: moving gap alongside inserts --- gap_buffer_test.v | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/gap_buffer_test.v b/gap_buffer_test.v index 2e7db874..de87786d 100644 --- a/gap_buffer_test.v +++ b/gap_buffer_test.v @@ -145,3 +145,34 @@ fn test_move_gap_buffer_to_middle_end_and_back() { assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' } +@[assert_continues] +fn test_move_gap_buffer_to_middle_and_back_alongside_inserts() { + mut gb := GapBuffer.new(content: 'abcdefghijk'.runes(), gap_size: 3) + assert gb.content() == 'abcdefghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '___abcdefghijk' + + gb.move_gap(5) + gb.insert_char(`1`) + assert gb.content() == 'abcde1fghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == 'abcde1__fghijk' + + gb.move_gap(0) + gb.insert_char(`2`) + assert gb.content() == '2abcde1fghijk' + assert gb.raw_content().map(null_code_point_to_str).string() == '2_abcde1fghijk' + + gb.move_gap(gb.content().runes().len) + gb.insert_char(`3`) + assert gb.content() == '2abcde1fghijk3' + assert gb.raw_content().map(null_code_point_to_str).string() == '2abcde1fghijk3' + + gb.insert_char(`4`) + assert gb.content() == '2abcde1fghijk34' + assert gb.raw_content().map(null_code_point_to_str).string() == '2abcde1fghijk34__' + + gb.move_gap(5) + gb.insert_char(`5`) + assert gb.content() == '2abcd5e1fghijk34' + assert gb.raw_content().map(null_code_point_to_str).string() == '2abcd5_e1fghijk34' +} +