aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/sciteco.7.template16
-rw-r--r--src/core-commands.c8
-rw-r--r--src/goto-commands.c31
-rw-r--r--src/interface.h2
-rw-r--r--src/qreg.c8
-rw-r--r--src/qreg.h2
-rw-r--r--tests/testsuite.at8
7 files changed, 50 insertions, 25 deletions
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index 9f0557e..066deb7 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -1262,12 +1262,12 @@ stack are discarded.
This way, \fPED\fP hooks should not interfere with
the stack-semantics of commands triggering them.
.LP
-Possible arguments to the \(lqED\(rq macro begin with 1 and
+Possible arguments to the \(lqED\(rq macro begin with 0 and
are defined consecutively so the macro can branch to the
operation using a computed goto.
The different values are defined as follows:
.TP
-.B 1
+.B 0
A file has been \fBadded\fP to the buffer ring.
It may or may not already exist in the file system.
This file is \*(ST's current document when this hook
@@ -1275,7 +1275,7 @@ executes.
Scintilla lexing may be configured in this hook \(em it
usually only has to be done once.
.TP
-.B 2
+.B 1
A buffer has been \fBedited\fP (made the current file).
This hook is not executed when a file is freshly added
to the buffer ring, since this can be simulated easily
@@ -1283,13 +1283,13 @@ by branching within the \(lqED\(rq macro.
In this hook you may want to define language-specific
auxiliary macros, for instance.
.TP
-.B 3
+.B 2
A buffer is about to be \fBclosed\fP (removed from the
buffer ring).
The buffer that is about to be closed, is still the
current document when this hook runs.
.TP
-.B 4
+.B 3
\*(ST is about to \fBquit\fP, i.e. exit normally.
This is \*(ST's equivalent of
.BR atexit (3)
@@ -2185,11 +2185,13 @@ in classic TECOs.
.
.SS Gotos and Labels
.
-The most basic flow control command in \*(ST is the Go-to command.
+An important flow control command in \*(ST is the Go-to command.
Since it is really an ordinary command, exceptional only in setting
the program counter and influencing parsing, it is described in this
document's command reference.
-\*(ST can perform simple unconditional and computed gotos.
+\*(ST can perform simple unconditional and computed gotos
+which are just as powerful as switch-case statements in other
+languages.
.LP
.SCITECO_TOPIC "!" label
Labels are symbolic and are defined with the following syntax:
diff --git a/src/core-commands.c b/src/core-commands.c
index 6d0a3dc..5fe960b 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -2142,13 +2142,13 @@ teco_state_ecommand_flags(teco_machine_main_t *ctx, GError **error)
* Type of the last mouse event (\fBread-only\fP).
* One of the following values will be returned:
* .RS
- * . IP 1: 4
+ * . IP 0: 4
* Some button has been pressed
- * . IP 2:
+ * . IP 1:
* Some button has been released
- * . IP 3:
+ * . IP 2:
* Scroll up
- * . IP 4:
+ * . IP 3:
* Scroll down
* .RE
* .IP -2:
diff --git a/src/goto-commands.c b/src/goto-commands.c
index d95886d..ac98b70 100644
--- a/src/goto-commands.c
+++ b/src/goto-commands.c
@@ -24,6 +24,7 @@
#include <glib.h>
#include "sciteco.h"
+#include "error.h"
#include "string-utils.h"
#include "expressions.h"
#include "parser.h"
@@ -110,15 +111,22 @@ teco_state_goto_done(teco_machine_main_t *ctx, const teco_string_t *str, GError
if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
+ if (!str->len) {
+ /* you can still write @O/,/, though... */
+ g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED,
+ "No labels given for <O>");
+ return NULL;
+ }
+
teco_int_t value;
- if (!teco_expressions_pop_num_calc(&value, 1, error))
+ if (!teco_expressions_pop_num_calc(&value, 0, error))
return NULL;
/*
* Find the comma-separated substring in str indexed by `value`.
*/
teco_string_t label = {NULL, 0};
- while (value > 0) {
+ while (value >= 0) {
label.data = label.data ? label.data+label.len+1 : str->data;
const gchar *p = label.data ? memchr(label.data, ',', str->len - (label.data - str->data)) : NULL;
label.len = p ? p - label.data : str->len - (label.data - str->data);
@@ -129,7 +137,7 @@ teco_state_goto_done(teco_machine_main_t *ctx, const teco_string_t *str, GError
break;
}
- if (value == 0) {
+ if (value < 0 && label.len > 0) {
gssize pc = teco_goto_table_find(&ctx->goto_table, label.data, label.len);
if (pc >= 0) {
@@ -156,19 +164,22 @@ gboolean teco_state_goto_insert_completion(teco_machine_main_t *ctx, const teco_
/*$ "O" goto
* Olabel$ -- Go to label
- * [n]Olabel1[,label2,...]$
+ * [n]Olabel0[,label1,...]$
*
* Go to <label>.
* The simple go-to command is a special case of the
* computed go-to command.
* A comma-separated list of labels may be specified
* in the string argument.
- * The label to jump to is selected by <n> (1 is <label1>,
- * 2 is <label2>, etc.).
- * If <n> is omitted, 1 is implied.
+ * The label to jump to is selected by <n> (0 is <label0>,
+ * 1 is <label1>, etc.).
+ * If <n> is omitted, 0 is implied.
+ * Computed go-tos can be used like switch-case statements
+ * other languages.
*
* If the label selected by <n> is does not exist in the
- * list of labels, the command does nothing.
+ * list of labels or is empty, the command does nothing
+ * and execution continues normally.
* Label definitions are cached in a table, so that
* if the label to go to has already been defined, the
* go-to command will jump immediately.
@@ -179,6 +190,10 @@ gboolean teco_state_goto_insert_completion(teco_machine_main_t *ctx, const teco_
* is terminated.
* In the latter case, the user will not be able to
* terminate the command-line.
+ *
+ * String building constructs are enabled in \fBO\fP
+ * which allows for a second kind of computed go-to,
+ * where the label name contains the value to select.
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_goto,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_goto_process_edit_cmd,
diff --git a/src/interface.h b/src/interface.h
index c0c41bd..9531d37 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -155,7 +155,7 @@ gboolean teco_interface_is_interrupted(void);
typedef struct {
enum {
- TECO_MOUSE_PRESSED = 1,
+ TECO_MOUSE_PRESSED = 0,
TECO_MOUSE_RELEASED,
TECO_MOUSE_SCROLLUP,
TECO_MOUSE_SCROLLDOWN
diff --git a/src/qreg.c b/src/qreg.c
index 332b5f6..d49a4d6 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -1334,10 +1334,10 @@ teco_ed_hook(teco_ed_hook_t type, GError **error)
teco_expressions_brace_close(error);
static const gchar *const type2name[] = {
- [TECO_ED_HOOK_ADD-1] = "ADD",
- [TECO_ED_HOOK_EDIT-1] = "EDIT",
- [TECO_ED_HOOK_CLOSE-1] = "CLOSE",
- [TECO_ED_HOOK_QUIT-1] = "QUIT"
+ [TECO_ED_HOOK_ADD] = "ADD",
+ [TECO_ED_HOOK_EDIT] = "EDIT",
+ [TECO_ED_HOOK_CLOSE] = "CLOSE",
+ [TECO_ED_HOOK_QUIT] = "QUIT"
};
error_add_frame:
diff --git a/src/qreg.h b/src/qreg.h
index 2b970aa..6daaff3 100644
--- a/src/qreg.h
+++ b/src/qreg.h
@@ -239,7 +239,7 @@ gboolean teco_qreg_stack_pop(teco_qreg_t *qreg, GError **error);
void teco_qreg_stack_clear(void);
typedef enum {
- TECO_ED_HOOK_ADD = 1,
+ TECO_ED_HOOK_ADD = 0,
TECO_ED_HOOK_EDIT,
TECO_ED_HOOK_CLOSE,
TECO_ED_HOOK_QUIT
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 3728723..3cca113 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -114,6 +114,14 @@ TE_CHECK([[3<%a:>-3"N(0/0)' $]], 0, ignore, ignore)
TE_CHECK([[3<%a :F>(0/0):>-3"N(0/0)' $]], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Gotos and labels])
+TE_CHECK([[@O//]], 1, ignore, ignore)
+TE_CHECK([[^^XUq @O/s.^EUq/ (0/0) !s.X!]], 0, ignore, ignore)
+TE_CHECK([[1@O/foo,bar/ (0/0) !bar!]], 0, ignore, ignore)
+# No-op gotos
+TE_CHECK([[-1@O/foo/ 1@O/foo/ @O/,foo/]], 0, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([String arguments])
TE_CHECK([[Ifoo^Q]]TE_ESCAPE[[(0/0)]]TE_ESCAPE, 0, ignore, ignore)
TE_CHECK([[@I"foo^Q"(0/0)"]], 0, ignore, ignore)