Adam's terminal suite explained
Posted 2020-01-27
Blog
Articles- String interpolation DIP prototype
- terminal inline syntax highlighting, sdpy fonts improved
- January 18, 2021
- gdb debugging tips
- A little work on sdpy/terminal interop and apng debugging
- New plain tcp fiber socket class (with "how it works" docs), new arsd docs started, new dub subpackages in arsd. Also Turkish newsgroups added to forum.dlang.org
- Little audio player in D
- Thoughts on tutorial writing benefits, D marketing, and some simpledisplay.d improvements.
- arsd 9.0 rollup release, my thoughts on "google it" culture and related practices
- dpldocs.info cross-package search finally released! and more terminal getline enhancements
- I did a dconf livestream!
- New selective mouse input in terminal stack, Xft used in simpledisplay to improve TrueType font support
- simpleaudio now has playOgg, Mp3, Wav with resampling and can access multiple soundcards on Linux, adrdox gets ddoc on function params
- Weekend experiment: declarative GUI in D
- October 26, 2020
- My DConf livestream sneak preview
- Off topic jrpg video game review
- My thoughts on breakage, and I'll be in DConf Online 2020
- cgi.d hybrid server basically working, terminal.d can redirect stdout to a window if requested
- Some talk on cgi.d in benchmarks
- September 14, 2020
- New D update "dwidder" website launched, making-of post here
- white noise app in D
- More modern opengl in simpledisplay, document undocumented on dpldocs.info, tip on default template args
- Xlib taskbar in D
- D Tetris running on Webassembly
- Tetris in D
- Zero-runtime classes
- DConf online in the works for Nov 21-22, image copy/paste coming to sdpy soon
- July 13, 2020
- July 6, 2020
- simpledisplay getting dynamic loads, terminal gui gracefully degrades, i muse on scope raii classes
- Adam's dynamic link transition
- June 15, 2020
- June 8, 2020
- June 1, 2020
- foot pedal and midi fun, some dmd speed enhancements. Forum argues about @safe by default on extern.
- May 18, 2020
- simpleaudio dev work, rasp pi gpio module, static foreach rant, gcc 10's D support upped
- May 4, 2020
- my http more compatible with ssl, script+jsvar can do subclasses of D objects
- i want to make a jrpg, and have eye damage.
- Dustmite post on official blog
- What if I were dictator?
- March 30, 2020
- terminal.d with built-in emulator option releaed
- Online DConf in the works
- Dconf 2020 cancelled, Adam plays with terminal gui integration
- March 2, 2020
- some adrdox/dpldocsinfo updates
- terminal.d gets clipboard functions, ldc 1.20 out.
- DConf keynote speaker announced: Lua architect Roberto Ierusalimschy, Named args DIP discussed
- February 3, 2020
- Adam's terminal suite explained
- Understanding mixin templates, terminal.d improvements
- My attribute-by-default proposal. Also dmd 2.090 came out.
- DConf 2020 announced: June 17-20 in London. @safe by default debated. Adam did: Android, JNI, WebSocket in arsd libs
- tar.xz, --DRT tip, dom bug fixes, more Android and JNI, link to old phobos docs
- LDC 1.19 - Android, AVR. My rant on tests, update on JNI and COM.
- Walter's string interpolation proposal is OK but not great. My Android thing nearing beta release. dub downtime explained.
- Android project update, introduction to arsd.jni
- New pattern about interface contracts
- Adam shares Windows console secrets - DO NOT USE chcp!!
- Adam's rant on benchmarks
- Socket tutorial
- November 4, 2019
- October 28, 2019
- arsd package updates, forum nonsense
- Update on Android
- Adam does iOS "goodbye world"
- September 30, 2019
- D turns 20, Adam rants on software freedom
- Named arg DIPs and my thoughts on code organization
- September 9, 2019
- I wrote about mixin templates vs string mixins on Stack Overflow
- August 26, 2019
- Bug bounty in D again - my hot take, on reusing code, a fun picture, my tentative plan for the next month
- Time invested is worth a lot
- cgi.d's new scheduler, static this tricks
- July 29, 2019
- July 22, 2019
- Solving vs managing problems
- A big week in the arsd repo
- July 1, 2019
- June 24, 2019
- June 17, 2019
- CRTP thoughts, named arguments DIP review, DConf videos now on youtube
- musings on hybrid CT/RT tests, some more progress on new web framework
- a little more webassembly
- May 20, 2019
- Adam's string interpolation proposal
- DMD 2.086 live, GCC 9 with D support formally released, DConf coming soon, links to posts on builder pattern and disallowing implicit conversions with templates, and 2d array op overloads
- template constraint error improvements coming?
- dmd 2.086 beta, dstep 1.0 released, Adam works on memory usage
- obj-c and webassembly report, tips on is expressions linked.
- new ldc, new dmd, dpp on the blog
- D's future discussed in forums
- LDC beta, DConf blog link, Adam introduces gamehelpers.d
- March 18, 2019
- LDC 1.15.0-beta1, responsive design rant
- dmd 2.085.0 released
- Obj-C interop and D without druntime code to copy/paste
- dmd beta, more info coming next time, demo of new web framework initial prototype
- automatic web interface discussion, reflection tips and tricks
- Adam busy with weather and a move, lots of community announcements
- January 28, 2019
- Working on official blog 2018 retro, C++ new wrapped, dmd reading zips?
- dmd obj-c growing, Adam static foreaches an interface to RPC
- dmd 2.084, hope for future, but busy non-D week for me
- IDE tools released, my cgi.d gets new features
- DConf announced, tip, Adam rants: mouse trap
- This Week in D is back!
Core D Development Statistics
In the community
Community announcements
See more at the announce forum.
What Adam is working on
I finally put my terminal emulator (that I started seven years ago! and have been using for myself for the majority of that time) up on the dub repo.
http://code.dlang.org/packages/adr-terminalemulator
And meanwhile did some updates to my terminal.d library. Let me describe what they all are:
terminal.d
terminal.d is my library file for applications that run inside a terminal (e.g. xterm, rxvt, konsole, putty, the linux console, etc.) or the Windows console. It provides input events (key pressed, mouse clicked, window resized, etc.), high-level functions (getline, tab completion, etc.), and output functions (write text, move cursor, change color, etc.). It aims for broad compatibility with user interfaces, meeting the user where they are.
terminalemulator.d
terminalemulator.d is a library file that emulates a terminal in code. This means it takes the raw bytes a program would write to a terminal and maintains internal state. It offers abstract functions you can implement in order to display this state to the user, and functions you can call to translate user input into the raw bytes a terminal would send back to an application.
Like with most my library modules, it has very few dependencies: only the color.d module from my arsd repo. Otherwise, it stands alone in its most basic configuration, not even doing I/O itself.
It also has a mixin template for use by the frontends. This mixin template provides a few middleware adapters - forkpty for Posix systems interacting with normal programs that run in the terminal, CreatePseudoConsole for Windows 10 systems interacting with Windows console programs, libssh2 for interacting with remote systems, and a simple pipe driver for older local Windows programs.
These all help implement the frontends.
main.d
main.d is the main frontend and provides a class that implements the terminalemulator.d abstract class via a GUI window. It uses my simpledisplay.d to provide this main window. When you interact with this window, it calls the appropriate methods in the terminal emulator and displays its screen in here.
It does fairly little - terminalemulator.d contains the bulk of the code. main.d also imports minigui.d to provide a debugging and details UI when you press ctrl+alt+f12, though I haven't put much in there yet.
dub run builds the main.d program, running this gui.
It currently works in Windows and Linux. When simpledisplay.d works on Mac again, it should work there too.
You can also dub run -c ssh-gui to build the ssh middleware on Windows or Linux, using libssh2 (the .lib for Windows is in my arsd repo on github). It will need the runtime dynamic library and you must use a ssh key from the command line to set it up.
nestedterminalemulator.d
nestedterminalemulator.d is a frontend implementation built on terminal.d, running the custom emulator inside an existing terminal.
I don't maintain it as well, since it is mostly a proof-of-concept or debugging aid to me. It should work on any OS when it is updated.
detachable.d and attach.d
detachable.d and attach.d are separate components, but intricately tied together. It takes the idea of nestedterminalemulator but turns it into something very useful: a grouping of terminals running inside another terminal.
If you have used GNU screen before, you know the use case for this. You can make a session grouping various terminals together for a particular task, and then detach and reconnect to them as needed, including across network connections, picking up exactly where you left off.
detachable.d runs an instance of terminalemulator.d in memory, with a command wrapper interface for talking to attach.d. When a frontend detaches from it (including closing a terminal window that hosts it, or a network disconnect), it simply keeps living in the background, waiting for a new frontend to reattach. It can be compiled and run separately for debugging, but is typically embedded inside attach.d's program.
attach.d is a terminal.d based frontend that can display, manage, and communicate with detachable instances. If you've used screen, dtach, or tmux, you'll probably be able to use this easily; it works similarly.
You can run this with dub run -c attach -- your_session_name.
These only work on Posix at this time, since it communicates between detachable and attach via a unix socket, using unix functions, and spawning the new process with fork(). There's no technical reason why it wouldn't work on Windows via a named pipe and CreateProcess either, I just haven't implemented it since I personally entirely use the detachable sessions on my Linux box and connect to them from Windows.
Why?!
The question on your mind is why? What's the benefit of my custom implementation instead of using any one of the myriad existing options?
Well, it mostly came down to two little things for me: adaptive color palettes and shift+page up just working via ssh attached sessions. I did a few other things too, like long text wrapping, spammed output management, and even inline images, but those two were the things I really wanted and found kinda painful to work into the other options I had.
Then xterm broke on my computer, giving me the final impetus to go all the way and switch fully over.
Full screen apps scrolling
I used to be a heavy GNU screen user, but one thing that bothered me is the shift+page up key combination doesn't work there. It is instead captured by the outermost window which is totally useless with a screen session inside.
So what I do is if an application requests the alternate screen (my terminal.d calls this Terminal(ConsoleOutputMode.cellular); what most full-screen terminal programs do), it also gets additional user input.
The keystrokes for shift+page up/down, shift+arrows, scroll lock, and others all just get sent as the same keystroke pattern as other keys. This lets the next layer handle it instead.
So these keystrokes are actually handled in behavior inside terminalemulator.d rather than in the frontends, who just need to tell the parent class what the user pressed.
It also means a user program could hook these to do their own thing... so long as they are OK with them not working on anyone else's terminal since they will never generate the necessary input sequences.
Palettes
It really bothered me to have blue text on black background and yellow text on white background. There's some color palette combinations that make this less awful, but what I really wanted was the colors to actually change based on background.
If you tell my terminal emulator to print blue on black, it will use a lighter blue than if you tell it to do blue on white. And similar with other various combinations. I reserve the right to change these colors and combinations at any time for myself, and with my own code, it is easy to do. All based on what is more readable to me. You might not even notice this when using the program, but you probably have noticed pain in other terminal emulators trying to read certain things.
Not straining my eyes is worth a lot to me; I spend a *lot* of time looking at my terminals.
Clipboard
My emulator implements the clipboard sequences xterm defines but generally compiles out for security purposes (so you don't ssh into a box and have it steal your clipboard data without your knowledge). But since I only use it for systems I trust and control I like it.
The value in such a feature for me is that I can copy and paste into attached sessions from Windows on ssh - something I do frequently. With existing things, data tends to get mangled if I try to take it across that boundary.
Window icons and taskbar notifications
Another minor feature that I find remarkably useful thanks to how much I use this is that my terminal emulator can change the window icon that appears on the taskbar. The utility.d function shows the sequence to do it, and the attach.d session file can specify an icon and unique title for that session, which it will display in the taskbar.
Each item in that taskbar is the same program, attach running inside my terminal emulator, but each is also recognizable at a glance. These icons also display in the Windows taskbar when I attach to it remotely through ssh - another benefit of me controlling both the gui terminal emulator (on *both* systems I use!) and the attached session inside.
Similarly, a program running inside a session can request attention from the user and that will be indicated in the taskbar via the appropriate GUI mechanism. An ascii bell output in a background terminal in attach will also trigger that behavior.
A few others
I also make it possible to process shift+enter with my emulator as well as other little things, but I don't use most of those yet. The majority of my enhancements are compatible with existing programs as much as possible, but responding to those key combinations require the client program to understand them.
My terminal.d library does support them, meaning you can get my special features when using my emulator (again, down the entire stack of attached and nested instances) and gracefully degrade on other systems.
And, of course, since I own 100% of the code, I can do whatever else I want too :) The big challenge is doing so in a way compatible with other things, but I've found many ways to make it work, some being compatible sequences and some being feature detection and runtime (I'm working on getting this all the way into terminal.d so it just works for others too).
Performance
I don't think throughput is important. You can't read text flying by at 60 fps anyway, and a terminal is meant to be a human interface device. So instead of even trying, I batch the data and display it differently in chunks. This also saves bandwidth and maintains ctrl+c capabilities on ssh.
The latency is good enough to me.
Inline images
You can write out images (via the utility.d helper) too, which adds them to the scrollable output. I find this is rarely useful but it is very nice to have when I do - again mostly over ssh when displaying an image can be very slow through X.
Horizontal scrolling
Press scroll lock in the terminal. Then press the arrow keys to scroll in all four directions. This helps me read exceedingly long lines like database table output.
Rejected features
I actually implemented 24 bit color, but I found it was not only utterly useless, but actually counterproductive. The simple implementation in terminalemulator.d used an awful lot of memory (2x as much!) with 24 bit color enabled than with it disabled... and it complicated the adaptive palette code to keep combinations legible, so I removed it. (Much of the code is still there under a version(with_24_bit_color) if you want to try playing with it anyway.)
It still recognizes the 24 bit color codes from the terminal applications though, it just rounds them off to a 256 color palette instead. Heck, sometimes I think I should further round it off to 16 colors! (That's what terminal.d does on Windows console btw, since that system has only 16 colors, so it gracefully degrades client applications.)
I also didn't do any built-in tabs, since attach.d makes its own inline tabs anyway.
In general, I just try to remember that a terminal is meant to be used by people to interact with computers via text. So anything that doesn't work toward this goal is not important to me.
Future directions
I want to expand some more things - like that ctrl+shift+f12 debug window - and maybe do some other radical things, but this moves very slowly. I'm generally happy with it as it is and use it very heavily... while simultaneously thinking Linux terminals are trash from top to bottom and we should just do gui programs instead. So I love to hate it lol.
I may also offer a dub subconfiguration so your terminal.d program will automatically spawn a custom window, so you write your program as if it is a terminal target yet it is actually a gui target. But right now I am focused on the progressive enhancement and graceful degradation angles for compatibility with existing terminals and programs as my first priority.