[RFC] ColorD

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Oct 26 10:49:56 PDT 2012


On Fri, Oct 26, 2012 at 10:06:38AM +0200, Jens Mueller wrote:
> H. S. Teoh wrote:
> > On Fri, Oct 26, 2012 at 12:27:38AM +0200, Jens Mueller wrote:
> > > Walter Bright wrote:
> > [...]
[...]
> > > > 1. getting mouse input
> > > 
> > > Anybody an idea how to this on Linux?
> > 
> > You can only do this in terminals that support it. XTerm, I believe,
> > has escape sequences that you can send to turn on mouse tracking.
> > Those will show up as special escape sequences on stdin, which will
> > have to be intercepted and removed from the program's normal input
> > stream. Other modern terminals probably have their own way of doing
> > mouse tracking.  AFAIK, there isn't any standard for this, so you'll
> > have to stick with terminal-specific code.
> > 
> > (Which is why I recommended earlier that this module must be modular
> > so that support for specific terminals can be plugged in easily --
> > for the initial stab, something very simple such as vt100 support
> > may be good enough, as long as it's easy to add support for new
> > terminals.)
> 
> So there exists no portable library abstracting mouse input?  If
> that's the case then being modular is the only option. How would you
> design it? I don't plan to implement this. But leaving the door open
> for others should be possible.

Hmm. I googled around a bit, and found that the only portable libraries
for abstracting terminal capabilities appear to be curses and its
derivatives like ncurses.  So if we're going to reengineer a D console
library that doesn't depend on ncurses, we'll have to get our hands
dirty with interpreting $TERM and parsing terminal capabilities. :-(

As for design, I think a very simple and easily extensible design would
be something along these lines:

Have a generic Terminal base class that contains all the API functions
for various terminal capabilities, like interacting with the mouse,
setting color, moving the cursor, etc. These functions are stubbed to
throw an UnsupportedTerminalCapability (or something like that)
exception when they are called. Then each supported terminal type will
derive from Terminal, and override those functions that are supported
for that terminal type. The module initialization code will determine at
runtime which of these subclasses to instantiate.

Then build an additional layer on top, with higher-level API functions
that eventually call the object's methods to perform various terminal
functions (e.g., writeln can be extended to support color by
interpreting color escape sequences that ultimately result in calling
some underlying method in Terminal).

When the module is extended to handle new capabilities, we just add new
methods to Terminal, stubbed to throw UnsupportedTerminalCapability.
When we add support for new terminal types, we just create a new
subclass of Terminal that implements the new methods.

I think for maintainability, Terminal should not be directly accessed by
the user, so that its methods can be kept concise and at the correct
abstraction level for interacting with low-level terminal functions. The
module should provide a higher-level API with underlying calls to these
functions, say by extending writeln, implementing screen buffering,
etc..


[...]
> > > > 7. getting no-echo raw input
> > > 
> > > Tried this but couldn't make it work yet. This is useful for
> > > passwords prompts, right?
> > 
> > Not just that, but also for fully-interactive programs that want to
> > capture every keystroke immediately (instead of waiting for the user
> > to hit Enter). Like games and stuff. Or menu-driven systems where
> > the user can navigate between menus and items without needing to hit
> > Enter each time.
> > 
> > For Unix terminals, you need to send certain escape sequences
> > (specific to the terminal) to enable what is called 'raw' mode or
> > 'cbreak' mode.  (Googling for 'cbreak' should give you useful
> > references.) This will cause the terminal to immediately transmit
> > keystrokes, instead of buffering them until the user hits Enter.
> > 
> > Also, make sure that there is a way to turn off this mode after the
> > program is finished, otherwise the terminal may become unusable when
> > it returns to the shell prompt. :)
> 
> Thanks for the pointers.
> So these are then two things. First noecho and the other one is raw
> input.

Yeah, noecho is useful for password input; raw input is needed for
interactive apps like games or menu-driven programs. Both should be
supported.


[...]
> > The important stuff are cursor positioning, box drawing, incremental
> > updates, cbreak mode, etc..
> 
> Can you say something about incremental updates? Any pointers?
[...]

The idea behind incremental updates is this: if I write a string
"ABCDEF" at position (10,10), then I write "ABDCEF" at the same
position, the console library should know to only replace "CD" with "DC"
the second time round, instead of redrawing the entire string. Or, on
larger scale, if my app draws an almost-identical copy of the current
screen, the library should know to only redraw the "diff" between the
previous state of the screen and the new one.

This is commonly implemented by buffering the current state of the
screen in the library, and marking parts of the buffer "dirty" when they
are changed. Then when there is a pause (say the app is waiting for
input) or the screen needs to scroll, etc., the library updates only the
parts of the screen that correspond with the "dirty" buffers, and clears
the dirty flag.

The basic motivation is that the terminal may be connected to a remote
machine via a slow or congested network, so it's faster to keep track of
things locally and only send "diffs" to the remote end. Waiting for a
pause also allows you to group several updates into a single network
packet, instead of sending one packet per character, which is very slow.

(Even if the terminal is local, it can be faster to do things this way,
because it minimizes writes to video RAM, which is slower than writing
to main memory. Or in the case of X11 terminal emulators, it saves the
cost of redrawing the same pixels over and over.)


T

-- 
People demand freedom of speech to make up for the freedom of thought
which they avoid. -- Soren Aabye Kierkegaard (1813-1855)


More information about the Digitalmars-d mailing list