From 7a09a4a639e0689804cfed1bdb063bfd77f1ac71 Mon Sep 17 00:00:00 2001 From: Eugene Pobochny Date: Tue, 26 Aug 2025 14:20:04 -0400 Subject: [PATCH 1/5] refactor: Node --- src/content.ts | 3 +++ src/node.ts | 23 ++++++++++++++++++++++- src/text-buf.ts | 29 +++++------------------------ 3 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 src/content.ts diff --git a/src/content.ts b/src/content.ts new file mode 100644 index 0000000..8e40b3e --- /dev/null +++ b/src/content.ts @@ -0,0 +1,3 @@ +export class Content { + +} diff --git a/src/node.ts b/src/node.ts index 791236a..feea2a0 100644 --- a/src/node.ts +++ b/src/node.ts @@ -27,7 +27,7 @@ export interface Node { eols_len: number; } -export function create_node( +export function create( buf: number, slice_start: number, slice_len: number, @@ -50,6 +50,27 @@ export function create_node( }; } +export function find( + x: Node, + index: number, +): { node: Node; offset: number } | undefined { + while (!x.nil) { + if (index < x.left.total_len) { + x = x.left; + continue; + } + + index -= x.left.total_len; + + if (index < x.slice_len) { + return { node: x, offset: index }; + } + + index -= x.slice_len; + x = x.right; + } +} + export function bubble(x: Node): void { while (!x.nil) { x.total_len = x.left.total_len + x.slice_len + x.right.total_len; diff --git a/src/text-buf.ts b/src/text-buf.ts index 89dd026..88df851 100644 --- a/src/text-buf.ts +++ b/src/text-buf.ts @@ -1,7 +1,8 @@ import { Buffer } from "./buffer.ts"; import { bubble, - create_node, + create as create_node, + find, maximum, minimum, NIL, @@ -145,7 +146,7 @@ export class TextBuf { * ``` */ *read(start: number, end = Number.MAX_SAFE_INTEGER): Generator { - const first = this.#find(start); + const first = find(this.root, start); if (!first) { return; } @@ -365,7 +366,7 @@ export class TextBuf { * ``` */ delete(start: number, end = Number.MAX_SAFE_INTEGER): void { - const first = this.#find(start); + const first = find(this.root, start); if (!first) { return; } @@ -396,7 +397,7 @@ export class TextBuf { x = this.#split_node(node, offset, 0); } - const last = this.#find(end); + const last = find(this.root, end); if (last && last.offset !== 0) { this.#split_node(last.node, last.offset, 0); } @@ -454,26 +455,6 @@ export class TextBuf { return i + pos[1]; } - #find(index: number): { node: Node; offset: number } | undefined { - let x = this.root; - - while (!x.nil) { - if (index < x.left.total_len) { - x = x.left; - continue; - } - - index -= x.left.total_len; - - if (index < x.slice_len) { - return { node: x, offset: index }; - } - - index -= x.slice_len; - x = x.right; - } - } - #find_line_start(ln: number): number | undefined { if (ln === 0) { return 0; From 97049a772443ce7de9f7c4c3f1fa7b88ff97db8c Mon Sep 17 00:00:00 2001 From: Eugene Pobochny Date: Tue, 26 Aug 2025 14:35:42 -0400 Subject: [PATCH 2/5] refactor: Content --- src/content.ts | 86 ++++++++++++++++++++++++++++++++++ src/text-buf.ts | 119 ++++++++---------------------------------------- 2 files changed, 104 insertions(+), 101 deletions(-) diff --git a/src/content.ts b/src/content.ts index 8e40b3e..bd99758 100644 --- a/src/content.ts +++ b/src/content.ts @@ -1,3 +1,89 @@ +import { Buffer } from "./buffer.ts"; +import { bubble, create as create_node, type Node, successor } from "./node.ts"; + export class Content { + readonly buffers: Buffer[] = []; + + create(text: string): Node { + const buf = new Buffer(text); + const buf_index = this.buffers.push(buf) - 1; + + return create_node(buf_index, 0, buf.len, 0, buf.eols_len); + } + + split(x: Node, index: number, gap: number): Node { + const buf = this.buffers[x.buf]!; + + const start = x.slice_start + index + gap; + const len = x.slice_len - index - gap; + + this.#resize(x, index); + bubble(x); + + const eols_start = buf.find_eol_index(start, x.eols_start + x.eols_len); + const eols_end = buf.find_eol_index(start + len, eols_start); + const eols_len = eols_end - eols_start; + + return create_node(x.buf, start, len, eols_start, eols_len); + } + + *read(x: Node, offset: number, n: number): Generator { + while (!x.nil && (n > 0)) { + const count = Math.min(x.slice_len - offset, n); + + yield this.buffers[x.buf]!.text.slice( + x.slice_start + offset, + x.slice_start + offset + count, + ); + + x = successor(x); + offset = 0; + n -= count; + } + } + + growable(x: Node): boolean { + const buf = this.buffers[x.buf]!; + + return (buf.len < 100) && (x.slice_start + x.slice_len === buf.len); + } + + grow(x: Node, text: string): void { + this.buffers[x.buf]!.append(text); + + this.#resize(x, x.slice_len + text.length); + } + + trim_start(x: Node, n: number): void { + const buf = this.buffers[x.buf]!; + + x.slice_start += n; + x.slice_len -= n; + + x.eols_start = buf.find_eol_index(x.slice_start, x.eols_start); + + const eols_end = buf.find_eol_index( + x.slice_start + x.slice_len, + x.eols_start, + ); + + x.eols_len = eols_end - x.eols_start; + } + + trim_end(x: Node, n: number): void { + this.#resize(x, x.slice_len - n); + } + + #resize(x: Node, len: number): void { + const buf = this.buffers[x.buf]!; + + x.slice_len = len; + + const eols_end = buf.find_eol_index( + x.slice_start + x.slice_len, + x.eols_start, + ); + x.eols_len = eols_end - x.eols_start; + } } diff --git a/src/text-buf.ts b/src/text-buf.ts index 88df851..1939d0f 100644 --- a/src/text-buf.ts +++ b/src/text-buf.ts @@ -1,7 +1,6 @@ -import { Buffer } from "./buffer.ts"; +import { Content } from "./content.ts"; import { bubble, - create as create_node, find, maximum, minimum, @@ -27,7 +26,7 @@ export class TextBuf { */ root = NIL; - #bufs: Buffer[] = []; + #content = new Content(); /** * Creates instances of `TextBuf` interpreting text characters as `UTF-16 code units`. @@ -38,7 +37,7 @@ export class TextBuf { */ constructor(text?: string) { if (text && text.length > 0) { - this.root = this.#create_node(text); + this.root = this.#content.create(text); this.root.red = false; } } @@ -153,7 +152,7 @@ export class TextBuf { const { node, offset } = first; - yield* this.#read(node, offset, end - start); + yield* this.#content.read(node, offset, end - start); } /** @@ -237,13 +236,13 @@ export class TextBuf { x = x.right; } - if (insert_case === InsertionCase.Right && this.#node_growable(p)) { - this.#grow_node(p, text); + if (insert_case === InsertionCase.Right && this.#content.growable(p)) { + this.#content.grow(p, text); bubble(p); return; } - const child = this.#create_node(text); + const child = this.#content.create(text); switch (insert_case) { case InsertionCase.Root: { @@ -260,7 +259,8 @@ export class TextBuf { break; } case InsertionCase.Split: { - const y = this.#split_node(p, i, 0); + const y = this.#content.split(p, i, 0); + this.#insert_after(p, y); this.#insert_before(y, child); break; } @@ -379,27 +379,30 @@ export class TextBuf { if (offset === 0) { this.#delete(node); } else { - this.#trim_node_end(node, count); + this.#content.trim_end(node, count); bubble(node); } } else if (offset2 < node.slice_len) { if (offset === 0) { - this.#trim_node_start(node, count); + this.#content.trim_start(node, count); bubble(node); } else { - this.#split_node(node, offset, count); + const y = this.#content.split(node, offset, count); + this.#insert_after(node, y); } } else { let x = node; let i = 0; if (offset !== 0) { - x = this.#split_node(node, offset, 0); + x = this.#content.split(node, offset, 0); + this.#insert_after(node, x); } const last = find(this.root, end); if (last && last.offset !== 0) { - this.#split_node(last.node, last.offset, 0); + const y = this.#content.split(last.node, last.offset, 0); + this.#insert_after(last.node, y); } while (!x.nil && (i < count)) { @@ -474,7 +477,7 @@ export class TextBuf { i += x.left.total_len; if (eol_index < x.eols_len) { - const buf = this.#bufs[x.buf]!; + const buf = this.#content.buffers[x.buf]!; const eol_end = buf.get_eol_end(x.eols_start + eol_index)!; return i + eol_end - x.slice_start; } @@ -485,21 +488,6 @@ export class TextBuf { } } - *#read(x: Node, offset: number, n: number): Generator { - while (!x.nil && (n > 0)) { - const count = Math.min(x.slice_len - offset, n); - - yield this.#bufs[x.buf]!.text.slice( - x.slice_start + offset, - x.slice_start + offset + count, - ); - - x = successor(x); - offset = 0; - n -= count; - } - } - #insert_before(p: Node, z: Node): void { if (p.left.nil) { this.#insert_left(p, z); @@ -740,75 +728,4 @@ export class TextBuf { v.p = u.p; } - - #create_node(text: string): Node { - const buf = new Buffer(text); - const buf_index = this.#bufs.push(buf) - 1; - - return create_node(buf_index, 0, buf.len, 0, buf.eols_len); - } - - #split_node(x: Node, index: number, gap: number): Node { - const buf = this.#bufs[x.buf]!; - - const start = x.slice_start + index + gap; - const len = x.slice_len - index - gap; - - this.#resize_node(x, index); - bubble(x); - - const eols_start = buf.find_eol_index(start, x.eols_start + x.eols_len); - const eols_end = buf.find_eol_index(start + len, eols_start); - const eols_len = eols_end - eols_start; - - const node = create_node(x.buf, start, len, eols_start, eols_len); - this.#insert_after(x, node); - - return node; - } - - #node_growable(x: Node): boolean { - const buf = this.#bufs[x.buf]!; - - return (buf.len < 100) && (x.slice_start + x.slice_len === buf.len); - } - - #grow_node(x: Node, text: string): void { - this.#bufs[x.buf]!.append(text); - - this.#resize_node(x, x.slice_len + text.length); - } - - #trim_node_start(x: Node, n: number): void { - const buf = this.#bufs[x.buf]!; - - x.slice_start += n; - x.slice_len -= n; - - x.eols_start = buf.find_eol_index(x.slice_start, x.eols_start); - - const eols_end = buf.find_eol_index( - x.slice_start + x.slice_len, - x.eols_start, - ); - - x.eols_len = eols_end - x.eols_start; - } - - #trim_node_end(x: Node, n: number): void { - this.#resize_node(x, x.slice_len - n); - } - - #resize_node(x: Node, len: number): void { - const buf = this.#bufs[x.buf]!; - - x.slice_len = len; - - const eols_end = buf.find_eol_index( - x.slice_start + x.slice_len, - x.eols_start, - ); - - x.eols_len = eols_end - x.eols_start; - } } From 0706e004180a146e5649048f01dc2eb3d47c0608 Mon Sep 17 00:00:00 2001 From: Eugene Pobochny Date: Tue, 26 Aug 2025 14:55:18 -0400 Subject: [PATCH 3/5] 1 --- src/text-buf.ts | 300 +++------------------------------- src/tree.ts | 246 ++++++++++++++++++++++++++++ test/assert.ts | 9 +- test/create.test.ts | 6 +- test/delete-from-line.test.ts | 6 +- test/delete-line.test.ts | 10 +- test/delete.test.ts | 28 ++-- test/insert-line.test.ts | 10 +- test/insert.test.ts | 106 ++++++------ test/read-from-line.test.ts | 8 +- test/read-line.test.ts | 20 +-- test/read.test.ts | 10 +- test/undo.test.ts | 10 +- 13 files changed, 384 insertions(+), 385 deletions(-) create mode 100644 src/tree.ts diff --git a/src/text-buf.ts b/src/text-buf.ts index 1939d0f..11d780d 100644 --- a/src/text-buf.ts +++ b/src/text-buf.ts @@ -1,13 +1,6 @@ import { Content } from "./content.ts"; -import { - bubble, - find, - maximum, - minimum, - NIL, - type Node, - successor, -} from "./node.ts"; +import { bubble, find, NIL, type Node, successor } from "./node.ts"; +import { Tree } from "./tree.ts"; export const enum InsertionCase { Root, @@ -24,7 +17,7 @@ export class TextBuf { * @ignore * @internal */ - root = NIL; + tree = new Tree(); #content = new Content(); @@ -37,8 +30,8 @@ export class TextBuf { */ constructor(text?: string) { if (text && text.length > 0) { - this.root = this.#content.create(text); - this.root.red = false; + this.tree.root = this.#content.create(text); + this.tree.root.red = false; } } @@ -59,7 +52,7 @@ export class TextBuf { * ``` */ get count(): number { - return this.root.total_len; + return this.tree.root.total_len; } /** @@ -79,7 +72,9 @@ export class TextBuf { * ``` */ get line_count(): number { - return this.root.total_len === 0 ? 0 : this.root.total_eols_len + 1; + return this.tree.root.total_len === 0 + ? 0 + : this.tree.root.total_eols_len + 1; } /** @@ -98,7 +93,7 @@ export class TextBuf { * ``` */ save(): Node { - return structuredClone(this.root); + return structuredClone(this.tree.root); } /** @@ -122,7 +117,7 @@ export class TextBuf { * ``` */ restore(node: Node): void { - this.root = structuredClone(node); + this.tree.root = structuredClone(node); } /** @@ -145,7 +140,7 @@ export class TextBuf { * ``` */ *read(start: number, end = Number.MAX_SAFE_INTEGER): Generator { - const first = find(this.root, start); + const first = find(this.tree.root, start); if (!first) { return; } @@ -210,7 +205,7 @@ export class TextBuf { let insert_case = InsertionCase.Root; let p = NIL; - let x = this.root; + let x = this.tree.root; while (!x.nil) { if (i <= x.left.total_len) { @@ -246,22 +241,22 @@ export class TextBuf { switch (insert_case) { case InsertionCase.Root: { - this.root = child; - this.root.red = false; + this.tree.root = child; + this.tree.root.red = false; break; } case InsertionCase.Left: { - this.#insert_left(p, child); + this.tree.insert_left(p, child); break; } case InsertionCase.Right: { - this.#insert_right(p, child); + this.tree.insert_right(p, child); break; } case InsertionCase.Split: { const y = this.#content.split(p, i, 0); - this.#insert_after(p, y); - this.#insert_before(y, child); + this.tree.insert_after(p, y); + this.tree.insert_before(y, child); break; } } @@ -366,7 +361,7 @@ export class TextBuf { * ``` */ delete(start: number, end = Number.MAX_SAFE_INTEGER): void { - const first = find(this.root, start); + const first = find(this.tree.root, start); if (!first) { return; } @@ -377,7 +372,7 @@ export class TextBuf { if (offset2 === node.slice_len) { if (offset === 0) { - this.#delete(node); + this.tree.delete(node); } else { this.#content.trim_end(node, count); bubble(node); @@ -388,7 +383,7 @@ export class TextBuf { bubble(node); } else { const y = this.#content.split(node, offset, count); - this.#insert_after(node, y); + this.tree.insert_after(node, y); } } else { let x = node; @@ -396,13 +391,13 @@ export class TextBuf { if (offset !== 0) { x = this.#content.split(node, offset, 0); - this.#insert_after(node, x); + this.tree.insert_after(node, x); } - const last = find(this.root, end); + const last = find(this.tree.root, end); if (last && last.offset !== 0) { const y = this.#content.split(last.node, last.offset, 0); - this.#insert_after(last.node, y); + this.tree.insert_after(last.node, y); } while (!x.nil && (i < count)) { @@ -410,7 +405,7 @@ export class TextBuf { const next = successor(x); - this.#delete(x); + this.tree.delete(x); x = next; } @@ -464,7 +459,7 @@ export class TextBuf { } let eol_index = ln - 1; - let x = this.root; + let x = this.tree.root; let i = 0; while (!x.nil) { @@ -487,245 +482,4 @@ export class TextBuf { x = x.right; } } - - #insert_before(p: Node, z: Node): void { - if (p.left.nil) { - this.#insert_left(p, z); - } else { - this.#insert_right(maximum(p.left), z); - } - } - - #insert_after(p: Node, z: Node): void { - if (p.right.nil) { - this.#insert_right(p, z); - } else { - this.#insert_left(minimum(p.right), z); - } - } - - #insert_left(p: Node, z: Node): void { - p.left = z; - z.p = p; - - bubble(z); - - this.#insert_fixup(z); - } - - #insert_right(p: Node, z: Node): void { - p.right = z; - z.p = p; - - bubble(z); - - this.#insert_fixup(z); - } - - #insert_fixup(z: Node): void { - while (z.p.red) { - if (z.p === z.p.p.left) { - const y = z.p.p.right; - if (y.red) { - z.p.red = false; - y.red = false; - z.p.p.red = true; - z = z.p.p; - } else { - if (z === z.p.right) { - z = z.p; - this.#left_rotate(z); - } - z.p.red = false; - z.p.p.red = true; - this.#right_rotate(z.p.p); - } - } else { - const y = z.p.p.left; - if (y.red) { - z.p.red = false; - y.red = false; - z.p.p.red = true; - z = z.p.p; - } else { - if (z === z.p.left) { - z = z.p; - this.#right_rotate(z); - } - z.p.red = false; - z.p.p.red = true; - this.#left_rotate(z.p.p); - } - } - } - - this.root.red = false; - } - - #delete(z: Node): void { - let y = z; - let y_original_color = y.red; - let x: Node; - - if (z.left.nil) { - x = z.right; - - this.#transplant(z, z.right); - bubble(z.right.p); - } else if (z.right.nil) { - x = z.left; - - this.#transplant(z, z.left); - bubble(z.left.p); - } else { - y = minimum(z.right); - - y_original_color = y.red; - x = y.right; - - if (y !== z.right) { - this.#transplant(y, y.right); - bubble(y.right.p); - - y.right = z.right; - y.right.p = y; - } else { - x.p = y; - } - - this.#transplant(z, y); - - y.left = z.left; - y.left.p = y; - y.red = z.red; - - bubble(y); - } - - if (!y_original_color) { - this.#delete_fixup(x); - } - } - - #delete_fixup(x: Node): void { - while (x !== this.root && !x.red) { - if (x === x.p.left) { - let w = x.p.right; - - if (w.red) { - w.red = false; - x.p.red = true; - this.#left_rotate(x.p); - w = x.p.right; - } - - if (!w.left.red && !w.right.red) { - w.red = true; - x = x.p; - } else { - if (!w.right.red) { - w.left.red = false; - w.red = true; - this.#right_rotate(w); - w = x.p.right; - } - - w.red = x.p.red; - x.p.red = false; - w.right.red = false; - this.#left_rotate(x.p); - x = this.root; - } - } else { - let w = x.p.left; - - if (w.red) { - w.red = false; - x.p.red = true; - this.#right_rotate(x.p); - w = x.p.left; - } - - if (!w.right.red && !w.left.red) { - w.red = true; - x = x.p; - } else { - if (!w.left.red) { - w.right.red = false; - w.red = true; - this.#left_rotate(w); - w = x.p.left; - } - - w.red = x.p.red; - x.p.red = false; - w.left.red = false; - this.#right_rotate(x.p); - x = this.root; - } - } - } - - x.red = false; - } - - #left_rotate(x: Node): void { - const y = x.right; - - x.right = y.left; - if (!y.left.nil) { - y.left.p = x; - } - - y.p = x.p; - - if (x.p.nil) { - this.root = y; - } else if (x === x.p.left) { - x.p.left = y; - } else { - x.p.right = y; - } - - y.left = x; - x.p = y; - - bubble(x); - } - - #right_rotate(y: Node): void { - const x = y.left; - - y.left = x.right; - if (!x.right.nil) { - x.right.p = y; - } - - x.p = y.p; - - if (y.p.nil) { - this.root = x; - } else if (y === y.p.left) { - y.p.left = x; - } else { - y.p.right = x; - } - - x.right = y; - y.p = x; - - bubble(y); - } - - #transplant(u: Node, v: Node): void { - if (u.p.nil) { - this.root = v; - } else if (u === u.p.left) { - u.p.left = v; - } else { - u.p.right = v; - } - - v.p = u.p; - } } diff --git a/src/tree.ts b/src/tree.ts new file mode 100644 index 0000000..8adb2ef --- /dev/null +++ b/src/tree.ts @@ -0,0 +1,246 @@ +import { bubble, maximum, minimum, NIL, type Node } from "./node.ts"; + +export class Tree { + root = NIL; + + insert_left(p: Node, z: Node): void { + p.left = z; + z.p = p; + + bubble(z); + + this.#insert_fixup(z); + } + + insert_right(p: Node, z: Node): void { + p.right = z; + z.p = p; + + bubble(z); + + this.#insert_fixup(z); + } + + insert_before(p: Node, z: Node): void { + if (p.left.nil) { + this.insert_left(p, z); + } else { + this.insert_right(maximum(p.left), z); + } + } + + insert_after(p: Node, z: Node): void { + if (p.right.nil) { + this.insert_right(p, z); + } else { + this.insert_left(minimum(p.right), z); + } + } + + #insert_fixup(z: Node): void { + while (z.p.red) { + if (z.p === z.p.p.left) { + const y = z.p.p.right; + if (y.red) { + z.p.red = false; + y.red = false; + z.p.p.red = true; + z = z.p.p; + } else { + if (z === z.p.right) { + z = z.p; + this.#left_rotate(z); + } + z.p.red = false; + z.p.p.red = true; + this.#right_rotate(z.p.p); + } + } else { + const y = z.p.p.left; + if (y.red) { + z.p.red = false; + y.red = false; + z.p.p.red = true; + z = z.p.p; + } else { + if (z === z.p.left) { + z = z.p; + this.#right_rotate(z); + } + z.p.red = false; + z.p.p.red = true; + this.#left_rotate(z.p.p); + } + } + } + + this.root.red = false; + } + + delete(z: Node): void { + let y = z; + let y_original_color = y.red; + let x: Node; + + if (z.left.nil) { + x = z.right; + + this.#transplant(z, z.right); + bubble(z.right.p); + } else if (z.right.nil) { + x = z.left; + + this.#transplant(z, z.left); + bubble(z.left.p); + } else { + y = minimum(z.right); + + y_original_color = y.red; + x = y.right; + + if (y !== z.right) { + this.#transplant(y, y.right); + bubble(y.right.p); + + y.right = z.right; + y.right.p = y; + } else { + x.p = y; + } + + this.#transplant(z, y); + + y.left = z.left; + y.left.p = y; + y.red = z.red; + + bubble(y); + } + + if (!y_original_color) { + this.#delete_fixup(x); + } + } + + #delete_fixup(x: Node): void { + while (x !== this.root && !x.red) { + if (x === x.p.left) { + let w = x.p.right; + + if (w.red) { + w.red = false; + x.p.red = true; + this.#left_rotate(x.p); + w = x.p.right; + } + + if (!w.left.red && !w.right.red) { + w.red = true; + x = x.p; + } else { + if (!w.right.red) { + w.left.red = false; + w.red = true; + this.#right_rotate(w); + w = x.p.right; + } + + w.red = x.p.red; + x.p.red = false; + w.right.red = false; + this.#left_rotate(x.p); + x = this.root; + } + } else { + let w = x.p.left; + + if (w.red) { + w.red = false; + x.p.red = true; + this.#right_rotate(x.p); + w = x.p.left; + } + + if (!w.right.red && !w.left.red) { + w.red = true; + x = x.p; + } else { + if (!w.left.red) { + w.right.red = false; + w.red = true; + this.#left_rotate(w); + w = x.p.left; + } + + w.red = x.p.red; + x.p.red = false; + w.left.red = false; + this.#right_rotate(x.p); + x = this.root; + } + } + } + + x.red = false; + } + + #left_rotate(x: Node): void { + const y = x.right; + + x.right = y.left; + if (!y.left.nil) { + y.left.p = x; + } + + y.p = x.p; + + if (x.p.nil) { + this.root = y; + } else if (x === x.p.left) { + x.p.left = y; + } else { + x.p.right = y; + } + + y.left = x; + x.p = y; + + bubble(x); + } + + #right_rotate(y: Node): void { + const x = y.left; + + y.left = x.right; + if (!x.right.nil) { + x.right.p = y; + } + + x.p = y.p; + + if (y.p.nil) { + this.root = x; + } else if (y === y.p.left) { + y.p.left = x; + } else { + y.p.right = x; + } + + x.right = y; + y.p = x; + + bubble(y); + } + + #transplant(u: Node, v: Node): void { + if (u.p.nil) { + this.root = v; + } else if (u === u.p.left) { + u.p.left = v; + } else { + u.p.right = v; + } + + v.p = u.p; + } +} diff --git a/test/assert.ts b/test/assert.ts index 32835c6..4837370 100644 --- a/test/assert.ts +++ b/test/assert.ts @@ -1,7 +1,6 @@ import { assert, assertEquals } from "@std/assert"; import type { Node } from "../src/node.ts"; -import type { TextBuf } from "../src/text-buf.ts"; export function assert_generator( actual: Generator, @@ -10,17 +9,17 @@ export function assert_generator( assertEquals(actual.reduce((a, x) => a + x, ""), expected); } -export function assert_tree(tree: TextBuf): void { +export function assert_root(root: Node): void { // 1. Every node is either red or black. // 2. The root is black. - assert(!tree.root.red); + assert(!root.red); - assert_node(tree.root); + assert_node(root); // 5. For each node, all simple paths from the node to descendant leaves // contain the same number of black nodes. const leafs = new Set(); - collect_leafs(tree.root, leafs); + collect_leafs(root, leafs); const heights = Array.from(leafs).map((x) => { let height = 0; diff --git a/test/create.test.ts b/test/create.test.ts index 0509aec..ce3115b 100644 --- a/test/create.test.ts +++ b/test/create.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Create empty", () => { const buf = new TextBuf(); @@ -10,7 +10,7 @@ Deno.test("Create empty", () => { assertEquals(buf.count, 0); assertEquals(buf.line_count, 0); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Create", () => { @@ -20,5 +20,5 @@ Deno.test("Create", () => { assertEquals(buf.count, 11); assertEquals(buf.line_count, 1); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/delete-from-line.test.ts b/test/delete-from-line.test.ts index 7af4dae..9ab1c8d 100644 --- a/test/delete-from-line.test.ts +++ b/test/delete-from-line.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Delete from line", () => { const buf = new TextBuf("Lorem \nipsum \ndolor \nsit \namet"); @@ -13,12 +13,12 @@ Deno.test("Delete from line", () => { assert_generator(buf.read(0), "Lorem \nipsum \ndolor \n"); assertEquals(buf.count, 21); assertEquals(buf.line_count, 4); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete2([1, 0]); assert_generator(buf.read(0), "Lorem \n"); assertEquals(buf.count, 7); assertEquals(buf.line_count, 2); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/delete-line.test.ts b/test/delete-line.test.ts index 11fc14a..cf710a9 100644 --- a/test/delete-line.test.ts +++ b/test/delete-line.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Delete line", () => { const buf = new TextBuf("Lorem \nipsum \ndolor \nsit \namet "); @@ -13,26 +13,26 @@ Deno.test("Delete line", () => { assert_generator(buf.read(0), "Lorem \nipsum \ndolor \nsit \n"); assertEquals(buf.count, 26); assertEquals(buf.line_count, 5); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete2([3, 0], [4, 0]); assert_generator(buf.read(0), "Lorem \nipsum \ndolor \n"); assertEquals(buf.count, 21); assertEquals(buf.line_count, 4); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete2([2, 0], [3, 0]); assert_generator(buf.read(0), "Lorem \nipsum \n"); assertEquals(buf.count, 14); assertEquals(buf.line_count, 3); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete2([1, 0], [2, 0]); assert_generator(buf.read(0), "Lorem \n"); assertEquals(buf.count, 7); assertEquals(buf.line_count, 2); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/delete.test.ts b/test/delete.test.ts index 1bddb67..d51ce56 100644 --- a/test/delete.test.ts +++ b/test/delete.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; const EXPECTED = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; @@ -64,7 +64,7 @@ function test_delete_head(buf: TextBuf, n: number): void { while (expected.length > 0) { assert_generator(buf.read(0), expected); assertEquals(buf.count, expected.length); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete(0, n); expected = expected.slice(n); @@ -72,7 +72,7 @@ function test_delete_head(buf: TextBuf, n: number): void { assert_generator(buf.read(0), ""); assertEquals(buf.count, 0); - assert_tree(buf); + assert_root(buf.tree.root); } function test_delete_tail(buf: TextBuf, n: number): void { @@ -81,7 +81,7 @@ function test_delete_tail(buf: TextBuf, n: number): void { while (expected.length > 0) { assert_generator(buf.read(0), expected); assertEquals(buf.count, expected.length); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete(Math.max(buf.count - n, 0), buf.count); expected = expected.slice(0, -n); @@ -89,7 +89,7 @@ function test_delete_tail(buf: TextBuf, n: number): void { assert_generator(buf.read(0), ""); assertEquals(buf.count, 0); - assert_tree(buf); + assert_root(buf.tree.root); } function test_delete_middle(buf: TextBuf, n: number): void { @@ -98,7 +98,7 @@ function test_delete_middle(buf: TextBuf, n: number): void { while (expected.length > 0) { assert_generator(buf.read(0), expected); assertEquals(buf.count, expected.length); - assert_tree(buf); + assert_root(buf.tree.root); const pos = Math.floor(buf.count / 2); buf.delete(pos, pos + n); @@ -107,7 +107,7 @@ function test_delete_middle(buf: TextBuf, n: number): void { assert_generator(buf.read(0), expected); assertEquals(buf.count, 0); - assert_tree(buf); + assert_root(buf.tree.root); } for (let n = 1; n <= 10; n += 1) { @@ -156,7 +156,7 @@ Deno.test("Delete splitting nodes", () => { for (let i = n - 1; i >= 1; i -= 1) { assert_generator(buf.read(0), expected); assertEquals(buf.count, expected.length); - assert_tree(buf); + assert_root(buf.tree.root); buf.delete(s * i, s * i + 2); expected = expected.slice(0, s * i) + expected.slice(s * i + 2); @@ -166,7 +166,7 @@ Deno.test("Delete splitting nodes", () => { assert_generator(buf.read(0), expected); assertEquals(buf.count, 0); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Delete count < 0", () => { @@ -175,7 +175,7 @@ Deno.test("Delete count < 0", () => { buf.delete(5, -6); assert_generator(buf.read(0), "Lorem ipsum"); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Delete removes lines", () => { @@ -193,7 +193,7 @@ Deno.test("Delete removes lines", () => { assertEquals(buf.line_count, 1); assert_generator(buf.read(0), "ipsum"); assert_generator(buf.read2([0, 0], [1, 0]), "ipsum"); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Delete newline char removes line", () => { @@ -205,7 +205,7 @@ Deno.test("Delete newline char removes line", () => { assert_generator(buf.read(0), " \n"); assertEquals(buf.line_count, 2); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Delete first newline char removes line", () => { @@ -217,7 +217,7 @@ Deno.test("Delete first newline char removes line", () => { assert_generator(buf.read(0), "\n"); assertEquals(buf.line_count, 2); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Delete line followed by newline", () => { @@ -229,5 +229,5 @@ Deno.test("Delete line followed by newline", () => { assert_generator(buf.read(0), " \n\n \n"); assertEquals(buf.line_count, 4); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/insert-line.test.ts b/test/insert-line.test.ts index 0168d94..5201dc3 100644 --- a/test/insert-line.test.ts +++ b/test/insert-line.test.ts @@ -1,5 +1,5 @@ import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Insert into 0 line", () => { const buf = new TextBuf(); @@ -9,7 +9,7 @@ Deno.test("Insert into 0 line", () => { assert_generator(buf.read(0), "Lorem ipsum"); assert_generator(buf.read2([0, 0], [1, 0]), "Lorem ipsum"); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert into a line", () => { @@ -21,7 +21,7 @@ Deno.test("Insert into a line", () => { assert_generator(buf.read(0), "Lorem ipsum"); assert_generator(buf.read2([0, 0], [1, 0]), "Lorem ipsum"); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert into a line which does not exist", () => { @@ -32,7 +32,7 @@ Deno.test("Insert into a line which does not exist", () => { assert_generator(buf.read(0), ""); assert_generator(buf.read2([0, 0], [1, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert into a column which does not exist", () => { @@ -43,5 +43,5 @@ Deno.test("Insert into a column which does not exist", () => { assert_generator(buf.read(0), ""); assert_generator(buf.read2([0, 0], [1, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/insert.test.ts b/test/insert.test.ts index da18423..d6b62a4 100644 --- a/test/insert.test.ts +++ b/test/insert.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Insert into the end", () => { const buf = new TextBuf(); @@ -9,32 +9,32 @@ Deno.test("Insert into the end", () => { buf.insert(buf.count, "Lorem"); assert_generator(buf.read(0), "Lorem"); assertEquals(buf.count, 5); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " ipsum"); assert_generator(buf.read(0), "Lorem ipsum"); assertEquals(buf.count, 11); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " dolor"); assert_generator(buf.read(0), "Lorem ipsum dolor"); assertEquals(buf.count, 17); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " sit"); assert_generator(buf.read(0), "Lorem ipsum dolor sit"); assertEquals(buf.count, 21); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " amet,"); assert_generator(buf.read(0), "Lorem ipsum dolor sit amet,"); assertEquals(buf.count, 27); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " consectetur"); assert_generator(buf.read(0), "Lorem ipsum dolor sit amet, consectetur"); assertEquals(buf.count, 39); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " adipiscing"); assert_generator( @@ -42,7 +42,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing", ); assertEquals(buf.count, 50); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " elit,"); assert_generator( @@ -50,7 +50,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit,", ); assertEquals(buf.count, 56); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " sed"); assert_generator( @@ -58,7 +58,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed", ); assertEquals(buf.count, 60); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " do"); assert_generator( @@ -66,7 +66,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do", ); assertEquals(buf.count, 63); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " eiusmod"); assert_generator( @@ -74,7 +74,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod", ); assertEquals(buf.count, 71); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " tempor"); assert_generator( @@ -82,7 +82,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", ); assertEquals(buf.count, 78); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " incididunt"); assert_generator( @@ -90,7 +90,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt", ); assertEquals(buf.count, 89); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " ut"); assert_generator( @@ -98,7 +98,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut", ); assertEquals(buf.count, 92); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " labore"); assert_generator( @@ -106,7 +106,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore", ); assertEquals(buf.count, 99); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " et"); assert_generator( @@ -114,7 +114,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et", ); assertEquals(buf.count, 102); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " dolore"); assert_generator( @@ -122,7 +122,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore", ); assertEquals(buf.count, 109); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " magna"); assert_generator( @@ -130,7 +130,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna", ); assertEquals(buf.count, 115); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(buf.count, " aliqua."); assert_generator( @@ -138,7 +138,7 @@ Deno.test("Insert into the end", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 123); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert into the beginning", () => { @@ -147,32 +147,32 @@ Deno.test("Insert into the beginning", () => { buf.insert(0, " aliqua."); assert_generator(buf.read(0), " aliqua."); assertEquals(buf.count, 8); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " magna"); assert_generator(buf.read(0), " magna aliqua."); assertEquals(buf.count, 14); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " dolore"); assert_generator(buf.read(0), " dolore magna aliqua."); assertEquals(buf.count, 21); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " et"); assert_generator(buf.read(0), " et dolore magna aliqua."); assertEquals(buf.count, 24); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " labore"); assert_generator(buf.read(0), " labore et dolore magna aliqua."); assertEquals(buf.count, 31); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " ut"); assert_generator(buf.read(0), " ut labore et dolore magna aliqua."); assertEquals(buf.count, 34); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " incididunt"); assert_generator( @@ -180,7 +180,7 @@ Deno.test("Insert into the beginning", () => { " incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 45); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " tempor"); assert_generator( @@ -188,7 +188,7 @@ Deno.test("Insert into the beginning", () => { " tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 52); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " eiusmod"); assert_generator( @@ -196,7 +196,7 @@ Deno.test("Insert into the beginning", () => { " eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 60); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " do"); assert_generator( @@ -204,7 +204,7 @@ Deno.test("Insert into the beginning", () => { " do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 63); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " sed"); assert_generator( @@ -212,7 +212,7 @@ Deno.test("Insert into the beginning", () => { " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 67); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " elit,"); assert_generator( @@ -220,7 +220,7 @@ Deno.test("Insert into the beginning", () => { " elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 73); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " adipiscing"); assert_generator( @@ -228,7 +228,7 @@ Deno.test("Insert into the beginning", () => { " adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 84); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " consectetur"); assert_generator( @@ -236,7 +236,7 @@ Deno.test("Insert into the beginning", () => { " consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 96); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " amet,"); assert_generator( @@ -244,7 +244,7 @@ Deno.test("Insert into the beginning", () => { " amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 102); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " sit"); assert_generator( @@ -252,7 +252,7 @@ Deno.test("Insert into the beginning", () => { " sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 106); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " dolor"); assert_generator( @@ -260,7 +260,7 @@ Deno.test("Insert into the beginning", () => { " dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 112); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, " ipsum"); assert_generator( @@ -268,7 +268,7 @@ Deno.test("Insert into the beginning", () => { " ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 118); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(0, "Lorem"); assert_generator( @@ -276,7 +276,7 @@ Deno.test("Insert into the beginning", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 123); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert splitting nodes", () => { @@ -285,17 +285,17 @@ Deno.test("Insert splitting nodes", () => { buf.insert(0, "Lorem aliqua."); assert_generator(buf.read(0), "Lorem aliqua."); assertEquals(buf.count, 13); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(5, " ipsum magna"); assert_generator(buf.read(0), "Lorem ipsum magna aliqua."); assertEquals(buf.count, 25); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(11, " dolor dolore"); assert_generator(buf.read(0), "Lorem ipsum dolor dolore magna aliqua."); assertEquals(buf.count, 38); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(17, " sit et"); assert_generator( @@ -303,7 +303,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit et dolore magna aliqua.", ); assertEquals(buf.count, 45); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(21, " amet, labore"); assert_generator( @@ -311,7 +311,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit amet, labore et dolore magna aliqua.", ); assertEquals(buf.count, 58); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(27, " consectetur ut"); assert_generator( @@ -319,7 +319,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit amet, consectetur ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 73); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(39, " adipiscing incididunt"); assert_generator( @@ -327,7 +327,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 95); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(50, " elit, tempor"); assert_generator( @@ -335,7 +335,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 108); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(56, " sed eiusmod"); assert_generator( @@ -343,7 +343,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 120); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(60, " do"); assert_generator( @@ -351,7 +351,7 @@ Deno.test("Insert splitting nodes", () => { "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", ); assertEquals(buf.count, 123); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert at the negative index", () => { @@ -360,17 +360,17 @@ Deno.test("Insert at the negative index", () => { buf.insert(0, "ipsum"); assert_generator(buf.read(0), "ipsum"); assertEquals(buf.count, 5); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(-5, " "); assert_generator(buf.read(0), " ipsum"); assertEquals(buf.count, 6); - assert_tree(buf); + assert_root(buf.tree.root); buf.insert(-6, "Lorem"); assert_generator(buf.read(0), "Lorem ipsum"); assertEquals(buf.count, 11); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert splitting node with fixup", () => { @@ -390,5 +390,5 @@ Deno.test("Insert splitting node with fixup", () => { buf.insert(4, "-"); assert_generator(buf.read(0), "1133-4422"); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/read-from-line.test.ts b/test/read-from-line.test.ts index 9d10e93..ace4cd9 100644 --- a/test/read-from-line.test.ts +++ b/test/read-from-line.test.ts @@ -1,5 +1,5 @@ import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Line at valid index", () => { const buf = new TextBuf("Lorem\nipsum\ndolor\nsit\namet"); @@ -10,7 +10,7 @@ Deno.test("Line at valid index", () => { assert_generator(buf.read2([3, 0]), "sit\namet"); assert_generator(buf.read2([4, 0]), "amet"); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Line at index >= line_count", () => { @@ -20,7 +20,7 @@ Deno.test("Line at index >= line_count", () => { assert_generator(buf.read2([5, 0]), ""); assert_generator(buf.read2([6, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Line at index < 0", () => { @@ -30,5 +30,5 @@ Deno.test("Line at index < 0", () => { assert_generator(buf.read2([buf.line_count - 1, 0]), "amet"); assert_generator(buf.read2([buf.line_count - 2, 0]), "sit\namet"); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/read-line.test.ts b/test/read-line.test.ts index 2288001..da76f8b 100644 --- a/test/read-line.test.ts +++ b/test/read-line.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Empty", () => { const buf = new TextBuf(); @@ -9,7 +9,7 @@ Deno.test("Empty", () => { assertEquals(buf.line_count, 0); assert_generator(buf.read2([0, 0], [1, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("1 line", () => { @@ -18,7 +18,7 @@ Deno.test("1 line", () => { assertEquals(buf.line_count, 1); assert_generator(buf.read2([0, 0], [1, 0]), "0"); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("2 lines", () => { @@ -28,7 +28,7 @@ Deno.test("2 lines", () => { assert_generator(buf.read2([0, 0], [1, 0]), "0\n"); assert_generator(buf.read2([1, 0], [2, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("3 lines", () => { @@ -39,7 +39,7 @@ Deno.test("3 lines", () => { assert_generator(buf.read2([1, 0], [2, 0]), "1\n"); assert_generator(buf.read2([2, 0], [3, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Line at valid index", () => { @@ -76,7 +76,7 @@ Deno.test("Line at valid index", () => { assert_generator(buf.read2([17, 0], [18, 0]), "magna\n"); assert_generator(buf.read2([18, 0], [19, 0]), "aliqua."); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Line at index >= line_count", () => { @@ -86,7 +86,7 @@ Deno.test("Line at index >= line_count", () => { assert_generator(buf.read2([5, 0], [6, 0]), ""); assert_generator(buf.read2([6, 0], [7, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Line at index < 0", () => { @@ -102,7 +102,7 @@ Deno.test("Line at index < 0", () => { "sit\n", ); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Insert adds lines", () => { @@ -113,10 +113,10 @@ Deno.test("Insert adds lines", () => { assertEquals(buf.line_count, i + 2); assert_generator(buf.read2([i, 0], [i + 1, 0]), `${i}\n`); - assert_tree(buf); + assert_root(buf.tree.root); } assertEquals(buf.line_count, 11); assert_generator(buf.read2([11, 0], [12, 0]), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/read.test.ts b/test/read.test.ts index 1b778ff..0bfbf10 100644 --- a/test/read.test.ts +++ b/test/read.test.ts @@ -1,18 +1,18 @@ import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Read empty", () => { const buf = new TextBuf(); assert_generator(buf.read(0), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Read", () => { const buf = new TextBuf("Lorem ipsum dolor"); assert_generator(buf.read(6, 12), "ipsum "); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Read at start >= count", () => { @@ -22,7 +22,7 @@ Deno.test("Read at start >= count", () => { assert_generator(buf.read(5), ""); assert_generator(buf.read(6), ""); - assert_tree(buf); + assert_root(buf.tree.root); }); Deno.test("Read at start < 0", () => { @@ -32,5 +32,5 @@ Deno.test("Read at start < 0", () => { assert_generator(buf.read(buf.count - 1), "m"); assert_generator(buf.read(buf.count - 2), "em"); - assert_tree(buf); + assert_root(buf.tree.root); }); diff --git a/test/undo.test.ts b/test/undo.test.ts index 705d513..bb570a1 100644 --- a/test/undo.test.ts +++ b/test/undo.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "@std/assert"; import { TextBuf } from "../src/text-buf.ts"; -import { assert_generator, assert_tree } from "./assert.ts"; +import { assert_generator, assert_root } from "./assert.ts"; Deno.test("Undo insert", () => { const buf = new TextBuf(); @@ -9,13 +9,13 @@ Deno.test("Undo insert", () => { buf.insert(buf.count, "Lorem"); assert_generator(buf.read(0), "Lorem"); assertEquals(buf.count, 5); - assert_tree(buf); + assert_root(buf.tree.root); - const a = structuredClone(buf.root); + const a = structuredClone(buf.tree.root); buf.insert(buf.count, "Lorem"); - buf.root = a; + buf.tree.root = a; assert_generator(buf.read(0), "Lorem"); assertEquals(buf.count, 5); - assert_tree(buf); + assert_root(buf.tree.root); }); From ee565f8411aae10966c733b5ee5fc66e4c45f8cd Mon Sep 17 00:00:00 2001 From: Eugene Pobochny Date: Wed, 27 Aug 2025 02:37:42 -0400 Subject: [PATCH 4/5] 1 --- src/text-buf.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-buf.ts b/src/text-buf.ts index 11d780d..f5b7645 100644 --- a/src/text-buf.ts +++ b/src/text-buf.ts @@ -17,7 +17,7 @@ export class TextBuf { * @ignore * @internal */ - tree = new Tree(); + tree: Tree = new Tree(); #content = new Content(); From fc0adb4a21535265f51b44ef6509f73603a1f201 Mon Sep 17 00:00:00 2001 From: Eugene Pobochny Date: Wed, 27 Aug 2025 14:36:04 -0400 Subject: [PATCH 5/5] 1 --- deno.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deno.json b/deno.json index a4a86e6..d9e6df1 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@eu-ge-ne/text-buf", - "version": "0.14.1", + "version": "0.14.2", "license": "MIT", "exports": "./src/mod.ts", "imports": {