/*
* 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 -