aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2015-06-18 16:24:32 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2015-06-22 04:05:02 +0200
commit8101cec729c07fd5bdeda70c12dbb43a2383cbe8 (patch)
tree41b212abb27bfe432e9de526425651c35652577a
parent5cc4daf4d51c4f17a824bd8a3ce04257e865f02c (diff)
downloadsciteco-8101cec729c07fd5bdeda70c12dbb43a2383cbe8.tar.gz
major Curses UI revision: initialize curses as late as possible
* relies on a patched version of Scinterm that allows you to construct Scintilla objects, send messages etc. before Curses is initialized. The Scintilla and Scinterm submodules have been updated. * This once and for all fixes batch mode and stdio redirections in batch mode on all Curses platforms and operating systems. * Fixes the ^C-does-not-interrupt bug on ncurses/UNIX. See #4. * On ncurses/UNIX we will still do a newterm()-initialization. This allows us to keep stdout/stderr alone in case they are redirected. This effectively allows redirecting SciTECO's output into a file even in interactive mode. ncurses/UNIX now behaves like, e.g. PDCurses/win32a and GTK+ in this regard. * Curses environment variable handling fixed. The environment registers are exported into the process environment so that Curses environment variables can be set/modified by the SciTECO profile. * Use term.h for accessing terminfo now. Explained set_window_title() limitations. * fixed interruption via SIGINT. If the UI is waiting for user input, SIGINT is effectively ignored instead of letting the next character fail always. * Updated sciteco(1) and sciteco(7): More options, environment variables and signals documented. Also rewritten DESCRIPTION section (different modes of operation).
-rw-r--r--doc/sciteco.1.in133
-rw-r--r--doc/sciteco.7.template8
m---------scintilla0
-rw-r--r--src/interface-curses.cpp413
-rw-r--r--src/interface-curses.h11
-rw-r--r--src/qregisters.cpp51
-rw-r--r--src/qregisters.h1
7 files changed, 380 insertions, 237 deletions
diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in
index ef49579..5b4c1e0 100644
--- a/doc/sciteco.1.in
+++ b/doc/sciteco.1.in
@@ -14,13 +14,13 @@ Scintilla-based \fBT\fPext \fBE\fPditor and \fBCO\fPrrector
.SH SYNOPSIS
.
.SY @PACKAGE@
-.OP \-h|\-\-help
-.OP \-e|\-\-eval macro
-.OP \-m|\-\-mung file
-.OP \-\-no\-profile
-.OP \-\-
-.RI [ argument
-.IR .\|.\|. ]
+.OP "-h|--help"
+.OP "-e|--eval" macro
+.OP "-m|--mung" file
+.OP "--no-profile"
+.RI [ "UI option .\|.\|." ]
+.OP "--"
+.RI [ "argument .\|.\|." ]
.YS
.
.
@@ -39,14 +39,14 @@ natively supports Microsoft Windows NT\*(Tm.
.LP
When executed, \*(ST mungs (executes) the TECO macro stored in the file
specified by the
-.B \-\-mung
-option.
-The munged file is executed in non-interactive
-.RI ( batch )
+.B "--mung"
+option or the macro specified via
+.B "--eval"
+respectively.
+Munged files and macros are executed in non-interactive (\fIbatch\fP)
mode, allowing the user to write stand-alone TECO scripts.
-In contrast to ordinary macro execution,
-if the first two characters of the file are \(lq#!\(rq its first line
-is ignored.
+Only when munging files as opposed to other means of executing macros,
+the first line is ignored if it begins with \(lq#!\(rq.
Therefore under UNIX-like operating systems, TECO macro files may be
invoked as scripts by using a Hashbang line like
.RS
@@ -54,13 +54,6 @@ invoked as scripts by using a Hashbang line like
#!@bindir@/sciteco -m
.EE
.RE
-If the munged macro does not request program termination using the
-.I EX
-command, \*(ST will automatically switch into its graphical
-.I interactive
-mode.
-\*(ST may be built with different graphical user interfaces,
-including Curses and GTK+ based ones.
.
.LP
Upon startup \*(ST's buffer ring contains only one unnamed empty buffer.
@@ -71,25 +64,58 @@ the buffer.
In any case the current buffer position (called
.IR dot )
is left at the beginning of the buffer.
-Optionally \(lq\-\-\(rq might be used to separate \*(ST options and
+Optionally \(lq\-\-\(rq might be used to explicitly separate \*(ST options and
macro arguments.
.
.LP
-Batch mode also has the following differences compared to interactive mode:
+If the munged macro does not request program termination using the
+\fBEX\fP command, \*(ST will automatically switch into its graphical
+\fIinteractive\fP mode.
+\*(ST may be built with different graphical user interfaces,
+including Curses and GTK+ based ones.
+Eventually when the user terminates interactive mode by calling
+\fBEX\fP, \*(ST will return to its batch mode before exiting.
+\*(ST macros may still execute in batch mode after leaving
+interactive mode and shutting down any GUI if the user has configured
+\fBED\fP hooks (see \fBsciteco\fP(7)).
+.
+.LP
+The differences between \fIbatch\fP and \fIinteractive\fP mode
+are outlined below:
.RS
.IP \(bu
-Messages are logged to
-.I stdout
-or
-.I stderr
-prefixed with a string signifying message severity.
+In batch mode, no terminal interaction takes place beyond writing
+plain-text messages to the \fIstdout\fP and \fIstderr\fP file descriptors.
+\fIstdin\fP is currently not read in batch mode.
+It is therefore safe to redirect \*(ST's \fIstdout\fP or \fIstderr\fP
+into files or pipes.
+On most UIs, it is even safe to redirect \fIstdout\fP or \fIstderr\fP
+if \*(ST enters interactive mode.
+Depending on the GUI compiled into \*(ST, either nothing is written
+to these streams while in interactive mode, or messages are continued to
+be written to these streams (in addition to being displayed in the GUI).
+.IP \(bu
+Messages logged to \fIstdout\fP or \fIstderr\fP \(em except
+for messages written explicitly via some \*(ST command \(em
+are prefixed with a string signifying the message's severity.
+In interactive mode, messages are also shown in a GUI-dependant
+manner.
+.IP \(bu
+In batch mode, any \*(ST command failure will terminate the program.
+A full stack trace of \*(ST macro invocations will be printed to
+\fIstderr\fP and the process' return code will signify failure.
+In interactive mode, \*(ST will \(lqrub out\(rq any character
+resulting in a command failure.
.IP \(bu
-Any error will terminate the program.
+The interactive mode enables character rub-out and thus undoing
+of command side-effects.
+Therefore code runs significantly slower in interactive mode
+and all algorithms have non-constant memory requirements
+as they will constantly accumulate \(lqundo tokens\(rqP.
+Batch mode does not have these restrictions.
.IP \(bu
-Character rubout is disabled.
-Therefore code runs significantly faster than in interactive mode
-and less care needs to be taken regarding memory clutter due to
-undo token accumulation.
+A few commands that modify the command line are only available
+in interactive mode.
.RE
.
.LP
@@ -134,6 +160,10 @@ munging an empty file.
This is useful to fix up a broken profile script.
This option has no effect when a file is explicitly munged with
.BR \-\-mung .
+.IP "\fIUI options .\|.\|.\fP"
+Some graphical user interfaces, notably GTK+, provide
+additional command line options.
+Execute \(lqsciteco --help\(rq for more details.
.
.
.SH EXIT STATUS
@@ -209,6 +239,43 @@ working directory of \*(ST when it starts up while macros
can work with the corresponding registers to locate files
even when the working directory of \*(ST is changed later on.
.
+.LP
+Additionally \*(ST may be influenced by the
+.UR https://developer.gnome.org/glib/stable/glib-running.html
+environment variables accessed by glib
+.UE .
+On a Curses UI, there are other important environment variables
+like \fBTERM\fP, \fBLINES\fP and \fBCOLUMNS\fP that may be
+accesses when \*(ST enters interactive mode.
+For ncurses, see section \fBENVIRONMENT\fP in
+.BR ncurses (3NCURSES)
+for details.
+\*(ST exports the environment registers into the process
+environment before initializing Curses, so these variables
+can be modified in the profile macro.
+.
+.
+.SH SIGNALS
+.
+\*(ST currently reacts to the following signals or uses them
+internally:
+.TP
+.B SIGINT
+Interrupts the currently running macro.
+The character resulting in the macro execution will fail
+causing \*(ST to exit in batch mode, or reject the character
+resulting in the execution when in interactive mode.
+For instance, this signal will interrupt long-running loops.
+If the GUI is waiting on user input, this signal is effectively
+ignored.
+Some GUIs may depend on delivery of \fBSIGINT\fP when \fB^C\fP
+is pressed in order to interrupt macros interactively.
+Note that this signal can usually also be generated when pressing
+\fB^C\fP on the process (also if there is a graphical window).
+This is useful for GUIs that do not yet support interruptions
+directly.
+.
+.
.SH FILES
.
.TP
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index 79b2eff..b777143 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -503,11 +503,13 @@ T};T{
.B "Not a real immediate editing command."
Will interrupt the current operation (character processing),
yielding a \*(ST error.
-It depends on asynchronous delivery of the
+On some GUIs it depends on asynchronous delivery of the
.B SIGINT
signal and is useful to interrupt infinite loops.
-Therefore with GUI user interfaces, the signal might has to be
-delivered via the attached console or from another process.
+Since not all user interfaces support interruptions via
+\fB^C\fP, it may be necessary to deliver the signal by
+pressing \fB^C\fP on the attached console or by explicitly
+sending it.
If \*(ST is not busy,
.B ^C
is self-inserting and might be used as a regular command.
diff --git a/scintilla b/scintilla
-Subproject 3c9eb812dc69b5b0d1e8cef3c8823e25f8e15d2
+Subproject 489243b18a6b377c571d9208c59a433eec7cd53
diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp
index 1dcca8f..9114422 100644
--- a/src/interface-curses.cpp
+++ b/src/interface-curses.cpp
@@ -30,8 +30,21 @@
#include <glib/gprintf.h>
#include <glib/gstdio.h>
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#endif
+
#include <curses.h>
+#ifdef HAVE_TIGETSTR
+#include <term.h>
+
+/*
+ * Some macros in term.h interfere with our code.
+ */
+#undef lines
+#endif
+
#include <Scintilla.h>
#include <ScintillaTerm.h>
@@ -63,12 +76,19 @@
#define PDCURSES_WIN32
#endif
+#ifdef NCURSES_VERSION
+#ifdef G_OS_UNIX
+/**
+ * Whether we're on ncurses/UNIX
+ */
+#define NCURSES_UNIX
+#elif defined(G_OS_WIN32)
/**
* Whether we're on ncurses/win32 console
*/
-#if defined(NCURSES_VERSION) && defined(G_OS_WIN32)
#define NCURSES_WIN32
#endif
+#endif
namespace SciTECO {
@@ -79,202 +99,182 @@ static void scintilla_notify(Scintilla *sci, int idFrom,
#define UNNAMED_FILE "(Unnamed)"
+/**
+ * Curses attribute for the color combination
+ * `f` (foreground) and `b` (background)
+ * according to the color pairs initialized by
+ * Scinterm.
+ * NOTE: This depends on the global variable
+ * `COLORS` and is thus not a constant expression.
+ */
#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_batch();
-
/*
- * We're in prog mode, so we must set it up
- * now, even though we're also in SciTECO batch mode.
- * This is because endwin() saves the prog mode
- * and Curses restores it automatically.
+ * Make sure we have a string for the info line
+ * even if info_update() is never called.
*/
- cbreak();
- noecho();
- /* Scintilla draws its own cursor */
- curs_set(0);
-
- 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);
-#elif !defined(PDCURSES_WIN32A)
- /* workaround: endwin() is somewhat broken in the win32a port */
- endwin();
-#endif
}
-#if defined(__PDCURSES__) || !defined(G_OS_UNIX)
+#ifdef NCURSES_UNIX
void
-InterfaceCurses::init_batch(void)
+InterfaceCurses::init_screen(void)
{
-#ifdef PDCURSES_WIN32A
- /* enables window resizing on Win32a port */
- PDC_set_resize_limits(25, 0xFFFF, 80, 0xFFFF);
-#endif
+ screen_tty = g_fopen("/dev/tty", "r+");
+ /* should never fail */
+ g_assert(screen_tty != NULL);
-#ifdef NCURSES_WIN32
- /* $TERM must be unset for the win32 driver to load */
- g_unsetenv("TERM");
-#endif
+ screen = newterm(NULL, screen_tty, screen_tty);
+ if (!screen) {
+ g_fprintf(stderr, "Error initializing interactive mode. "
+ "$TERM may be incorrect.\n");
+ exit(EXIT_FAILURE);
+ }
/*
- * PDCurses cannot support terminal redirection
- * into files, nor can it support multiple terminals.
- * So we do a classic Curses initialization here.
- * Unfortunately, this clears the screen in
- * PDCurses/win32, so that batch mode is somewhat
- * broken there.
+ * If stdout or stderr would go to the terminal,
+ * redirect it. Otherwise, they are already redirected
+ * (e.g. to a file) and writing to them does not
+ * interrupt terminal interaction.
*/
- initscr();
+ if (isatty(1)) {
+ FILE *stdout_new;
+ stdout_orig = dup(1);
+ g_assert(stdout_orig >= 0);
+ stdout_new = g_freopen("/dev/null", "a+", stdout);
+ g_assert(stdout_new != NULL);
+ }
+ if (isatty(2)) {
+ FILE *stderr_new;
+ stderr_orig = dup(2);
+ g_assert(stderr_orig >= 0);
+ stderr_new = g_freopen("/dev/null", "a+", stderr);
+ g_assert(stderr_new != NULL);
+ }
}
+#else
+
void
-InterfaceCurses::init_interactive(void)
+InterfaceCurses::init_screen(void)
{
- /*
- * Nothing to do, we are already controlling the
- * terminal.
- */
+ initscr();
}
-#else /* UNIX, no PDCurses */
+#endif
void
-InterfaceCurses::init_batch(void)
+InterfaceCurses::init_interactive(void)
{
/*
- * NOTE: It's still safe to use g_getenv().
- * Actually the process environment has not yet been
- * imported into the Q-Register table.
- * Also, the batch mode initialization will be
- * simplified soon, anyway.
+ * Curses accesses many environment variables
+ * internally. In order to be able to modify them in
+ * the SciTECO profile, we must update the process
+ * environment before initscr()/newterm().
+ * This is safe to do here since there are no threads.
*/
- const gchar *term = g_getenv("TERM");
+ QRegisters::globals.update_environ();
+#ifdef NCURSES_WIN32
/*
- * In headless or broken environments,
- * $TERM may be unset or empty.
- * Still batch-mode operation is supposed
- * to work.
- * Therefore we initialize Curses with
- * a terminal type that ensures it will at least
- * start up ("ansi" is in ncurses-base).
- * We do not always use "ansi" since
- * it is also not guaranteed to work and we cannot
- * change it later on.
+ * $TERM must be unset for the win32 driver to load.
+ * So we always ignore any $TERM changes by the user.
*/
- if (!term || !*term)
- term = "ansi";
+ //g_unsetenv("TERM");
+ // May be necessary to set window title on ncurses/win32
+ g_setenv("TERM", "#win32con", TRUE);
+#endif
- /*
- * This sets stdscr to a new screen associated
- * with /dev/null.
- * This way we get ncurses to leave the current
- * controlling tty alone, while still initializing
- * Curses (required by Scintilla and thus for
- * batch processing).
- */
- screen_tty = g_fopen("/dev/null", "r+");
- /* should never fail */
- g_assert(screen_tty != NULL);
+#ifdef PDCURSES_WIN32A
+ /* enables window resizing on Win32a port */
+ PDC_set_resize_limits(25, 0xFFFF, 80, 0xFFFF);
+#endif
- setvbuf(screen_tty, NULL, _IOFBF, 0);
+ /* for displaying UTF-8 characters properly */
+ setlocale(LC_CTYPE, "");
- screen = newterm(term, screen_tty, screen_tty);
- if (!screen) {
- /* $TERM may be set but to a wrong value */
- g_fprintf(stderr, "Error initializing batch mode. "
- "$TERM may be incorrent.\n"
- "Try unsetting it if you do not need "
- "the interactive mode.\n");
- exit(EXIT_FAILURE);
- }
+ init_screen();
+
+ cbreak();
+ noecho();
+ /* Scintilla draws its own cursor */
+ curs_set(0);
+
+ info_window = newwin(1, 0, 0, 0);
+
+ msg_window = newwin(1, 0, LINES - 2, 0);
- def_shell_mode();
+ cmdline_window = newwin(0, 0, LINES - 1, 0);
+
+#ifdef EMSCRIPTEN
+ nodelay(cmdline_window, TRUE);
+#endif
+
+ /*
+ * Will also initialize Scinterm, Curses color pairs
+ * and resizes the current view.
+ */
+ if (current_view)
+ show_view(current_view);
}
void
-InterfaceCurses::init_interactive(void)
+InterfaceCurses::restore_batch(void)
{
- const gchar *term = g_getenv("TERM");
+ /*
+ * Set window title to a reasonable default,
+ * in case it is not reset immediately by the
+ * shell.
+ * FIXME: See set_window_title() why this
+ * is necessary.
+ */
+#if defined(NCURSES_UNIX) && defined(HAVE_TIGETSTR)
+ set_window_title(g_getenv("TERM") ? : "");
+#endif
/*
- * At least try to report a broken $TERM.
- * g_getenv() may still be used here since we must refer to
- * same value as used in init_batch() as opposed to the
- * current value of the "$TERM" register.
- * Also, this code will have to be simplified soon, anyway.
+ * Restore ordinary terminal behaviour
+ * (i.e. return to batch mode)
*/
- if (!term || !*term) {
- g_fprintf(stderr, "Error initializing interactive mode: "
- "$TERM is unset or empty.\n");
- exit(EXIT_FAILURE);
- }
+ endwin();
/*
- * Reopen screen_tty on the real terminal
- * device.
- * NOTE: It would be better to create a new
- * terminal with newterm() since the current
- * terminal might still be configured as
- * "ansi" to get the batch mode working.
- * If this is the case because we are in a head-less
- * or broken environment NOW would be the time
- * to tell the user.
- * However, I cannot get ncurses to switch
- * to a new terminal. Perhaps existing windows are
- * somehow "bound" to the current screen.
- * Perhaps this only works if we delete and recreate
- * ALL windows...
+ * Restore stdout and stderr, so output goes to
+ * the terminal again in case we "muted" them.
*/
- if (!g_freopen("/dev/tty", "r+", screen_tty)) {
- /* no controlling terminal? */
- g_fprintf(stderr, "Error initializing interactice mode: %s\n",
- g_strerror(errno));
- exit(EXIT_FAILURE);
+#ifdef NCURSES_UNIX
+ if (stdout_orig >= 0) {
+ int fd = dup2(stdout_orig, 1);
+ g_assert(fd == 1);
+ }
+ if (stderr_orig >= 0) {
+ int fd = dup2(stderr_orig, 2);
+ g_assert(fd == 2);
}
+#endif
- def_shell_mode();
+ /*
+ * See vmsg_impl(): It looks at msg_win to determine
+ * whether we're in batch mode.
+ */
+ if (msg_window) {
+ delwin(msg_window);
+ msg_window = NULL;
+ }
}
-#endif
-
void
InterfaceCurses::resize_all_windows(void)
{
@@ -299,37 +299,50 @@ InterfaceCurses::resize_all_windows(void)
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 */
- };
+ attr_t attr;
-#ifdef PDCURSES_WIN32A
+ /*
+ * On most platforms we can write to stdout/stderr
+ * even in interactive mode.
+ */
+#if defined(PDCURSES_WIN32A) || defined(NCURSES_UNIX)
stdio_vmsg(type, fmt, ap);
- if (isendwin()) /* batch mode */
+ if (!msg_window) /* batch mode */
return;
#else
- if (isendwin()) { /* batch mode */
+ if (!msg_window) { /* batch mode */
stdio_vmsg(type, fmt, ap);
return;
}
#endif
+ switch (type) {
+ default:
+ case MSG_USER:
+ attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE);
+ break;
+ case MSG_INFO:
+ attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_GREEN);
+ break;
+ case MSG_WARNING:
+ attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_YELLOW);
+ break;
+ case MSG_ERROR:
+ attr = SCI_COLOR_ATTR(COLOR_BLACK, COLOR_RED);
+ beep();
+ break;
+ }
+
wmove(msg_window, 0, 0);
- wbkgdset(msg_window, ' ' | type2attr[type]);
+ wbkgdset(msg_window, ' ' | attr);
vw_printw(msg_window, fmt, ap);
wclrtoeol(msg_window);
-
- if (type == MSG_ERROR)
- beep();
}
void
InterfaceCurses::msg_clear(void)
{
- if (isendwin()) /* batch mode */
+ if (!msg_window) /* batch mode */
return;
wmove(msg_window, 0, 0);
@@ -341,16 +354,23 @@ void
InterfaceCurses::show_view_impl(ViewCurses *view)
{
int lines, cols; /* screen dimensions */
+ WINDOW *current_view_win;
current_view = view;
+ if (!cmdline_window) /* batch mode */
+ return;
+
+ current_view_win = current_view->get_window();
+
/*
* 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);
+ wresize(current_view_win, lines - 3, cols);
+ /* Set up window position: never changes */
+ mvwin(current_view_win, 1, 0);
}
#if PDCURSES
@@ -361,19 +381,12 @@ InterfaceCurses::set_window_title(const gchar *title)
PDC_set_title(title);
}
-#elif defined(HAVE_TIGETSTR) && defined(G_OS_UNIX)
+#elif defined(HAVE_TIGETSTR)
void
InterfaceCurses::set_window_title(const gchar *title)
{
- /*
- * NOTE: terminfo variables in term.h interfere with
- * the rest of our code
- */
- const char *tsl = tigetstr((char *)"tsl");
- const char *fsl = tigetstr((char *)"fsl");
-
- if (!tsl || !fsl)
+ if (!has_status_line || !to_status_line || !from_status_line)
return;
/*
@@ -381,17 +394,37 @@ InterfaceCurses::set_window_title(const gchar *title)
* the historic status line.
* This feature is not standardized in ncurses,
* so we query the terminfo database.
- * NOTE: The terminfo manpage advises us to use putp(),
- * but I don't feel comfortable with writing to stdout.
+ * This feature may make problems with terminal emulators
+ * that do support a status line but do not map them
+ * to the window title. Some emulators (like xterm)
+ * support setting the window title via custom escape
+ * sequences and via the status line but their
+ * terminfo entry does not say so. (xterm can also
+ * save and restore window titles but there is not
+ * even a terminfo capability defined for this.)
+ * Taken the different emulator incompatibilites
+ * it may be best to make this configurable.
+ * Once we support configurable status lines,
+ * there could be a special status line that's sent
+ * to the terminal that may be set up in the profile
+ * depending on $TERM.
+ *
+ * NOTE: The terminfo manpage advises us to use putp()
+ * but on ncurses/UNIX (where terminfo is available),
+ * we do not let curses write to stdout.
* NOTE: This leaves the title set after we quit.
- * xterm has escape sequences to save/restore a window title,
- * but there do not seem to be terminfo capabilities for that.
- * NOTE: Resetting the title does not always work ;-)
*/
- fputs(tsl, screen_tty);
- fputs(info_current, screen_tty);
- fputs(fsl, screen_tty);
+#ifdef G_OS_UNIX
+ fputs(to_status_line, screen_tty);
+ fputs(title, screen_tty);
+ fputs(from_status_line, screen_tty);
fflush(screen_tty);
+#else /* presumably ncurses/win32 */
+ putp(to_status_line);
+ putp(title);
+ putp(from_status_line);
+ //fflush(stdout);
+#endif
}
#else
@@ -407,7 +440,7 @@ InterfaceCurses::set_window_title(const gchar *title)
void
InterfaceCurses::draw_info(void)
{
- if (isendwin()) /* batch mode */
+ if (!info_window) /* batch mode */
return;
wmove(info_window, 0, 0);
@@ -494,7 +527,7 @@ InterfaceCurses::cmdline_update_impl(const Cmdline *cmdline)
* Also A_UNDERLINE is not supported by PDCurses/win32
* and causes weird colors, so we better leave it away.
*/
- static const attr_t rubout_attr =
+ const attr_t rubout_attr =
#ifndef PDCURSES_WIN32
A_UNDERLINE |
#endif
@@ -558,7 +591,7 @@ InterfaceCurses::popup_add_impl(PopupEntryType type,
{
gchar *entry;
- if (isendwin()) /* batch mode */
+ if (!cmdline_window) /* batch mode */
return;
entry = g_strconcat(highlight ? "*" : " ", name, NIL);
@@ -578,7 +611,7 @@ InterfaceCurses::popup_show_impl(void)
gint popup_colwidth;
gint cur_col;
- if (isendwin() || !popup.length)
+ if (!cmdline_window || !popup.length)
/* batch mode or nothing to display */
return;
@@ -699,6 +732,7 @@ event_loop_iter()
raw();
key = wgetch(interface.cmdline_window);
/* allow asynchronous interruptions on <CTRL/C> */
+ sigint_occurred = FALSE;
cbreak();
if (key == ERR)
return;
@@ -764,8 +798,6 @@ event_loop_iter()
cmdline.keypress((gchar)key);
}
- sigint_occurred = FALSE;
-
/*
* Info window is updated very often which is very
* costly, especially when using PDC_set_title(),
@@ -825,24 +857,7 @@ InterfaceCurses::event_loop_impl(void)
/* SciTECO termination (e.g. EX$$) */
}
- /*
- * Set window title to a reasonable default,
- * in case it is not reset immediately by the
- * shell.
- * FIXME: It may be unsafe to access $TERM here
- * and the value of Q-Register $TERM may have
- * diverged. This should be adapted once we rewrite
- * batch-mode initialization!
- */
-#if !PDCURSES && defined(HAVE_TIGETSTR)
- set_window_title(g_getenv("TERM") ? : "");
-#endif
-
- /*
- * Restore ordinary terminal behaviour
- * (i.e. return to batch mode)
- */
- endwin();
+ restore_batch();
#endif
}
@@ -873,6 +888,10 @@ InterfaceCurses::~InterfaceCurses()
delscreen(screen);
if (screen_tty)
fclose(screen_tty);
+ if (stderr_orig >= 0)
+ close(stderr_orig);
+ if (stdout_orig >= 0)
+ close(stdout_orig);
}
/*
diff --git a/src/interface-curses.h b/src/interface-curses.h
index 971d2fa..471b462 100644
--- a/src/interface-curses.h
+++ b/src/interface-curses.h
@@ -44,8 +44,8 @@ public:
{
/*
* NOTE: This deletes/frees the view's
- * curses WINDOW, despite of what Scinterm's
- * documentation says.
+ * curses WINDOW, despite of what old versions
+ * of the Scinterm documentation claim.
*/
if (sci)
scintilla_delete(sci);
@@ -72,6 +72,7 @@ public:
} ViewCurrent;
typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> {
+ int stdout_orig, stderr_orig;
SCREEN *screen;
FILE *screen_tty;
@@ -100,7 +101,8 @@ typedef class InterfaceCurses : public Interface<InterfaceCurses, ViewCurses> {
} popup;
public:
- InterfaceCurses() : screen(NULL),
+ InterfaceCurses() : stdout_orig(-1), stderr_orig(-1),
+ screen(NULL),
screen_tty(NULL),
info_window(NULL),
info_current(NULL),
@@ -146,8 +148,9 @@ public:
void event_loop_impl(void);
private:
- void init_batch(void);
+ void init_screen(void);
void init_interactive(void);
+ void restore_batch(void);
void resize_all_windows(void);
diff --git a/src/qregisters.cpp b/src/qregisters.cpp
index 22d7300..ef47627 100644
--- a/src/qregisters.cpp
+++ b/src/qregisters.cpp
@@ -529,6 +529,16 @@ QRegisterTable::edit(QRegister *reg)
QRegisters::current = reg;
}
+/**
+ * Import process environment into table
+ * by setting environment registers for every
+ * environment variable.
+ * It is assumed that the table does not yet
+ * contain any environment register.
+ *
+ * In general this method is only safe to call
+ * at startup.
+ */
void
QRegisterTable::set_environ(void)
{
@@ -553,6 +563,13 @@ QRegisterTable::set_environ(void)
g_strfreev(env);
}
+/**
+ * Export environment registers as a list of environment
+ * variables compatible with `g_get_environ()`.
+ *
+ * @return Zero-terminated list of strings in the form
+ * `NAME=VALUE`. Should be freed with `g_strfreev()`.
+ */
gchar **
QRegisterTable::get_environ(void)
{
@@ -601,6 +618,40 @@ QRegisterTable::get_environ(void)
}
/**
+ * Update process environment with environment registers
+ * using `g_setenv()`.
+ * It does not try to unset environment variables that
+ * are no longer in the Q-Register table.
+ *
+ * This method may be dangerous in a multi-threaded environment
+ * but may be necessary for libraries that access important
+ * environment variables internally without providing alternative
+ * APIs.
+ */
+void
+QRegisterTable::update_environ(void)
+{
+ for (QRegister *cur = nfind("$");
+ cur && cur->name[0] == '$';
+ cur = (QRegister *)cur->next()) {
+ gchar *value;
+
+ /*
+ * Ignore the "$" register (not an environment
+ * variable register) and registers whose
+ * name contains "=" (not allowed in environment
+ * variable names).
+ */
+ if (!cur->name[1] || strchr(cur->name+1, '='))
+ continue;
+
+ value = cur->get_string();
+ g_setenv(cur->name+1, value, TRUE);
+ g_free(value);
+ }
+}
+
+/**
* Free resources associated with table.
*
* This is similar to RBTree::clear() but
diff --git a/src/qregisters.h b/src/qregisters.h
index 0ca230e..dc560b8 100644
--- a/src/qregisters.h
+++ b/src/qregisters.h
@@ -308,6 +308,7 @@ public:
void set_environ(void);
gchar **get_environ(void);
+ void update_environ(void);
void clear(void);
};