From 0bb608b09ef35bfdd243c2db0c3cc60633260ecd Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sun, 25 Sep 2016 12:08:15 +0200 Subject: [PATCH] Support 8-bit/24-bit color and more escape codes in the graphical console. The console has gained these escape codes: - Set color to any of 256 entries in the palette. - Set color to any 24-bit RGB value. - Inverse mode. - Bold mode. - Underline mode. - Move cursor to line N. - \a is now ignored. The effectively unused ATTR_CHAR has been removed. Parsing of escape codes has been improved. The graphical palette has been changed to the tango colors, which makes Sortix look a bit differently. Some user-space programs have been changed to use different colors that look better under the new palette. Remove const from methods that weren't really const and remove mutable keyword workaround. --- kernel/include/sortix/kernel/textbuffer.h | 14 +- kernel/lfbtextbuffer.cpp | 33 +-- kernel/lfbtextbuffer.h | 1 - kernel/palette.h | 283 ++++++++++++++++++++++ kernel/textbuffer.cpp | 2 +- kernel/textterminal.cpp | 279 ++++++++++++++++----- kernel/textterminal.h | 25 +- kernel/vgatextbuffer.cpp | 4 +- sh/sh.c | 2 +- utils/ls.c | 16 +- 10 files changed, 560 insertions(+), 99 deletions(-) create mode 100644 kernel/palette.h diff --git a/kernel/include/sortix/kernel/textbuffer.h b/kernel/include/sortix/kernel/textbuffer.h index 7e8b2e9d..52c21328 100644 --- a/kernel/include/sortix/kernel/textbuffer.h +++ b/kernel/include/sortix/kernel/textbuffer.h @@ -30,7 +30,7 @@ namespace Sortix { -static const uint16_t ATTR_CHAR = 1 << 0; +static const uint16_t ATTR_INVERSE = 1 << 0; static const uint16_t ATTR_BOLD = 1 << 1; static const uint16_t ATTR_UNDERLINE = 1 << 2; @@ -47,19 +47,23 @@ struct TextCharPOD wchar_t c; uint8_t vgacolor; // Format of uint16_t attr; + uint32_t fg; + uint32_t bg; }; struct TextChar { TextChar() { } TextChar(const TextCharPOD& o) : - c(o.c), vgacolor(o.vgacolor), attr(o.attr) { } - TextChar(wchar_t c, uint8_t vgacolor, uint16_t attr) : - c(c), vgacolor(vgacolor), attr(attr) { } - operator TextCharPOD() { return TextCharPOD{c, vgacolor, attr}; } + c(o.c), vgacolor(o.vgacolor), attr(o.attr), fg(o.fg), bg(o.bg) { } + TextChar(wchar_t c, uint8_t vgacolor, uint16_t attr, uint32_t fg, uint32_t bg) : + c(c), vgacolor(vgacolor), attr(attr), fg(fg), bg(bg) { } + operator TextCharPOD() { return TextCharPOD{c, vgacolor, attr, fg, bg}; } wchar_t c; uint8_t vgacolor; // Format of uint16_t attr; + uint32_t fg; // 32-bit foreground color. + uint32_t bg; // 32-bit background color. }; static inline bool IsTextPosBeforeTextPos(const TextPos& a, const TextPos& b) diff --git a/kernel/lfbtextbuffer.cpp b/kernel/lfbtextbuffer.cpp index 3a1dc008..167e7a10 100644 --- a/kernel/lfbtextbuffer.cpp +++ b/kernel/lfbtextbuffer.cpp @@ -33,8 +33,20 @@ namespace Sortix { -static uint32_t ColorFromRGB(uint8_t r, uint8_t g, uint8_t b) +static uint32_t boldify(uint32_t color) { + int b = color >> 0 & 0xFF; + int g = color >> 8 & 0xFF; + int r = color >> 16 & 0xFF; + b += 63; + if ( 255 < b ) + b = 255; + g += 63; + if ( 255 < g ) + g = 255; + r += 63; + if ( 255 < r ) + r = 255; return (uint32_t) b << 0 | (uint32_t) g << 8 | (uint32_t) r << 16; } @@ -96,13 +108,6 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat, ret->font = font; memset(chars, 0, sizeof(chars[0]) * columns * rows); ret->chars = chars; - for ( size_t i = 0; i < 16UL; i++ ) - { - uint8_t r = i & 0b0100 ? (i & 0b1000 ? 255 : 191) : (i & 0b1000 ? 63 : 0); - uint8_t g = i & 0b0010 ? (i & 0b1000 ? 255 : 191) : (i & 0b1000 ? 63 : 0); - uint8_t b = i & 0b0001 ? (i & 0b1000 ? 255 : 191) : (i & 0b1000 ? 63 : 0); - ret->colors[i] = ColorFromRGB(r, g, b); - } ret->cursorenabled = true; ret->cursorpos = TextPos(0, 0); ret->emergency_state = false; @@ -216,12 +221,10 @@ void LFBTextBuffer::RenderChar(TextChar textchar, size_t posx, size_t posy) if ( VGA_FONT_WIDTH != 8UL ) return; bool drawcursor = cursorenabled && posx == cursorpos.x && posy == cursorpos.y; - uint8_t fgcoloridx = textchar.vgacolor >> 0 & 0x0F; + uint32_t fgcolor = textchar.fg; + uint32_t bgcolor = textchar.bg; if ( textchar.attr & ATTR_BOLD ) - fgcoloridx |= 0x08; - uint8_t bgcoloridx = textchar.vgacolor >> 4 & 0x0F; - uint32_t fgcolor = colors[fgcoloridx]; - uint32_t bgcolor = colors[bgcoloridx]; + fgcolor = boldify(fgcolor); int remap = VGA::MapWideToVGAFont(textchar.c); const uint8_t* charfont = VGA::GetCharacterFont(font, remap); size_t pixelyoff = rows * VGA_FONT_HEIGHT; @@ -408,7 +411,7 @@ TextChar LFBTextBuffer::GetChar(TextPos pos) ResumeRendering(); return ret; } - return {0, 0, 0}; + return {0, 0, 0, 0, 0}; } void LFBTextBuffer::SetChar(TextPos pos, TextChar c) @@ -781,7 +784,7 @@ void LFBTextBuffer::EmergencyReset() { // TODO: Reset everything here! - Fill(TextPos{0, 0}, TextPos{columns-1, rows-1}, TextChar{0, 0, 0}); + Fill(TextPos{0, 0}, TextPos{columns-1, rows-1}, TextChar{0, 0, 0, 0, 0}); SetCursorPos(TextPos{0, 0}); } diff --git a/kernel/lfbtextbuffer.h b/kernel/lfbtextbuffer.h index 49732ed5..d2953cf1 100644 --- a/kernel/lfbtextbuffer.h +++ b/kernel/lfbtextbuffer.h @@ -133,7 +133,6 @@ private: size_t pixelsx; size_t pixelsy; size_t scansize; - uint32_t colors[16UL]; uint32_t lfbformat; size_t bytes_per_pixel; bool cursorenabled; diff --git a/kernel/palette.h b/kernel/palette.h new file mode 100644 index 00000000..44c8f87e --- /dev/null +++ b/kernel/palette.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2016 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * palette.h + * Console color palette, matches the xterm palette with tango colors. + */ + +#ifndef PALETTE_H +#define PALETTE_H + +static const uint32_t palette[256] = +{ + 0x000000, + 0xcc0000, + 0x3e9a06, + 0xc4a000, + 0x3465a4, + 0x75507b, + 0x06989a, + 0xbfbfbf, + 0x555753, + 0xef2929, + 0x8ae234, + 0xfce94f, + 0x729fcf, + 0xad7fa8, + 0x34e2e2, + 0xffffff, + 0x000000, + 0x00005f, + 0x000087, + 0x0000af, + 0x0000d7, + 0x0000ff, + 0x005f00, + 0x005f5f, + 0x005f87, + 0x005faf, + 0x005fd7, + 0x005fff, + 0x008700, + 0x00875f, + 0x008787, + 0x0087af, + 0x0087d7, + 0x0087ff, + 0x00af00, + 0x00af5f, + 0x00af87, + 0x00afaf, + 0x00afd7, + 0x00afff, + 0x00d700, + 0x00d75f, + 0x00d787, + 0x00d7af, + 0x00d7d7, + 0x00d7ff, + 0x00ff00, + 0x00ff5f, + 0x00ff87, + 0x00ffaf, + 0x00ffd7, + 0x00ffff, + 0x5f0000, + 0x5f005f, + 0x5f0087, + 0x5f00af, + 0x5f00d7, + 0x5f00ff, + 0x5f5f00, + 0x5f5f5f, + 0x5f5f87, + 0x5f5faf, + 0x5f5fd7, + 0x5f5fff, + 0x5f8700, + 0x5f875f, + 0x5f8787, + 0x5f87af, + 0x5f87d7, + 0x5f87ff, + 0x5faf00, + 0x5faf5f, + 0x5faf87, + 0x5fafaf, + 0x5fafd7, + 0x5fafff, + 0x5fd700, + 0x5fd75f, + 0x5fd787, + 0x5fd7af, + 0x5fd7d7, + 0x5fd7ff, + 0x5fff00, + 0x5fff5f, + 0x5fff87, + 0x5fffaf, + 0x5fffd7, + 0x5fffff, + 0x870000, + 0x87005f, + 0x870087, + 0x8700af, + 0x8700d7, + 0x8700ff, + 0x875f00, + 0x875f5f, + 0x875f87, + 0x875faf, + 0x875fd7, + 0x875fff, + 0x878700, + 0x87875f, + 0x878787, + 0x8787af, + 0x8787d7, + 0x8787ff, + 0x87af00, + 0x87af5f, + 0x87af87, + 0x87afaf, + 0x87afd7, + 0x87afff, + 0x87d700, + 0x87d75f, + 0x87d787, + 0x87d7af, + 0x87d7d7, + 0x87d7ff, + 0x87ff00, + 0x87ff5f, + 0x87ff87, + 0x87ffaf, + 0x87ffd7, + 0x87ffff, + 0xaf0000, + 0xaf005f, + 0xaf0087, + 0xaf00af, + 0xaf00d7, + 0xaf00ff, + 0xaf5f00, + 0xaf5f5f, + 0xaf5f87, + 0xaf5faf, + 0xaf5fd7, + 0xaf5fff, + 0xaf8700, + 0xaf875f, + 0xaf8787, + 0xaf87af, + 0xaf87d7, + 0xaf87ff, + 0xafaf00, + 0xafaf5f, + 0xafaf87, + 0xafafaf, + 0xafafd7, + 0xafafff, + 0xafd700, + 0xafd75f, + 0xafd787, + 0xafd7af, + 0xafd7d7, + 0xafd7ff, + 0xafff00, + 0xafff5f, + 0xafff87, + 0xafffaf, + 0xafffd7, + 0xafffff, + 0xd70000, + 0xd7005f, + 0xd70087, + 0xd700af, + 0xd700d7, + 0xd700ff, + 0xd75f00, + 0xd75f5f, + 0xd75f87, + 0xd75faf, + 0xd75fd7, + 0xd75fff, + 0xd78700, + 0xd7875f, + 0xd78787, + 0xd787af, + 0xd787d7, + 0xd787ff, + 0xd7af00, + 0xd7af5f, + 0xd7af87, + 0xd7afaf, + 0xd7afd7, + 0xd7afff, + 0xd7d700, + 0xd7d75f, + 0xd7d787, + 0xd7d7af, + 0xd7d7d7, + 0xd7d7ff, + 0xd7ff00, + 0xd7ff5f, + 0xd7ff87, + 0xd7ffaf, + 0xd7ffd7, + 0xd7ffff, + 0xff0000, + 0xff005f, + 0xff0087, + 0xff00af, + 0xff00d7, + 0xff00ff, + 0xff5f00, + 0xff5f5f, + 0xff5f87, + 0xff5faf, + 0xff5fd7, + 0xff5fff, + 0xff8700, + 0xff875f, + 0xff8787, + 0xff87af, + 0xff87d7, + 0xff87ff, + 0xffaf00, + 0xffaf5f, + 0xffaf87, + 0xffafaf, + 0xffafd7, + 0xffafff, + 0xffd700, + 0xffd75f, + 0xffd787, + 0xffd7af, + 0xffd7d7, + 0xffd7ff, + 0xffff00, + 0xffff5f, + 0xffff87, + 0xffffaf, + 0xffffd7, + 0xffffff, + 0x080808, + 0x121212, + 0x1c1c1c, + 0x262626, + 0x303030, + 0x3a3a3a, + 0x444444, + 0x4e4e4e, + 0x585858, + 0x626262, + 0x6c6c6c, + 0x767676, + 0x808080, + 0x8a8a8a, + 0x949494, + 0x9e9e9e, + 0xa8a8a8, + 0xb2b2b2, + 0xbcbcbc, + 0xc6c6c6, + 0xd0d0d0, + 0xdadada, + 0xe4e4e4, + 0xeeeeee, +}; + +#endif diff --git a/kernel/textbuffer.cpp b/kernel/textbuffer.cpp index 729e99dd..b6a5c744 100644 --- a/kernel/textbuffer.cpp +++ b/kernel/textbuffer.cpp @@ -138,7 +138,7 @@ void TextBufferHandle::FinishReplace(TextBuffer* newtextbuf) size_t src_x = dst_x; TextPos src_pos{src_x, src_y}; TextPos dst_pos{dst_x, dst_y}; - TextChar tc{0, 0, 0}; + TextChar tc{0, 0, 0, 0, 0}; if ( src_x < src_width && src_y < src_height ) tc = textbuf->GetChar(src_pos); else if ( src_width && src_height ) diff --git a/kernel/textterminal.cpp b/kernel/textterminal.cpp index b5e36236..4006c440 100644 --- a/kernel/textterminal.cpp +++ b/kernel/textterminal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,11 +27,19 @@ #include #include +#include "palette.h" #include "textterminal.h" namespace Sortix { -static const uint16_t DEFAULT_COLOR = COLOR8_LIGHT_GREY | COLOR8_BLACK << 4; +static const uint16_t DEFAULT_VGACOLOR = COLOR8_LIGHT_GREY | COLOR8_BLACK << 4; +static const unsigned int DEFAULT_FOREGROUND = 7; +static const unsigned int DEFAULT_BACKGROUND = 0; + +static uint32_t ColorFromRGB(uint8_t r, uint8_t g, uint8_t b) +{ + return (uint32_t) b << 0 | (uint32_t) g << 8 | (uint32_t) r << 16; +} TextTerminal::TextTerminal(TextBufferHandle* textbufhandle) { @@ -47,15 +55,18 @@ TextTerminal::~TextTerminal() void TextTerminal::Reset() { + attr = 0; next_attr = 0; - vgacolor = DEFAULT_COLOR; + vgacolor = DEFAULT_VGACOLOR; + fgcolor = palette[DEFAULT_FOREGROUND]; + bgcolor = palette[DEFAULT_BACKGROUND]; column = line = 0; ansisavedposx = ansisavedposy = 0; ansimode = NONE; TextBuffer* textbuf = textbufhandle->Acquire(); TextPos fillfrom(0, 0); TextPos fillto(textbuf->Width()-1, textbuf->Height()-1); - TextChar fillwith(' ', vgacolor, 0); + TextChar fillwith(' ', vgacolor, 0, fgcolor, bgcolor); textbuf->Fill(fillfrom, fillto, fillwith); textbuf->SetCursorEnabled(true); UpdateCursor(textbuf); @@ -88,7 +99,7 @@ size_t TextTerminal::PrintRaw(const char* string, size_t stringlen) return stringlen; } -size_t TextTerminal::Width() const +size_t TextTerminal::Width() { ScopedLock lock(&termlock); TextBuffer* textbuf = textbufhandle->Acquire(); @@ -97,7 +108,7 @@ size_t TextTerminal::Width() const return width; } -size_t TextTerminal::Height() const +size_t TextTerminal::Height() { ScopedLock lock(&termlock); TextBuffer* textbuf = textbufhandle->Acquire(); @@ -106,7 +117,7 @@ size_t TextTerminal::Height() const return height; } -void TextTerminal::GetCursor(size_t* column, size_t* row) const +void TextTerminal::GetCursor(size_t* column, size_t* row) { ScopedLock lock(&termlock); *column = this->column; @@ -253,7 +264,7 @@ size_t TextTerminal::EmergencyPrintRaw(const char* string, size_t stringlen) return stringlen; } -size_t TextTerminal::EmergencyWidth() const +size_t TextTerminal::EmergencyWidth() { // This is during a kernel emergency where preemption has been disabled and // this is the only thread running. Another thread may have been interrupted @@ -266,7 +277,7 @@ size_t TextTerminal::EmergencyWidth() const return width; } -size_t TextTerminal::EmergencyHeight() const +size_t TextTerminal::EmergencyHeight() { // This is during a kernel emergency where preemption has been disabled and // this is the only thread running. Another thread may have been interrupted @@ -279,7 +290,7 @@ size_t TextTerminal::EmergencyHeight() const return height; } -void TextTerminal::EmergencyGetCursor(size_t* column, size_t* row) const +void TextTerminal::EmergencyGetCursor(size_t* column, size_t* row) { // This is during a kernel emergency where preemption has been disabled and // this is the only thread running. Another thread may have been interrupted @@ -308,6 +319,7 @@ void TextTerminal::PutChar(TextBuffer* textbuf, char c) { switch ( c ) { + case '\a': return; case '\n': Newline(textbuf); return; case '\r': column = 0; return; case '\b': Backspace(textbuf); return; @@ -336,7 +348,23 @@ void TextTerminal::PutChar(TextBuffer* textbuf, char c) Newline(textbuf); } TextPos pos(column++, line); - TextChar tc(wc, vgacolor, ATTR_CHAR | next_attr); + uint16_t tcvgacolor; + uint16_t tcattr = attr | next_attr; + uint32_t tcfgcolor; + uint32_t tcbgcolor; + if ( !(tcattr & ATTR_INVERSE) ) + { + tcvgacolor = vgacolor; + tcfgcolor = fgcolor; + tcbgcolor = bgcolor; + } + else + { + tcvgacolor = (vgacolor >> 4 & 0xF) << 0 | (vgacolor >> 0 & 0xF) << 4; + tcfgcolor = bgcolor; + tcbgcolor = fgcolor; + } + TextChar tc(wc, tcvgacolor, tcattr, tcfgcolor, tcbgcolor); textbuf->SetChar(pos, tc); next_attr = 0; } @@ -353,11 +381,14 @@ void TextTerminal::Newline(TextBuffer* textbuf) line++; else { - textbuf->Scroll(1, TextChar(' ', vgacolor, 0)); + uint32_t fillfg = attr & ATTR_INVERSE ? bgcolor : fgcolor; + uint32_t fillbg = attr & ATTR_INVERSE ? fgcolor : bgcolor; + textbuf->Scroll(1, TextChar(' ', vgacolor, 0, fillfg, fillbg)); line = textbuf->Height()-1; } } +#if 0 static TextPos DecrementTextPos(TextBuffer* textbuf, TextPos pos) { if ( !pos.x && !pos.y ) @@ -366,27 +397,23 @@ static TextPos DecrementTextPos(TextBuffer* textbuf, TextPos pos) return TextPos(textbuf->Width(), pos.y-1); return TextPos(pos.x-1, pos.y); } +#endif void TextTerminal::Backspace(TextBuffer* textbuf) { - TextPos pos(column, line); - while ( pos.x || pos.y ) + if ( column ) { - pos = DecrementTextPos(textbuf, pos); + column--; + TextPos pos(column, line); TextChar tc = textbuf->GetChar(pos); next_attr = tc.attr & (ATTR_BOLD | ATTR_UNDERLINE); if ( tc.c == L'_' ) next_attr |= ATTR_UNDERLINE; else if ( tc.c == L' ' ) - next_attr &= ~(ATTR_BOLD | ATTR_CHAR); + next_attr &= ~ATTR_BOLD; else next_attr |= ATTR_BOLD; - textbuf->SetChar(pos, TextChar(' ', vgacolor, 0)); - if ( tc.attr & ATTR_CHAR ) - break; } - column = pos.x; - line = pos.y; } void TextTerminal::Tab(TextBuffer* textbuf) @@ -396,15 +423,11 @@ void TextTerminal::Tab(TextBuffer* textbuf) column = 0; Newline(textbuf); } - unsigned int count = 8 - (column % 8); - for ( unsigned int i = 0; i < count; i++ ) - { - if ( column == textbuf->Width() ) - break; - TextPos pos(column++, line); - TextChar tc(' ', vgacolor, i == 0 ? ATTR_CHAR : 0); - textbuf->SetChar(pos, tc); - } + column++; + column = -(-column & ~0x7U); + size_t width = textbuf->Width(); + if ( width <= column ) + column = width; } // TODO: This implementation of the 'Ansi Escape Codes' is incomplete and hacky. @@ -412,9 +435,7 @@ void TextTerminal::AnsiReset() { next_attr = 0; ansiusedparams = 0; - currentparamindex = 0; ansiparams[0] = 0; - paramundefined = true; ignoresequence = false; ansimode = CSI; } @@ -424,32 +445,47 @@ void TextTerminal::PutAnsiEscaped(TextBuffer* textbuf, char c) // Check the proper prefixes are used. if ( ansimode == CSI ) { - if ( c != '[' ) { ansimode = NONE; return; } - ansimode = COMMAND; + if ( c == '[' ) + ansimode = COMMAND; + else if ( c == '(' || c == ')' || c == '*' || c == '+' || + c == '-' || c == '.' || c == '/' ) + ansimode = CHARSET; + // TODO: Enter and exit alternatve keypad mode. + else if ( c == '=' || c == '>' ) + ansimode = NONE; + else + { + ansimode = NONE; + ansimode = NONE; + } + return; + } + + if ( ansimode == CHARSET ) + { + ansimode = NONE; return; } // Read part of a parameter. if ( '0' <= c && c <= '9' ) { - if ( paramundefined ) + if ( ansiusedparams == 0 ) ansiusedparams++; - paramundefined = false; unsigned val = c - '0'; - ansiparams[currentparamindex] *= 10; - ansiparams[currentparamindex] += val; + ansiparams[ansiusedparams-1] *= 10; + ansiparams[ansiusedparams-1] += val; } // Parameter delimiter. else if ( c == ';' ) { - if ( currentparamindex == ANSI_NUM_PARAMS - 1 ) + if ( ansiusedparams == ANSI_NUM_PARAMS ) { ansimode = NONE; return; } - paramundefined = true; - ansiparams[++currentparamindex] = 0; + ansiparams[ansiusedparams++] = 0; } // Left for future standardization, so discard this sequence. @@ -458,11 +494,35 @@ void TextTerminal::PutAnsiEscaped(TextBuffer* textbuf, char c) ignoresequence = true; } + else if ( c == '>' ) + { + ansimode = GREATERTHAN; + } + // Run a command. else if ( 64 <= c && c <= 126 ) { if ( !ignoresequence ) - RunAnsiCommand(textbuf, c); + { + if ( ansimode == COMMAND ) + RunAnsiCommand(textbuf, c); + else if ( ansimode == GREATERTHAN ) + { + // Send Device Attributes + if ( c == 'c' ) + { + // TODO: Send an appropriate response through the terminal. + } + else + { + ansimode = NONE; + return; + } + ansimode = NONE; + } + } + else + ansimode = NONE; } // Something I don't understand, and ignore intentionally. @@ -573,7 +633,9 @@ void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c) from = TextPos{0, 0}, to = TextPos{width-1, height-1}; - textbuf->Fill(from, to, TextChar(' ', vgacolor, 0)); + uint32_t fillfg = attr & ATTR_INVERSE ? bgcolor : fgcolor; + uint32_t fillbg = attr & ATTR_INVERSE ? fgcolor : bgcolor; + textbuf->Fill(from, to, TextChar(' ', vgacolor, 0, fillfg, fillbg)); } break; case 'K': // Erase parts of the current line. { @@ -593,18 +655,35 @@ void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c) from = TextPos{0, line}, to = TextPos{width-1, line}; - textbuf->Fill(from, to, TextChar(' ', vgacolor, 0)); + uint32_t fillfg = attr & ATTR_INVERSE ? bgcolor : fgcolor; + uint32_t fillbg = attr & ATTR_INVERSE ? fgcolor : bgcolor; + textbuf->Fill(from, to, TextChar(' ', vgacolor, 0, fillfg, fillbg)); } break; + // TODO: CSI Ps M Delete Ps Line(s) (default = 1) (DL). + // (delete those lines and move the rest of the lines upwards). + // TODO: CSI Ps P Delete Ps Character(s) (default = 1) (DCH). + // (delete those characters and move the rest of the line leftward). case 'S': // Scroll a line up and place a new line at the buttom. { - textbuf->Scroll(1, TextChar(' ', vgacolor, 0)); + uint32_t fillfg = attr & ATTR_INVERSE ? bgcolor : fgcolor; + uint32_t fillbg = attr & ATTR_INVERSE ? fgcolor : bgcolor; + textbuf->Scroll(1, TextChar(' ', vgacolor, 0, fillfg, fillbg)); line = height-1; } break; case 'T': // Scroll a line up and place a new line at the top. { - textbuf->Scroll(-1, TextChar(' ', vgacolor, 0)); + uint32_t fillfg = attr & ATTR_INVERSE ? bgcolor : fgcolor; + uint32_t fillbg = attr & ATTR_INVERSE ? fgcolor : bgcolor; + textbuf->Scroll(-1, TextChar(' ', vgacolor, 0, fillfg, fillbg)); line = 0; } break; + case 'd': // Move the cursor to line N. + { + unsigned posy = 0 < ansiusedparams ? ansiparams[0]-1 : 0; + if ( height <= posy ) + posy = height-1; + line = posy; + } break; case 'm': // Change how the text is rendered. { if ( ansiusedparams == 0 ) @@ -616,8 +695,12 @@ void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c) // Convert from the ANSI color scheme to the VGA color scheme. const unsigned conversion[8] = { +#if 0 + 0, 4, 2, 6, 1, 5, 3, 7 +#else COLOR8_BLACK, COLOR8_RED, COLOR8_GREEN, COLOR8_BROWN, COLOR8_BLUE, COLOR8_MAGENTA, COLOR8_CYAN, COLOR8_LIGHT_GREY, +#endif }; for ( size_t i = 0; i < ansiusedparams; i++ ) @@ -626,20 +709,72 @@ void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c) // Turn all attributes off. if ( cmd == 0 ) { - vgacolor = DEFAULT_COLOR; + vgacolor = DEFAULT_VGACOLOR; + attr = 0; + fgcolor = palette[DEFAULT_FOREGROUND]; + bgcolor = palette[DEFAULT_BACKGROUND]; } + // Boldness. + else if ( cmd == 1 ) + attr |= ATTR_BOLD; + // TODO: 2, Faint + // TODO: 3, Italicized + // Underline. + else if ( cmd == 4 ) + attr |= ATTR_UNDERLINE; + // TODO: 5, Blink (appears as Bold) + // Inverse. + else if ( cmd == 7 ) + attr |= ATTR_INVERSE; + // TODO: 8, Invisible + // TODO: 9, Crossed-out + // TODO: 21, Doubly-underlined + // Normal (neither bold nor faint). + else if ( cmd == 22 ) + attr &= ~ATTR_BOLD; + // TODO: 23, Not italicized + // Not underlined. + else if ( cmd == 24 ) + attr &= ~ATTR_UNDERLINE; + // TODO: 25, Steady (not blinking) + // Positive (not inverse). + else if ( cmd == 27 ) + attr &= ~ATTR_INVERSE; + // TODO: 28, Visible (not hidden) // Set text color. else if ( 30 <= cmd && cmd <= 37 ) { unsigned val = cmd - 30; vgacolor &= 0xF0; vgacolor |= conversion[val] << 0; + fgcolor = palette[val]; + } + // Set text color. + else if ( cmd == 38 ) + { + if ( 5 <= ansiusedparams - i && ansiparams[i+1] == 2 ) + { + uint8_t r = ansiparams[i+2]; + uint8_t g = ansiparams[i+3]; + uint8_t b = ansiparams[i+4]; + i += 5 - 1; + fgcolor = ColorFromRGB(r, g, b); + // TODO: Approxpiate vgacolor. + } + else if ( 3 <= ansiusedparams - i && ansiparams[i+1] == 5 ) + { + uint8_t index = ansiparams[i+2]; + i += 3 - 1; + fgcolor = palette[index]; + // TODO: Approxpiate vgacolor. + } } // Set default text color. else if ( cmd == 39 ) { vgacolor &= 0xF0; - vgacolor |= DEFAULT_COLOR & 0x0F; + vgacolor |= DEFAULT_VGACOLOR & 0x0F; + fgcolor = palette[DEFAULT_FOREGROUND]; } // Set background color. else if ( 40 <= cmd && cmd <= 47 ) @@ -647,32 +782,60 @@ void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c) unsigned val = cmd - 40; vgacolor &= 0x0F; vgacolor |= conversion[val] << 4; + bgcolor = palette[val]; + } + // Set background color. + else if ( cmd == 48 ) + { + if ( 5 <= ansiusedparams - i && ansiparams[i+1] == 2 ) + { + uint8_t r = ansiparams[i+2]; + uint8_t g = ansiparams[i+3]; + uint8_t b = ansiparams[i+4]; + i += 5 - 1; + bgcolor = ColorFromRGB(r, g, b); + // TODO: Approxpiate vgacolor. + } + else if ( 3 <= ansiusedparams - i && ansiparams[i+1] == 5 ) + { + uint8_t index = ansiparams[i+2]; + i += 3 - 1; + bgcolor = palette[index]; + // TODO: Approxpiate vgacolor. + } } // Set default background color. else if ( cmd == 49 ) { vgacolor &= 0x0F; - vgacolor |= DEFAULT_COLOR & 0xF0; + vgacolor |= DEFAULT_VGACOLOR & 0xF0; + bgcolor = palette[DEFAULT_BACKGROUND]; } // Set text color. else if ( 90 <= cmd && cmd <= 97 ) { - unsigned val = cmd - 90; + unsigned val = cmd - 90 + 8; vgacolor &= 0xF0; - vgacolor |= (0x8 | conversion[val]) << 0; + vgacolor |= (0x8 | conversion[val - 8]) << 0; + fgcolor = palette[val]; } // Set background color. else if ( 100 <= cmd && cmd <= 107 ) { - unsigned val = cmd - 100; + unsigned val = cmd - 100 + 8; vgacolor &= 0x0F; - vgacolor |= (0x8 | conversion[val]) << 4; + vgacolor |= (0x8 | conversion[val - 8]) << 4; + bgcolor = palette[val]; + } + else + { + ansimode = NONE; } - // TODO: There are many other things we don't support. } } break; case 'n': // Request special information from terminal. { + ansimode = NONE; // TODO: Handle this code. } break; case 's': // Save cursor position. @@ -694,13 +857,21 @@ void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c) // TODO: This is somehow related to the special char '?'. if ( 0 < ansiusedparams && ansiparams[0] == 25 ) textbuf->SetCursorEnabled(false); + if ( 0 < ansiusedparams && ansiparams[0] == 1049 ) + {}; // TODO: Save scrollback. } break; case 'h': // Show cursor. { // TODO: This is somehow related to the special char '?'. if ( 0 < ansiusedparams && ansiparams[0] == 25 ) textbuf->SetCursorEnabled(true); + if ( 0 < ansiusedparams && ansiparams[0] == 1049 ) + {}; // TODO: Restore scrollback. } break; + default: + { + ansimode = NONE; + } // TODO: Handle other cases. } diff --git a/kernel/textterminal.h b/kernel/textterminal.h index f3badfcd..3d84fd9a 100644 --- a/kernel/textterminal.h +++ b/kernel/textterminal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -36,9 +36,9 @@ public: ~TextTerminal(); size_t Print(const char* string, size_t stringlen); size_t PrintRaw(const char* string, size_t stringlen); - size_t Width() const; - size_t Height() const; - void GetCursor(size_t* column, size_t* row) const; + size_t Width(); + size_t Height(); + void GetCursor(size_t* column, size_t* row); bool Sync(); bool Invalidate(); void BeginReplace(); @@ -49,9 +49,9 @@ public: void EmergencyReset(); size_t EmergencyPrint(const char* string, size_t stringlen); size_t EmergencyPrintRaw(const char* string, size_t stringlen); - size_t EmergencyWidth() const; - size_t EmergencyHeight() const; - void EmergencyGetCursor(size_t* column, size_t* row) const; + size_t EmergencyWidth(); + size_t EmergencyHeight(); + void EmergencyGetCursor(size_t* column, size_t* row); bool EmergencySync(); private: @@ -67,20 +67,21 @@ private: private: mbstate_t ps; - mutable TextBufferHandle* textbufhandle; - mutable kthread_mutex_t termlock; + TextBufferHandle* textbufhandle; + kthread_mutex_t termlock; uint16_t next_attr; + uint32_t attr; + uint32_t fgcolor; + uint32_t bgcolor; uint8_t vgacolor; unsigned column; unsigned line; unsigned ansisavedposx; unsigned ansisavedposy; - enum { NONE = 0, CSI, COMMAND, } ansimode; + enum { NONE = 0, CSI, CHARSET, COMMAND, GREATERTHAN, } ansimode; static const size_t ANSI_NUM_PARAMS = 16; unsigned ansiusedparams; unsigned ansiparams[ANSI_NUM_PARAMS]; - unsigned currentparamindex; - bool paramundefined; bool ignoresequence; }; diff --git a/kernel/vgatextbuffer.cpp b/kernel/vgatextbuffer.cpp index 416b9c5d..e5012eb1 100644 --- a/kernel/vgatextbuffer.cpp +++ b/kernel/vgatextbuffer.cpp @@ -88,7 +88,7 @@ TextChar VGATextBuffer::GetChar(TextPos pos) { if ( UsablePosition(pos) ) return chars[OffsetOfPos(pos)]; - return {0, 0, 0}; + return {0, 0, 0, 0, 0}; } void VGATextBuffer::SetChar(TextPos pos, TextChar c) @@ -203,7 +203,7 @@ bool VGATextBuffer::EmergencyRecoup() void VGATextBuffer::EmergencyReset() { - Fill(TextPos{0, 0}, TextPos{width-1, height-1}, TextChar{0, 0, 0}); + Fill(TextPos{0, 0}, TextPos{width-1, height-1}, TextChar{0, 0, 0, 0, 0}); SetCursorPos(TextPos{0, 0}); } diff --git a/sh/sh.c b/sh/sh.c index b3a36ff6..4595ee0f 100644 --- a/sh/sh.c +++ b/sh/sh.c @@ -1833,7 +1833,7 @@ void read_command_interactive(struct sh_read_command* sh_read_command) } char* ps1; - asprintf(&ps1, "\e[32m%s@%s \e[36m%s%s %c\e[37m ", + asprintf(&ps1, "\e[;1;32m%s@%s \e[1;34m%s%s %c\e[m ", print_username, print_hostname, print_dir_1, diff --git a/utils/ls.c b/utils/ls.c index d197c2a0..fc3900c6 100644 --- a/utils/ls.c +++ b/utils/ls.c @@ -298,7 +298,7 @@ static void color(const char** pre, if ( failure ) { - *pre = "\e[31m"; + *pre = "\e[1;31m"; *post = "\e[m"; return; } @@ -306,16 +306,16 @@ static void color(const char** pre, *post = "\e[m"; switch ( mode_to_dt(st->st_mode) ) { - case DT_UNKNOWN: *pre = "\e[91m"; break; - case DT_BLK: *pre = "\e[93m"; break; - case DT_CHR: *pre = "\e[93m"; break; - case DT_DIR: *pre = "\e[36m"; break; + case DT_UNKNOWN: *pre = "\e[1;31m"; break; + case DT_BLK: *pre = "\e[1;33m"; break; + case DT_CHR: *pre = "\e[1;33m"; break; + case DT_DIR: *pre = "\e[1;34m"; break; case DT_FIFO: *pre = "\e[33m"; break; - case DT_LNK: *pre = "\e[96m"; break; - case DT_SOCK: *pre = "\e[35m"; break; + case DT_LNK: *pre = "\e[1;36m"; break; + case DT_SOCK: *pre = "\e[1;35m"; break; case DT_REG: if ( st->st_mode & 0111 ) - *pre = "\e[32m"; + *pre = "\e[1;32m"; else *post = ""; break;