aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/cmdline.cpp33
-rw-r--r--src/cmdline.h1
-rw-r--r--src/parser.cpp78
-rw-r--r--src/parser.h2
-rw-r--r--src/undo.cpp3
5 files changed, 89 insertions, 28 deletions
diff --git a/src/cmdline.cpp b/src/cmdline.cpp
index 4d9cfd6..6e4c9d3 100644
--- a/src/cmdline.cpp
+++ b/src/cmdline.cpp
@@ -49,6 +49,7 @@ static const gchar *last_occurrence(const gchar *str,
static inline gboolean filename_is_dir(const gchar *filename);
gchar *cmdline = NULL;
+gint cmdline_pos = 0;
static gchar *last_cmdline = NULL;
bool quit_requested = false;
@@ -60,7 +61,6 @@ namespace States {
void
cmdline_keypress(gchar key)
{
- gchar *cmdline_p;
const gchar *insert;
gchar *echo;
@@ -76,28 +76,15 @@ cmdline_keypress(gchar key)
insert = process_edit_cmd(key);
/*
- * Parse/execute characters
- */
- if (cmdline) {
- gint len = strlen(cmdline);
- cmdline = (gchar *)g_realloc(cmdline, len + strlen(insert) + 1);
- cmdline_p = cmdline + len;
- } else {
- cmdline = (gchar *)g_malloc(strlen(insert) + 1);
- *cmdline = '\0';
- cmdline_p = cmdline;
- }
-
- /*
- * Execute one insertion character, extending cmdline, at a time so
+ * Parse/execute characters, one at a time so
* undo tokens get emitted for the corresponding characters.
*/
- for (const gchar *p = insert; *p; p++) {
- *cmdline_p++ = *p;
- *cmdline_p = '\0';
+ cmdline_pos = cmdline ? strlen(cmdline)+1 : 1;
+ String::append(cmdline, insert);
+ while (cmdline_pos <= (gint)strlen(cmdline)) {
try {
- Execute::step(cmdline);
+ Execute::step((const gchar *&)cmdline, cmdline_pos);
} catch (...) {
/*
* Undo tokens may have been emitted (or had to be)
@@ -105,12 +92,14 @@ cmdline_keypress(gchar key)
* executed so as if the character had never been
* inserted.
*/
- undo.pop(cmdline_p - cmdline);
- cmdline_p[-1] = '\0';
+ undo.pop(cmdline_pos);
+ cmdline[cmdline_pos-1] = '\0';
/* program counter could be messed up */
- macro_pc = cmdline_p - cmdline - 1;
+ macro_pc = cmdline_pos - 1;
break;
}
+
+ cmdline_pos++;
}
/*
diff --git a/src/cmdline.h b/src/cmdline.h
index b88599a..8747f63 100644
--- a/src/cmdline.h
+++ b/src/cmdline.h
@@ -25,6 +25,7 @@
#include "qregisters.h"
extern gchar *cmdline;
+extern gint cmdline_pos;
extern bool quit_requested;
void cmdline_keypress(gchar key);
diff --git a/src/parser.cpp b/src/parser.cpp
index 37dd055..cb4180e 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -71,9 +71,9 @@ gchar *strings[2] = {NULL, NULL};
gchar escape_char = '\x1B';
void
-Execute::step(const gchar *macro) throw (State::Error)
+Execute::step(const gchar *&macro, gint &stop_pos) throw (State::Error)
{
- while (macro[macro_pc]) {
+ while (macro_pc < stop_pos) {
#ifdef DEBUG
g_printf("EXEC(%d): input='%c'/%x, state=%p, mode=%d\n",
macro_pc, macro[macro_pc], macro[macro_pc],
@@ -91,6 +91,8 @@ Execute::step(const gchar *macro) throw (State::Error)
void
Execute::macro(const gchar *macro, bool locals) throw (State::Error)
{
+ gint macro_len = strlen(macro);
+
GotoTable *parent_goto_table = Goto::table;
GotoTable macro_goto_table(false);
@@ -114,7 +116,7 @@ Execute::macro(const gchar *macro, bool locals) throw (State::Error)
}
try {
- step(macro);
+ step(macro, macro_len);
if (Goto::skip_label)
throw State::Error("Label \"%s\" not found",
Goto::skip_label);
@@ -819,6 +821,76 @@ StateStart::custom(gchar chr) throw (Error)
break;
/*
+ * Command-line editing
+ */
+ case '{': {
+ void *document;
+
+ BEGIN_EXEC(this);
+ if (!undo.enabled)
+ throw Error("Command-line editing only possible in "
+ "interactive mode");
+
+ current_save_dot();
+
+ if (ring.current)
+ ring.current->undo_edit();
+ else if (QRegisters::current)
+ QRegisters::current->undo_edit();
+
+ document = (void *)interface.ssm(SCI_CREATEDOCUMENT);
+ interface.ssm(SCI_SETDOCPOINTER, 0, (sptr_t)document);
+ interface.ssm(SCI_ADDTEXT, cmdline_pos-1, (sptr_t)cmdline);
+
+ undo.push_msg(SCI_RELEASEDOCUMENT, 0, (sptr_t)document);
+ break;
+ }
+
+ case '}': {
+ gint size, i;
+ gchar *old_cmdline, *new_cmdline;
+
+ BEGIN_EXEC(this);
+ if (!undo.enabled)
+ throw Error("Command-line editing only possible in "
+ "interactive mode");
+
+ size = interface.ssm(SCI_GETLENGTH) + 1;
+ new_cmdline = (gchar *)g_malloc(size);
+ interface.ssm(SCI_GETTEXT, size, (sptr_t)new_cmdline);
+
+ for (i = 0; cmdline[i] && cmdline[i] == new_cmdline[i]; i++);
+ undo.pop(i+1);
+
+ old_cmdline = cmdline;
+ cmdline = new_cmdline;
+ cmdline_pos = i+1;
+ macro_pc = i; /* FIXME */
+
+ while (cmdline_pos <= (gint)strlen(cmdline)) {
+ try {
+ Execute::step((const gchar *&)cmdline, cmdline_pos);
+ } catch (...) {
+ undo.pop(i+1);
+ cmdline = old_cmdline;
+ cmdline[strlen(cmdline)-1] = '\0';
+ g_free(new_cmdline);
+ old_cmdline = NULL;
+ cmdline_pos = i;
+ macro_pc = i-1; /* FIXME */
+ break;
+ }
+
+ cmdline_pos++;
+ }
+
+ g_free(old_cmdline);
+
+ /* state may have changed due to undoing */
+ return States::current;
+ }
+
+ /*
* modifiers
*/
case '@':
diff --git a/src/parser.h b/src/parser.h
index 69a6d93..8ee15d7 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -253,7 +253,7 @@ extern gchar *strings[2];
extern gchar escape_char;
namespace Execute {
- void step(const gchar *macro) throw (State::Error);
+ void step(const gchar *&macro, gint &stop_pos) throw (State::Error);
void macro(const gchar *macro, bool locals = true) throw (State::Error);
bool file(const gchar *filename, bool locals = true);
}
diff --git a/src/undo.cpp b/src/undo.cpp
index 82f1eda..1ee7cb4 100644
--- a/src/undo.cpp
+++ b/src/undo.cpp
@@ -20,7 +20,6 @@
#endif
#include <stdio.h>
-#include <string.h>
#include <bsd/sys/queue.h>
#include <glib.h>
@@ -50,7 +49,7 @@ UndoStack::push(UndoToken *token)
#ifdef DEBUG
g_printf("UNDO PUSH %p\n", token);
#endif
- token->pos = strlen(cmdline);
+ token->pos = cmdline_pos;
SLIST_INSERT_HEAD(&head, token, tokens);
} else {
delete token;