aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2025-08-01 22:53:54 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2025-08-01 22:53:54 +0300
commitdaead48672e56af966911abc4efe1e54573c02cc (patch)
tree897a7e525882adb0e24cddcafd17bdddd0f0695d
parentca70c9061146386ce0986631cd7fc9209a935a34 (diff)
downloadsciteco-daead48672e56af966911abc4efe1e54573c02cc.tar.gz
implemented the ^W command for refreshing the screen in loops, for sleeping and also the CTRL+L immediate editing command
* ^W can be added to loops in order to view progress in interactive mode. It also sleeps for a given number of milliseconds (10ms by default). * In batch mode it is therefore the sleep command. * Since CTRL+W is an immediate editing command, you will usually type it Caret+W. ASCII 23 however will also be accepted. * While ^W only updates the screen, you can force a complete redraw by pressing CTRL+L. This is what most terminal applications use for redrawing. It will make it harder to insert ASCII 12, but this is seldom necessary since it is a form feed. ^L (ASCII 12 and the upcaret variant ) is still a whitespace character and therefore treated as a NOP. * DEC TECO had CTRL+W as the refresh immediate editing command. Video TECO uses <ET> as a regular command for refreshign in loops. I'd rather keep ET reserved as a potential terminal configuration command as in DEC TECO, though.
-rw-r--r--doc/sciteco.7.template10
-rw-r--r--src/cmdline.c5
-rw-r--r--src/core-commands.c43
-rw-r--r--src/interface-curses/interface.c24
-rw-r--r--src/interface-gtk/interface.c39
-rw-r--r--src/interface.h9
-rw-r--r--tests/testsuite.at2
7 files changed, 107 insertions, 25 deletions
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index 965e203..3bf8d2e 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -680,6 +680,16 @@ work as an immediate editing command in the GUI or as a signal
dispatched from an associated console or from another process.
T}
T{
+.SCITECO_TOPIC ^L redraw
+Redraw
+T};12;^L;T{
+Everywhere
+T};T{
+Enforces a complete redraw of the entire window.
+This is useful when the display becomes corrupted,
+especially when using the Curses UI.
+T}
+T{
.SCITECO_TOPIC interrupt
Interrupt
T};3;^C;T{
diff --git a/src/cmdline.c b/src/cmdline.c
index 605af73..1f12c7b 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -472,6 +472,11 @@ teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gun
raise(SIGTSTP);
return TRUE;
#endif
+
+ case TECO_CTL_KEY('L'):
+ /* causes a complete screen redraw */
+ teco_interface_refresh(TRUE);
+ return TRUE;
}
teco_interface_popup_clear();
diff --git a/src/core-commands.c b/src/core-commands.c
index a2d3c92..c71ee95 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -1605,6 +1605,46 @@ teco_state_control_time(teco_machine_main_t *ctx, GError **error)
}
}
+/*$ ^W refresh sleep delay wait
+ * [n]^W -- Wait and refresh screen
+ *
+ * First sleep <n> milliseconds before refreshing the view,
+ * i.e. drawing it.
+ * By default it sleeps for 10ms.
+ * This can be added to loops to make progress visible
+ * in interactive mode.
+ * In batch mode this command is useful as a sleep command.
+ * Sleeps can of course be interrupted with CTRL+C.
+ *
+ * Since CTRL+W is an immediate editing command, you may
+ * have to type this command in upcaret mode.
+ * To enforce a complete screen redraw you can also
+ * press CTRL+L.
+ */
+static void
+teco_state_control_refresh(teco_machine_main_t *ctx, GError **error)
+{
+ teco_int_t ms;
+
+ if (!teco_expressions_pop_num_calc(&ms, 10, error))
+ return;
+
+ while (ms > 0 && !teco_interface_is_interrupted()) {
+ /*
+ * UNIX' usleep() would also be interrupted by
+ * SIGINT, but polling for interruptions is
+ * probably precise enough.
+ * We need this as a fallback anyway.
+ */
+ g_usleep(MIN(ms*1000, TECO_POLL_INTERVAL));
+ ms -= TECO_POLL_INTERVAL/1000;
+ }
+
+ teco_interface_unfold();
+ teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
+ teco_interface_refresh(FALSE);
+}
+
static teco_state_t *
teco_state_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
{
@@ -1647,7 +1687,8 @@ teco_state_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
['Y'] = {&teco_state_start, teco_state_control_last_range},
['S'] = {&teco_state_start, teco_state_control_last_length},
['T'] = {&teco_state_start, teco_state_control_typeout,
- .modifier_colon = 1}
+ .modifier_colon = 1},
+ ['W'] = {&teco_state_start, teco_state_control_refresh}
};
/*
diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c
index d92eade..381c188 100644
--- a/src/interface-curses/interface.c
+++ b/src/interface-curses/interface.c
@@ -134,7 +134,6 @@ teco_console_ctrl_handler(DWORD type)
static gint teco_xterm_version(void) G_GNUC_UNUSED;
-static void teco_interface_refresh(void);
static gint teco_interface_blocking_getch(void);
#define UNNAMED_FILE "(Unnamed)"
@@ -924,7 +923,7 @@ teco_interface_getch(gboolean widechar)
if (!teco_interface.cmdline_window) /* batch mode */
return teco_interface_stdio_getch(widechar);
- teco_interface_refresh();
+ teco_interface_refresh(FALSE);
/*
* Signal that we accept input by drawing a real cursor in the message bar.
@@ -1819,8 +1818,8 @@ teco_interface_is_interrupted(void)
* filtering out CTRL+C.
* It's currently necessary as a fallback e.g. for PDCURSES_GUI or XCurses.
*
- * NOTE: Theoretically, this can be optimized by doing wgetch() only every X
- * microseconds like on Gtk+.
+ * NOTE: Theoretically, this can be optimized by doing wgetch() only every
+ * TECO_POLL_INTERVAL microseconds like on Gtk+.
* But this turned out to slow things down, at least on PDCurses/WinGUI.
*/
gboolean
@@ -1848,9 +1847,16 @@ teco_interface_is_interrupted(void)
#endif
-static void
-teco_interface_refresh(void)
+void
+teco_interface_refresh(gboolean force)
{
+ if (!teco_interface.cmdline_window)
+ /* batch mode */
+ return;
+
+ if (G_UNLIKELY(force))
+ clearok(curscr, TRUE);
+
/*
* Info window is updated very often which is very
* costly, especially when using PDC_set_title(),
@@ -2124,7 +2130,7 @@ teco_interface_event_loop_iter(void)
* in the ^KMOUSE macro, allowing dot to be outside of the view.
*/
teco_interface_unfold();
- teco_interface_refresh();
+ teco_interface_refresh(FALSE);
return;
#endif
@@ -2183,7 +2189,7 @@ teco_interface_event_loop_iter(void)
teco_interface_unfold();
teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
- teco_interface_refresh();
+ teco_interface_refresh(FALSE);
}
gboolean
@@ -2199,7 +2205,7 @@ teco_interface_event_loop(GError **error)
teco_interface_cmdline_update(&empty_cmdline);
teco_interface_msg_clear();
teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
- teco_interface_refresh();
+ teco_interface_refresh(FALSE);
#ifdef EMCURSES
PDC_emscripten_set_handler(teco_interface_event_loop_iter, TRUE);
diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c
index ae1dd74..dcf3660 100644
--- a/src/interface-gtk/interface.c
+++ b/src/interface-gtk/interface.c
@@ -77,12 +77,6 @@ static gboolean teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *
static gboolean teco_interface_sigterm_handler(gpointer user_data) G_GNUC_UNUSED;
static gchar teco_interface_get_ansi_key(GdkEventKey *event);
-/**
- * Interval between polling for keypresses.
- * In other words, this is the maximum latency to detect CTRL+C interruptions.
- */
-#define TECO_POLL_INTERVAL 100000 /* microseconds */
-
#define UNNAMED_FILE "(Unnamed)"
#define USER_CSS_FILE ".teco_css"
@@ -437,10 +431,6 @@ teco_interface_getch_commit_cb(GtkIMContext *context, gchar *str, gpointer user_
gtk_main_quit();
}
-/*
- * FIXME: Redundancies with teco_interface_handle_keypress()
- * FIXME: Report function keys
- */
static gboolean
teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
@@ -865,6 +855,27 @@ teco_interface_is_interrupted(void)
return teco_interrupted != FALSE;
}
+void
+teco_interface_refresh(gboolean force)
+{
+ if (!gtk_main_level()) /* batch mode */
+ return;
+
+ if (G_UNLIKELY(force))
+ gtk_widget_queue_draw(teco_interface.window);
+
+ GdkWindow *top_window = gdk_window_get_toplevel(gtk_widget_get_window(teco_interface.window));
+ gdk_window_thaw_updates(top_window);
+
+ /*
+ * FIXME: Why do we need two iterations to see any updates?
+ */
+ for (gint i = 0; i < 2; i++)
+ gtk_main_iteration_do(FALSE);
+
+ gdk_window_freeze_updates(top_window);
+}
+
static void
teco_interface_set_css_variables(teco_view_t *view)
{
@@ -942,7 +953,7 @@ teco_interface_set_css_variables(teco_view_t *view)
}
static void
-teco_interface_refresh(gboolean current_view_changed)
+teco_interface_update(gboolean current_view_changed)
{
/*
* The styles configured via Scintilla might change
@@ -1290,7 +1301,7 @@ teco_interface_event_loop(GError **error)
GTK_STYLE_PROVIDER(user_css_provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
- teco_interface_refresh(TRUE);
+ teco_interface_update(TRUE);
gtk_widget_show_all(teco_interface.window);
/* don't show popup by default */
@@ -1512,7 +1523,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
}
teco_interrupted = FALSE;
- teco_interface_refresh(teco_interface_current_view != last_view);
+ teco_interface_update(teco_interface_current_view != last_view);
/* always expand folds, even after mouse clicks */
teco_interface_unfold();
/*
@@ -1597,7 +1608,7 @@ teco_interface_popup_clicked_cb(GtkWidget *popup, gchar *str, gulong len, gpoint
teco_interface_popup_clear();
teco_interface_cmdline_update(&teco_cmdline);
- teco_interface_refresh(teco_interface_current_view != last_view);
+ teco_interface_update(teco_interface_current_view != last_view);
}
static gboolean
diff --git a/src/interface.h b/src/interface.h
index f22c023..02af8a2 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -41,6 +41,12 @@
* feature.
*/
+/**
+ * Interval between polling for keypresses (if necessary).
+ * In other words, this is the maximum latency to detect CTRL+C interruptions.
+ */
+#define TECO_POLL_INTERVAL 100000 /* microseconds */
+
/** @protected */
extern teco_view_t *teco_interface_current_view;
@@ -179,6 +185,9 @@ void teco_interface_stdio_msg(teco_msg_t type, const gchar *str, gsize len);
/** @protected */
teco_int_t teco_interface_stdio_getch(gboolean widechar);
+/** @protected */
+void teco_interface_refresh(gboolean force);
+
/** @pure */
void teco_interface_cleanup(void);
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 78e6f48..7fecc45 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -357,7 +357,7 @@ AT_CLEANUP
AT_SETUP([Timestamps])
# TODO: Test the date (^B) and time (^H and :^H) variants as well.
-TE_CHECK([[::^HUa ::^H-Qa"<(0/0)']], 0, ignore, ignore)
+TE_CHECK([[::^HUt 100^W (::^H-Qt)-100"<(0/0)']], 0, ignore, ignore)
AT_CLEANUP
AT_SETUP([Program version])