aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2015-07-13 23:35:26 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2015-07-14 00:18:28 +0200
commitf69d1f04c841521c17542cd00f9851db1ff3e220 (patch)
treeca3f9e85cccac4901cafc67ad2bdc3cd154ea7b4 /src
parentbf5745b95ca0a0edfb0b1129835f0e48c20ef6fa (diff)
downloadsciteco-f69d1f04c841521c17542cd00f9851db1ff3e220.tar.gz
programmable terminal color redefinition and theming SciTECO curses UI based on Scintilla styles
* The first 16 colors of the terminal palette can be redefined using the 3EJ property - with all restrictions that ncurses and UNIX terminals impose on us. It is still important to be able to redefine the palette for some color schemes like Solarized since it may be difficult for users to set up the terminal emulator's palette manually. Also when using PDCurses, setting the palette is port-specific or only possible using init_color(). In order to allow color redefinitions across all curses ports it makes sense if SciTECO gives access to the color initialization of curses even if it can guarantee very little about its semantics in general. * 3EJ is completely ignored for GTK+ * use the STYLE_DEFAULT of the current document to style the message line. Fg and bg colors are reversed to guarantee a good contrast to the Scintilla view. Errors are still hardcoded to a red background, warnings to yellow and info messages to green. This allows color-scheming more of SciTECO given that the red, yellow and green terminal colors are not changed fundamentally in the terminal's palette. * info line is now also styled using STYLE_DEFAULT (reverse colors). The Q-Register and buffer names are now written out using format_str() which means that control characters are written out in REVERSE just like in the command line. String::canonicalize_ctl() is still used to canonicalize window titles. * Command line is now modelled as a curses Pad and "blitted" to the command line window. This allowed simplification of the command line drawing code and introduction of format_str(). The command line is now styled according to STYLE_DEFAULT (original fg and bg colors). The rubbed-out part of the command line can now longer be shown in bold black - or even bold light black - since that is not visible in all color themes. Instead it is now only shown in bold. Command line theming problems will be gone once we use a Scintilla view for the command line. * The popup widget is now styled according to STYLE_CALLTIP. * This means that all relevant parts of SciTECO's user interface can now be themed. This allows the creation of themes that redefine the terminal palette radically (e.g. Solarized) and the creation of "bright" themes (e.g. Solarized/bright). * theming of the non-scintilla-view parts of SciTECO is currently unsupported on GTK+. The reason is that both the popup widget and command line widgets have to be rewritten completely in GTK+ and are work in progress, so adapting the current code would be a waste of time. * Added a manual section about the UI and theming.
Diffstat (limited to 'src')
-rw-r--r--src/interface-curses.cpp390
-rw-r--r--src/interface-curses.h30
-rw-r--r--src/interface.cpp27
-rw-r--r--src/interface.h4
-rw-r--r--src/parser.cpp63
5 files changed, 408 insertions, 106 deletions
diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp
index 5dc6aa8..7f5693c 100644
--- a/src/interface-curses.cpp
+++ b/src/interface-curses.cpp
@@ -142,6 +142,32 @@ console_ctrl_handler(DWORD type)
#define UNNAMED_FILE "(Unnamed)"
/**
+ * Get bright variant of one of the 8 standard
+ * curses colors.
+ * On 8 color terminals, this returns the non-bright
+ * color - but you __may__ get a bright version using
+ * the A_BOLD attribute.
+ * NOTE: This references `COLORS` and is thus not a
+ * constant expression.
+ */
+#define COLOR_LIGHT(C) \
+ (COLORS < 16 ? (C) : (C) + 8)
+
+/*
+ * The 8 bright colors (if terminal supports at
+ * least 16 colors), else they are identical to
+ * the non-bright colors (default curses colors).
+ */
+#define COLOR_LBLACK COLOR_LIGHT(COLOR_BLACK)
+#define COLOR_LRED COLOR_LIGHT(COLOR_RED)
+#define COLOR_LGREEN COLOR_LIGHT(COLOR_GREEN)
+#define COLOR_LYELLOW COLOR_LIGHT(COLOR_YELLOW)
+#define COLOR_LBLUE COLOR_LIGHT(COLOR_BLUE)
+#define COLOR_LMAGENTA COLOR_LIGHT(COLOR_MAGENTA)
+#define COLOR_LCYAN COLOR_LIGHT(COLOR_CYAN)
+#define COLOR_LWHITE COLOR_LIGHT(COLOR_WHITE)
+
+/**
* Curses attribute for the color combination
* `f` (foreground) and `b` (background)
* according to the color pairs initialized by
@@ -152,6 +178,54 @@ console_ctrl_handler(DWORD type)
#define SCI_COLOR_ATTR(f, b) \
((attr_t)COLOR_PAIR(SCI_COLOR_PAIR(f, b)))
+/**
+ * Translate a Scintilla-compatible RGB color value
+ * (0xBBGGRR) to a Curses color triple (0 to 1000
+ * for each component).
+ */
+static inline void
+rgb2curses(guint32 rgb, short &r, short &g, short &b)
+{
+ /* NOTE: We could also use 200/51 */
+ r = ((rgb & 0x0000FF) >> 0)*1000/0xFF;
+ g = ((rgb & 0x00FF00) >> 8)*1000/0xFF;
+ b = ((rgb & 0xFF0000) >> 16)*1000/0xFF;
+}
+
+/**
+ * Convert a Scintilla-compatible RGB color value
+ * (0xBBGGRR) to a Curses color code (e.g. COLOR_BLACK).
+ * This does not work with arbitrary RGB values but
+ * only the 16 RGB color values defined by Scinterm
+ * corresponding to the 16 terminal colors.
+ * It is equivalent to Scinterm's internal `term_color`
+ * function.
+ */
+static short
+rgb2curses(guint32 rgb)
+{
+ switch (rgb) {
+ case 0x000000: return COLOR_BLACK;
+ case 0x000080: return COLOR_RED;
+ case 0x008000: return COLOR_GREEN;
+ case 0x008080: return COLOR_YELLOW;
+ case 0x800000: return COLOR_BLUE;
+ case 0x800080: return COLOR_MAGENTA;
+ case 0x808000: return COLOR_CYAN;
+ case 0xC0C0C0: return COLOR_WHITE;
+ case 0x404040: return COLOR_LBLACK;
+ case 0x0000FF: return COLOR_LRED;
+ case 0x00FF00: return COLOR_LGREEN;
+ case 0x00FFFF: return COLOR_LYELLOW;
+ case 0xFF0000: return COLOR_LBLUE;
+ case 0xFF00FF: return COLOR_LMAGENTA;
+ case 0xFFFF00: return COLOR_LCYAN;
+ case 0xFFFFFF: return COLOR_LWHITE;
+ }
+
+ return COLOR_WHITE;
+}
+
void
ViewCurses::initialize_impl(void)
{
@@ -179,6 +253,46 @@ InterfaceCurses::main_impl(int &argc, char **&argv)
info_current = g_strdup(PACKAGE_NAME);
}
+void
+InterfaceCurses::init_color(guint color, guint32 rgb)
+{
+#if defined(__PDCURSES__) && !defined(PDC_RGB)
+ /*
+ * PDCurses will usually number color codes differently
+ * (least significant bit is the blue component) while
+ * SciTECO macros will assume a standard terminal color
+ * code numbering with red as the LSB.
+ * Therefore we have to swap the bit order of the least
+ * significant 3 bits here.
+ */
+ if (color < 16)
+ color = (color & ~0x5) |
+ ((color & 0x1) << 2) | ((color & 0x4) >> 2);
+#endif
+
+ if (cmdline_window) {
+ /* interactive mode */
+ short r, g, b;
+
+ if (!can_change_color())
+ return;
+
+ rgb2curses(rgb, r, g, b);
+ ::init_color((short)color, r, g, b);
+ } else {
+ /*
+ * batch mode: store colors,
+ * they can only be initialized after start_color()
+ * which is called by Scinterm when interactive
+ * mode is initialized
+ */
+ if (color >= G_N_ELEMENTS(color_table))
+ return;
+
+ color_table[color] = (gint32)rgb;
+ }
+}
+
#ifdef NCURSES_UNIX
void
@@ -311,6 +425,45 @@ InterfaceCurses::init_interactive(void)
*/
if (current_view)
show_view(current_view);
+
+ /*
+ * Only now it's safe to redefine the 16 default colors.
+ *
+ * FIXME: On UNIX/ncurses this __may__ change the terminal's palette
+ * permanently and there does not appear to be any portable way of
+ * restoring the original one.
+ * Curses has color_content(), but there is actually no terminal
+ * that allows querying the current palette and so color_content()
+ * will return bogus "default" values and only for the first 8 colors.
+ * xterm has the escape sequence "\e]104\x04" which restores
+ * the palette from Xdefaults but not all terminal emulators
+ * claiming to be "xterm" via $TERM support this escape sequence.
+ * lxterminal for instance will print gibberish instead.
+ * There are hardly any other terminal emulators that support palette
+ * resets.
+ * The only emulator I'm aware of which can be identified reliably
+ * by $TERM supporting a palette reset is the linux console
+ * (see console_codes(4)). The escape sequence "\e]R" is already
+ * part of its terminfo description (orig_colors capability)
+ * which is apparently sent by endwin(), so the palette is
+ * already properly restored on endwin().
+ * Welcome in Curses hell.
+ */
+ if (can_change_color()) {
+ for (guint i = 0; i < G_N_ELEMENTS(color_table); i++) {
+ short r, g, b;
+
+ if (color_table[i] < 0)
+ /* no redefinition */
+ continue;
+
+ /*
+ * init_color() may still fail if COLORS < 16
+ */
+ rgb2curses((guint32)color_table[i], r, g, b);
+ ::init_color((short)i, r, g, b);
+ }
+ }
}
void
@@ -379,10 +532,59 @@ InterfaceCurses::resize_all_windows(void)
draw_cmdline();
}
+static gsize
+format_str(WINDOW *win, const gchar *str, gsize len)
+{
+ int old_x = getcurx(win);
+
+ while (len > 0) {
+ /*
+ * NOTE: This mapping is similar to
+ * View::set_representations()
+ */
+ switch (*str) {
+ case CTL_KEY_ESC:
+ waddch(win, '$' | A_REVERSE);
+ break;
+ case '\r':
+ waddch(win, 'C' | A_REVERSE);
+ waddch(win, 'R' | A_REVERSE);
+ break;
+ case '\n':
+ waddch(win, 'L' | A_REVERSE);
+ waddch(win, 'F' | A_REVERSE);
+ break;
+ case '\t':
+ waddch(win, 'T' | A_REVERSE);
+ waddch(win, 'A' | A_REVERSE);
+ waddch(win, 'B' | A_REVERSE);
+ break;
+ default:
+ if (IS_CTL(*str)) {
+ waddch(win, '^' | A_REVERSE);
+ waddch(win, CTL_ECHO(*str) | A_REVERSE);
+ } else {
+ waddch(win, *str);
+ }
+ }
+
+ str++;
+ len--;
+ }
+
+ return getcurx(win) - old_x;
+}
+
+static inline gsize
+format_str(WINDOW *win, const gchar *str)
+{
+ return format_str(win, str, strlen(str));
+}
+
void
InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap)
{
- attr_t attr;
+ short fg, bg;
if (!msg_window) { /* batch mode */
stdio_vmsg(type, fmt, ap);
@@ -401,25 +603,27 @@ InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap)
va_end(aq);
#endif
+ fg = rgb2curses(ssm(SCI_STYLEGETBACK, STYLE_DEFAULT));
+
switch (type) {
default:
case MSG_USER:
- attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE);
+ bg = rgb2curses(ssm(SCI_STYLEGETFORE, STYLE_DEFAULT));
break;
case MSG_INFO:
- attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_GREEN);
+ bg = COLOR_GREEN;
break;
case MSG_WARNING:
- attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_YELLOW);
+ bg = COLOR_YELLOW;
break;
case MSG_ERROR:
- attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_RED);
+ bg = COLOR_RED;
beep();
break;
}
wmove(msg_window, 0, 0);
- wbkgdset(msg_window, ' ' | attr);
+ wbkgdset(msg_window, ' ' | SCI_COLOR_ATTR(fg, bg));
vw_printw(msg_window, fmt, ap);
wclrtoeol(msg_window);
}
@@ -427,12 +631,16 @@ InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap)
void
InterfaceCurses::msg_clear(void)
{
+ short fg, bg;
+
if (!msg_window) /* batch mode */
return;
- wmove(msg_window, 0, 0);
- wbkgdset(msg_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE));
- wclrtoeol(msg_window);
+ fg = rgb2curses(ssm(SCI_STYLEGETBACK, STYLE_DEFAULT));
+ bg = rgb2curses(ssm(SCI_STYLEGETFORE, STYLE_DEFAULT));
+
+ wbkgdset(msg_window, ' ' | SCI_COLOR_ATTR(fg, bg));
+ werase(msg_window);
}
void
@@ -533,32 +741,42 @@ InterfaceCurses::set_window_title(const gchar *title)
void
InterfaceCurses::draw_info(void)
{
+ short fg, bg;
+ gchar *title;
+
if (!info_window) /* batch mode */
return;
+ /*
+ * The info line is printed in reverse colors of
+ * the current buffer's STYLE_DEFAULT.
+ * The same style is used for MSG_USER messages.
+ */
+ fg = rgb2curses(ssm(SCI_STYLEGETBACK, STYLE_DEFAULT));
+ bg = rgb2curses(ssm(SCI_STYLEGETFORE, STYLE_DEFAULT));
+
wmove(info_window, 0, 0);
- wbkgdset(info_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE));
- waddstr(info_window, info_current);
+ wbkgdset(info_window, ' ' | SCI_COLOR_ATTR(fg, bg));
+ /* same formatting as in command lines */
+ format_str(info_window, info_current);
wclrtoeol(info_window);
- set_window_title(info_current);
+ /*
+ * Make sure the title will consist only of printable
+ * characters
+ */
+ title = String::canonicalize_ctl(info_current);
+ set_window_title(title);
+ g_free(title);
}
void
InterfaceCurses::info_update_impl(const QRegister *reg)
{
- /*
- * We cannot rely on Curses' control character drawing
- * and we need the info_current string for other purposes
- * (like PDC_set_title()), so we "canonicalize" the
- * register name here:
- */
- gchar *name = String::canonicalize_ctl(reg->name);
-
g_free(info_current);
+ /* NOTE: will contain control characters */
info_current = g_strconcat(PACKAGE_NAME " - <QRegister> ",
- name, NIL);
- g_free(name);
+ reg->name, NIL);
/* NOTE: drawn in event_loop_iter() */
}
@@ -573,87 +791,65 @@ InterfaceCurses::info_update_impl(const Buffer *buffer)
}
void
-InterfaceCurses::format_chr(chtype *&target, gchar chr, attr_t attr)
-{
- /*
- * NOTE: This mapping is similar to
- * View::set_representations()
- */
- switch (chr) {
- case CTL_KEY_ESC:
- *target++ = '$' | attr | A_REVERSE;
- break;
- case '\r':
- *target++ = 'C' | attr | A_REVERSE;
- *target++ = 'R' | attr | A_REVERSE;
- break;
- case '\n':
- *target++ = 'L' | attr | A_REVERSE;
- *target++ = 'F' | attr | A_REVERSE;
- break;
- case '\t':
- *target++ = 'T' | attr | A_REVERSE;
- *target++ = 'A' | attr | A_REVERSE;
- *target++ = 'B' | attr | A_REVERSE;
- break;
- default:
- if (IS_CTL(chr)) {
- *target++ = '^' | attr | A_REVERSE;
- *target++ = CTL_ECHO(chr) | attr | A_REVERSE;
- } else {
- *target++ = chr | attr;
- }
- }
-}
-
-void
InterfaceCurses::cmdline_update_impl(const Cmdline *cmdline)
{
- gsize alloc_len = 1;
- chtype *p;
-
- /*
- * AFAIK bold black should be rendered grey by any
- * common terminal.
- * If not, this problem will be gone once we support
- * a Scintilla view command line.
- * Also A_UNDERLINE is not supported by PDCurses/win32
- * and causes weird colors, so we better leave it away.
- */
- const attr_t rubout_attr =
-#ifndef PDCURSES_WIN32
- A_UNDERLINE |
-#endif
- A_BOLD | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_BLACK);
+ short fg, bg;
+ int max_cols = 1;
/*
* Replace entire pre-formatted command-line.
* We don't know if it is similar to the last one,
- * so realloc makes no sense.
+ * so resizing makes no sense.
* We approximate the size of the new formatted command-line,
* wasting a few bytes for control characters.
*/
- delete[] cmdline_current;
+ if (cmdline_pad)
+ delwin(cmdline_pad);
for (guint i = 0; i < cmdline->len+cmdline->rubout_len; i++)
- alloc_len += IS_CTL((*cmdline)[i]) ? 3 : 1;
- p = cmdline_current = new chtype[alloc_len];
+ max_cols += IS_CTL((*cmdline)[i]) ? 3 : 1;
+ cmdline_pad = newpad(1, max_cols);
+
+ fg = rgb2curses(ssm(SCI_STYLEGETFORE, STYLE_DEFAULT));
+ bg = rgb2curses(ssm(SCI_STYLEGETBACK, STYLE_DEFAULT));
+ wcolor_set(cmdline_pad, SCI_COLOR_PAIR(fg, bg), NULL);
/* format effective command line */
- for (guint i = 0; i < cmdline->len; i++)
- format_chr(p, (*cmdline)[i]);
- cmdline_len = p - cmdline_current;
+ cmdline_len = format_str(cmdline_pad, cmdline->str, cmdline->len);
+
+ /*
+ * Also A_UNDERLINE is not supported by PDCurses/win32
+ * and causes weird colors, so we better leave it away.
+ * A_BOLD should result in either a bold font or a brighter
+ * color both on 8 and 16 color terminals.
+ * This is not quite color-scheme-agnostic, but works
+ * with both the `terminal` and `solarized` themes.
+ * This problem will be gone once we use a Scintilla view
+ * as command line, since we can then define a style
+ * for rubbed out parts of the command line which will
+ * be user-configurable.
+ */
+#ifndef PDCURSES_WIN32
+ wattron(cmdline_pad, A_UNDERLINE);
+#endif
+ wattron(cmdline_pad, A_BOLD);
/* Format rubbed-out command line. */
- for (guint i = cmdline->len; i < cmdline->len+cmdline->rubout_len; i++)
- format_chr(p, (*cmdline)[i], rubout_attr);
- cmdline_rubout_len = p - cmdline_current - cmdline_len;
+ cmdline_rubout_len = format_str(cmdline_pad, cmdline->str + cmdline->len,
+ cmdline->rubout_len);
/* highlight cursor after effective command line */
if (cmdline_rubout_len) {
- cmdline_current[cmdline_len] &= A_CHARTEXT | A_UNDERLINE;
- cmdline_current[cmdline_len] |= A_REVERSE;
+ attr_t attr;
+ short pair;
+
+ wmove(cmdline_pad, 0, cmdline_len);
+ wattr_get(cmdline_pad, &attr, &pair, NULL);
+ wchgat(cmdline_pad, 1,
+ (attr & A_UNDERLINE) | A_REVERSE, pair, NULL);
} else {
- cmdline_current[cmdline_len++] = ' ' | A_REVERSE;
+ cmdline_len++;
+ wattroff(cmdline_pad, A_UNDERLINE | A_BOLD);
+ waddch(cmdline_pad, ' ' | A_REVERSE);
}
draw_cmdline();
@@ -662,8 +858,9 @@ InterfaceCurses::cmdline_update_impl(const Cmdline *cmdline)
void
InterfaceCurses::draw_cmdline(void)
{
+ short fg, bg;
/* total width available for command line */
- guint total_width = getmaxx(stdscr) - 1;
+ guint total_width = getmaxx(cmdline_window) - 1;
/* beginning of command line to show */
guint disp_offset;
/* length of command line to show */
@@ -671,11 +868,20 @@ InterfaceCurses::draw_cmdline(void)
disp_offset = cmdline_len -
MIN(cmdline_len, total_width/2 + cmdline_len % (total_width/2));
+ /*
+ * NOTE: we do not use getmaxx(cmdline_pad) here since it may be
+ * larger than the text the pad contains.
+ */
disp_len = MIN(total_width, cmdline_len+cmdline_rubout_len - disp_offset);
+ fg = rgb2curses(ssm(SCI_STYLEGETFORE, STYLE_DEFAULT));
+ bg = rgb2curses(ssm(SCI_STYLEGETBACK, STYLE_DEFAULT));
+
+ wbkgdset(cmdline_window, ' ' | SCI_COLOR_ATTR(fg, bg));
werase(cmdline_window);
mvwaddch(cmdline_window, 0, 0, '*' | A_BOLD);
- waddchnstr(cmdline_window, cmdline_current+disp_offset, disp_len);
+ copywin(cmdline_pad, cmdline_window,
+ 0, disp_offset, 0, 1, 0, disp_len, FALSE);
}
void
@@ -704,6 +910,8 @@ InterfaceCurses::popup_show_impl(void)
gint popup_colwidth;
gint cur_col;
+ short fg, bg;
+
if (!cmdline_window || !popup.length)
/* batch mode or nothing to display */
return;
@@ -738,7 +946,10 @@ InterfaceCurses::popup_show_impl(void)
/* window covers message, scintilla and info windows */
popup.window = newwin(popup_lines, 0, lines - 1 - popup_lines, 0);
- wbkgd(popup.window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_BLUE));
+
+ fg = rgb2curses(ssm(SCI_STYLEGETFORE, STYLE_CALLTIP));
+ bg = rgb2curses(ssm(SCI_STYLEGETBACK, STYLE_CALLTIP));
+ wbkgd(popup.window, ' ' | SCI_COLOR_ATTR(fg, bg));
/*
* cur_col is the row currently written.
@@ -995,7 +1206,8 @@ InterfaceCurses::~InterfaceCurses()
g_free(info_current);
if (cmdline_window)
delwin(cmdline_window);
- delete[] cmdline_current;
+ if (cmdline_pad)
+ delwin(cmdline_pad);
if (msg_window)
delwin(msg_window);
diff --git a/src/interface-curses.h b/src/interface-curses.h
index 471b462..ca3ce04 100644
--- a/src/interface-curses.h
+++ b/src/interface-curses.h
@@ -72,6 +72,16 @@ public:
} ViewCurrent;
typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> {
+ /**
+ * Mapping of the first 16 curses color codes (that may or may not
+ * correspond with the standard terminal color codes) to
+ * Scintilla-compatible RGB values (red is LSB) to initialize after
+ * Curses startup.
+ * Negative values mean no color redefinition (keep the original
+ * palette entry).
+ */
+ gint32 color_table[16];
+
int stdout_orig, stderr_orig;
SCREEN *screen;
FILE *screen_tty;
@@ -81,8 +91,7 @@ typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> {
WINDOW *msg_window;
- WINDOW *cmdline_window;
- chtype *cmdline_current;
+ WINDOW *cmdline_window, *cmdline_pad;
gsize cmdline_len, cmdline_rubout_len;
struct Popup {
@@ -92,7 +101,7 @@ typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> {
gint length; /**! total number of popup entries */
GSList *cur_list; /**! next entry to display */
- gint cur_entry; /**! next entry to display (position) */
+ gint cur_entry; /**! next entry to display (position) */
Popup() : window(NULL), list(NULL),
longest(3), length(0),
@@ -107,14 +116,20 @@ public:
info_window(NULL),
info_current(NULL),
msg_window(NULL),
- cmdline_window(NULL),
- cmdline_current(NULL),
- cmdline_len(0), cmdline_rubout_len(0) {}
+ cmdline_window(NULL), cmdline_pad(NULL),
+ cmdline_len(0), cmdline_rubout_len(0)
+ {
+ for (guint i = 0; i < G_N_ELEMENTS(color_table); i++)
+ color_table[i] = -1;
+ }
~InterfaceCurses();
/* implementation of Interface::main() */
void main_impl(int &argc, char **&argv);
+ /* override of Interface::init_color() */
+ void init_color(guint color, guint32 rgb);
+
/* implementation of Interface::vmsg() */
void vmsg_impl(MessageType type, const gchar *fmt, va_list ap);
/* override of Interface::msg_clear() */
@@ -156,9 +171,6 @@ private:
void set_window_title(const gchar *title);
void draw_info(void);
-
- void format_chr(chtype *&target, gchar chr,
- attr_t attr = 0);
void draw_cmdline(void);
friend void event_loop_iter();
diff --git a/src/interface.cpp b/src/interface.cpp
index 29ab22c..597924c 100644
--- a/src/interface.cpp
+++ b/src/interface.cpp
@@ -76,20 +76,39 @@ View<ViewImpl>::setup(void)
*/
ssm(SCI_SETMARGINWIDTHN, 1, 0);
+ /*
+ * Set some basic styles in order to provide
+ * a consistent look across UIs if no profile
+ * is used. This makes writing UI-agnostic profiles
+ * and color schemes easier.
+ * FIXME: Some settings like fonts should probably
+ * be set per UI (i.e. Scinterm doesn't use it,
+ * GTK might try to use a system-wide default
+ * monospaced font).
+ */
ssm(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK);
ssm(SCI_SETCARETPERIOD, 0);
ssm(SCI_SETCARETFORE, 0xFFFFFF);
- /*
- * FIXME: Default styles should probably be set interface-based
- * (system defaults)
- */
ssm(SCI_STYLESETFORE, STYLE_DEFAULT, 0xFFFFFF);
ssm(SCI_STYLESETBACK, STYLE_DEFAULT, 0x000000);
ssm(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Courier");
ssm(SCI_STYLECLEARALL);
+ /*
+ * FIXME: The line number background is apparently not
+ * affected by SCI_STYLECLEARALL
+ */
ssm(SCI_STYLESETBACK, STYLE_LINENUMBER, 0x000000);
+
+ /*
+ * Use (light) blue as the default background color
+ * for call tips. Necessary since this style is also
+ * used for popup windows and we need to provide a sane
+ * default if no color-scheme is applied (and --no-profile).
+ */
+ ssm(SCI_STYLESETFORE, STYLE_CALLTIP, 0x000000);
+ ssm(SCI_STYLESETBACK, STYLE_CALLTIP, 0xFF0000);
}
template class View<ViewCurrent>;
diff --git a/src/interface.h b/src/interface.h
index 6c847f4..e93ebe3 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -193,13 +193,15 @@ public:
return NULL;
}
- /* expected to initialize Scintilla */
inline void
main(int &argc, char **&argv)
{
impl().main_impl(argc, argv);
}
+ /* makes sense only on Curses */
+ inline void init_color(guint color, guint32 rgb) {}
+
enum MessageType {
MSG_USER,
MSG_INFO,
diff --git a/src/parser.cpp b/src/parser.cpp
index 9ef3d64..1da6905 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1989,6 +1989,7 @@ StateECommand::custom(gchar chr)
* [key]EJ -> value -- Get and set system properties
* -EJ -> value
* value,keyEJ
+ * rgb,color,3EJ
*
* This command may be used to get and set system
* properties.
@@ -1997,8 +1998,9 @@ StateECommand::custom(gchar chr)
* If \fIkey\fP is omitted, the prefix sign is implied
* (1 or -1).
* With two arguments, it sets property \fIkey\fP to
- * \fIvalue\fP and returns nothing. Properties may be
- * read-only.
+ * \fIvalue\fP and returns nothing. Some property \fIkeys\fP
+ * may require more than one value. Properties may be
+ * write-only or read-only.
*
* The following property keys are defined:
* .IP 0 4
@@ -2028,6 +2030,50 @@ StateECommand::custom(gchar chr)
* is too large for the new limit \(em if this happens
* you may have to clear your command-line first.
* Undo stack memory limiting is enabled by default.
+ * .IP 3
+ * This \fBwrite-only\fP property allows redefining the
+ * first 16 entries of the terminal color palette \(em a
+ * feature required by some
+ * color schemes when using the Curses user interface.
+ * When setting this property, you are making a request
+ * to define the terminal \fIcolor\fP as the Scintilla-compatible
+ * RGB color value given in the \fIrgb\fP parameter.
+ * \fIcolor\fP must be a value between 0 and 15
+ * corresponding to black, red, green, yellow, blue, magenta,
+ * cyan, white, bright black, bright red, etc. in that order.
+ * The \fIrgb\fP value has the format 0xBBGGRR, i.e. the red
+ * component is the least-significant byte and all other bytes
+ * are ignored.
+ * Note that on curses, RGB color values sent to Scintilla
+ * are actually mapped to these 16 colors by the Scinterm port
+ * and may represent colors with no resemblance to the \(lqRGB\(rq
+ * value used (depending on the current palette) \(em they should
+ * instead be viewed as placeholders for 16 standard terminal
+ * color codes.
+ * Please refer to the Scinterm manual for details on the allowed
+ * \(lqRGB\(rq values and how they map to terminal colors.
+ * This command provides a crude way to request exact RGB colors
+ * for the first 16 terminal colors.
+ * The color definition may be queued or be completely ignored
+ * on other user interfaces and no feedback is given
+ * if it fails. In fact feedback cannot be given reliably anyway.
+ * Note that on 8 color terminals, only the first 8 colors
+ * can be redefined (if you are lucky).
+ * Note that due to restrictions of most terminal emulators
+ * and some curses implementations, this command will not
+ * and cannot restore the original palette entry or request
+ * when rubbed out and should generally only be used in
+ * \fIbatch-mode\fP \(em typically when loading a color scheme.
+ * For the same reasons, palette changes may persist
+ * after \*(ST terminates on most terminal emulators.
+ * The only emulator which restores the palette on exit the
+ * author is aware of is the Linux console driver.
+ * Few other emulators like \fBxterm\fP(1) might support
+ * palette resets but this cannot be done automatically
+ * by \*(ST for technical and historical reasons.
+ * Users might try to work around this by tweaking their
+ * \fBterminfo\fP(5) database.
+ * You have been warned. Good luck.
*/
case 'J': {
BEGIN_EXEC(&States::start);
@@ -2035,7 +2081,8 @@ StateECommand::custom(gchar chr)
enum {
EJ_USER_INTERFACE = 0,
EJ_BUFFERS,
- EJ_UNDO_MEMORY_LIMIT
+ EJ_UNDO_MEMORY_LIMIT,
+ EJ_INIT_COLOR
};
tecoInt property;
@@ -2050,6 +2097,16 @@ StateECommand::custom(gchar chr)
undo.set_memory_limit(MAX(0, value));
break;
+ case EJ_INIT_COLOR:
+ if (value < 0 || value >= 16)
+ throw Error("Invalid color code %" TECO_INTEGER_FORMAT
+ " specified for <EJ>", value);
+ if (!expressions.args())
+ throw ArgExpectedError("EJ");
+ interface.init_color((guint)value,
+ (guint32)expressions.pop_num_calc());
+ break;
+
default:
throw Error("Cannot set property %" TECO_INTEGER_FORMAT
" for <EJ>", property);