ed

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 6dfb054aea170b36344a04e02349543241ca4d7e
parent ef9ea186acb7f6e90a631d897c04095adb8fed2c
Author: Byron Torres <b@torresjrjr.com>
Date:   Sun, 12 Sep 2021 23:37:56 +0100

Add address.ha

Diffstat:
MMakefile | 1+
Aaddress.ha | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbuffer.ha | 1+
Med.ha | 2++
4 files changed, 107 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,6 +3,7 @@ HAREFLAGS= source=\ ed.ha \ + address.ha \ buffer.ha \ operation.ha \ parse.ha \ diff --git a/address.ha b/address.ha @@ -0,0 +1,103 @@ +use strings; + +// These functions do not mutate. Their job is to find linenodes by addresses. + +// Returns the linenode at a given line number. +fn addr_linenum(buf: *buffer, n: size) *linenode = { + let ln = buf.head; + let i = 0z; + + for (i < n) { + match (ln.value) { + headnode => abort("Unreachable"), + tailnode => abort("Invalid range"), // TODO: return error + str => ln = ln.next, + }; + }; + + return ln; +}; + +// Returns the linenode of the last line in the edit buffer. +fn addr_lastline(buf: *buffer) *linenode = { + let ln = buf.tail.prev; + + match (ln.value) { + tailnode => abort("Unreachable"), + headnode => abort("TODO"), // TODO: ??? + str => void, + }; + + return ln; +}; + +// Searches for the first linenode which matches a regular expression. +fn addr_regex(buf: *buffer, ln: *linenode, re: str, dir: bool) *linenode = { + if (buf.head.next == buf.tail) { + // buffer empty + abort("No match"); // TODO: return error + }; + + const startln = ln; + ln = ln.next; + + for (true) { + match (ln.value) { + headnode => ln = buf.tail.prev, + tailnode => ln = buf.head.next, + txt: str => { + if (startln == ln) { + abort("No match"); // TODO: return error + }; + switch (strings::contains(txt, re)) { // TODO: use real regex + false => switch (dir) { + true => ln = ln.next, + false => ln = ln.prev, + }, + true => return ln, + }; + }, + }; + }; + + abort("Unreachable"); +}; + +// Searches for the first linenode which matches a regular expression. +fn addr_mark(buf: *buffer, mark: rune) *linenode = { + let ln = buf.head; + for (true) { + match (ln.value) { + headnode => ln = ln.next, + tailnode => abort("Invalid address"), // TODO: return error + str => if (ln.mark == mark) { + return ln; + } else { + ln = ln.next; + continue; + }, + }; + }; + + abort("Unreachable"); +}; + +// Searches for the first linenode which matches a regular expression. +fn addr_offset(buf: *buffer, ln: *linenode, n: size) *linenode = { + for (n != 0) { + match (ln.value) { + headnode => abort("Invalid address"), // TODO: return error + tailnode => abort("Invalid address"), // TODO: return error + str => if (n > 0) { + ln = ln.next; + n -= 1; + } else if (n < 0) { + ln = ln.prev; + n += 1; + }, + }; + }; + + return ln; +}; + diff --git a/buffer.ha b/buffer.ha @@ -20,6 +20,7 @@ type linenode = struct { value: value, prev: *linenode, next: *linenode, + mark: rune, }; // Represents what kind of linenode a linenode is, or its content text. diff --git a/ed.ha b/ed.ha @@ -63,6 +63,8 @@ export fn main() void = { for (let i = 0z; i < len(ops); i += 1) :ops { const op = ops[i]; + // TODO: refactor ops into function pointers, + // and move alias to func mapping to parse_cmd(). switch (op.cmd_alias) { "e" => op_edit(buf), "r" => op_read(buf),