I wrote a 2d esolang called asciidots inspired by ascii art and circuits, where “dots” follow ascii art paths and undergo operations. I posted it to Show HN a while back (2017!), where it ended up getting attention on HN and elsewhere.
Since then, I used Pyodide to make a home page with an interactive demo of the language. This let me use the existing Python reference implementation of asciidots in the browser, allowing exact feature parity (bugs and all) to support existing code. As a fun trick, I used a CSS animation for the logo instead of a GIF so it wouldn’t freeze while Pyodide is loading.
Nix is a package builder & manager that creates reproducible build environments. Using the Nix language, you specify what the build environment should look like ($PATH, what should be in the build folder, etc). Nix then calls a program of your choice to do the actual building.
Just like Nix lets you specify a build environment using the Nix language, NixOS lets you specify, using the Nix language, what you want your operating system to look like (systemd services, $PATH, etc).
You should be able to use Nix, the package builder & manager, on any POSIX system afaik.
> why am I expecting an error? Shouldn't that keyword be "on_exception" or something?
`expect` takes an input that is either an error or a value, then turns that input into just a value. The provided string is the error message if something goes wrong (i.e. the input was an error).
The way recoverable errors are signalled in Rust is through the return value, which is done using the `Result` enum. That enum is basically[0] defined like this:
enum Result<T, E> {
Ok(T),
Err(E),
}
Opening a file can, of course, fail for whatever reason, so `File::open` returns a `Result`. The `expect` method in that example is one defined on `Result` which takes that result and a message string, and if it's the `Ok` variant will return the value stored that variant. If its the `Err` variant it will print the input string and start an unrecoverable [1] panic, ending the program.
You would typically use `expect` (or `unwrap`, which does the same thing but without a custom message) when you either know for certain that it can't fail, or the failure condition is not something the program can recover from.
[1] Technically, you can catch a panic unwind [2], but it's more awkward and intended more for FFI boundaries than normal code. There's also no guarantee that the program will unwind. The compiler might have been set to abort on a panic instead of unwinding, in which case there's no unwind to catch.
My understanding is that i3 would intercept the keypress, not passing it onto the terminal. While I want 3mux to work with i3, I decided to choose defaults that appeal to the audience that would need 3mux most (i.e. non-i3 users). I plan to soon make the key bindings configurable.
I agree that non-i3 users need it the most, but have one use case in mind where you might want to combine i3wm + 3mux: remote work. If you ssh into a remote computer, you can not easily spawn new remote terminals. Having one terminal that runs ssh + 3mux lets you use i3wm-like keybindings inside the terminal to open remote splits and tabs with similar keybindings as you would locally. In particular, setting the i3wm $mod to super would make super+enter, super+hjkl, etc. act on local windows, while alt+enter, alt+hjkl, etc. act on remote windows. In a sense, ssh + 3mux would act as a "i3wm-style remote desktop".
If I understand correctly, 3mux does not have session management, but combining 3mux with abduco or dtach should solve that. (And arguably be a more Unix-philosphy solution.)
I think the best way to combine i3wm and 3mux would however be to change the i3wm $mod to win/super, instead of trying to use different modifiers in 3mux. As far as I know, no common terminals support other modifiers than ctrl and alt, and ctrl would collide with most terminal programs. (In tilish, I ended up offering a prefix key as an alternative to alt for people using Kakoune or Emacs.)
The biggest thing stored by 3mux should be the state of the terminal screen, so memory usage should be negligible.
> Can you (easily) nest 3mux like tmux with (auto-)grouped sessions to produce a (max) 9x9 "grid" of windows to organize your remote hosts, and their windows into an easily accessible structure. (I use this to be able to reach any window in any other terminal window on any host with max 4 keypresses)
This is an awfully specific request. However, I plan to soon add support for workspaces, which should give the user access to, for example, 40 panes within 2 keypresses, given a hypothetical 10 workspaces and 4 panes per workspace.
> Why choose Go? Just curious.
Good question! I chose Go for its go routines and channels. I somewhat wish I used Rust simply because of its elegance. 3mux's performance bottleneck right now is completely IO, so I don't think moving to Rust would make a noticeable difference to the end user apart from the installation process.
I described my workflow, because since I discovered automatically grouped sessions on TMUX, I'd never want to use a terminal multiplexer without that, or comparable functionality.
What I do:
* Open new terminal with a hot-key
* This terminal automatically joins my local (default) session group
* All windows in this session group are now available
* Most windows connect to remote TMUXs
* With CTRL+ 4 keypresses I can navigate to any preexisting window/session, or create a new one locally (or on a remote host)
* After using the window, either i close the terminal, and/or the window, depending on if i want to keep this one.
* On the remote end, people can join my sessions, and can independently of me navigate in the remote window space.
* if I need to concurrently see two (probably different) windows of my local/remote window grid, I just open/auto-attach another terminal.
* the above makes it easy to "place another live tmux view" on a screen different than my main screen, for presentation, or teaching purposes.
Everybody (who previously used tmux in non-grouped mode) I've shown/explained this setup to, has setup their environment just like it afterwards.
I'm a long-time user of i3 (now sway). I wrote this tool to provide the elegance of i3 to terminal users everywhere, especially for people like myself who sometimes use a non-i3 wm or no window manager at all (e.g. when testing code on a bare-bones raspberry pi).
In my experiments for a good multiplexer to go with nnn https://github.com/jarun/nnn, I have tried dvtm and tmux. dvtm is extremely light but it appears there's no way to open a new command in a new pane from within a session. This is where tmux trumped.
So if I want to open 2 panes, I run
dvtm n n # n is aliased to nnn + some program options
But if I want to open text/image files detached in a new pane, my custom opener calls:
tmux split-window -h "vim \"$*\""
Can 3mux do both for me?
- present a lightweight multiplexer
- support options to open split windows and run a command
Note: This is not necessarily i3-specific, please consider cross-DE/WM scenarios.
Looks awesome, thanks for sharing! I've been using Byoyu[0] which has a similar goal, but I'm keen on trying out. Even though I've been a long-time tmux user, as a developer I don't even know where I would start if I wanted to build my own terminal multiplexer. Can you share some resources etc on what could a good starting point if I want to explore this as a side-project?
My understanding is that a terminal multiplexer consists of three parts:
1. Managing shells and windows
2. Parsing the ECMA-35/ECMA-48 escape/control sequences
3. Rendering the shells' parsed output within their window boundaries
> Can you share some resources etc on what could a good starting point if I want to explore this as a side-project?
I have a somewhat different, layered, architecture with finer grained components. The terminal emulators, multiplexor, input method handler, and realizers are all separate processes, and the communication among them is via (memory-mapped) regular files and FIFOs.
It's more rigid in the multiplexing layer, with little notion of creating and destroying inner terminals on the fly and no notion of windows or panes, because it was initially created to be a user-space workalike for the kernel virtual terminals in Linux and FreeBSD, that are derived from SCO Multiscreen. So there's just the notion of a fixed set of virtual terminals, presented one at a time, with the Alt+function-key switching and a replacement chvt command.
It's more flexible in other ways, though. The components of the system are replaceable, and don't have to be put together in this particular way. There's no reason that one couldn't write another type of emulator, handling a completely different suite of escape and control sequences, and just plug it in alongside the existing one. And there's similar flexibility in the other layers: one can (and I do) simultaneously realize the same set of multiplexed terminals onto a remote terminal over an SSH connection as well as directly onto the local machine's framebuffer and keyboard(s). It could be realized onto X11, or (if someone finally documents the undocumented Mosh protocol) a Mosh client.
Indeed, there's no reason that a more complex multiplexing layer couldn't be substituted, providing something more like the screen/tmux paradigm, with the multiplexor starting up subordinate shell and terminal-emulator processes on the fly and compositing the lower screen buffers. But I didn't set out to reinvent screen/tmux. I set out to do virtual terminals in user-space instead of the kernel, with application mode code almost none of which (apart from the stuff that grants access to the framebuffer and keyboard devices) needs or runs with superuser privileges, and where the components are isolated even from one another.
See the StackExchange answer that I hyperlinked to for more on the actual terminal emulation part.
Since then, I used Pyodide to make a home page with an interactive demo of the language. This let me use the existing Python reference implementation of asciidots in the browser, allowing exact feature parity (bugs and all) to support existing code. As a fun trick, I used a CSS animation for the logo instead of a GIF so it wouldn’t freeze while Pyodide is loading.