diff options
-rw-r--r-- | TODO | 12 | ||||
-rw-r--r-- | src/parser.cpp | 50 | ||||
-rw-r--r-- | src/parser.h | 15 |
3 files changed, 53 insertions, 24 deletions
@@ -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 { |