ed

[hare] The standard editor
Log | Files | Refs | README | LICENSE

commit 3b7f8d3a4fe2b5c0c259d3604572bf213f92e75e
parent 3c9de16b8ac47fbda677d1b9c52faac470f405ef
Author: Byron Torres <b@torresjrjr.com>
Date:   Tue,  9 Jan 2024 11:33:07 +0000

add regex search pattern memory

Diffstat:
Maddress.ha | 28+++++++++++++++++++++++++---
Mcommand.ha | 5+++--
Mexecute.ha | 2+-
Mglobal.ha | 8++++----
Mmain.ha | 4++++
5 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/address.ha b/address.ha @@ -1,4 +1,5 @@ use regex; +use strings; type Address = struct{ addrform: AddressForm, @@ -26,6 +27,9 @@ type InvalidAddress = !void; // A regular expression search found no match. type NoMatch = !void; +// There is no previously used regex search pattern. +type NoPrevRegex = !void; + fn addr_nextline(buf: *Buffer, n: size) size = { if (len(buf.lines) - 1 == n) return n; @@ -65,10 +69,10 @@ fn addr_regex( buf: *Buffer, rad: RegexAddr, start: size, -) (size | NoMatch | regex::error) = { + s: *Session, +) (size | NoPrevRegex | NoMatch | regex::error) = { const length = len(buf.lines); - // TODO: use BRE, not ERE. - const re = regex::compile(rad.expr)?; defer regex::finish(&re); + const re = newregex(s, rad.expr)?; defer regex::finish(&re); for (let x = 1z; x <= length; x += 1) { const n = @@ -86,3 +90,21 @@ fn addr_regex( return NoMatch; }; + +fn newregex(s: *Session, expr: str) (regex::regex | NoPrevRegex | regex::error) = { + debug("expr=<{}>", expr); + debug("s.lastregex=<{}>", s.lastregex); + + const newexpr = + if (expr != "") + expr + else if (s.lastregex is str) + s.lastregex as str + else + return NoPrevRegex; + + // TODO: use BRE, not ERE. + const re = regex::compile(newexpr)?; + s.lastregex = strings::dup(newexpr); + yield re; +}; diff --git a/command.ha b/command.ha @@ -36,6 +36,7 @@ type CmdError = !( | NoFilename | WarnBufferModified | NoMatch + | NoPrevRegex | NoPrevShCmd | NoPrevGlobalSubCmd | InvalidGlobalSubCmd @@ -456,7 +457,7 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = { )?; assert_nonzero(s, a)?; - const regex = regex::compile(cmd.arg1)?; defer regex::finish(&regex); + const re = newregex(s, cmd.arg1)?; defer regex::finish(&re); const replacement = cmd.arg2; const flags = cmd.arg3; // TODO: parse and use substitution flags `cmd.arg3` @@ -465,7 +466,7 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = { for (let i = a; i <= b; i += 1) { const old = s.buf.lines[i].text; - const results = regex::findall(&regex, old); + const results = regex::findall(&re, old); defer regex::result_freeall(results); if (len(results) == 0) diff --git a/execute.ha b/execute.ha @@ -37,7 +37,7 @@ fn exec_addr(s: *Session, addr: Address) (size | CmdError) = { case let mark: rune => return addr_mark(s.buf, mark)?; case let rad: RegexAddr => - return addr_regex(s.buf, rad, s.buf.cursor)?; + return addr_regex(s.buf, rad, s.buf.cursor, s)?; }; }; diff --git a/global.ha b/global.ha @@ -17,12 +17,12 @@ fn global(s: *Session, cmd: *Command, matched: bool) (void | Error) = { )?; assert_nonzero(s, a)?; - const regex = regex::compile(cmd.arg1)?; defer regex::finish(&regex); + const re = newregex(s, cmd.arg1)?; defer regex::finish(&re); for (let i = a; i <= b; i += 1) { const line = s.buf.lines[i]; line.globalmark = false; // TODO: is this necessary? - if (matched == regex::test(&regex, line.text)) + if (matched == regex::test(&re, line.text)) line.globalmark = true; }; @@ -116,12 +116,12 @@ fn global_interactive(s: *Session, cmd: *Command, matched: bool) (void | Error) )?; assert_nonzero(s, a)?; - const regex = regex::compile(cmd.arg1)?; defer regex::finish(&regex); + const re = newregex(s, cmd.arg1)?; defer regex::finish(&re); for (let i = a; i <= b; i += 1) { const line = s.buf.lines[i]; line.globalmark = false; // TODO: is this necessary? - if (matched == regex::test(&regex, line.text)) + if (matched == regex::test(&re, line.text)) line.globalmark = true; }; diff --git a/main.ha b/main.ha @@ -21,6 +21,7 @@ type Session = struct{ prompt: str, warned: bool, prev_shcmd: (str | void), + lastregex: (void | str), }; type Error = !(...InteractionError | ...ParseError | ...CmdError); @@ -52,6 +53,7 @@ export fn main() void = { prompt = "*", prev_shcmd = void, lasterror = void, + lastregex = void, ... }; @@ -160,6 +162,8 @@ fn strerror(err: Error) str = { return "Invalid destination"; case NoMatch => return "No match"; + case NoPrevRegex => + return "No previous search pattern"; case NoPrevShCmd => return "No previous shell command"; case NoPrevGlobalSubCmd =>