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.
This commit is contained in:
Jonas 'Sortie' Termansen 2016-09-25 12:08:15 +02:00
parent ce54be34da
commit 0bb608b09e
10 changed files with 560 additions and 99 deletions

View File

@ -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 <sortix/vga.h>
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 <sortix/vga.h>
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)

View File

@ -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});
}

View File

@ -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;

283
kernel/palette.h Normal file
View File

@ -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

View File

@ -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 )

View File

@ -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 <sortix/kernel/refcount.h>
#include <sortix/kernel/textbuffer.h>
#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.
}

View File

@ -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;
};

View File

@ -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});
}

View File

@ -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,

View File

@ -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;