aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--TODO12
-rw-r--r--src/parser.cpp50
-rw-r--r--src/parser.h15
3 files changed, 53 insertions, 24 deletions
diff --git a/TODO b/TODO
index d9418a6..390c6c5 100644
--- a/TODO
+++ b/TODO
@@ -160,10 +160,20 @@ Features:
between effective and rubbed out command line - without
resetting it. This would add another alternative to { and }
for fixing up a command line.
- * some missing useful VideoTECO/TECO-11 commands:
+ * some missing useful VideoTECO/TECO-11 commands and unnecessary
+ incompatibilities:
* EF with buffer id
* ER command: read file into current buffer at dot
* nEW to save a buffer by id
+ * EI is used to open an indirect macro file in classic TECO.
+ EM should thus be renamed EI.
+ EM (position magtape in classic TECO) would be free again,
+ e.g. for execute macro with string argument or as a special version
+ of EI that considers $SCITECOPATH.
+ Current use of EI (insert without string building) will have
+ to move, e.g. to FI.
+ * ^S (-(length) of last referenced string), ^Y as .+^S,.
+ * ^Q convert line arg into character arg
* ^A and stdio in general
* Buffer ids should be "circular", i.e. interpreted modulo the
number of buffers in the ring. This allows "%*" to wrap at the
diff --git a/src/parser.cpp b/src/parser.cpp
index db68c18..048389e 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -244,22 +244,11 @@ Execute::macro(const gchar *macro, bool locals)
throw Error("Label \"%s\" not found",
Goto::skip_label);
- if (States::current == &States::escape) {
- /*
- * Due to the deferred nature of ^[,
- * it is valid to end in the "escape" state.
- * FIXME: This could be avoided by signalling
- * the state the end of macro using a new
- * virtual method.
- */
- expressions.discard_args();
- } else if (G_UNLIKELY(States::current != &States::start)) {
- /*
- * can only happen if we returned because
- * of macro end
- */
- throw Error("Unterminated command");
- }
+ /*
+ * Some states (esp. commands involving a
+ * "lookahead") are valid at the end of a macro.
+ */
+ States::current->end_of_macro();
/*
* This handles the problem of Q-Registers
@@ -688,6 +677,7 @@ StateStart::StateStart() : State()
transitions['\0'] = this;
init(" \f\r\n\v");
+ transitions['$'] = &States::escape;
transitions['!'] = &States::label;
transitions['O'] = &States::gotocmd;
transitions['^'] = &States::control;
@@ -2113,7 +2103,7 @@ StateEscape::StateEscape()
State *
StateEscape::custom(gchar chr)
{
- /*$ ^[^[ terminate return
+ /*$ ^[^[ ^[$ $$ terminate return
* [a1,a2,...]$$ -- Terminate command line or return from macro
* [a1,a2,...]^[$
*
@@ -2143,11 +2133,13 @@ StateEscape::custom(gchar chr)
* when terminating a command line \(em the new command line
* will always start with a clean expression stack.
*
- * Only the first \fIescape\fP of \fB$$\fP may be typed
- * in up-arrow mode as \fB^[$\fP \(em the second character
- * must be a real escape character.
+ * The first \fIescape\fP of \fB$$\fP may be typed either
+ * as an escape character (ASCII 27), in up-arrow mode
+ * (e.g. \fB^[$\fP) or as a dollar character \(em the
+ * second character must be either a real escape character
+ * or a dollar character.
*/
- if (chr == CTL_KEY_ESC) {
+ if (chr == CTL_KEY_ESC || chr == '$') {
BEGIN_EXEC(&States::start);
States::current = &States::start;
expressions.eval();
@@ -2155,9 +2147,9 @@ StateEscape::custom(gchar chr)
}
/*
- * Alternatives: ^[, <CTRL/[>, <ESC>
+ * Alternatives: ^[, <CTRL/[>, <ESC>, $ (dollar)
*/
- /*$ ^[ escape discard
+ /*$ ^[ $ escape discard
* $ -- Discard all arguments
* ^[
*
@@ -2173,12 +2165,24 @@ StateEscape::custom(gchar chr)
* The up-arrow notation however is processed like any
* ordinary command and only works at the begining of
* a command.
+ * Additionally, this command may be written as a single
+ * dollar character.
*/
if (mode == MODE_NORMAL)
expressions.discard_args();
return States::start.get_next_state(chr);
}
+void
+StateEscape::end_of_macro(void)
+{
+ /*
+ * Due to the deferred nature of ^[,
+ * it is valid to end in the "escape" state.
+ */
+ expressions.discard_args();
+}
+
StateECommand::StateECommand() : State()
{
transitions['\0'] = this;
diff --git a/src/parser.h b/src/parser.h
index 3356600..a7059a9 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -66,6 +66,17 @@ public:
*/
virtual void refresh(void) {}
+ /**
+ * Called at the end of a macro.
+ * Most states/commands are not allowed to end unterminated
+ * at the end of a macro.
+ */
+ virtual void
+ end_of_macro(void)
+ {
+ throw Error("Unterminated command");
+ }
+
protected:
static bool eval_colon(void);
@@ -209,6 +220,8 @@ private:
tecoBool delete_words(tecoInt n);
State *custom(gchar chr);
+
+ void end_of_macro(void) {}
};
class StateControl : public State {
@@ -233,6 +246,8 @@ public:
private:
State *custom(gchar chr);
+
+ void end_of_macro(void);
};
class StateFCommand : public State {