The “click” mechanism to associate the command and the output has been done a couple other ways:
https://www.warp.dev/ injects code that writes terminal escape sequences into your $PS1 prompt string (bash and zsh supported). Then the terminal can parse these terminal codes to figure out where the command begins and ends. There are probably some downsides, but I imagine it works 99% in practice. I haven’t used it myself, as it’s a “cloud” terminal.
(Weirdly, visiting this website instantly made my computer jank up. I’m not recommending it, but just mentioning it before my own project)
https://www.oilshell.org/ has a tiny protocol called FANOS for a GUI to communicate with the shell. The slogan is that a shell GUI should have a terminal; it doesn’t have to be a terminal.
In other words, the shell itself will never write to a terminal – it can be GUI only. But its child processes like pip or cargo build will write to terminals. The goal is to rewrite the shell only (which we’ve done!), not break/rewrite every command line tool that’s ever been written!!
As mentioned, definitely join #shell-gui on our Zulip if you want to help work on this! There are a couple contributors working on it (not me right now, but I want to use it!)
As mentioned elsewhere in this thread, I don’t think you will be getting rid of the shell, so much as reimplementing a tiny / quirky version inside your terminal emulator process.
That’s a pretty bad layering violation IMO. The shell can be used both interactively and as a scripting language – that’s a feature and not a bug! Just as it is with Lisp, etc.
And there are a bunch of other projects to look at
Though I will say what Oils is going for is different than all these projects. The key difference is that we control the shell implementation, which opens up more possibiliities
So we don’t just want to delimit the prompt in the terminal with escape codes, but actually have the prompt be part of the GUI itself, like the address bar in a browser is part of a GUI
That’s basically impossible without changing the shell, and I think can lead to a better UI
That’s a pretty bad layering violation IMO. The shell can be used both interactively and as a scripting language – that’s a feature and not a bug! Just as it is with Lisp, etc.
:tada: makes me very excited about the thing. One feature which would make me switching from kitty+fish to this: non-blocking commands. I want to be able to type cargo build and then immediately run git commit without waiting for the build to finish or otherwise messing with foreground/background.
As far as I can see, this project wouldn’t really getting rid of shell, so much as putting a tiny shell inside the terminal emulator process, which you can’t reuse over SSH or anything.
How do I cd /tmp to a directory? That’s now in the terminal emulator?
When I type zig, how does it find the binary? Does it use $PATH, or a non-scriptable mechanism in the terminal GUI?
What if I want to run two commands in sequence? build && test ?
Not to mention virtualenv not working (setting PYTHONPATH), opam switch, etc.
As an aside, for running cargo build, what’s wrong with either:
Opening a new tab you your terminal emulator.
Using tmux.
?
I do the latter, I usually have about 3 tmux windows open per directory. I don’t cd regularly because I have all the context I need set up in different shells.
That’s what I do, and it’s a poor workaround for a bad UX. Interactive programs should never ever block user input. It’s the job of an interactive shell to take a sequence of commands from the user and run them, and the current stack of technologies fails spectacularly at that.
Using tmux.
That’s 1., but implemented as recursive terminal emulation.
Meh, I can imagine the UX being improved, but I don’t think it’s bad. If I have two processes going in parallel, then switching tabs seems like the right UX?
That’s exactly how a browser works? I can’t click two links at the same time in the same tab – I have to open a new tab for one of them.
But good news is you can implement whatever UX you want on top of Oils’ headless mode :)
I can imagine there being something that’s more “in line”. Although git commit is still a bit tricky because it will often pop up an editor. Something to experiment with!
Tabs in general are a bad UI https://youtu.be/bFcaO1pXzws?t=730 :-) it’s a work-around for when you can’t design the software to just show what the user needs.
I can see that, when you’re within a project you may not want to be “finding the other tab” (although I generally use tmux keyboard shortcuts to mitigate that problem)
I think tabs / windows can be good for multiple “workspaces” for different projects, but for a single project, you may want to have some semantic connection between the things you’re doing
I would kind of like some web shell thing where everything is hyperlinked together, and you can search past commands in a bash Ctrl-R fashion, and even search the output of commands
And then save all that state, publish it, push it to another machine, etc.
If you include splits as a part of the tab design space then I am going to hard disagree. If splits are considered separate, I’m a soft maybe on this. Sometimes it’s too useful to have two separate files open and visible at the same time. I think that’s where the tmux workflows really shine. You can create as many panels as you need for context.
Yeah, splits are occasionally useful, when you essentially diff two files. When coding, I occasionally view two files side-by-side.
In my terminal emulator though, I routinely end up with like five spits, not because I need five different contexts, but because the architecture where terminal emulator, shell, and subordinate process suck from the same pipe that goes into the kernel make single context less useful then it could otherwise be.
Author here. I acknowledge at the end that any new features I bring are local to the emulator (they can’t travel over the network. Yet.)
How do I cd /tmp to a directory? That’s now in the terminal emulator?
You mean create a symlink? Yeah that’d be up to emulator now (I don’t support it.) I just stick to using the built-in file explorer. It’s going to be a better experience.
When I type zig, how does it find the binary? Does it use $PATH, or a non-scriptable mechanism in the terminal GUI?
It searches all the obvious places $PATH would have by default. Beyond that, since there is no shell, it’ll be up to the emulator to support any equivalent behavior on the GUI side.
What if I want to run two commands in sequence? build && test ?
Have a fall-through calling bash -c behind-the-scenes. At least while people get used to a new graphical approach.
You’re just saying you have a workflow powered by shell environments, which is lost in Terminal Click. As this emulator matures, a lot of the visual-interaction experiments will make up for that loss.
It searches all the obvious places $PATH would have by default
What does that mean? I can’t think of a single computer that I’ve used in the last 20 years (*NIX or Windows) where my PATH environment variable has not included some non-standard things, though some of them came from places like Homebrew. Looking at the path on this machine, I have:
Something added by RubyGems to find locally installed things
Something added by opam to find locally installed things.
Something added by Homebrew to find things.
Something added for a place I install things I’ve built by hand.
A few exciting paths I wasn’t expecting that seem to have been added by macOS security things.
Anything interesting can eventually be tunneled over other protocols so you can have your fancy terminal remotely. If I can use VS Code remotely, surely I can use Terminal Click remotely too.
Limiting yourself to existing terminal protocols is hopelessly limiting (and in my opinion, short-sighted).
I want to be able to type cargo build and then immediately run git commit without waiting for the build to finish or otherwise messing with foreground/background.
cargo build &
I think even modern PowerShell supports this via runspaces now. You don’t have to mess with the background job if you just want to kick it off as a sanity check.
I’m not sure how async commands would be sanely implemented by default with the wide variety of behaviors CLIs implement. Would it get something akin to a div and do a scrolling render in a fixed space? Would it just pummel stdout instead? Hard to say what is correct there.
& is horrible ux — it outputs tons of stuff on stdout completely messing up my further work, and I can’t even kill it easily.
Would it get something akin to a div and do a scrolling render in a fixed space? Would it just pummel stdout instead? Hard to say what is correct there.
There’s one fairly obvious option:
$ cargo build
Compiling foo
….
<further output goes here as it comes in>
$ git commit <I can continue to just type in here>
I’m not sure how obvious this is, or how it differs from using tmux or another multiplexer.
Like, in this system, how do you provide input if cargo build wants it? How do you access cargo build‘s return code? How do you send it a kill signal? If cargo build finishes and you want to re-run it under sudo, or with modified options, how do you navigate between history of the async shell vs history of where you’re running git commit? If git commit produces a lot of output, or opens an editor, how does that affect cargo build’s stdin/stdout? Does the top pane scroll separately from the bottom?
I think you need clear, predictable answers to all these questions and a thousand more. That’s what a multiplexer gives you. My expectation is you’d be well-served by a little wrapper script that takes a command and executes it inside a new tmux pane.
This calls to mind MUD clients, which was probably one of the most extreme situations of needing to compose text input among a sea of output. Makes perfect sense to apply it to general-purpose terminals too.
And I guess Enter if I want to spawn such “asynchronous” command (the default) and ctrl+Enter if I want to spawn a synchronous, interactive command and focus on its stdin.
One feature which would make me switching from kitty+fish to this: non-blocking commands.
I want this for a REPL. It would be very cool if you could build clients and servers iteratively from within the same REPL by switching between them. I thought this might be doable from Erlang/Elixir if you could create tab in the REPL per BEAM process. (Well, not literally per process, but per process that you want to interact with separately.)
I have to admit that I was a bit underwhelmed by the features. There was nothing that I found myself thinking “I need this”. I think that emacs is already the best option for a cross platform text-based computing environment. It can do pretty much everything shown and a lot more.
I would be happy to see more projects that were emacs-like in spirit, but were more accessible and had some modern appeal.
Kudos to the author for attempting to improve the terminal. Closed + only Linux/macOS/Windows means I can’t try it out for now (on NetBSD). The output reuse bit is not clear: is it a named reference to a chunk of (output) text? can I cat file and edit the resulting output and put it back? CLIM style presentation objects would enable those things. Emacs’s eshell lets you output to named buffers and you can edit from there for example. 9term has the “hold mode” which buffers input allowing you to edit normally before sending the content to the program. You can also freely edit any text, select and “Send”. And then there is the plumber to dispatch selections based on a rule set. The calculator example could be a rule matching expressions and sending the string to bc. Oberon and Acme also break up the linear flow of text into tiled viewers offering a flexible user environment: Oberon with a full language + module system and Acme with existing commands/programs and 9p.
I’m always interested in innovation in the terminal space. My latest experiment has been using a Jupyter notebook instead of the shell for some kinds of tasks. My favorite of your two features were the file explorer with an editable path, and enhanced history. Kakoune has a plugin for find file with fzf, so I wonder if I could put together a fzf over the directory tree and cd into that.
I didn’t find very many of the motivating use cases very motivating, your presentation was off-putting, and you missed the primary reason IMO why people are still using terminals. If you use tmux, that handles a couple of these features, eg. output re-use, saving output to files, and searching for output (not quite the same as grep if you are doing a batch). Even if it’s not as good, the gap being smaller de-motivates a big shift. For a calculator, I can use a different shell like xonsh, or I can pull up a python terminal. No big changes needed. Finally, what you describe as the brain of the terminal emulator just sounds like putting a shell into the emulator in a way that isn’t composable or customizable. Minor note, the hyperbolic presentation “insane and powerful” feels off-putting both for its hubris, and because it feels dismissive of people’s choices about their workflow.
You’ll note that I am defaulting to inertia here. That’s because the primary reason, IMO, people are still using terminals and shells is because of the ecosystem around them. You get to access to a wealth of documentation and community around the status quo, and people build things on that. Abandoning the ecosystem requires strong justification with improvements beyond the incremental.
Yes, the level of innovation shown does not justify the level of hyperbole used to describe it, and not acknowledging terminal multiplexers like tmux or zellij cut even deeper into their credibility. Not to mention even without a multiplexer that gives you access to the buffer, some existing terminals have nice bindings for searching history, clicking links, etc.
Closed source and public beta not expected until 2024. This feel a lot like the fig announcement from a while back. Hello hype train. And goodbye to hacking your own tools.
This is very cool! While I understand the solutions presented are objectively simpler than what exists today, I’ve got a lot of muscle memory tied to the way it works today. That makes me fast, so I don’t know that I’d need to switch.
That said, it will certainly help people without that familiarity. Plus, I always welcome re-examining “the way we’ve always done it”.
The “click” mechanism to associate the command and the output has been done a couple other ways:
$PS1
prompt string (bash and zsh supported). Then the terminal can parse these terminal codes to figure out where the command begins and ends. There are probably some downsides, but I imagine it works 99% in practice. I haven’t used it myself, as it’s a “cloud” terminal.(Weirdly, visiting this website instantly made my computer jank up. I’m not recommending it, but just mentioning it before my own project)
In other words, the shell itself will never write to a terminal – it can be GUI only. But its child processes like
pip
orcargo build
will write to terminals. The goal is to rewrite the shell only (which we’ve done!), not break/rewrite every command line tool that’s ever been written!!The protocol is tiny:
Screenshots: https://www.oilshell.org/blog/2023/06/release-0.16.0.html#headless-shell-screenshots
As mentioned, definitely join
#shell-gui
on our Zulip if you want to help work on this! There are a couple contributors working on it (not me right now, but I want to use it!)FWIW if you want a more minimal shell, there’s also https://skarnet.org/software/execline/ , but it’s not interactive.
As mentioned elsewhere in this thread, I don’t think you will be getting rid of the shell, so much as reimplementing a tiny / quirky version inside your terminal emulator process.
That’s a pretty bad layering violation IMO. The shell can be used both interactively and as a scripting language – that’s a feature and not a bug! Just as it is with Lisp, etc.
There’s https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md which is supported by wezterm, domterm and foot (though foot only does jumping between prompts, not selecting output).
And kitty can open the last output in a pager
Wow thank you, I didn’t know about all this prior art! I didn’t realize so many terminal emulators that have explored this area in recent years
I posted one story here: https://lobste.rs/s/czhzew/finally_terminated_2015_finalterm
And it looks like DomTerm has a lot of good ideas and is quite featureful.
I had it on this wiki page, but never tried it - https://github.com/oilshell/oil/wiki/Interactive-Shell
And there are a bunch of other projects to look at
Though I will say what Oils is going for is different than all these projects. The key difference is that we control the shell implementation, which opens up more possibiliities
So we don’t just want to delimit the prompt in the terminal with escape codes, but actually have the prompt be part of the GUI itself, like the address bar in a browser is part of a GUI
That’s basically impossible without changing the shell, and I think can lead to a better UI
Yeah I want to spend some time checking out oil
100% agreed
Mods deleted this
Most things are going on at https://oilshell.zulipchat.com/ right now
Fairly active discussion on the shell GUI
as well as trying to parallelize the project. I haven’t done a great job of spreading the knowledge, and that’s a primary focus now
So even just asking the right questions and spreading knowledge around helps a lot
BTW it should be fairly easy to get a local
bin/osh
working – https://github.com/oilshell/oil/wiki/Contributingthough I’m looking at folding the C++ instructions in, to make it even more friendly
thanks!
:tada: makes me very excited about the thing. One feature which would make me switching from kitty+fish to this: non-blocking commands. I want to be able to type
cargo build
and then immediately rungit commit
without waiting for the build to finish or otherwise messing with foreground/background.As far as I can see, this project wouldn’t really getting rid of shell, so much as putting a tiny shell inside the terminal emulator process, which you can’t reuse over SSH or anything.
cd /tmp
to a directory? That’s now in the terminal emulator?zig
, how does it find the binary? Does it use$PATH
, or a non-scriptable mechanism in the terminal GUI?build && test
?Not to mention
virtualenv
not working (settingPYTHONPATH
),opam switch
, etc.As an aside, for running
cargo build
, what’s wrong with either:?
I do the latter, I usually have about 3 tmux windows open per directory. I don’t
cd
regularly because I have all the context I need set up in different shells.That’s what I do, and it’s a poor workaround for a bad UX. Interactive programs should never ever block user input. It’s the job of an interactive shell to take a sequence of commands from the user and run them, and the current stack of technologies fails spectacularly at that.
That’s 1., but implemented as recursive terminal emulation.
Meh, I can imagine the UX being improved, but I don’t think it’s bad. If I have two processes going in parallel, then switching tabs seems like the right UX?
That’s exactly how a browser works? I can’t click two links at the same time in the same tab – I have to open a new tab for one of them.
But good news is you can implement whatever UX you want on top of Oils’ headless mode :)
https://lobste.rs/s/uhmygc/terminal_click_new_terminal_bringing#c_cflui6
I can imagine there being something that’s more “in line”. Although
git commit
is still a bit tricky because it will often pop up an editor. Something to experiment with!Tabs in general are a bad UI https://youtu.be/bFcaO1pXzws?t=730 :-) it’s a work-around for when you can’t design the software to just show what the user needs.
Hm interesting perspective
I can see that, when you’re within a project you may not want to be “finding the other tab” (although I generally use tmux keyboard shortcuts to mitigate that problem)
I think tabs / windows can be good for multiple “workspaces” for different projects, but for a single project, you may want to have some semantic connection between the things you’re doing
I would kind of like some web shell thing where everything is hyperlinked together, and you can search past commands in a bash Ctrl-R fashion, and even search the output of commands
And then save all that state, publish it, push it to another machine, etc.
If you include splits as a part of the tab design space then I am going to hard disagree. If splits are considered separate, I’m a soft maybe on this. Sometimes it’s too useful to have two separate files open and visible at the same time. I think that’s where the tmux workflows really shine. You can create as many panels as you need for context.
Yeah, splits are occasionally useful, when you essentially diff two files. When coding, I occasionally view two files side-by-side.
In my terminal emulator though, I routinely end up with like five spits, not because I need five different contexts, but because the architecture where terminal emulator, shell, and subordinate process suck from the same pipe that goes into the kernel make single context less useful then it could otherwise be.
Author here. I acknowledge at the end that any new features I bring are local to the emulator (they can’t travel over the network. Yet.)
You mean create a symlink? Yeah that’d be up to emulator now (I don’t support it.) I just stick to using the built-in file explorer. It’s going to be a better experience.
It searches all the obvious places $PATH would have by default. Beyond that, since there is no shell, it’ll be up to the emulator to support any equivalent behavior on the GUI side.
Have a fall-through calling
bash -c
behind-the-scenes. At least while people get used to a new graphical approach.You’re just saying you have a workflow powered by shell environments, which is lost in Terminal Click. As this emulator matures, a lot of the visual-interaction experiments will make up for that loss.
What does that mean? I can’t think of a single computer that I’ve used in the last 20 years (*NIX or Windows) where my PATH environment variable has not included some non-standard things, though some of them came from places like Homebrew. Looking at the path on this machine, I have:
Which of these are obvious to you?
I had to submit a patch for a large FOSS project recently because their “obvious places” did not include the places my binaries actually lived.
If I may fork the thread…
It’s a fascinating project.
So is Lash#Cat9, part of the Arcan project. I wrote about it myself. Author Bjorn @crazyloglad Stahl is on Lobsters.
I wondered if you’d seen that, or considered working with him? I see considerable overlap between your projects.
Anything interesting can eventually be tunneled over other protocols so you can have your fancy terminal remotely. If I can use VS Code remotely, surely I can use Terminal Click remotely too.
Limiting yourself to existing terminal protocols is hopelessly limiting (and in my opinion, short-sighted).
Yes indeed. I can see a future with remote support.
I think even modern PowerShell supports this via runspaces now. You don’t have to mess with the background job if you just want to kick it off as a sanity check.
I’m not sure how async commands would be sanely implemented by default with the wide variety of behaviors CLIs implement. Would it get something akin to a div and do a scrolling render in a fixed space? Would it just pummel stdout instead? Hard to say what is correct there.
& is horrible ux — it outputs tons of stuff on stdout completely messing up my further work, and I can’t even kill it easily.
There’s one fairly obvious option:
I’m not sure how obvious this is, or how it differs from using
tmux
or another multiplexer.Like, in this system, how do you provide input if
cargo build
wants it? How do you accesscargo build
‘s return code? How do you send it a kill signal? Ifcargo build
finishes and you want to re-run it under sudo, or with modified options, how do you navigate between history of the async shell vs history of where you’re runninggit commit
? Ifgit commit
produces a lot of output, or opens an editor, how does that affectcargo build
’s stdin/stdout? Does the top pane scroll separately from the bottom?I think you need clear, predictable answers to all these questions and a thousand more. That’s what a multiplexer gives you. My expectation is you’d be well-served by a little wrapper script that takes a command and executes it inside a new tmux pane.
This calls to mind MUD clients, which was probably one of the most extreme situations of needing to compose text input among a sea of output. Makes perfect sense to apply it to general-purpose terminals too.
If you’re using a windowing system, perhaps opening another window in the same directory would completely solve your problem.
And I guess
Enter
if I want to spawn such “asynchronous” command (the default) andctrl+Enter
if I want to spawn a synchronous, interactive command and focus on its stdin.I want this for a REPL. It would be very cool if you could build clients and servers iteratively from within the same REPL by switching between them. I thought this might be doable from Erlang/Elixir if you could create tab in the REPL per BEAM process. (Well, not literally per process, but per process that you want to interact with separately.)
I have to admit that I was a bit underwhelmed by the features. There was nothing that I found myself thinking “I need this”. I think that emacs is already the best option for a cross platform text-based computing environment. It can do pretty much everything shown and a lot more.
I would be happy to see more projects that were emacs-like in spirit, but were more accessible and had some modern appeal.
Kudos to the author for attempting to improve the terminal. Closed + only Linux/macOS/Windows means I can’t try it out for now (on NetBSD). The output reuse bit is not clear: is it a named reference to a chunk of (output) text? can I
cat file
and edit the resulting output and put it back? CLIM style presentation objects would enable those things. Emacs’s eshell lets you output to named buffers and you can edit from there for example. 9term has the “hold mode” which buffers input allowing you to edit normally before sending the content to the program. You can also freely edit any text, select and “Send”. And then there is the plumber to dispatch selections based on a rule set. The calculator example could be a rule matching expressions and sending the string tobc
. Oberon and Acme also break up the linear flow of text into tiled viewers offering a flexible user environment: Oberon with a full language + module system and Acme with existing commands/programs and 9p.I’m always interested in innovation in the terminal space. My latest experiment has been using a Jupyter notebook instead of the shell for some kinds of tasks. My favorite of your two features were the file explorer with an editable path, and enhanced history. Kakoune has a plugin for find file with fzf, so I wonder if I could put together a fzf over the directory tree and cd into that.
I didn’t find very many of the motivating use cases very motivating, your presentation was off-putting, and you missed the primary reason IMO why people are still using terminals. If you use tmux, that handles a couple of these features, eg. output re-use, saving output to files, and searching for output (not quite the same as grep if you are doing a batch). Even if it’s not as good, the gap being smaller de-motivates a big shift. For a calculator, I can use a different shell like xonsh, or I can pull up a python terminal. No big changes needed. Finally, what you describe as the brain of the terminal emulator just sounds like putting a shell into the emulator in a way that isn’t composable or customizable. Minor note, the hyperbolic presentation “insane and powerful” feels off-putting both for its hubris, and because it feels dismissive of people’s choices about their workflow.
You’ll note that I am defaulting to inertia here. That’s because the primary reason, IMO, people are still using terminals and shells is because of the ecosystem around them. You get to access to a wealth of documentation and community around the status quo, and people build things on that. Abandoning the ecosystem requires strong justification with improvements beyond the incremental.
Yes, the level of innovation shown does not justify the level of hyperbole used to describe it, and not acknowledging terminal multiplexers like
tmux
orzellij
cut even deeper into their credibility. Not to mention even without a multiplexer that gives you access to the buffer, some existing terminals have nice bindings for searching history, clicking links, etc.Closed source and public beta not expected until 2024. This feel a lot like the
fig
announcement from a while back. Hello hype train. And goodbye to hacking your own tools.This is very cool! While I understand the solutions presented are objectively simpler than what exists today, I’ve got a lot of muscle memory tied to the way it works today. That makes me fast, so I don’t know that I’d need to switch.
That said, it will certainly help people without that familiarity. Plus, I always welcome re-examining “the way we’ve always done it”.