support for using default colors (sort of)

This commit is contained in:
Adam D. Ruppe 2013-10-04 15:39:01 -04:00
parent 05172d7d91
commit 25906483bd
1 changed files with 132 additions and 17 deletions

View File

@ -16,7 +16,7 @@
*/ */
module terminal; module terminal;
// FIXME: SIGWINCH // FIXME: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx
version(linux) version(linux)
enum SIGWINCH = 28; // FIXME: confirm this is correct on other posix enum SIGWINCH = 28; // FIXME: confirm this is correct on other posix
@ -24,13 +24,25 @@ version(linux)
version(Posix) { version(Posix) {
__gshared bool windowSizeChanged = false; __gshared bool windowSizeChanged = false;
__gshared bool interrupted = false; __gshared bool interrupted = false;
version(with_eventloop)
struct SignalFired {}
extern(C) extern(C)
void sizeSignalHandler(int sigNumber) { void sizeSignalHandler(int sigNumber) {
windowSizeChanged = true; windowSizeChanged = true;
version(with_eventloop) {
import arsd.eventloop;
send(SignalFired());
}
} }
extern(C) extern(C)
void interruptSignalHandler(int sigNumber) { void interruptSignalHandler(int sigNumber) {
interrupted = true; interrupted = true;
version(with_eventloop) {
import arsd.eventloop;
send(SignalFired());
}
} }
} }
@ -228,7 +240,8 @@ enum Color : ushort {
blue = BLUE_BIT, /// . blue = BLUE_BIT, /// .
magenta = red | blue, /// . magenta = red | blue, /// .
cyan = blue | green, /// . cyan = blue | green, /// .
white = red | green | blue /// . white = red | green | blue, /// .
DEFAULT = 256,
} }
/// When capturing input, what events are you interested in? /// When capturing input, what events are you interested in?
@ -568,6 +581,23 @@ struct Terminal {
/// ditto /// ditto
this(ConsoleOutputType type) { this(ConsoleOutputType type) {
hConsole = GetStdHandle(STD_OUTPUT_HANDLE); hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if(type == ConsoleOutputType.cellular) {
/*
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686125%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683193%28v=vs.85%29.aspx
*/
COORD size;
/*
CONSOLE_SCREEN_BUFFER_INFO sbi;
GetConsoleScreenBufferInfo(hConsole, &sbi);
size.X = cast(short) GetSystemMetrics(SM_CXMIN);
size.Y = cast(short) GetSystemMetrics(SM_CYMIN);
*/
size.X = 80;
size.Y = 24;
SetConsoleScreenBufferSize(hConsole, size);
moveTo(0, 0, ForceOption.alwaysSend); // we need to know where the cursor is for some features to work, and moving it is easier than querying it
}
} }
version(Posix) version(Posix)
@ -579,8 +609,13 @@ struct Terminal {
flush(); flush();
} }
int _currentForeground = Color.black; // FIXME: this isn't necessarily right version(Windows)
int _currentBackground = Color.white; ~this() {
showCursor();
}
int _currentForeground = Color.DEFAULT;
int _currentBackground = Color.DEFAULT;
/// Changes the current color. See enum Color for the values. /// Changes the current color. See enum Color for the values.
void color(int foreground, int background, ForceOption force = ForceOption.automatic) { void color(int foreground, int background, ForceOption force = ForceOption.automatic) {
@ -592,11 +627,20 @@ struct Terminal {
background ^= LowContrast; background ^= LowContrast;
*/ */
ushort setTof = cast(ushort) foreground;
ushort setTob = cast(ushort) background;
// this isn't necessarily right but meh
if(background == Color.DEFAULT)
setTob = Color.black;
if(foreground == Color.DEFAULT)
setTof = Color.white;
// FIXME: is this if good? // FIXME: is this if good?
//if(force == ForceOption.alwaysSend || foreground != _currentForeground || background != _currentBackground) { //if(force == ForceOption.alwaysSend || foreground != _currentForeground || background != _currentBackground) {
SetConsoleTextAttribute( SetConsoleTextAttribute(
GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_OUTPUT_HANDLE),
cast(ushort)((background << 4) | foreground)); cast(ushort)((setTob << 4) | setTof));
} else { } else {
import std.process; import std.process;
// I started using this envvar for my text editor, but now use it elsewhere too // I started using this envvar for my text editor, but now use it elsewhere too
@ -610,13 +654,21 @@ struct Terminal {
} }
*/ */
ushort setTof = cast(ushort) foreground & ~Bright;
ushort setTob = cast(ushort) background & ~Bright;
if(foreground == Color.DEFAULT)
setTof = 9; // ansi sequence for reset
if(background == Color.DEFAULT)
setTob = 9;
import std.string; import std.string;
if(force == ForceOption.alwaysSend || foreground != _currentForeground || background != _currentBackground) { if(force == ForceOption.alwaysSend || foreground != _currentForeground || background != _currentBackground) {
writeStringRaw(format("\033[%dm\033[3%dm\033[4%dm", writeStringRaw(format("\033[%dm\033[3%dm\033[4%dm",
(foreground & Bright) ? 1 : 0, (foreground != Color.DEFAULT && (foreground & Bright)) ? 1 : 0,
cast(int) foreground & ~Bright, cast(int) setTof,
cast(int) background & ~Bright)); cast(int) setTob));
} }
} }
} }
@ -665,6 +717,31 @@ struct Terminal {
_cursorY = y; _cursorY = y;
} }
/// shows the cursor
void showCursor() {
version(Posix)
doTermcap("ve");
else {
CONSOLE_CURSOR_INFO info;
GetConsoleCursorInfo(hConsole, &info);
info.bVisible = true;
SetConsoleCursorInfo(hConsole, &info);
}
}
/// hides the cursor
void hideCursor() {
version(Posix)
doTermcap("vi");
else {
CONSOLE_CURSOR_INFO info;
GetConsoleCursorInfo(hConsole, &info);
info.bVisible = false;
SetConsoleCursorInfo(hConsole, &info);
}
}
/* /*
// alas this doesn't work due to a bunch of delegate context pointer and postblit problems // alas this doesn't work due to a bunch of delegate context pointer and postblit problems
// instead of using: auto input = terminal.captureInput(flags) // instead of using: auto input = terminal.captureInput(flags)
@ -1023,6 +1100,9 @@ struct RealTimeConsoleInput {
auto listenTo = this.fd; auto listenTo = this.fd;
else static assert(0, "idk about this OS"); else static assert(0, "idk about this OS");
version(Posix)
addListener(&signalFired);
addFileEventListeners(listenTo, &eventListener, null, null); addFileEventListeners(listenTo, &eventListener, null, null);
destructor ~= { removeFileEventListeners(listenTo); }; destructor ~= { removeFileEventListeners(listenTo); };
addOnIdle(&terminal.flush); addOnIdle(&terminal.flush);
@ -1031,6 +1111,16 @@ struct RealTimeConsoleInput {
} }
version(with_eventloop) { version(with_eventloop) {
version(Posix)
void signalFired(SignalFired) {
if(interrupted) {
interrupted = false;
send(InputEvent(UserInterruptionEvent()));
}
if(windowSizeChanged)
send(checkWindowSizeChanged());
}
import arsd.eventloop; import arsd.eventloop;
void eventListener(OsFileHandle fd) { void eventListener(OsFileHandle fd) {
auto queue = readNextEvents(); auto queue = readNextEvents();
@ -1145,6 +1235,16 @@ struct RealTimeConsoleInput {
return decode(buffer, throwAway); return decode(buffer, throwAway);
} }
InputEvent checkWindowSizeChanged() {
auto oldWidth = terminal.width;
auto oldHeight = terminal.height;
terminal.updateSize();
version(Posix)
windowSizeChanged = false;
return InputEvent(SizeChangedEvent(oldWidth, oldHeight, terminal.width, terminal.height));
}
// character event // character event
// non-character key event // non-character key event
// paste event // paste event
@ -1164,16 +1264,15 @@ struct RealTimeConsoleInput {
} }
wait_for_more: wait_for_more:
version(Posix)
if(interrupted) { if(interrupted) {
interrupted = false;
return InputEvent(UserInterruptionEvent()); return InputEvent(UserInterruptionEvent());
} }
version(Posix)
if(windowSizeChanged) { if(windowSizeChanged) {
auto oldWidth = terminal.width; return checkWindowSizeChanged();
auto oldHeight = terminal.height;
terminal.updateSize();
windowSizeChanged = false;
return InputEvent(SizeChangedEvent(oldWidth, oldHeight, terminal.width, terminal.height));
} }
auto more = readNextEvents(); auto more = readNextEvents();
@ -1237,9 +1336,15 @@ struct RealTimeConsoleInput {
e.character = cast(dchar) cast(wchar) ev.UnicodeChar; e.character = cast(dchar) cast(wchar) ev.UnicodeChar;
newEvents ~= InputEvent(e); newEvents ~= InputEvent(e);
} else { } else {
// FIXME actually translate
ne.key = cast(NonCharacterKeyEvent.Key) ev.wVirtualKeyCode; ne.key = cast(NonCharacterKeyEvent.Key) ev.wVirtualKeyCode;
newEvents ~= InputEvent(ne);
// FIXME: make this better. the goal is to make sure the key code is a valid enum member
// Windows sends more keys than Unix and we're doing lowest common denominator here
foreach(member; __traits(allMembers, NonCharacterKeyEvent.Key))
if(__traits(getMember, NonCharacterKeyEvent.Key, member) == ne.key) {
newEvents ~= InputEvent(ne);
break;
}
} }
break; break;
case MOUSE_EVENT: case MOUSE_EVENT:
@ -1267,13 +1372,18 @@ struct RealTimeConsoleInput {
else else
e.buttons = MouseEvent.Button.ScrollUp; e.buttons = MouseEvent.Button.ScrollUp;
break; break;
default:
} }
newEvents ~= InputEvent(e); newEvents ~= InputEvent(e);
break; break;
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:
auto ev = record.WindowBufferSizeEvent; auto ev = record.WindowBufferSizeEvent;
// FIXME auto oldWidth = terminal.width;
auto oldHeight = terminal.height;
terminal._width = ev.dwSize.X;
terminal._height = ev.dwSize.Y;
newEvents ~= InputEvent(SizeChangedEvent(oldWidth, oldHeight, terminal.width, terminal.height));
break; break;
// FIXME: can we catch ctrl+c here too? // FIXME: can we catch ctrl+c here too?
default: default:
@ -1695,9 +1805,10 @@ void main() {
auto terminal = Terminal(ConsoleOutputType.linear); auto terminal = Terminal(ConsoleOutputType.linear);
terminal.setTitle("Basic I/O"); terminal.setTitle("Basic I/O");
auto input = RealTimeConsoleInput(&terminal, ConsoleInputFlags.raw | ConsoleInputFlags.mouse | ConsoleInputFlags.paste | ConsoleInputFlags.size); auto input = RealTimeConsoleInput(&terminal, ConsoleInputFlags.raw | ConsoleInputFlags.allInputEvents);
terminal.color(Color.green | Bright, Color.black); terminal.color(Color.green | Bright, Color.black);
//terminal.color(Color.DEFAULT, Color.DEFAULT);
terminal.write("test some long string to see if it wraps or what because i dont really know what it is going to do so i just want to test i think it will wrap but gotta be sure lolololololololol"); terminal.write("test some long string to see if it wraps or what because i dont really know what it is going to do so i just want to test i think it will wrap but gotta be sure lolololololololol");
terminal.writefln("%d %d", terminal.cursorX, terminal.cursorY); terminal.writefln("%d %d", terminal.cursorX, terminal.cursorY);
@ -1712,6 +1823,10 @@ void main() {
final switch(event.type) { final switch(event.type) {
case InputEvent.Type.UserInterruptionEvent: case InputEvent.Type.UserInterruptionEvent:
timeToBreak = true; timeToBreak = true;
version(with_eventloop) {
import arsd.eventloop;
exit();
}
break; break;
case InputEvent.Type.SizeChangedEvent: case InputEvent.Type.SizeChangedEvent:
auto ev = event.get!(InputEvent.Type.SizeChangedEvent); auto ev = event.get!(InputEvent.Type.SizeChangedEvent);