/* * Copyright (C) 2012-2015 Robin Haberkorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #ifdef EMSCRIPTEN #include #endif #include "sciteco.h" #include "cmdline.h" #include "qregisters.h" #include "ring.h" #include "interface.h" #include "interface-curses.h" namespace SciTECO { extern "C" { static void scintilla_notify(Scintilla *sci, int idFrom, void *notify, void *user_data); } #define UNNAMED_FILE "(Unnamed)" #define SCI_COLOR_ATTR(f, b) \ ((attr_t)COLOR_PAIR(SCI_COLOR_PAIR(f, b))) void ViewCurses::initialize_impl(void) { WINDOW *window; /* NOTE: Scintilla initializes color pairs */ sci = scintilla_new(scintilla_notify); window = get_window(); /* * Window must have dimension before it can be * positioned. * Perhaps it's better to leave the window * unitialized and set the position in * InterfaceCurses::show_view(). */ wresize(window, 1, 1); /* Set up window position: never changes */ mvwin(window, 1, 0); setup(); } void InterfaceCurses::main_impl(int &argc, char **&argv) { init_screen(); 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); msg_window = newwin(1, 0, LINES - 2, 0); cmdline_window = newwin(0, 0, LINES - 1, 0); #ifdef EMSCRIPTEN nodelay(cmdline_window, TRUE); #else #ifndef PDCURSES_WIN32A /* workaround: endwin() is somewhat broken in the win32a port */ endwin(); #endif #endif } #ifdef __PDCURSES__ void InterfaceCurses::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 InterfaceCurses::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 InterfaceCurses::resize_all_windows(void) { int lines, cols; /* screen dimensions */ getmaxyx(stdscr, lines, cols); wresize(info_window, 1, cols); wresize(current_view->get_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(); msg_clear(); /* FIXME: use saved message */ popup_clear(); draw_cmdline(); } void InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap) { 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 */ 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); } void InterfaceCurses::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); } void InterfaceCurses::show_view_impl(ViewCurses *view) { int lines, cols; /* screen dimensions */ current_view = view; /* * screen size might have changed since * this view's WINDOW was last active */ getmaxyx(stdscr, lines, cols); wresize(current_view->get_window(), lines - 3, cols); } void InterfaceCurses::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); } void InterfaceCurses::info_update_impl(const QRegister *reg) { g_free(info_current); info_current = g_strdup_printf("%s - %s", PACKAGE_NAME, reg->name); draw_info(); } void InterfaceCurses::info_update_impl(const Buffer *buffer) { g_free(info_current); info_current = g_strdup_printf("%s - %s%s", PACKAGE_NAME, buffer->filename ? : UNNAMED_FILE, buffer->dirty ? "*" : ""); draw_info(); } void InterfaceCurses::format_chr(chtype *&target, gchar chr, attr_t attr) { /* * 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; } } } 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_current[cmdline_len++] = ' ' | A_REVERSE; } draw_cmdline(); } 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); HTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="interface-curses.cpp" Content-Disposition: inline; filename="interface-curses.cpp" Content-Disposition: inline; filename="interface-curses.cpp" Content-Length: 14817 Content-Length: 14817 Content-Length: 14817 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Thu, 16 Oct 2025 12:17:07 UTC ETag: "dd08e8f0dc4db2bf588ecef3855f32df7af6195b" ETag: "dd08e8f0dc4db2bf588ecef3855f32df7af6195b" ETag: "dd08e8f0dc4db2bf588ecef3855f32df7af6195b" Expires: Sun, 14 Oct 2035 12:17:07 GMT Expires: Sun, 14 Oct 2035 12:17:07 GMT Expires: Sun, 14 Oct 2035 12:17:07 GMT Last-Modified: Thu, 16 Oct 2025 12:17:07 GMT Last-Modified: Thu, 16 Oct 2025 12:17:07 GMT Last-Modified: Thu, 16 Oct 2025 12:17:07 GMT Server: OpenBSD httpd Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff /* * Copyright (C) 2012-2015 Robin Haberkorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #ifdef EMSCRIPTEN #include #endif #include "sciteco.h" #include "cmdline.h" #include "qregisters.h" #include "ring.h" #include "interface.h" #include "interface-curses.h" namespace SciTECO { extern "C" { static void scintilla_notify(Scintilla *sci, int idFrom, void *notify, void *user_data); } #define UNNAMED_FILE "(Unnamed)" #define SCI_COLOR_ATTR(f, b) \ ((attr_t)COLOR_PAIR(SCI_COLOR_PAIR(f, b))) void ViewCurses::initialize_impl(void) { WINDOW *window; /* NOTE: Scintilla initializes color pairs */ sci = scintilla_new(scintilla_notify); window = get_window(); /* * Window must have dimension before it can be * positioned. * Perhaps it's better to leave the window * unitialized and set the position in * InterfaceCurses::show_view(). */ wresize(window, 1, 1); /* Set up window position: never changes */ mvwin(window, 1, 0); setup(); } void InterfaceCurses::main_impl(int &argc, char **&argv) { init_screen(); 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); msg_window = newwin(1, 0, LINES - 2, 0); cmdline_window = newwin(0, 0, LINES - 1, 0); #ifdef EMSCRIPTEN nodelay(cmdline_window, TRUE); #else #ifndef PDCURSES_WIN32A /* workaround: endwin() is somewhat broken in the win32a port */ endwin(); #endif #endif } #ifdef __PDCURSES__ void InterfaceCurses::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 InterfaceCurses::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 InterfaceCurses::resize_all_windows(void) { int lines, cols; /* screen dimensions */ getmaxyx(stdscr, lines, cols); wresize(info_window, 1, cols); wresize(current_view->get_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(); msg_clear(); /* FIXME: use saved message */ popup_clear(); draw_cmdline(); } void InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap) { 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 */ 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); } void InterfaceCurses::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); } void InterfaceCurses::show_view_impl(ViewCurses *view) { int lines, cols; /* screen dimensions */ current_view = view; /* * screen size might have changed since * this view's WINDOW was last active */ getmaxyx(stdscr, lines, cols); wresize(current_view->get_window(), lines - 3, cols); } void InterfaceCurses::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); } void InterfaceCurses::info_update_impl(const QRegister *reg) { g_free(info_current); info_current = g_strdup_printf("%s - %s", PACKAGE_NAME, reg->name); draw_info(); } void InterfaceCurses::info_update_impl(const Buffer *buffer) { g_free(info_current); info_current = g_strdup_printf("%s -