~ecs/public-inbox

madeline: Add actions histtokup and histtokdown v1 PROPOSED

Max Schillinger: 1
 Add actions histtokup and histtokdown

 4 files changed, 53 insertions(+), 0 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~ecs/public-inbox/patches/48055/mbox | git am -3
Learn more about email & git

[PATCH madeline] Add actions histtokup and histtokdown Export this patch

These actions complete the current command line with the last token of
the previous/next command in history. They are bound to "Alt+." and
"Alt+>"/"Alt+" (which is "Alt+Shift+." on QWERTY/QWERTZ).

Example:

% echo "hello world"
% folder=/tmp/folder
% mkdir $folder
% cd $folder
% mv ~/Downloads/x .
% echo folder=$folder
% echo [Alt+.]

On pressing "Alt+." multiple times, the current command line will be
completed to

% echo folder=$folder
% echo .
% echo $folder
% echo hello world

The duplicate $folder token will be skipped. "folder=/tmp/folder" will
be skipped as well (because there are no arguments). "hello world" will be
considered one token (using made::split_sh).

Possible TODO's:

- "hello world" it is inserted without quotes. made::sh_escape could be
  used to escape the space but this would also escape the "$" in
  "$folder". Maybe made::split_sh can be modified to optionally return
  tokens including surrounding quotes.
- IMO, these actions should iterate over all arguments not only the last
  one of every command. This would require to modify made::split_sh to
  optionally return a token with a requested index.
---
 made/actions.ha | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 made/hist.ha    |  1 +
 made/line.ha    |  4 ++++
 made/types.ha   |  1 +
 4 files changed, 53 insertions(+)

diff --git a/made/actions.ha b/made/actions.ha
index 10f8021..dea1b2f 100644
--- a/made/actions.ha
+++ b/made/actions.ha
@@ -2,6 +2,7 @@ use bufio;
use io;
use strings;
use sort;
use crypto;

// Pull new lines from other madeline instances into the in-memory history
fn update_hist(s: *state) (void | error) = {
@@ -53,6 +54,52 @@ fn histdown(s: *state) (void | error) = {
	};
};

fn histtokenup(s: *state) (void | error) = {
	update_hist(s)?;
	let h = &s.ctx.hist;
	if (s.mode == mode::NORMAL) {
		if (len(h.our_hist) == 0) return;
		h.htokidx = len(h.our_hist);
		s.buftyped = s.buf;
	};
	if (s.mode == mode::SEARCH) return;
	s.mode = mode::HIST;
	for (h.htokidx > 0) {
		h.htokidx -= 1;
		let (token, count) = s.ctx.split.split(h.our_hist[h.htokidx]);
		if (count == 0) continue; // command only, no arguments
		let tempbuf = strings::concat(strings::fromutf8(s.buftyped)!, token);
		defer free(tempbuf);
		let newbufutf8 = strings::toutf8(strings::dup(tempbuf));
		if (crypto::compare(s.buf, newbufutf8)) continue;
		s.buf = newbufutf8;
		s.pos = len(s.buf);
		break;
	};
};

fn histtokendown(s: *state) (void | error) = {
	if (s.mode != mode::HIST) return;
	update_hist(s)?;
	let h = &s.ctx.hist;
	for (h.htokidx < len(h.our_hist) - 1) {
		h.htokidx += 1;
		let (token, count) = s.ctx.split.split(h.our_hist[h.htokidx]);
		if (count == 0) continue; // command only, no arguments
		let tempbuf = strings::concat(strings::fromutf8(s.buftyped)!, token);
		defer free(tempbuf);
		let newbufutf8 = strings::toutf8(strings::dup(tempbuf));
		if (crypto::compare(s.buf, newbufutf8)) continue;
		// update command line with new token
		s.buf = newbufutf8;
		s.pos = len(s.buf);
		return;
	};
	s.buf = s.buftyped;
	s.pos = len(s.buf);
	s.mode = mode::NORMAL;
};

fn complete(s: *state) void = {
	freecompletions(s);
	s.completions = s.ctx.complete(s.ctx, s.buf, s.pos);
diff --git a/made/hist.ha b/made/hist.ha
index 7f867bd..04ddaf4 100644
--- a/made/hist.ha
+++ b/made/hist.ha
@@ -13,6 +13,7 @@ export type history = struct {
	hist: []str,
	our_hist: []str,
	hidx: size,
	htokidx: size,
};

// Stores [[history]] in memory without a backing handle.
diff --git a/made/line.ha b/made/line.ha
index a66600d..ebbfebd 100644
--- a/made/line.ha
+++ b/made/line.ha
@@ -138,6 +138,10 @@ export fn line(ctx: *context) (str | void | io::EOF | error) = {
				kill(&s, &prevword, false);
			case 'y' => // alt+y
				unkill(&s, false);
			case '.' => // alt+.
				histtokenup(&s)?;
			case '>', ':' => // alt+shift+.
				histtokendown(&s)?;
			case '\x0a', '\x0d' => // alt+enter
				appendstr(&s, "\n");
			case => void;
diff --git a/made/types.ha b/made/types.ha
index 8359903..15cad42 100644
--- a/made/types.ha
+++ b/made/types.ha
@@ -20,6 +20,7 @@ type state = struct {
	in: io::file,
	out: io::handle,
	buf: []u8,
	buftyped: []u8, // typed manually, without token completion
	pos: size,
	mode: mode,
	completions: (str, [](str, str)),
-- 
2.42.0