aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/interface-ncurses.cpp
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-12-04 17:29:01 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-12-04 22:07:08 +0100
commitd8a316514c03d85b771a9dce4a8a51b875d955b3 (patch)
tree8966c29db767a155848f6d90f76771ce5b9de32e /src/interface-ncurses.cpp
parentb120616b6da52e951097f69ad267de06081d218a (diff)
downloadsciteco-d8a316514c03d85b771a9dce4a8a51b875d955b3.tar.gz
autoconf preparation: move everything into src/ subdir
Diffstat (limited to 'src/interface-ncurses.cpp')
-rw-r--r--src/interface-ncurses.cpp426
1 files changed, 426 insertions, 0 deletions
diff --git a/src/interface-ncurses.cpp b/src/interface-ncurses.cpp
new file mode 100644
index 0000000..0e08914
--- /dev/null
+++ b/src/interface-ncurses.cpp
@@ -0,0 +1,426 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include <curses.h>
+/* only a hack until we have Autoconf checks */
+#if defined(__PDCURSES__) && CHTYPE_LONG >= 2
+#define PDCURSES_WIN32A
+#endif
+
+#include <Scintilla.h>
+#include <ScintillaTerm.h>
+
+#include "sciteco.h"
+#include "qregisters.h"
+#include "ring.h"
+#include "interface.h"
+#include "interface-ncurses.h"
+
+InterfaceNCurses interface;
+
+extern "C" {
+static void scintilla_notify(Scintilla *sci, int idFrom,
+ void *notify, void *user_data);
+}
+
+#define UNNAMED_FILE "(Unnamed)"
+
+/* FIXME: should be configurable in TECO (Function key substitutes) */
+#define ESCAPE_SURROGATE KEY_DC
+
+#ifndef SCI_COLOR_PAIR
+/* from ScintillaTerm.cxx */
+#define SCI_COLOR_PAIR(f, b) \
+ ((b) * 8 + (f) + 1)
+#endif
+
+#define SCI_COLOR_ATTR(f, b) \
+ COLOR_PAIR(SCI_COLOR_PAIR(f, b))
+
+InterfaceNCurses::InterfaceNCurses()
+{
+ init_screen();
+ raw();
+ cbreak();
+ noecho();
+ curs_set(0); /* Scintilla draws its own cursor */
+
+ setlocale(LC_CTYPE, ""); /* for displaying UTF-8 characters properly */
+
+ info_window = newwin(1, 0, 0, 0);
+ info_current = g_strdup(PACKAGE_NAME);
+
+ /* NOTE: Scintilla initializes color pairs */
+ sci = scintilla_new(scintilla_notify);
+ sci_window = scintilla_get_window(sci);
+ wresize(sci_window, LINES - 3, COLS);
+ mvwin(sci_window, 1, 0);
+
+ msg_window = newwin(1, 0, LINES - 2, 0);
+
+ cmdline_window = newwin(0, 0, LINES - 1, 0);
+ keypad(cmdline_window, TRUE);
+ cmdline_current = NULL;
+
+ ssm(SCI_SETFOCUS, TRUE);
+
+ draw_info();
+ /* scintilla will be refreshed in event loop */
+ msg_clear();
+ cmdline_update("");
+
+#ifndef PDCURSES_WIN32A
+ /* workaround: endwin() is somewhat broken in the win32a port */
+ endwin();
+#endif
+}
+
+#ifdef __PDCURSES__
+
+void
+InterfaceNCurses::init_screen(void)
+{
+#ifdef PDCURSES_WIN32A
+ /* enables window resizing on Win32a port */
+ PDC_set_resize_limits(25, 0xFFFF, 80, 0xFFFF);
+#endif
+
+ initscr();
+
+ screen_tty = NULL;
+ screen = NULL;
+}
+
+#else
+
+void
+InterfaceNCurses::init_screen(void)
+{
+ /*
+ * Prevent the initial redraw and any escape sequences that may
+ * interfere with stdout, so we may use the terminal in
+ * cooked mode, for commandline help and batch processing.
+ * Scintilla must be initialized for batch processing to work.
+ * (Frankly I have no idea why this works!)
+ */
+ screen_tty = g_fopen("/dev/tty", "r+b");
+ screen = newterm(NULL, screen_tty, screen_tty);
+ set_term(screen);
+}
+
+#endif /* !__PDCURSES__ */
+
+void
+InterfaceNCurses::resize_all_windows(void)
+{
+ int lines, cols; /* screen dimensions */
+
+ getmaxyx(stdscr, lines, cols);
+
+ wresize(info_window, 1, cols);
+ wresize(sci_window, lines - 3, cols);
+ wresize(msg_window, 1, cols);
+ mvwin(msg_window, lines - 2, 0);
+ wresize(cmdline_window, 1, cols);
+ mvwin(cmdline_window, lines - 1, 0);
+
+ draw_info();
+ /* scintilla will be refreshed in event loop */
+ msg_clear(); /* FIXME: use saved message */
+ cmdline_update();
+}
+
+void
+InterfaceNCurses::vmsg(MessageType type, const gchar *fmt, va_list ap)
+{
+ static const chtype 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 */
+ SCI_COLOR_ATTR(COLOR_BLACK, COLOR_RED) /* MSG_ERROR */
+ };
+
+#ifdef PDCURSES_WIN32A
+ stdio_vmsg(type, fmt, ap);
+ if (isendwin()) /* batch mode */
+ return;
+#else
+ if (isendwin()) { /* batch mode */
+ stdio_vmsg(type, fmt, ap);
+ return;
+ }
+#endif
+
+ wmove(msg_window, 0, 0);
+ wbkgdset(msg_window, ' ' | type2attr[type]);
+ vw_printw(msg_window, fmt, ap);
+ wclrtoeol(msg_window);
+
+ wrefresh(msg_window);
+}
+
+void
+InterfaceNCurses::msg_clear(void)
+{
+ if (isendwin()) /* batch mode */
+ return;
+
+ wmove(msg_window, 0, 0);
+ wbkgdset(msg_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE));
+ wclrtoeol(msg_window);
+
+ wrefresh(msg_window);
+}
+
+void
+InterfaceNCurses::draw_info(void)
+{
+ if (isendwin()) /* batch mode */
+ return;
+
+ wmove(info_window, 0, 0);
+ wbkgdset(info_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE));
+ waddstr(info_window, info_current);
+ wclrtoeol(info_window);
+
+ wrefresh(info_window);
+}
+
+void
+InterfaceNCurses::info_update(QRegister *reg)
+{
+ g_free(info_current);
+ info_current = g_strdup_printf("%s - <QRegister> %s", PACKAGE_NAME,
+ reg->name);
+
+ draw_info();
+}
+
+void
+InterfaceNCurses::info_update(Buffer *buffer)
+{
+ g_free(info_current);
+ info_current = g_strdup_printf("%s - <Buffer> %s%s", PACKAGE_NAME,
+ buffer->filename ? : UNNAMED_FILE,
+ buffer->dirty ? "*" : "");
+
+ draw_info();
+}
+
+void
+InterfaceNCurses::cmdline_update(const gchar *cmdline)
+{
+ size_t len;
+ int half_line = (getmaxx(stdscr) - 2) / 2;
+ const gchar *line;
+
+ if (cmdline) {
+ g_free(cmdline_current);
+ cmdline_current = g_strdup(cmdline);
+ } else {
+ cmdline = cmdline_current;
+ }
+ len = strlen(cmdline);
+
+ /* 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(PopupEntryType type __attribute__((unused)),
+ const gchar *name, bool highlight)
+{
+ gchar *entry;
+
+ if (isendwin()) /* batch mode */
+ return;
+
+ entry = g_strconcat(highlight ? "*" : " ", name, NULL);
+
+ popup.longest = MAX(popup.longest, (gint)strlen(name));
+ popup.length++;
+
+ popup.list = g_slist_prepend(popup.list, entry);
+}
+
+void
+InterfaceNCurses::popup_show(void)
+{
+ int lines, cols; /* screen dimensions */
+ int popup_lines;
+ gint popup_cols;
+ gint cur_file, cur_line;
+
+ if (isendwin()) /* batch mode */
+ goto cleanup;
+
+ getmaxyx(stdscr, lines, cols);
+
+ popup.longest += 3;
+ popup.list = g_slist_reverse(popup.list);
+
+ /* popup_cols = floor(cols / popup.longest) */
+ popup_cols = MAX(cols / popup.longest, 1);
+ /* popup_lines = ceil(popup.length / popup_cols) */
+ popup_lines = popup.length / popup_cols;
+ if ((popup.length % popup_cols))
+ popup_lines++;
+ popup_lines = MIN(popup_lines, lines - 1);
+
+ /* window covers message, scintilla and info windows */
+ popup.window = newwin(popup_lines, 0, lines - 1 - popup_lines, 0);
+ wbkgdset(popup.window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_BLUE));
+
+ cur_file = 0;
+ cur_line = 1;
+ 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');
+ cur_line++;
+ }
+
+ cur_file++;
+
+ if (cur_line == popup_lines && !(cur_file % popup_cols) &&
+ cur_file < popup.length) {
+ (void)wattrset(popup.window, A_BOLD);
+ waddstr(popup.window, "...");
+ break;
+ }
+
+ (void)wattrset(popup.window, *entry == '*' ? A_BOLD : A_NORMAL);
+ waddstr(popup.window, entry + 1);
+ for (int i = popup.longest - strlen(entry) + 1; i; i--)
+ waddch(popup.window, ' ');
+
+ g_free(cur->data);
+ }
+ wclrtoeol(popup.window);
+
+cleanup:
+ g_slist_free(popup.list);
+ popup.list = NULL;
+ popup.longest = popup.length = 0;
+}
+
+void
+InterfaceNCurses::popup_clear(void)
+{
+ if (!popup.window)
+ return;
+
+ redrawwin(info_window);
+ wrefresh(info_window);
+ redrawwin(sci_window);
+ scintilla_refresh(sci);
+ redrawwin(msg_window);
+ wrefresh(msg_window);
+
+ delwin(popup.window);
+ popup.window = NULL;
+}
+
+void
+InterfaceNCurses::event_loop(void)
+{
+ /* in commandline (visual) mode, enforce redraw */
+ wrefresh(curscr);
+ draw_info();
+
+ 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) {
+#ifdef KEY_RESIZE
+ case ERR:
+ case KEY_RESIZE:
+#ifdef PDCURSES
+ resize_term(0, 0);
+#endif
+ resize_all_windows();
+ break;
+#endif
+ case ESCAPE_SURROGATE:
+ cmdline_keypress('\x1B');
+ break;
+ case KEY_BACKSPACE:
+ cmdline_keypress('\b');
+ break;
+ case KEY_ENTER:
+ case '\r':
+ 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::Popup::~Popup()
+{
+ if (window)
+ delwin(window);
+ if (list)
+ g_slist_free(list);
+}
+
+InterfaceNCurses::~InterfaceNCurses()
+{
+ delwin(info_window);
+ g_free(info_current);
+ /* also deletes curses window */
+ scintilla_delete(sci);
+ delwin(cmdline_window);
+ g_free(cmdline_current);
+ delwin(msg_window);
+
+ if (!isendwin())
+ endwin();
+
+ delscreen(screen);
+ if (screen_tty)
+ fclose(screen_tty);
+}
+
+/*
+ * Callbacks
+ */
+
+static void
+scintilla_notify(Scintilla *sci, int idFrom, void *notify, void *user_data)
+{
+ interface.process_notify((SCNotification *)notify);
+}