[Toybox] [PATCH] more.c: More stuff, down cursor key scrolls down. Also stuff about less

Rob Landley rob at landley.net
Wed Mar 20 16:17:02 PDT 2024


On 3/20/24 11:56, Oliver Webb wrote:
> On Wednesday, March 20th, 2024 at 11:39, Rob Landley <rob at landley.net> wrote: 
>> More never had the ability to go backwards, less did. Different command.
> 
>>From the more help text you get when you press "h":
> 
> b or ctrl-B             Skip backwards k screenfuls of text [1]

$ ls -l /bin/more
-rwxr-xr-x 1 root root 47816 Nov 27  2019 /bin/more
$ dpkg-query -S /bin/more
util-linux: /bin/more
$ cat README | more

I hit space twice to advance, then hit b and ctrl-b a lot, no effect. At a
guess, that particular gnu/dammit extension which isn't in posix or busybox more
only works on a seekable file.

I personally don't want to complicate more because less exists.

>> > Looking at the other keybindings GNU more provides which I can implement, There's "=" (prints current
>> > line number) ":f" (print filename and line), as well as being able to use the down arrow to go down
>> > (with the added side effect of any escape key doing so too, not the end of the world, especially
>> > since we can't scroll up) That are Implemented them in the attached patch.
>> 
>> Again, more and less are not the same command.
> 
> No, all of that is more behavior that you can use in more. Try it.

I just did, above.

One easy way to distinguish between less and more is that ctrl-c exits more, but
ctrl-c only kills the command producing less's output while leaving less
displaying the scrollback buffer. You need to hit 'q' to get out of less (unless
you've hit something like forward slash where q just appends to the string and
esc doesn't exit that either, but ctrl-c will exit... back to the less prompt),
meaning newbies can get STUCK in less not knowing how to exit it, the way you
can't in "more".

Oh, here's another difference:

$ { echo -e '\e[42mcolor\e[0m text'; while true; do echo hello; done; } | more
shows the color change
$ { echo -e '\e[42mcolor\e[0m text'; while true; do echo hello; done; } | less
shows the escape sequences

That's why I'm still pondering if they can/should usefully share code.

>> > There is also a testing problem. vi.c doesn't do TEST_HOST because it needs a -s option
>> > to pass in scripts to test with.
>> 
>> Which is an issue I need to figure out how to address. What does a test that
>> only toybox passes actually prove? (That it hasn't changed since we last
>> looked at it?)
> 
> There is vi -c which preforms a ex command which we could implement

I leave vi to the people who are maintaining that vi. I got out of way for that
command.

>> I have been planning one all along, yes. The crunch_str() stuff I did was a
>> first pass at general line handling stuff that could be used by less and by
>> shell line editing and by vi and so on, but people wrote a vi that does not and
>> never will share code with the rest of those so that's off the table
>> permanently.
> 
> My experience is in vi.c which is why I mentioned using code from it. I haven't read
> through top or hexedit

I haven't read through the vi.c in pending.

>> > But I have to ask the question "If it's so easy, why isn't it in toybox yet?" Is it just because
>> > other TODO items taking up time, or is it because it's harder to implement than it seems.
>> 
>> Because I care about edge cases like ansi escapes and utf8 fontmetrics and
>> resizing the screen partway through displaying, because I haven't got test suite
>> infrastructure that can emulate the other half of a PTY yet without which
>> testing has to be manual, because I wanted multiple things to share
>> infrastructure (including potentially stuff like "fold")...
> 
> So it's harder to implement than it seems, thank you.

Well it's harder to TEST. There's a reason I've been working towards mkroot
based test infrastructure with a known kernel and pty wrappers. Kinda hard to
test "ps" or "top" or "watch" at present either.

I have PART of that test infrastructure in the txpect plumbing in
scripts/runtest.sh which do expect style input/output scripts, currently just
used for sh tests via a "shxpect" wrapper, but the general idea is explained in
the comment before the shell function in runtest.sh:

# Simple implementation of "expect" written in shell.

# txpect NAME COMMAND [I/O/E/X/R[OE]string]...
# Run COMMAND and interact with it:
# I send string to input
# OE read exactly this string from stdout or stderr (bare = read+discard line)
#    note: non-bare does not read \n unless you include it with O$'blah\n'
# R prefix means O or E is regex match (read line, must contain substring)
# X close stdin/stdout/stderr and match return code (blank means nonzero)

So you can go:

txpect "test name" "bash --noediting -i" \
  E'$ ' I$'echo hello\n' O$'hello\n' E'$ ' I$'exit 42\n' X42

Which runs bash with a pile of flags (the shxpect wrapper also calls env -i and
manually sets PATH and PS1, and then adds --noprofile and --norc so it doesn't
override them on its way up), and then:

1) reads the '$ ' prompt from the child's stderr, dying if it can't (um, 10
second timeout I think?) And yes, interactive shell prompts to go stderr, not
stdout.

2) Feeds 'echo hello' followed by a newline to the child's stdin, using the
shell's $'blah' escape parsing syntax to convert the \n into low ascii.

3) reads "hello\n' from the child's stdout.

4) reads another prompt on stderr.

5) tells the shell to exit with error code 42.

6) waits for the child to exit with error code 42.

Actually making that WORK reliably involved creating FIFOs behind the scenes,
you'd think the shell would be better about circular pipes but so far... Since I
wrote that, bash added a "coproc" command which I probably have to implement at
some point but am NEVER going to personally care about because they built it on
arrays, which is just sad.

Meanwhile, the people who took vi away and ran with it seem to think testing the
interactive bits are irrelevant, and that "vi" is just "ex" with a GUI. I have
not attempted to argue with them.

Anyway, what txpect does NOT do is let you specify a screen size or query cursor
position for the child process, the way a command like "screen" does. I need to
set up a pty master process and interact with the child through it somehow,
which is pending design work. I probably have to create a
toys/example/demo_pty.c and command and have the test depend on that being in
the $PATH, because I am NOT having the test suite call a compiler at the design
level. (The test suite is not dependent on the build environment, therefore it
cannot compile small C programs as part of a test.)

In THEORY mkroot/packages/tests should be able to do something like:

  cp -D scripts/{runtest,portability,test}.sh "$ROOT/test/scripts/"

And just run the tests with a smallish wrapper script to make directories and
maybe set up environment variables. Installing a native toolchain into the new
filesystem is _not_ a dependency. Which makes the pty wrapping awkward at a
design level...

Rob


More information about the Toybox mailing list