~ecs/mrsh-dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH madeline] Add hinter type

Details
Message ID
<20230714184958.16989-1-sebastian@sebsite.pw>
DKIM signature
pass
Download raw message
Patch: +68 -58
This allows a hinter to be set similarly to a completer. A function
"hinthistory" is provided which replicates the old default behavior.

Signed-off-by: Sebastian <sebastian@sebsite.pw>
---
 example.ha                           |  4 ++--
 made/actions.ha                      | 18 +++++++-------
 made/{complete/fs.ha => complete.ha} | 22 +++++++++++++----
 made/complete/types.ha               | 12 ----------
 made/hint.ha                         | 19 +++++++++++++++
 made/hist.ha                         |  7 +++---
 made/line.ha                         |  4 +---
 made/types.ha                        |  5 ++--
 made/util.ha                         | 35 +++++++++++-----------------
 9 files changed, 68 insertions(+), 58 deletions(-)
 rename made/{complete/fs.ha => complete.ha} (72%)
 delete mode 100644 made/complete/types.ha
 create mode 100644 made/hint.ha

diff --git a/example.ha b/example.ha
index 07c919e..4f5f561 100644
--- a/example.ha
+++ b/example.ha
@@ -1,7 +1,6 @@
use dirs;
use fmt;
use io;
use made::complete;
use made::split;
use made;
use path;
@@ -12,7 +11,8 @@ export fn main() void = {
	path::set(&buf, dirs::data("madeline"), "history")!;
	let hist = made::histfile(path::string(&buf))!;
	let ctx = made::context {
		complete = &complete::fs,
		complete = &made::complete_fs,
		hint = &made::hinthistory,
		hist = &hist,
		prompt = &made::prompt_string("$ "),
		split = split::sh,
diff --git a/made/actions.ha b/made/actions.ha
index 9991fdd..03a9341 100644
--- a/made/actions.ha
+++ b/made/actions.ha
@@ -17,14 +17,14 @@ fn histup(s: *state) (void | error) = {
	let h = &s.ctx.hist;
	if (s.mode == mode::NORMAL) {
		if (len(h.our_hist) == 0) return;
		s.hidx = len(h.our_hist);
		h.hidx = len(h.our_hist);
		hist_add(s, strings::dup(strings::fromutf8(s.buf)!), true);
	};
	if (s.hidx != 0) s.hidx -= 1;
	if (h.hidx != 0) h.hidx -= 1;
	if (s.mode == mode::SEARCH) return;
	clear(s);
	s.mode = mode::HIST;
	s.buf = strings::toutf8(strings::dup(h.our_hist[s.hidx]));
	s.buf = strings::toutf8(strings::dup(h.our_hist[h.hidx]));
	s.pos = len(s.buf);
};

@@ -32,21 +32,21 @@ fn histdown(s: *state) (void | error) = {
	update_hist(s)?;
	let h = &s.ctx.hist;
	let buf = strings::fromutf8(s.buf)!;
	s.hidx += 1;
	h.hidx += 1;
	switch (s.mode) {
	case mode::NORMAL =>
		hist_add(s, strings::dup(buf), true);
		clear(s);
	case mode::SEARCH =>
		for (s.hidx < len(h.hist); s.hidx += 1) {
			if (strings::contains(h.hist[s.hidx], buf)) {
		for (h.hidx < len(h.hist); h.hidx += 1) {
			if (strings::contains(h.hist[h.hidx], buf)) {
				break;
			};
		};
	case mode::HIST =>
		clear(s);
		if (s.hidx < len(h.our_hist)) {
			appendstr(s, h.our_hist[s.hidx]);
		if (h.hidx < len(h.our_hist)) {
			appendstr(s, h.our_hist[h.hidx]);
		} else {
			s.mode = mode::NORMAL;
		};
@@ -55,7 +55,7 @@ fn histdown(s: *state) (void | error) = {

fn complete(s: *state) void = {
	freecompletions(s);
	s.completions = s.ctx.complete(&s.ctx.split, s.buf, s.pos);
	s.completions = s.ctx.complete(s.ctx, s.buf, s.pos);
	sort::sort(s.completions.1, size((str, str)), &cmp_completion);
	for (let i = 1z; i < len(s.completions.1); i += 1) {
		let prev = s.completions.1[i - 1];
diff --git a/made/complete/fs.ha b/made/complete.ha
similarity index 72%
rename from made/complete/fs.ha
rename to made/complete.ha
index 6855dd1..ce47c57 100644
--- a/made/complete/fs.ha
+++ b/made/complete.ha
@@ -1,6 +1,5 @@
use fs;
use io;
use made::split;
use os;
use path;
use strings;
@@ -8,11 +7,24 @@ use strio;
use unix::passwd;
use unix;

// Returns a new buffer (or any empty string to leave the buffer
// unchanged), and a list of possible completions (text, addendum),
// where addendum is appended to the buffer after text if the
// completion is selected.
export type completer = fn(ctx: *context, buf: []u8, pos: size) (str, [](str, str));

// A [[completer]] that doesn't create any completions.
export fn complete_none(
	ctx: *context,
	buf: []u8,
	pos: size,
) (str, [](str, str)) = ("", []);

// A [[completer]] that completes the final token with existing paths
// on the filesystem.
export fn fs(s: *split::splitter, buf: []u8, pos: size) (str, [](str, str)) = {
	let ctx = strings::fromutf8(buf[..pos])!;
	let (buf, toknum) = s.split(ctx);
export fn complete_fs(ctx: *context, buf: []u8, pos: size) (str, [](str, str)) = {
	let bufctx = strings::fromutf8(buf[..pos])!;
	let (buf, _) = ctx.split.split(bufctx);
	defer free(buf);
	let (first, rest) = strings::cut(buf, "/");
	let first = strings::iter(first);
@@ -71,7 +83,7 @@ export fn fs(s: *split::splitter, buf: []u8, pos: size) (str, [](str, str)) = {
				name = strings::concat(name, "/");
				end = "";
			};
			match (s.escape(ctx, name)) {
			match (ctx.split.escape(bufctx, name)) {
			case void => void;
			case let r: (str, str) =>
				let (escaped, eend) = r;
diff --git a/made/complete/types.ha b/made/complete/types.ha
deleted file mode 100644
index 6a536eb..0000000
--- a/made/complete/types.ha
@@ -1,12 +0,0 @@
use made::split;

// Returns either a new buffer, or a list of possible
// completions (text, addendum), where addendum is appended to the
// buffer after text if the completion is selected.
export type completer = fn(s: *split::splitter, buf: []u8, pos: size) (str, [](str, str));

export fn default(
	s: *split::splitter,
	buf: []u8,
	pos: size,
) (str, [](str, str)) = ("", []);
diff --git a/made/hint.ha b/made/hint.ha
new file mode 100644
index 0000000..d405b95
--- /dev/null
+++ b/made/hint.ha
@@ -0,0 +1,19 @@
use strings;

// Returns a string to be used as the hint text. The return value
// may be statically allocated.
export type hinter = fn(s: *context, buf: []u8) str;

// A [[hinter]] that hints previous entries in the history.
export fn hinthistory(ctx: *context, buf: []u8) str = {
	let buf = strings::fromutf8(buf)!;
	if (buf == "") return "";
	let h = &ctx.hist;
	for (let i = len(h.hist) + 1; i > 0; i -= 1) if (i <= len(h.hist)) {
		let i = i - 1;
		if (strings::hasprefix(h.hist[i], buf)) {
			return strings::trimprefix(h.hist[i], buf);
		};
	};
	return "";
};
diff --git a/made/hist.ha b/made/hist.ha
index 17d16e5..5b12a46 100644
--- a/made/hist.ha
+++ b/made/hist.ha
@@ -13,6 +13,7 @@ export type history = struct {
	source: io::handle,
	hist: []str,
	our_hist: []str,
	hidx: size,
};

// Stores [[history]] in memory without a backing handle.
@@ -126,10 +127,10 @@ fn hist_add(s: *state, new: str, ours: bool) void = {
			free(h.hist[i]);
			delete(h.hist[i]);
			i -= 1;
			if (s.mode == mode::SEARCH && i < s.hidx) s.hidx -= 1;
			if (s.mode == mode::SEARCH && i < h.hidx) h.hidx -= 1;
		};
	};
	if (s.mode == mode::SEARCH && s.hidx == len(h.hist)) s.hidx += 1;
	if (s.mode == mode::SEARCH && h.hidx == len(h.hist)) h.hidx += 1;
	append(h.hist, new);
	if (!ours) return;
	for (let i = 0z; i < len(h.our_hist); i += 1) {
@@ -137,7 +138,7 @@ fn hist_add(s: *state, new: str, ours: bool) void = {
			free(h.our_hist[i]);
			delete(h.our_hist[i]);
			i -= 1;
			if (i < s.hidx) s.hidx -= 1;
			if (i < h.hidx) h.hidx -= 1;
		};
	};
	append(h.our_hist, strings::dup(new));
diff --git a/made/line.ha b/made/line.ha
index 4aae584..eb116ad 100644
--- a/made/line.ha
+++ b/made/line.ha
@@ -3,8 +3,6 @@ use bufio;
use encoding::utf8;
use fmt;
use io;
use made::complete;
use made::split;
use os;
use strings;
use unix::tty;
@@ -100,7 +98,7 @@ export fn line(ctx: *context) (str | void | io::EOF | error) = {
			switch (s.mode) {
			case mode::NORMAL, mode::HIST =>
				s.mode = mode::SEARCH;
				s.hidx = len(s.ctx.hist.hist);
				s.ctx.hist.hidx = len(s.ctx.hist.hist);
			case mode::SEARCH =>
				histup(&s)?;
			};
diff --git a/made/types.ha b/made/types.ha
index 58c042f..0ffb076 100644
--- a/made/types.ha
+++ b/made/types.ha
@@ -1,7 +1,6 @@
use encoding::utf8;
use fs;
use io;
use made::complete;
use made::split;
use strconv;
use unix::tty;
@@ -25,7 +24,6 @@ type state = struct {
	pos: size,
	mode: mode,
	completions: (str, [](str, str)),
	hidx: size,
	hint: str,
	pasting: bool,
	lines: [2]u16,
@@ -36,7 +34,8 @@ type state = struct {

// Context for a sequence of calls to [[line]].
export type context = struct {
	complete: *complete::completer,
	complete: *completer,
	hint: *hinter,
	hist: *history,
	prompt: *prompter,
	split: split::splitter,
diff --git a/made/util.ha b/made/util.ha
index f0ee286..a0b47a6 100644
--- a/made/util.ha
+++ b/made/util.ha
@@ -65,33 +65,26 @@ fn freecompletions(s: *state) void = {
};

fn update_hint(s: *state) void = {
	let buf = strings::fromutf8(s.buf)!;
	s.hint = "";
	if (s.ret is str) return;
	let h = s.ctx.hist.hist;
	let i = switch (s.mode) {
	switch (s.mode) {
	case mode::NORMAL =>
		if (buf == "") return;
		yield len(h) + 1;
		s.hint = s.ctx.hint(s.ctx, s.buf);
	case mode::SEARCH =>
		yield s.hidx + 1;
		update_search_hint(s);
	case mode::HIST => return;
	};
	for (i > 0; i -= 1) if (i <= len(h)) {
};

fn update_search_hint(s: *state) void = {
	let buf = strings::fromutf8(s.buf)!;
	let h = &s.ctx.hist;
	s.hint = "";
	for (let i = h.hidx + 1; i > 0; i -= 1) if (i <= len(h.hist)) {
		let i = i - 1;
		switch (s.mode) {
		case mode::NORMAL =>
			if (strings::hasprefix(h[i], buf)) {
				s.hint = strings::trimprefix(h[i], buf);
				break;
			};
		case mode::SEARCH =>
			if (strings::contains(h[i], buf)) {
				s.hint = h[i];
				s.hidx = i;
				break;
			};
		case mode::HIST => abort();
		if (strings::contains(h.hist[i], buf)) {
			s.hint = h.hist[i];
			h.hidx = i;
			break;
		};
	};
};
-- 
2.40.1
Details
Message ID
<CU304KYTZ8TS.323WNSNALE0RV@monch>
In-Reply-To
<20230714184958.16989-1-sebastian@sebsite.pw> (view parent)
DKIM signature
missing
Download raw message
thanks!

to git@git.d2evs.net:~ecs/madeline
  2074061..ad5fc67  madeline -> madeline

also pushed some reorganization of the splitter api, you'll need to
update hare-c for that
Reply to thread Export thread (mbox)