diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core-commands.c | 123 | ||||
| -rw-r--r-- | src/interface-curses/interface.c | 503 | ||||
| -rw-r--r-- | src/interface-gtk/interface.c | 94 | ||||
| -rw-r--r-- | src/interface.h | 10 | ||||
| -rw-r--r-- | src/main.c | 24 | ||||
| -rw-r--r-- | src/ring.c | 10 | ||||
| -rw-r--r-- | src/sciteco.h | 6 | ||||
| -rw-r--r-- | src/search.c | 12 | ||||
| -rw-r--r-- | src/spawn.c | 2 | ||||
| -rw-r--r-- | src/stdio-commands.c | 37 | ||||
| -rw-r--r-- | src/view.c | 16 |
11 files changed, 468 insertions, 369 deletions
diff --git a/src/core-commands.c b/src/core-commands.c index 528fa64..63d8dbc 100644 --- a/src/core-commands.c +++ b/src/core-commands.c @@ -2084,7 +2084,7 @@ teco_state_ecommand_flags(teco_machine_main_t *ctx, GError **error) /*$ EJ properties * [key]EJ -> value -- Get and set system properties * value,keyEJ - * rgb,color,3EJ + * [fore,]back,7EJ * -EJ -> event * -2EJ -> y, x * @@ -2136,46 +2136,36 @@ teco_state_ecommand_flags(teco_machine_main_t *ctx, GError **error) * first. * 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 simply will not - * 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 \(em even though \*(ST tries hard to - * restore the original palette on exit \(em palette changes may - * persist after \*(ST terminates on most terminal emulators on Unix. - * The only emulator which will restore their default palette - * on exit the author is aware of is \fBxterm\fP(1) and - * the Linux console driver. - * You have been warned. Good luck. + * .SCITECO_TOPIC palette + * This \fBwrite-only\fP property allows disabling use of + * the 16 color palette of default colors when using + * the Curses user interface. + * By default, when working with RGB values in Scintilla + * messages (and \*(ST color schemes for that matter) + * the 16 \(lqdefault\(rq colors are represented by + * special RGB placeholders (e.g. 0x000080 for \fICOLOR_RED\fP) + * as documented in the Scinterm manual. + * Any other RGB values will be automatically allocated + * in the terminal emulator if supported, giving the illusion + * of true color support, even though the actual number of + * concurrent colors on screen may be limited by the terminal + * emulator (see \fImax_colors\fP and \fImax_pairs\fP + * .B terminfo (1) + * capabilities) and other factors. + * \*(ST tries to avoid the first 16 color ids so as not to + * interfer with other terminal-based applications. + * The default palette however may be overwritten when requesting + * new colors in terminals restricted to 16 colors. + * In this case the original palette might not be restored properly on + * program termination and affect other terminal applications. + * The 16 predefined colors do not map to exact RGB values, + * though, but point into a palette at the terminal emulator. + * \*(ST therefore allows you to disable the 16 RGB placeholders + * by calling \(lq0,3EJ\(rq so that all colors are freshly initialized + * and will represent their exact RGB values. + * It has no effect when using the GTK interface. + * You are recommended to add \(lq0,3EJ\(rq to all color + * schemes that rely on exact RGB values. * .IP 4: * The column after the last horizontal movement. * This is only used by \fBfnkeys.tes\fP and is similar to the Scintilla-internal @@ -2194,9 +2184,30 @@ teco_state_ecommand_flags(teco_machine_main_t *ctx, GError **error) * They are removed automatically when no longer required, * but may be left around when the \*(ST crashes or terminates * unexpectedly. + * During graceful shutdowns (\fBSIGTERM\fP etc.) recovery + * files may be dumped immediately even before the interval expires. * After changing the interval, the new value may become * active only after the previous interval expires. * Recovery files are not dumped in batch mode. + * .IP 7: + * .SCITECO_TOPIC "default colors" + * This \fBwrite-only\fP property allows configuring the default + * foreground and background colors, given as two + * Scintilla-encoded RGB (0xBBGGRR) numbers. + * When asked to draw these colors, the terminal's native + * default colors \(em which may be some kind of white on black or + * black on white \(em are used instead. + * Therefore this command does not change any colors on screen + * \(em it just defines placeholder values for the terminal's + * default colors. + * This may be used e.g. to get a true black background where + * the terminal emulator's palette uses a different hue for + * Curses color COLOR_BLACK without having to resort to + * color redefinitions. + * With caution this may even be used to build color schemes that + * work both on white on black and black on white terminals. + * Use -1 to disable default foreground or background colors. + * It has no effect when using the GTK interface. * . * .IP -1: * Type of the last mouse event (\fBread-only\fP). @@ -2248,10 +2259,11 @@ teco_state_ecommand_properties(teco_machine_main_t *ctx, GError **error) EJ_USER_INTERFACE = 0, EJ_BUFFERS, EJ_MEMORY_LIMIT, - EJ_INIT_COLOR, + EJ_PALETTE, EJ_CARETX, EJ_CMDLINE_HEIGHT, - EJ_RECOVERY_INTERVAL + EJ_RECOVERY_INTERVAL, + EJ_DEFAULT_COLORS }; static teco_int_t caret_x = 0; @@ -2272,19 +2284,13 @@ teco_state_ecommand_properties(teco_machine_main_t *ctx, GError **error) return; break; - case EJ_INIT_COLOR: - if (value < 0 || value >= 16) { - g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, - "Invalid color code %" TECO_INT_FORMAT " " - "specified for <EJ>", value); - return; - } - if (!teco_expressions_args()) { - teco_error_argexpected_set(error, "EJ"); + case EJ_PALETTE: + if (teco_is_success(value)) { + g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, + "Default color palette can only be disabled"); return; } - teco_interface_init_color((guint)value, - (guint32)teco_expressions_pop_num(0)); + teco_interface_disable_palette(); break; case EJ_CARETX: @@ -2313,6 +2319,15 @@ teco_state_ecommand_properties(teco_machine_main_t *ctx, GError **error) /* FIXME: Perhaps signal the interface to reprogram timers */ break; + case EJ_DEFAULT_COLORS: { + teco_int_t fore; + + if (!teco_expressions_pop_num_calc(&fore, -1, error)) + return; + teco_interface_set_default_colors(fore, value); + break; + } + default: g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, "Cannot set property %" TECO_INT_FORMAT " " diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c index 45821f9..ff6a0f2 100644 --- a/src/interface-curses/interface.c +++ b/src/interface-curses/interface.c @@ -125,7 +125,8 @@ teco_console_ctrl_handler(DWORD type) { switch (type) { case CTRL_C_EVENT: - teco_interrupted = TRUE; + case CTRL_BREAK_EVENT: + teco_interrupted = TECO_INTERRUPTED; return TRUE; } @@ -137,6 +138,17 @@ teco_console_ctrl_handler(DWORD type) static gint teco_xterm_version(void) G_GNUC_UNUSED; static gint teco_interface_blocking_getch(void); +static inline gboolean teco_interface_check_key(gint key); + +#define MAX_COLORS (MIN(COLORS, G_MAXSHORT)/2) +/** + * Maximum effective number of color pairs. + * Scinterm uses shorts for color pairs, so G_MAXSHORT is the maximum. + * Some Curses implementations (NetBSD, PDCurses) may support less, + * but set COLOR_PAIRS accordingly. + * Half of the range is reserved to Scinterm. + */ +#define MAX_PAIRS (MIN(COLOR_PAIRS, G_MAXSHORT)/2) /** * Get bright variant of one of the 8 standard @@ -154,6 +166,12 @@ static gint teco_interface_blocking_getch(void); * The 8 bright colors (if terminal supports at * least 16 colors), else they are identical to * the non-bright colors (default curses colors). + * + * As a consequence a light black (grey) foreground + * on black background might be invisible on 8 color + * terminals. + * If you add in A_BOLD, there is a good chance that + * the text will still become grey. */ #define COLOR_LBLACK COLOR_LIGHT(COLOR_BLACK) #define COLOR_LRED COLOR_LIGHT(COLOR_RED) @@ -166,30 +184,28 @@ static gint teco_interface_blocking_getch(void); static struct { /** + * Mapping of RGB codes (encoded into a pointer) + * to a curses color number. + */ + GHashTable *color_table; + /** * Mapping of foreground and background curses color tuples * (encoded into a pointer) to a color pair number. */ GHashTable *pair_table; - /** - * 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). + * Whether to map the 16 standard palettized colors + * in color_table. + * Should be disabled when using arbitrary RGB values, + * so every color is initialized to exact RGB values. */ - gint32 color_table[16]; - + gboolean use_palette; /** - * Mapping of the first 16 curses color codes to their - * original values for restoring them on shutdown. - * Unfortunately, this may not be supported on all - * curses ports, so this array may be unused. + * Scintilla RGB values which should be rendered + * as the terminal's default foreground/background colors. + * This is -1 if colors haven't been configured. */ - struct { - gshort r, g, b; - } orig_color_table[16]; + gint32 default_fg, default_bg; int stdin_orig, stdout_orig, stderr_orig; SCREEN *screen; @@ -227,6 +243,76 @@ static struct { } teco_interface; /** + * Translate a Scintilla-compatible RGB color value + * (0xBBGGRR) to a Curses color triple (0 to 1000 + * for each component). + */ +static inline void +teco_rgb2curses_triple(guint32 rgb, gshort *r, gshort *g, gshort *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; +} + +static inline void +teco_interface_insert_color(guint32 rgb, gshort color) +{ + /* + * Color ids are stored one-offset, so that COLOR_BLACK + * can be discerned from a missing entry. + */ + g_hash_table_insert(teco_interface.color_table, + GUINT_TO_POINTER(rgb), GUINT_TO_POINTER(color)+1); +} + +/** + * Convert a Scintilla-compatible RGB color value + * (0xBBGGRR) to a Curses color code (e.g. COLOR_BLACK). + * + * This will automatically initialize new curses colors + * when necessary. + * Unless the palette is disabled with + * teco_interface_disable_palette(), this will return + * the 16 "standard" colors for a predefined list of + * RGB values (just like defined by Scinterm). + */ +static gshort +teco_rgb2curses(guint32 rgb) +{ + static guint colors = 0; + + if (!has_colors()) + return COLOR_WHITE; + + gpointer value = g_hash_table_lookup(teco_interface.color_table, + GUINT_TO_POINTER(rgb)); + if (G_LIKELY(value != NULL)) + return GPOINTER_TO_UINT(value)-1; + + /* + * Even when initializing new colors, we will __try__ not to + * touch the 16 palettized colors. + * First of all, we might still need them and secondly, + * this ensures we don't have to reset them on exit + * (which is not always possible anyway). + * There can still be 16 color terminals with + * can_change_color() == TRUE, though. + */ + guint next_color = colors + (COLORS > 16 ? 16 : 0); + + if (G_UNLIKELY(next_color >= MAX_COLORS) || !can_change_color()) + return COLOR_WHITE; + gshort r, g, b; + teco_rgb2curses_triple(rgb, &r, &g, &b); + init_color(next_color, r, g, b); + teco_interface_insert_color(rgb, next_color); + colors++; + return next_color; +} + +/** * Returns the curses color pair for the given curses foreground and background colors. * Initializes a new pair if necessary. * @@ -237,12 +323,12 @@ static struct { * color pair space on demand, while the second half is reserved to Scinterm. * * @param attr attributes to modify (for supporting monochrome terminals) - * @param fg curses foreground color - * @param bg curses background color + * @param fg curses foreground color (0xBBGGRR) + * @param bg curses background color (0xBBGGRR) * @return curses color pair number */ static gshort -teco_color_pair(attr_t *attr, gshort fg, gshort bg) +teco_color_pair(attr_t *attr, guint32 fg, guint32 bg) { static guint next_pair = 1; @@ -254,78 +340,44 @@ teco_color_pair(attr_t *attr, gshort fg, gshort bg) * color schemes. */ if (!has_colors()) { - if (bg != COLOR_BLACK) - *attr |= WA_REVERSE; + if (bg != 0x000000) + *attr ^= WA_REVERSE; return 0; } + gshort fg_id, bg_id; + + /* + * Prefer to use reverse attribute since it will work with + * the terminals default colors. + */ + if (fg == teco_interface.default_bg && bg == teco_interface.default_fg) { + fg_id = bg_id = -1; + *attr ^= WA_REVERSE; + } else { + fg_id = fg == teco_interface.default_fg ? -1 : teco_rgb2curses(fg); + bg_id = bg == teco_interface.default_bg ? -1 : teco_rgb2curses(bg); + } + G_STATIC_ASSERT(sizeof(gshort)*2 <= sizeof(guint)); - gpointer key = GUINT_TO_POINTER(((guint)fg << 8*sizeof(bg)) | bg); + gpointer key = GUINT_TO_POINTER(((guint)fg_id << 8*sizeof(bg_id)) | bg_id); gpointer value = g_hash_table_lookup(teco_interface.pair_table, key); if (G_LIKELY(value != NULL)) return GPOINTER_TO_UINT(value); - if (G_UNLIKELY(next_pair >= COLOR_PAIRS || next_pair > G_MAXSHORT)) + if (G_UNLIKELY(next_pair >= MAX_PAIRS)) return 0; - init_pair(next_pair, fg, bg); + init_pair(next_pair, fg_id, bg_id); g_hash_table_insert(teco_interface.pair_table, key, GUINT_TO_POINTER(next_pair)); return next_pair++; } static inline gint -teco_wattr_set(WINDOW *win, attr_t attr, gshort fg, gshort bg) +teco_wattr_set(WINDOW *win, attr_t attr, guint32 fg, guint32 bg) { gshort pair = teco_color_pair(&attr, fg, bg); return wattr_set(win, attr, pair, NULL); } -/** - * Translate a Scintilla-compatible RGB color value - * (0xBBGGRR) to a Curses color triple (0 to 1000 - * for each component). - */ -static inline void -teco_rgb2curses_triple(guint32 rgb, gshort *r, gshort *g, gshort *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 gshort -teco_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; -} - static gint teco_xterm_version(void) { @@ -414,9 +466,6 @@ teco_view_free(teco_view_t *ctx) scintilla_delete(ctx); } -static void teco_interface_init_color_safe(guint color, guint32 rgb); -static void teco_interface_restore_colors(void); - static void teco_interface_init_screen(void); static gboolean teco_interface_init_interactive(GError **error); static void teco_interface_restore_batch(void); @@ -431,10 +480,9 @@ static void teco_interface_draw_info(void); void teco_interface_init(gint argc, gchar **argv) { - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.color_table); i++) - teco_interface.color_table[i] = -1; - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.orig_color_table); i++) - teco_interface.orig_color_table[i].r = -1; + teco_interface.use_palette = TRUE; + teco_interface.default_fg = 0xC0C0C0; /* white */ + teco_interface.default_bg = 0x000000; /* black */; teco_interface.stdin_orig = teco_interface.stdout_orig = teco_interface.stderr_orig = -1; @@ -476,133 +524,17 @@ teco_interface_get_options(void) return NULL; } -static void -teco_interface_init_color_safe(guint color, guint32 rgb) -{ -#if defined(__PDCURSES__) && !defined(PDCURSES_GUI) - if (teco_interface.orig_color_table[color].r < 0) { - color_content((short)color, - &teco_interface.orig_color_table[color].r, - &teco_interface.orig_color_table[color].g, - &teco_interface.orig_color_table[color].b); - } -#endif - - gshort r, g, b; - teco_rgb2curses_triple(rgb, &r, &g, &b); - init_color((short)color, r, g, b); -} - -#if defined(__PDCURSES__) && !defined(PDCURSES_GUI) - -/* - * On PDCurses/WinCon, color_content() will actually return - * the real console color palette - or at least the default - * palette when the console started. - */ -static void -teco_interface_restore_colors(void) -{ - if (!can_change_color()) - return; - - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.orig_color_table); i++) { - if (teco_interface.orig_color_table[i].r < 0) - continue; - - init_color((short)i, - teco_interface.orig_color_table[i].r, - teco_interface.orig_color_table[i].g, - teco_interface.orig_color_table[i].b); - } -} - -#elif defined(CURSES_TTY) - -/* - * FIXME: On UNIX/ncurses teco_interface_init_color_safe() __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. - * It would do more damage to restore the palette returned by - * color_content() than it helps. - * xterm has the escape sequence "\e]104\a" 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. - * So we try to look whether $XTERM_VERSION is set. - * 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. - */ -static void -teco_interface_restore_colors(void) -{ - if (teco_xterm_version() < 0) - return; - - /* - * Looks like a real XTerm - */ - fputs("\e]104\a", teco_interface.screen_tty); - fflush(teco_interface.screen_tty); -} - -#else /* (!__PDCURSES__ || PDCURSES_GUI) && !CURSES_TTY */ - -static void -teco_interface_restore_colors(void) +void +teco_interface_disable_palette(void) { - /* - * No way to restore the palette, or it's - * unnecessary (e.g. XCurses) - */ + teco_interface.use_palette = FALSE; } -#endif - void -teco_interface_init_color(guint color, guint32 rgb) +teco_interface_set_default_colors(gint32 fg, gint32 bg) { - if (color >= G_N_ELEMENTS(teco_interface.color_table)) - return; - -#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. - */ - color = (color & ~0x5) | - ((color & 0x1) << 2) | ((color & 0x4) >> 2); -#endif - - if (teco_interface.input_pad) { - /* interactive mode */ - if (!can_change_color()) - return; - - teco_interface_init_color_safe(color, rgb); - } else { - /* - * batch mode: store colors, - * they can only be initialized after start_color() - * which is called by Scinterm when interactive - * mode is initialized - */ - teco_interface.color_table[color] = (gint32)rgb; - } + teco_interface.default_fg = fg; + teco_interface.default_bg = bg; } #ifdef CURSES_TTY @@ -744,14 +676,41 @@ teco_interface_init_interactive(GError **error) teco_interface_init_screen(); + teco_interface.color_table = g_hash_table_new(g_direct_hash, g_direct_equal); teco_interface.pair_table = g_hash_table_new(g_direct_hash, g_direct_equal); start_color(); - /* - * Scinterm uses shorts for color pairs, so G_MAXSHORT is the maximum. - * Some Curses implementations (NetBSD, PDCurses) may support less, - * but set COLOR_PAIRS accordingly. - */ - scintilla_set_color_offsets(0, MIN(COLOR_PAIRS, G_MAXSHORT)/2); + scintilla_set_color_offsets(MAX_COLORS, MAX_PAIRS); + if (!teco_interface.use_palette) + scintilla_disable_color_palette(); +#ifdef HAVE_USE_DEFAULT_COLORS + /* color -1 will be the terminal's default foreground or background color */ + use_default_colors(); +#endif + scintilla_set_default_colors(teco_interface.default_fg, + teco_interface.default_bg); + + if (teco_interface.use_palette && has_colors()) { + teco_interface_insert_color(0x000000, COLOR_BLACK); + teco_interface_insert_color(0x000080, COLOR_RED); + teco_interface_insert_color(0x008000, COLOR_GREEN); + teco_interface_insert_color(0x008080, COLOR_YELLOW); + teco_interface_insert_color(0x800000, COLOR_BLUE); + teco_interface_insert_color(0x800080, COLOR_MAGENTA); + teco_interface_insert_color(0x808000, COLOR_CYAN); + teco_interface_insert_color(0xC0C0C0, COLOR_WHITE); + /* + * On 8-color terminals, we still support the + * higher (light) colors, but map them to the lower codes as well. + */ + teco_interface_insert_color(0x404040, COLOR_LBLACK); + teco_interface_insert_color(0x0000FF, COLOR_LRED); + teco_interface_insert_color(0x00FF00, COLOR_LGREEN); + teco_interface_insert_color(0x00FFFF, COLOR_LYELLOW); + teco_interface_insert_color(0xFF0000, COLOR_LBLUE); + teco_interface_insert_color(0xFF00FF, COLOR_LMAGENTA); + teco_interface_insert_color(0xFFFF00, COLOR_LCYAN); + teco_interface_insert_color(0xFFFFFF, COLOR_LWHITE); + } /* * On UNIX terminals, the escape key is usually @@ -833,19 +792,6 @@ teco_interface_init_interactive(GError **error) teco_interface_show_view(teco_interface_current_view); /* - * Only now it's safe to redefine the 16 default colors. - */ - if (can_change_color()) { - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.color_table); i++) { - /* - * init_color() may still fail if COLORS < 16 - */ - if (teco_interface.color_table[i] >= 0) - teco_interface_init_color_safe(i, (guint32)teco_interface.color_table[i]); - } - } - - /* * Only now (in interactive mode), it's safe to initialize * the clipboard Q-Registers on ncurses with a compatible terminal * emulator since clipboard operations will no longer interfer @@ -877,7 +823,6 @@ teco_interface_restore_batch(void) * (i.e. return to batch mode) */ endwin(); - teco_interface_restore_colors(); /* * Restore stdin, stdout and stderr, so output goes to @@ -942,23 +887,23 @@ teco_interface_msg_literal(teco_msg_t type, const gchar *str, gsize len) teco_interface_stdio_msg(type, str, len); #endif - gshort fg, bg; + guint32 fg, bg; - fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); + fg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0); switch (type) { default: case TECO_MSG_USER: - bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + bg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0); break; case TECO_MSG_INFO: - bg = COLOR_GREEN; + bg = 0x008000; /* green */ break; case TECO_MSG_WARNING: - bg = COLOR_YELLOW; + bg = 0x008080; /* yellow */ break; case TECO_MSG_ERROR: - bg = COLOR_RED; + bg = 0x000080; /* red */ beep(); break; } @@ -975,8 +920,8 @@ teco_interface_msg_clear(void) if (!teco_interface.input_pad) /* batch mode */ return; - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0); wmove(teco_interface.msg_window, 0, 0); teco_wattr_set(teco_interface.msg_window, 0, fg, bg); @@ -1004,15 +949,30 @@ teco_interface_getch(gboolean widechar) gint32 cp; do { - cp = teco_interface_blocking_getch(); - if (cp == TECO_CTL_KEY('C')) - teco_interrupted = TRUE; - if (cp == TECO_CTL_KEY('C') || cp == TECO_CTL_KEY('D')) { - cp = -1; - break; - } - if (cp < 0 || cp > 0xFF) - continue; + do { + cp = teco_interface_blocking_getch(); + switch (cp) { +#ifdef KEY_RESIZE + case KEY_RESIZE: + teco_interface_resize_all_windows(); + teco_interface_refresh(FALSE); + /* cursor was moved by the resize */ + wmove(teco_interface.msg_window, 0, 0); + wrefresh(teco_interface.msg_window); + break; +#endif + case KEY_BACKSPACE: + return TECO_CTL_KEY('H'); + case KEY_ENTER: + return '\n'; + case TECO_CTL_KEY('C'): + teco_interrupted = TECO_INTERRUPTED; + /* fall through */ + case TECO_CTL_KEY('D'): + /* emulates EOF on stdin */ + return -1; + } + } while (cp < 0 || cp > 0xFF || !teco_interface_check_key(cp)); if (!widechar || !cp) break; @@ -1153,8 +1113,8 @@ teco_interface_draw_info(void) * the current buffer's STYLE_DEFAULT. * The same style is used for MSG_USER messages. */ - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0); wmove(teco_interface.info_window, 0, 0); teco_wattr_set(teco_interface.info_window, 0, fg, bg); @@ -1726,8 +1686,8 @@ teco_interface_popup_show(gsize prefix_len) /* batch mode */ return; - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0); teco_interface.popup_prefix_len = prefix_len; attr_t attr = 0; @@ -1783,7 +1743,7 @@ teco_interface_popup_clear(void) gboolean teco_interface_is_interrupted(void) { - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; } #else /* !CURSES_TTY && !PDCURSES_WINCON && !NCURSES_WIN32 */ @@ -1802,7 +1762,7 @@ teco_interface_is_interrupted(void) { if (!teco_interface.input_pad) /* batch mode */ - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; /* * NOTE: wgetch() is configured to be nonblocking. @@ -1817,7 +1777,7 @@ teco_interface_is_interrupted(void) GINT_TO_POINTER(key)); } - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; } #endif @@ -1932,8 +1892,8 @@ teco_interface_process_mevent(MEVENT *event, GError **error) else if (event->bstate & BUTTON_NUM(5)) teco_curses_info_popup_scroll(&teco_interface.popup, +2); - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0); attr_t attr = 0; gshort pair = teco_color_pair(&attr, fg, bg); teco_curses_info_popup_show(&teco_interface.popup, attr, pair); @@ -2106,7 +2066,7 @@ teco_interface_blocking_getch(void) gint key = wgetch(teco_interface.input_pad); teco_memory_start_limiting(); /* allow asynchronous interruptions on <CTRL/C> */ - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; wtimeout(teco_interface.input_pad, 0); #if defined(CURSES_TTY) || defined(PDCURSES_WINCON) || defined(NCURSES_WIN32) noraw(); /* FIXME: necessary because of NCURSES_WIN32 bug */ @@ -2122,6 +2082,31 @@ teco_interface_blocking_getch(void) return key; } +#ifdef __PDCURSES__ + +/* + * Especially PDCurses/WinGUI likes to report two keypresses, + * e.g. for CTRL+Shift+6 (CTRL+^). + * Make sure we don't filter out AltGr, which may be reported as CTRL+ALT. + */ +static inline gboolean +teco_interface_check_key(gint key) +{ + return (PDC_get_key_modifiers() & + (PDC_KEY_MODIFIER_CONTROL | PDC_KEY_MODIFIER_ALT)) != PDC_KEY_MODIFIER_CONTROL || + TECO_IS_CTL(key); +} + +#else /* __PDCURSES__ */ + +static inline gboolean +teco_interface_check_key(gint key) +{ + return TRUE; +} + +#endif + /** * One iteration of the event loop. * @@ -2227,21 +2212,9 @@ teco_interface_event_loop_iter(void) * Control keys and keys with printable representation */ default: - if (key > 0xFF) - /* unhandled function key */ - return; - -#ifdef __PDCURSES__ - /* - * Especially PDCurses/WinGUI likes to report two keypresses, - * e.g. for CTRL+Shift+6 (CTRL+^). - * Make sure we don't filter out AltGr, which may be reported as CTRL+ALT. - */ - if ((PDC_get_key_modifiers() & - (PDC_KEY_MODIFIER_CONTROL | PDC_KEY_MODIFIER_ALT)) == PDC_KEY_MODIFIER_CONTROL && - !TECO_IS_CTL(key)) + if (key > 0xFF || !teco_interface_check_key(key)) + /* unhandled function key or bogus key press */ return; -#endif /* * NOTE: There's also wget_wch(), but it requires @@ -2373,6 +2346,8 @@ teco_interface_cleanup(void) if (teco_interface.stdout_orig >= 0) close(teco_interface.stdout_orig); + if (teco_interface.color_table) + g_hash_table_destroy(teco_interface.color_table); if (teco_interface.pair_table) g_hash_table_destroy(teco_interface.pair_table); diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c index 08ccf5d..1f6259f 100644 --- a/src/interface-gtk/interface.c +++ b/src/interface-gtk/interface.c @@ -78,7 +78,7 @@ static void teco_interface_popup_clicked_cb(GtkWidget *popup, gchar *str, gulong gpointer user_data); static gboolean teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer user_data); -static gboolean teco_interface_sigterm_handler(gpointer user_data) G_GNUC_UNUSED; +static gboolean teco_interface_termination_handler(gpointer user_data) G_GNUC_UNUSED; static gchar teco_interface_get_ansi_key(GdkEventKey *event); #define TECO_UNNAMED_FILE "(Unnamed)" @@ -404,7 +404,8 @@ teco_interface_get_options(void) return group; } -void teco_interface_init_color(guint color, guint32 rgb) {} +void teco_interface_disable_palette(void) {} +void teco_interface_set_default_colors(gint32 fg, gint32 bg) {} void teco_interface_msg_literal(teco_msg_t type, const gchar *str, gsize len) @@ -451,14 +452,15 @@ teco_interface_getch_commit_cb(GtkIMContext *context, gchar *str, gpointer user_ */ *cp = g_utf8_get_char_validated(str, -1); g_assert(*cp >= 0); - gtk_main_quit(); + + /* we might be invoked outside of a nested event loop */ + if (gtk_main_level() > 1) + gtk_main_quit(); } static gboolean -teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +teco_interface_getch_process_event(GdkEvent *event, teco_int_t *cp) { - teco_int_t *cp = user_data; - g_assert(event->type == GDK_KEY_PRESS); switch (event->key.keyval) { @@ -476,19 +478,34 @@ teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_ *cp = TECO_CTL_KEY(g_ascii_toupper(*cp)); switch (*cp) { case TECO_CTL_KEY('C'): - teco_interrupted = TRUE; + teco_interrupted = TECO_INTERRUPTED; /* fall through */ case TECO_CTL_KEY('D'): + /* emulates EOF on stdin */ *cp = -1; } break; } + /* + * NOTE: The teco_interface_getch_commit_cb() could be called immediately + * without returning to the event loop. + */ gtk_im_context_filter_keypress(teco_interface.input_method, &event->key); - return TRUE; + return *cp >= 0; } - gtk_main_quit(); + return TRUE; +} + +static gboolean +teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + teco_int_t *cp = user_data; + + if (teco_interface_getch_process_event(event, cp)) + gtk_main_quit(); + return TRUE; } @@ -513,6 +530,22 @@ teco_interface_getch(gboolean widechar) G_CALLBACK(teco_interface_getch_commit_cb), &cp); /* + * The original teco_interface_input_cb() could have already enqueued events + * (also between ^T calls). + * This must be done after registering teco_interface_getch_commit_cb() already. + * + * NOTE: Already enqueued mouse events will currently be discarded silently. + */ + for (;;) { + g_autoptr(GdkEvent) event = g_queue_pop_head(teco_interface.event_queue); + if (!event) + break; + if (event->type == GDK_KEY_PRESS && + teco_interface_getch_process_event(event, &cp)) + goto cleanup; + } + + /* * Highlights the first character in the label. * This mimics what the Curses UI does. * Is there a better way to signal that we expect input? @@ -526,6 +559,7 @@ teco_interface_getch(gboolean widechar) gdk_window_freeze_updates(top_window); +cleanup: g_signal_handler_disconnect(teco_interface.input_method, commit_handler); g_signal_handlers_unblock_by_func(teco_interface.input_method, teco_interface_cmdline_commit_cb, NULL); g_signal_handler_disconnect(teco_interface.window, key_handler); @@ -790,7 +824,7 @@ teco_interface_is_interrupted(void) { if (!gtk_main_level()) /* batch mode */ - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; /* * By polling only every TECO_POLL_INTERVAL microseconds @@ -800,11 +834,11 @@ teco_interface_is_interrupted(void) guint64 now_ts = g_get_monotonic_time(); if (G_LIKELY(last_poll_ts+TECO_POLL_INTERVAL > now_ts)) - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; last_poll_ts = now_ts; gtk_main_iteration_do(FALSE); - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; } void @@ -1265,13 +1299,12 @@ teco_interface_event_loop(GError **error) #endif /* - * SIGTERM emulates the "Close" key just like when - * closing the window if supported by this version of glib. - * Note that this replaces SciTECO's default SIGTERM handler - * so it will additionally raise(SIGINT). + * SIGTERM and SIGHUP terminate the program, but will + * dump recovery files first (if enabled). */ #ifdef G_OS_UNIX - g_unix_signal_add(SIGTERM, teco_interface_sigterm_handler, NULL); + g_unix_signal_add(SIGTERM, teco_interface_termination_handler, NULL); + g_unix_signal_add(SIGHUP, teco_interface_termination_handler, NULL); #endif /* the interval might have been changed in the profile */ @@ -1395,7 +1428,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) * If the execution thread is currently blocking, * the key is delivered like an ordinary key press. */ - teco_interrupted = TRUE; + teco_interrupted = TECO_INTERRUPTED; else g_queue_push_tail(teco_interface.event_queue, gdk_event_copy(event)); @@ -1436,7 +1469,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) const teco_view_t *last_view = teco_interface_current_view; sptr_t last_vpos = teco_interface_ssm(SCI_GETFIRSTVISIBLELINE, 0, 0); - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; switch (event->type) { case GDK_KEY_PRESS: teco_interface_handle_key_press(&event->key, &error); @@ -1453,7 +1486,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) default: g_assert_not_reached(); } - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; teco_interface_update(teco_interface_current_view != last_view); /* always expand folds, even after mouse clicks */ @@ -1563,16 +1596,23 @@ teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer } static gboolean -teco_interface_sigterm_handler(gpointer user_data) +teco_interface_termination_handler(gpointer user_data) { + teco_interface_msg(TECO_MSG_WARNING, "Received termination signal - dumping recovery files"); + teco_interrupted = TECO_TERMINATED; + /* - * Similar to window deletion - emulate "close" key press. + * This may be an emergency shutdown or another kind of + * termination that we cannot ignore, so better dump + * recovery files before terminating. */ - GtkWidget *widget = teco_interface.window; + if (teco_ring_recovery_interval != 0) + teco_ring_dump_recovery(); - g_autoptr(GdkEvent) close_event = gdk_event_new(GDK_KEY_PRESS); - close_event->key.window = gtk_widget_get_parent_window(widget); - close_event->key.keyval = GDK_KEY_Close; + /* + * Otherwise we terminate and clean up as if by `-EX`. + */ + gtk_main_quit(); - return teco_interface_input_cb(widget, close_event, NULL); + return G_SOURCE_REMOVE; } diff --git a/src/interface.h b/src/interface.h index 54f807b..a7968d1 100644 --- a/src/interface.h +++ b/src/interface.h @@ -57,13 +57,17 @@ void teco_interface_init(gint argc, gchar **argv); GOptionGroup *teco_interface_get_options(void); /** @pure makes sense only on Curses */ -void teco_interface_init_color(guint color, guint32 rgb); +void teco_interface_disable_palette(void); + +/** @pure makes sense only on Curses */ +void teco_interface_set_default_colors(gint32 fg, gint32 bg); typedef enum { - TECO_MSG_USER, + TECO_MSG_USER = 0, TECO_MSG_INFO, TECO_MSG_WARNING, - TECO_MSG_ERROR + TECO_MSG_ERROR, + TECO_MSG_MAX = TECO_MSG_ERROR } teco_msg_t; extern teco_msg_t teco_interface_msg_level; @@ -66,12 +66,15 @@ teco_int_t teco_ed = TECO_ED_AUTOEOL; /** - * Whether there was an asyncronous interruption (usually after pressing CTRL+C). + * Whether there was an asynchronous interruption (usually after + * pressing CTRL+C) or termination (SIGTERM). * However you should always use teco_interface_is_interrupted(), * to check for interruptions because of its side effects. * This variable is safe to set to TRUE from signal handlers and threads. + * + * This is a teco_interrupted_t. */ -volatile sig_atomic_t teco_interrupted = FALSE; +volatile sig_atomic_t teco_interrupted = TECO_NORMAL; /* * FIXME: Move this into file-utils.c? @@ -346,7 +349,7 @@ teco_initialize_environment(void) static void teco_sigint_handler(int signal) { - teco_interrupted = TRUE; + teco_interrupted = TECO_INTERRUPTED; } #ifdef G_OS_WIN32 @@ -385,8 +388,21 @@ main(int argc, char **argv) getchar(); #endif + /* + * FIXME: Gracefully handle SIGTERM. + * This however would require polling for the flag in Curses + * getch() loops. + * GTK already catches SIGTERM. + */ +#ifdef HAVE_SIGACTION + static const struct sigaction sigint = { + .sa_handler = teco_sigint_handler, + .sa_flags = 0 /* don't auto-restart syscalls */ + }; + sigaction(SIGINT, &sigint, NULL); +#else signal(SIGINT, teco_sigint_handler); - signal(SIGTERM, teco_sigint_handler); +#endif /* * Important for Unicode handling in curses and glib. @@ -143,7 +143,12 @@ teco_buffer_save(teco_buffer_t *ctx, const gchar *filename, GError **error) static inline void teco_buffer_free(teco_buffer_t *ctx) { - if (ctx->state > TECO_BUFFER_DIRTY_NO_DUMP) { + /* + * During graceful, but unexpected shutdowns (SIGTERM etc.), + * we must preserve the recovery files. + */ + if (ctx->state > TECO_BUFFER_DIRTY_NO_DUMP && + teco_interrupted != TECO_TERMINATED) { g_autofree gchar *filename_recovery = teco_buffer_get_recovery(ctx); g_unlink(filename_recovery); } @@ -317,7 +322,8 @@ guint teco_ring_recovery_interval = 2*60; /** * Create recovery files for all dirty buffers. * - * Should be called by the interface every teco_ring_recovery_interval seconds. + * Should be called by the interface every teco_ring_recovery_interval seconds + * or before graceful terminations (SIGTERM etc.). * This does not generate or expect undo tokens, so it can be called * even when idlying. */ diff --git a/src/sciteco.h b/src/sciteco.h index 16dba69..88078c2 100644 --- a/src/sciteco.h +++ b/src/sciteco.h @@ -109,6 +109,12 @@ teco_default_codepage(void) return teco_ed & TECO_ED_DEFAULT_ANSI ? SC_CHARSET_ANSI : SC_CP_UTF8; } +typedef enum { + TECO_NORMAL = 0, + TECO_INTERRUPTED, + TECO_TERMINATED +} teco_interrupted_t; + /* in main.c */ extern volatile sig_atomic_t teco_interrupted; diff --git a/src/search.c b/src/search.c index 856d079..89bf688 100644 --- a/src/search.c +++ b/src/search.c @@ -603,6 +603,11 @@ teco_do_search(GRegex *re, gsize from, gsize to, gint *count, GError **error) g_propagate_error(error, tmp_error); return FALSE; } + + if (G_UNLIKELY(teco_interface_is_interrupted())) { + teco_error_interrupted_set(error); + return FALSE; + } } if (!*count) @@ -659,6 +664,13 @@ teco_do_search(GRegex *re, gsize from, gsize to, gint *count, GError **error) return FALSE; } + if (G_UNLIKELY(teco_interface_is_interrupted())) { + teco_error_interrupted_set(error); + for (int i = 0; i < matched_num; i++) + g_free(matched[i].ranges); + return FALSE; + } + i = ++matched_total % -(*count); } diff --git a/src/spawn.c b/src/spawn.c index 61718fd..716bafa 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -869,7 +869,7 @@ teco_spawn_idle_cb(gpointer user_data) { if (G_LIKELY(!teco_interface_is_interrupted())) return G_SOURCE_CONTINUE; - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; /* * The first CTRL+C will try to gracefully terminate the process. diff --git a/src/stdio-commands.c b/src/stdio-commands.c index abb6566..c2a1c16 100644 --- a/src/stdio-commands.c +++ b/src/stdio-commands.c @@ -255,17 +255,42 @@ teco_state_print_string_initial(teco_machine_main_t *ctx, GError **error) static teco_state_t * teco_state_print_string_done(teco_machine_main_t *ctx, teco_string_t str, GError **error) { - teco_interface_msg_literal(TECO_MSG_USER, str.data, str.len); + teco_int_t type; + + if (ctx->flags.mode > TECO_MODE_NORMAL) + return &teco_state_start; + + if (!teco_expressions_pop_num_calc(&type, TECO_MSG_USER, error)) + return NULL; + if (type < TECO_MSG_USER || type > TECO_MSG_MAX) { + g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, + "Invalid message level specified for <^A>"); + return NULL; + } + + teco_interface_msg_literal(type, str.data, str.len); return &teco_state_start; } /*$ "^A" ":^A" print "print string" - * ^A<string>^A -- Print string as message - * @^A/string/ - * :^A<string>^A + * [type]^A<string>^A -- Print string as message + * [type]@^A/string/ + * [type]:^A<string>^A * - * Print <string> as a message, i.e. in the message line - * in interactive mode and if possible on the terminal (stdout) as well. + * Print <string> as a message with severity <type>, i.e. in the + * message line in interactive mode and if possible on the terminal + * as well. + * The following message levels are supported: + * .IP 0: 3 + * User-level message: + * They are written without any prefixes directly to stdout. + * This is the default if <type> is omitted. + * .IP 1: + * Info-level message + * .IP 2: + * Warnings + * .IP 3: + * Errors * * \fB^A\fP differs from all other commands in the way <string> * is terminated. @@ -109,12 +109,12 @@ teco_view_setup(teco_view_t *ctx) teco_view_ssm(ctx, SCI_SETCARETSTYLE, CARETSTYLE_BLOCK | CARETSTYLE_OVERSTRIKE_BLOCK | CARETSTYLE_BLOCK_AFTER, 0); teco_view_ssm(ctx, SCI_SETCARETPERIOD, 0, 0); - teco_view_ssm(ctx, SCI_SETCARETFORE, 0xFFFFFF, 0); + teco_view_ssm(ctx, SCI_SETCARETFORE, 0xC0C0C0, 0); teco_view_ssm(ctx, SCI_SETSELFORE, TRUE, 0x000000); - teco_view_ssm(ctx, SCI_SETSELBACK, TRUE, 0xFFFFFF); + teco_view_ssm(ctx, SCI_SETSELBACK, TRUE, 0xC0C0C0); - teco_view_ssm(ctx, SCI_STYLESETFORE, STYLE_DEFAULT, 0xFFFFFF); + teco_view_ssm(ctx, SCI_STYLESETFORE, STYLE_DEFAULT, 0xC0C0C0); teco_view_ssm(ctx, SCI_STYLESETBACK, STYLE_DEFAULT, 0x000000); teco_view_ssm(ctx, SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Monospace"); teco_view_ssm(ctx, SCI_STYLECLEARALL, 0, 0); @@ -132,7 +132,7 @@ teco_view_setup(teco_view_t *ctx) * default if no color-scheme is applied (and --no-profile). */ teco_view_ssm(ctx, SCI_STYLESETFORE, STYLE_CALLTIP, 0x000000); - teco_view_ssm(ctx, SCI_STYLESETBACK, STYLE_CALLTIP, 0xFFFFFF); + teco_view_ssm(ctx, SCI_STYLESETBACK, STYLE_CALLTIP, 0xC0C0C0); /* * Since we have patched out Scintilla's original SetRepresentations(), @@ -234,8 +234,8 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, */ guint cp = teco_view_get_codepage(ctx); if (cp == SC_CP_UTF8) - teco_interface_ssm(SCI_RELEASELINECHARACTERINDEX, - SC_LINECHARACTERINDEX_UTF32, 0); + teco_view_ssm(ctx, SCI_RELEASELINECHARACTERINDEX, + SC_LINECHARACTERINDEX_UTF32, 0); teco_view_ssm(ctx, SCI_BEGINUNDOACTION, 0, 0); if (clear) { @@ -314,8 +314,8 @@ cleanup: teco_view_ssm(ctx, SCI_ENDUNDOACTION, 0, 0); if (cp == SC_CP_UTF8) - teco_interface_ssm(SCI_ALLOCATELINECHARACTERINDEX, - SC_LINECHARACTERINDEX_UTF32, 0); + teco_view_ssm(ctx, SCI_ALLOCATELINECHARACTERINDEX, + SC_LINECHARACTERINDEX_UTF32, 0); return ret; } |
