diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interface-curses.cpp | 390 | ||||
-rw-r--r-- | src/interface-curses.h | 30 | ||||
-rw-r--r-- | src/interface.cpp | 27 | ||||
-rw-r--r-- | src/interface.h | 4 | ||||
-rw-r--r-- | src/parser.cpp | 63 |
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); |