aboutsummaryrefslogtreecommitdiffhomepage
path: root/interface-ncurses.cpp
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-15 08:28:49 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-15 08:28:49 +0100
commit7d68fdafcd42e42c8bceeb384af7be1b5dfd3a65 (patch)
tree5db0bfa0b96b8e1842e6dd8ad9bdc61df758db99 /interface-ncurses.cpp
parent7d0a161e5297d0d29905facb2b290d1084ab29ac (diff)
downloadsciteco-7d68fdafcd42e42c8bceeb384af7be1b5dfd3a65.tar.gz
added NCurses user interface (based on Scinterm)
* terminal resizing not yet supported * file popups are sort of a hack
Diffstat (limited to 'interface-ncurses.cpp')
-rw-r--r--interface-ncurses.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/interface-ncurses.cpp b/interface-ncurses.cpp
new file mode 100644
index 0000000..48dbec6
--- /dev/null
+++ b/interface-ncurses.cpp
@@ -0,0 +1,226 @@
+#include <string.h>
+#include <stdarg.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include <ncurses.h>
+
+#include <Scintilla.h>
+#include <ScintillaTerm.h>
+
+#include "sciteco.h"
+#include "interface.h"
+#include "interface-ncurses.h"
+
+InterfaceNCurses interface;
+
+extern "C" {
+static void scnotification(Scintilla *view, int i, void *p1, void *p2);
+}
+
+/* FIXME: should be configurable in TECO */
+#define ESCAPE_SURROGATE KEY_DC
+
+/* from ScintillaTerm.cxx */
+#define SCI_COLOR_PAIR(f, b) ((b) * COLORS + (f) + 1)
+
+InterfaceNCurses::InterfaceNCurses()
+ : popup_window(NULL), popup_list(NULL),
+ popup_list_longest(0), popup_list_length(0)
+{
+ initscr();
+ raw();
+ cbreak();
+ noecho();
+ curs_set(0); // Scintilla draws its own cursor
+
+ setlocale(LC_CTYPE, ""); // for displaying UTF-8 characters properly
+
+ /* TODO: handle terminal resize */
+ /* NOTE: initializes color pairs */
+ sci = scintilla_new(scnotification);
+ sci_window = scintilla_get_window(sci);
+ wresize(sci_window, LINES - 2, COLS);
+
+ msg_window = newwin(1, 0, LINES - 2, 0);
+
+ cmdline_window = newwin(0, 0, LINES - 1, 0);
+ keypad(cmdline_window, TRUE);
+
+ ssm(SCI_SETFOCUS, TRUE);
+
+ msg(MSG_USER, " ");
+ cmdline_update();
+}
+
+void
+InterfaceNCurses::msg(MessageType type, const gchar *fmt, ...)
+{
+ static const short type2colorid[] = {
+ SCI_COLOR_PAIR(COLOR_BLACK, COLOR_WHITE), /* MSG_USER */
+ SCI_COLOR_PAIR(COLOR_BLACK, COLOR_GREEN), /* MSG_INFO */
+ SCI_COLOR_PAIR(COLOR_BLACK, COLOR_YELLOW), /* MSG_WARNING */
+ SCI_COLOR_PAIR(COLOR_BLACK, COLOR_RED) /* MSG_ERROR */
+ };
+
+ va_list ap;
+
+ wmove(msg_window, 0, 0);
+ wbkgdset(msg_window, ' ' | COLOR_PAIR(type2colorid[type]));
+ va_start(ap, fmt);
+ vw_printw(msg_window, fmt, ap);
+ va_end(ap);
+ wclrtoeol(msg_window);
+
+ wrefresh(msg_window);
+}
+
+void
+InterfaceNCurses::cmdline_update(const gchar *cmdline)
+{
+ size_t len = strlen(cmdline);
+ int half_line = (COLS - 2) / 2;
+ const gchar *line;
+
+ /* FIXME: optimize */
+ line = cmdline + len - MIN(len, half_line + len % half_line);
+
+ mvwaddch(cmdline_window, 0, 0, '*');
+ waddstr(cmdline_window, line);
+ waddch(cmdline_window, ' ' | A_REVERSE);
+ wclrtoeol(cmdline_window);
+
+ wrefresh(cmdline_window);
+}
+
+void
+InterfaceNCurses::popup_add_filename(PopupFileType type,
+ const gchar *filename, bool highlight)
+{
+ gchar *entry = g_strconcat(highlight ? "*" : " ", filename, NULL);
+
+ popup_list_longest = MAX(popup_list_longest, (gint)strlen(filename));
+ popup_list_length++;
+
+ popup_list = g_slist_prepend(popup_list, entry);
+}
+
+void
+InterfaceNCurses::popup_show(void)
+{
+ int popup_lines;
+ gint popup_cols, cur_file;
+
+ popup_list_longest += 3;
+ popup_list = g_slist_reverse(popup_list);
+
+ popup_cols = MIN(popup_list_length, COLS / popup_list_longest);
+ popup_lines = (popup_list_length + popup_list_length % popup_cols)/
+ popup_cols;
+ /* window covers message and scintilla windows */
+ popup_window = newwin(popup_lines, 0, LINES - 1 - popup_lines, 0);
+ wbkgdset(popup_window,
+ ' ' | COLOR_PAIR(SCI_COLOR_PAIR(COLOR_BLACK, COLOR_BLUE)));
+
+ cur_file = 0;
+ for (GSList *cur = popup_list; cur; cur = g_slist_next(cur)) {
+ gchar *entry = (gchar *)cur->data;
+
+ if (cur_file && !(cur_file % popup_cols)) {
+ wclrtoeol(popup_window);
+ waddch(popup_window, '\n');
+ }
+
+ (void)wattrset(popup_window, *entry == '*' ? A_BOLD : A_NORMAL);
+ waddstr(popup_window, entry + 1);
+ for (int i = popup_list_longest - strlen(entry) + 1; i; i--)
+ waddch(popup_window, ' ');
+
+ g_free(cur->data);
+ cur_file++;
+ }
+ wclrtoeol(popup_window);
+
+ g_slist_free(popup_list);
+ popup_list = NULL;
+ popup_list_longest = 0;
+ popup_list_length = 0;
+}
+
+void
+InterfaceNCurses::popup_clear(void)
+{
+ scintilla_refresh(sci);
+ redrawwin(msg_window);
+ wrefresh(msg_window);
+ if (popup_window)
+ delwin(popup_window);
+ popup_window = NULL;
+}
+
+void
+InterfaceNCurses::event_loop(void)
+{
+ for (;;) {
+ int key;
+
+ /* also handles initial refresh (styles are configured...) */
+ scintilla_refresh(sci);
+ if (popup_window)
+ wrefresh(popup_window);
+
+ key = wgetch(cmdline_window);
+ switch (key) {
+ case ESCAPE_SURROGATE:
+ cmdline_keypress('\x1B');
+ break;
+ case KEY_BACKSPACE:
+ cmdline_keypress('\b');
+ break;
+ case KEY_ENTER:
+ switch (ssm(SCI_GETEOLMODE)) {
+ case SC_EOL_CR:
+ cmdline_keypress('\r');
+ break;
+ case SC_EOL_CRLF:
+ cmdline_keypress('\r');
+ /* fall through */
+ case SC_EOL_LF:
+ default:
+ cmdline_keypress('\n');
+ }
+ break;
+ default:
+ if (key <= 0xFF)
+ cmdline_keypress((gchar)key);
+ }
+ }
+}
+
+InterfaceNCurses::~InterfaceNCurses()
+{
+ scintilla_delete(sci);
+ delwin(sci_window);
+
+ delwin(cmdline_window);
+ delwin(msg_window);
+
+ if (popup_window)
+ delwin(popup_window);
+ if (popup_list)
+ g_slist_free(popup_list);
+
+ endwin();
+}
+
+/*
+ * Callbacks
+ */
+
+static void
+scnotification(Scintilla *view, int i, void *p1, void *p2)
+{
+ /* TODO */
+}