aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/interface-curses.cpp
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2015-03-01 17:56:34 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2015-03-01 18:20:27 +0100
commit83ebaea1abc39cae990e0fd22b6e4b428abfa95f (patch)
treed297dab707836d05b9d46bad621b8e02d6506ab9 /src/interface-curses.cpp
parent68eb8e5c427877abae43f2e2aba7fcca5a3471de (diff)
downloadsciteco-83ebaea1abc39cae990e0fd22b6e4b428abfa95f.tar.gz
keep rubbed out command line for later re-insertion and massive Cmdline cleanup/refactoring
* characters rubbed out are not totally removed from the command line, but only from the *effective* command line. * The rubbed out command line is displayed after the command line cursor. On Curses it is grey and underlined. * When characters are inserted that are on the rubbed out part of the command line, the cursor simply moves forward. NOTE: There's currently no immediate editing command for reinserting the next character/word from the rubbed out command line. * Characters resulting in errors are no longer simply discarded but rubbed out, so they will stay in the rubbed out part of the command line, reminding you which character caused the error. * Improved Cmdline formatting on Curses UI: * Asterisk is printed bold * Control characters are printed in REVERSE style, similar to what Scinterm does. The controll character formatting has thus been moved from macro_echo() in cmdline.cpp to the UI implementations. * Updated the GTK+ UI (UNTESTED): I did only, the most important API adaptions. The command line still does not use any colors. * Refactored entire command line handling: * The command line is now a class (Cmdline), and most functions in cmdline.cpp have been converted to methods. * Esp. process_edit_cmd() (now Cmdline::process_edit_cmd()) has been simplified. There is no longer the possibility of a buffer overflow because of static insertion buffer sizes * Cleaned up usage of the cmdline_pos variable (now Cmdline::pc) which is really a program counter that used a different origin as macro_pc which was really confusing. * The new Cmdline class is theoretically 8-bit clean. However all of this will change again when we introduce Scintilla views for the command line. * Added 8-bit clean (null-byte aware) versions of QRegisterData::set_string() and QRegisterData::append_string()
Diffstat (limited to 'src/interface-curses.cpp')
-rw-r--r--src/interface-curses.cpp133
1 files changed, 105 insertions, 28 deletions
diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp
index 6d2feb0..1f4506a 100644
--- a/src/interface-curses.cpp
+++ b/src/interface-curses.cpp
@@ -54,7 +54,7 @@ static void scintilla_notify(Scintilla *sci, int idFrom,
#define UNNAMED_FILE "(Unnamed)"
#define SCI_COLOR_ATTR(f, b) \
- ((chtype)COLOR_PAIR(SCI_COLOR_PAIR(f, b)))
+ ((attr_t)COLOR_PAIR(SCI_COLOR_PAIR(f, b)))
void
ViewCurses::initialize_impl(void)
@@ -95,7 +95,6 @@ InterfaceCurses::main_impl(int &argc, char **&argv)
msg_window = newwin(1, 0, LINES - 2, 0);
cmdline_window = newwin(0, 0, LINES - 1, 0);
- cmdline_current = NULL;
#ifdef EMSCRIPTEN
nodelay(cmdline_window, TRUE);
@@ -160,13 +159,13 @@ InterfaceCurses::resize_all_windows(void)
draw_info();
msg_clear(); /* FIXME: use saved message */
popup_clear();
- cmdline_update();
+ draw_cmdline();
}
void
InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap)
{
- static const chtype type2attr[] = {
+ static const attr_t type2attr[] = {
SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE), /* MSG_USER */
SCI_COLOR_ATTR(COLOR_BLACK, COLOR_GREEN), /* MSG_INFO */
SCI_COLOR_ATTR(COLOR_BLACK, COLOR_YELLOW), /* MSG_WARNING */
@@ -230,7 +229,7 @@ InterfaceCurses::draw_info(void)
}
void
-InterfaceCurses::info_update_impl(QRegister *reg)
+InterfaceCurses::info_update_impl(const QRegister *reg)
{
g_free(info_current);
info_current = g_strdup_printf("%s - <QRegister> %s", PACKAGE_NAME,
@@ -240,7 +239,7 @@ InterfaceCurses::info_update_impl(QRegister *reg)
}
void
-InterfaceCurses::info_update_impl(Buffer *buffer)
+InterfaceCurses::info_update_impl(const Buffer *buffer)
{
g_free(info_current);
info_current = g_strdup_printf("%s - <Buffer> %s%s", PACKAGE_NAME,
@@ -251,27 +250,103 @@ InterfaceCurses::info_update_impl(Buffer *buffer)
}
void
-InterfaceCurses::cmdline_update_impl(const gchar *cmdline)
+InterfaceCurses::format_chr(chtype *&target, gchar chr, attr_t attr)
{
- size_t len;
- int half_line = (getmaxx(stdscr) - 2) / 2;
- const gchar *line;
+ /*
+ * NOTE: This mapping is similar to
+ * View::set_representations()
+ */
+ switch (chr) {
+ case '\x1B': /* escape */
+ *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;
+ }
+ }
+}
- if (cmdline) {
- g_free(cmdline_current);
- cmdline_current = g_strdup(cmdline);
+void
+InterfaceCurses::cmdline_update_impl(const Cmdline *cmdline)
+{
+ gsize alloc_len = 1;
+ chtype *p;
+
+ /*
+ * Replace entire pre-formatted command-line.
+ * We don't know if it is similar to the last one,
+ * so realloc makes no sense.
+ * We approximate the size of the new formatted command-line,
+ * wasting a few bytes for control characters.
+ */
+ delete[] cmdline_current;
+ 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];
+
+ /* format effective command line */
+ for (guint i = 0; i < cmdline->len; i++)
+ format_chr(p, (*cmdline)[i]);
+ cmdline_len = p - cmdline_current;
+
+ /*
+ * Format rubbed-out command line.
+ * 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.
+ */
+ for (guint i = cmdline->len; i < cmdline->len+cmdline->rubout_len; i++)
+ format_chr(p, (*cmdline)[i],
+ A_UNDERLINE | A_BOLD |
+ SCI_COLOR_ATTR(COLOR_BLACK, COLOR_BLACK));
+ cmdline_rubout_len = p - cmdline_current - cmdline_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;
} else {
- cmdline = cmdline_current;
+ cmdline_current[cmdline_len++] = ' ' | A_REVERSE;
}
- len = strlen(cmdline);
- /* FIXME: optimize */
- line = cmdline + len - MIN(len, half_line + len % half_line);
+ draw_cmdline();
+}
- mvwaddch(cmdline_window, 0, 0, '*');
- waddstr(cmdline_window, line);
- waddch(cmdline_window, ' ' | A_REVERSE);
- wclrtoeol(cmdline_window);
+void
+InterfaceCurses::draw_cmdline(void)
+{
+ /* total width available for command line */
+ guint total_width = getmaxx(stdscr) - 1;
+ /* beginning of command line to show */
+ guint disp_offset;
+ /* length of command line to show */
+ guint disp_len;
+
+ disp_offset = cmdline_len -
+ MIN(cmdline_len, total_width/2 + cmdline_len % (total_width/2));
+ disp_len = MIN(total_width, cmdline_len+cmdline_rubout_len - disp_offset);
+
+ werase(cmdline_window);
+ mvwaddch(cmdline_window, 0, 0, '*' | A_BOLD);
+ waddchnstr(cmdline_window, cmdline_current+disp_offset, disp_len);
}
void
@@ -430,18 +505,18 @@ event_loop_iter()
#endif
case 0x7F: /* DEL */
case KEY_BACKSPACE:
- cmdline_keypress('\b');
+ cmdline.keypress('\b');
break;
case KEY_ENTER:
case '\r':
case '\n':
- cmdline_keypress(get_eol());
+ cmdline.keypress(get_eol());
break;
/*
* Function key macros
*/
-#define FN(KEY) case KEY_##KEY: cmdline_fnmacro(#KEY); break
+#define FN(KEY) case KEY_##KEY: cmdline.fnmacro(#KEY); break
#define FNS(KEY) FN(KEY); FN(S##KEY)
FN(DOWN); FN(UP); FNS(LEFT); FNS(RIGHT);
FNS(HOME);
@@ -450,7 +525,7 @@ event_loop_iter()
g_snprintf(macro_name, sizeof(macro_name),
"F%d", key - KEY_F0);
- cmdline_fnmacro(macro_name);
+ cmdline.fnmacro(macro_name);
break;
}
FNS(DC);
@@ -468,7 +543,7 @@ event_loop_iter()
*/
default:
if (key <= 0xFF)
- cmdline_keypress((gchar)key);
+ cmdline.keypress((gchar)key);
}
sigint_occurred = FALSE;
@@ -486,6 +561,8 @@ event_loop_iter()
void
InterfaceCurses::event_loop_impl(void)
{
+ static const Cmdline empty_cmdline;
+
/* initial refresh */
/* FIXME: this does wrefresh() internally */
current_view->refresh();
@@ -493,7 +570,7 @@ InterfaceCurses::event_loop_impl(void)
wnoutrefresh(info_window);
msg_clear();
wnoutrefresh(msg_window);
- cmdline_update("");
+ cmdline_update(&empty_cmdline);
wnoutrefresh(cmdline_window);
doupdate();
@@ -540,7 +617,7 @@ InterfaceCurses::~InterfaceCurses()
g_free(info_current);
if (cmdline_window)
delwin(cmdline_window);
- g_free(cmdline_current);
+ delete[] cmdline_current;
if (msg_window)
delwin(msg_window);