aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-12-04 16:58:20 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-12-04 17:09:31 +0100
commitb120616b6da52e951097f69ad267de06081d218a (patch)
tree0407f216dd5020ecd4096c93326272d358d26993
parent266cdca115c7e9b14f734da478d04a8ce0c2cb69 (diff)
downloadsciteco-b120616b6da52e951097f69ad267de06081d218a.tar.gz
refactoring: split qbuffers.cpp|h into a q-registers (qregisters.cpp) and Buffer ring part (ring.cpp)
-rw-r--r--Makefile2
-rw-r--r--cmdline.cpp3
-rw-r--r--interface-gtk.cpp3
-rw-r--r--interface-ncurses.cpp3
-rw-r--r--main.cpp3
-rw-r--r--parser.cpp3
-rw-r--r--qregisters.cpp522
-rw-r--r--qregisters.h (renamed from qbuffers.h)219
-rw-r--r--ring.cpp (renamed from qbuffers.cpp)526
-rw-r--r--ring.h246
-rw-r--r--search.cpp3
-rw-r--r--search.h2
12 files changed, 796 insertions, 739 deletions
diff --git a/Makefile b/Makefile
index 91dc300..27eef53 100644
--- a/Makefile
+++ b/Makefile
@@ -53,7 +53,7 @@ ifneq ($(findstring MINGW32,$(OS)),)
CPPFLAGS+=-Icompat
endif
-MINIMAL_OBJS:=main.o cmdline.o undo.o expressions.o qbuffers.o \
+MINIMAL_OBJS:=main.o cmdline.o undo.o expressions.o qregisters.o ring.o \
parser.o search.o goto.o rbtree.o symbols.o \
interface.a
diff --git a/cmdline.cpp b/cmdline.cpp
index 80cd2d7..212722a 100644
--- a/cmdline.cpp
+++ b/cmdline.cpp
@@ -9,7 +9,8 @@
#include "interface.h"
#include "expressions.h"
#include "parser.h"
-#include "qbuffers.h"
+#include "qregisters.h"
+#include "ring.h"
#include "goto.h"
#include "undo.h"
#include "symbols.h"
diff --git a/interface-gtk.cpp b/interface-gtk.cpp
index a55a2c8..7515b2f 100644
--- a/interface-gtk.cpp
+++ b/interface-gtk.cpp
@@ -14,7 +14,8 @@
#include <ScintillaWidget.h>
#include "sciteco.h"
-#include "qbuffers.h"
+#include "qregisters.h"
+#include "ring.h"
#include "interface.h"
#include "interface-gtk.h"
diff --git a/interface-ncurses.cpp b/interface-ncurses.cpp
index fe2c7e7..0e08914 100644
--- a/interface-ncurses.cpp
+++ b/interface-ncurses.cpp
@@ -17,7 +17,8 @@
#include <ScintillaTerm.h>
#include "sciteco.h"
-#include "qbuffers.h"
+#include "qregisters.h"
+#include "ring.h"
#include "interface.h"
#include "interface-ncurses.h"
diff --git a/main.cpp b/main.cpp
index e23eca8..4526da3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -14,7 +14,8 @@
#include "interface.h"
#include "parser.h"
#include "goto.h"
-#include "qbuffers.h"
+#include "qregisters.h"
+#include "ring.h"
#include "undo.h"
#ifdef G_OS_UNIX
diff --git a/parser.cpp b/parser.cpp
index bb05d66..5ba96fa 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -10,7 +10,8 @@
#include "undo.h"
#include "expressions.h"
#include "goto.h"
-#include "qbuffers.h"
+#include "qregisters.h"
+#include "ring.h"
#include "parser.h"
#include "symbols.h"
#include "search.h"
diff --git a/qregisters.cpp b/qregisters.cpp
new file mode 100644
index 0000000..06947f7
--- /dev/null
+++ b/qregisters.cpp
@@ -0,0 +1,522 @@
+#include <string.h>
+#include <bsd/sys/queue.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include <Scintilla.h>
+
+#include "sciteco.h"
+#include "interface.h"
+#include "undo.h"
+#include "parser.h"
+#include "expressions.h"
+#include "ring.h"
+#include "qregisters.h"
+
+namespace States {
+ StatePushQReg pushqreg;
+ StatePopQReg popqreg;
+ StateEQCommand eqcommand;
+ StateLoadQReg loadqreg;
+ StateCtlUCommand ctlucommand;
+ StateSetQRegString setqregstring;
+ StateGetQRegString getqregstring;
+ StateGetQRegInteger getqreginteger;
+ StateSetQRegInteger setqreginteger;
+ StateIncreaseQReg increaseqreg;
+ StateMacro macro;
+ StateCopyToQReg copytoqreg;
+}
+
+namespace QRegisters {
+ QRegisterTable globals;
+ QRegisterTable *locals = NULL;
+ QRegister *current = NULL;
+
+ static QRegisterStack stack;
+}
+
+static QRegister *register_argument = NULL;
+
+static inline void
+current_edit(void)
+{
+ if (ring.current)
+ ring.current->edit();
+ else if (QRegisters::current)
+ QRegisters::current->edit();
+}
+
+void
+QRegisterData::set_string(const gchar *str)
+{
+ edit();
+ dot = 0;
+
+ interface.ssm(SCI_BEGINUNDOACTION);
+ interface.ssm(SCI_SETTEXT, 0, (sptr_t)(str ? : ""));
+ interface.ssm(SCI_ENDUNDOACTION);
+
+ current_edit();
+}
+
+void
+QRegisterData::undo_set_string(void)
+{
+ /* set_string() assumes that dot has been saved */
+ current_save_dot();
+
+ if (!must_undo)
+ return;
+
+ if (ring.current)
+ ring.current->undo_edit();
+ else if (QRegisters::current)
+ QRegisters::current->undo_edit();
+
+ undo.push_var<gint>(dot);
+ undo.push_msg(SCI_UNDO);
+
+ undo_edit();
+}
+
+void
+QRegisterData::append_string(const gchar *str)
+{
+ if (!str)
+ return;
+
+ edit();
+
+ interface.ssm(SCI_BEGINUNDOACTION);
+ interface.ssm(SCI_APPENDTEXT, strlen(str), (sptr_t)str);
+ interface.ssm(SCI_ENDUNDOACTION);
+
+ current_edit();
+}
+
+gchar *
+QRegisterData::get_string(void)
+{
+ gint size;
+ gchar *str;
+
+ current_save_dot();
+ edit();
+
+ size = interface.ssm(SCI_GETLENGTH) + 1;
+ str = (gchar *)g_malloc(size);
+ interface.ssm(SCI_GETTEXT, size, (sptr_t)str);
+
+ current_edit();
+
+ return str;
+}
+
+void
+QRegisterData::edit(void)
+{
+ interface.ssm(SCI_SETDOCPOINTER, 0, (sptr_t)get_document());
+ interface.ssm(SCI_GOTOPOS, dot);
+}
+
+void
+QRegisterData::undo_edit(void)
+{
+ if (!must_undo)
+ return;
+
+ undo.push_msg(SCI_GOTOPOS, dot);
+ undo.push_msg(SCI_SETDOCPOINTER, 0, (sptr_t)get_document());
+}
+
+void
+QRegister::edit(void)
+{
+ QRegisterData::edit();
+ interface.info_update(this);
+}
+
+void
+QRegister::undo_edit(void)
+{
+ if (!must_undo)
+ return;
+
+ interface.undo_info_update(this);
+ QRegisterData::undo_edit();
+}
+
+void
+QRegister::execute(bool locals) throw (State::Error)
+{
+ gchar *str = get_string();
+
+ try {
+ Execute::macro(str, locals);
+ } catch (...) {
+ g_free(str);
+ throw; /* forward */
+ }
+
+ g_free(str);
+}
+
+bool
+QRegister::load(const gchar *filename)
+{
+ gchar *contents;
+ gsize size;
+
+ /* FIXME: prevent excessive allocations by reading file into buffer */
+ if (!g_file_get_contents(filename, &contents, &size, NULL))
+ return false;
+
+ edit();
+ dot = 0;
+
+ interface.ssm(SCI_BEGINUNDOACTION);
+ interface.ssm(SCI_CLEARALL);
+ interface.ssm(SCI_APPENDTEXT, size, (sptr_t)contents);
+ interface.ssm(SCI_ENDUNDOACTION);
+
+ g_free(contents);
+
+ current_edit();
+
+ return true;
+}
+
+gint64
+QRegisterBufferInfo::get_integer(void)
+{
+ gint64 id = 1;
+
+ if (!ring.current)
+ return 0;
+
+ for (Buffer *buffer = ring.first();
+ buffer != ring.current;
+ buffer = buffer->next())
+ id++;
+
+ return id;
+}
+
+gchar *
+QRegisterBufferInfo::get_string(void)
+{
+ gchar *filename = ring.current ? ring.current->filename : NULL;
+
+ return g_strdup(filename ? : "");
+}
+
+void
+QRegisterBufferInfo::edit(void)
+{
+ gchar *filename = ring.current ? ring.current->filename : NULL;
+
+ QRegister::edit();
+
+ interface.ssm(SCI_BEGINUNDOACTION);
+ interface.ssm(SCI_SETTEXT, 0, (sptr_t)(filename ? : ""));
+ interface.ssm(SCI_ENDUNDOACTION);
+
+ undo.push_msg(SCI_UNDO);
+}
+
+void
+QRegisterTable::initialize(void)
+{
+ /* general purpose registers */
+ for (gchar q = 'A'; q <= 'Z'; q++)
+ initialize(q);
+ for (gchar q = '0'; q <= '9'; q++)
+ initialize(q);
+}
+
+void
+QRegisterTable::edit(QRegister *reg)
+{
+ current_save_dot();
+ reg->edit();
+
+ ring.current = NULL;
+ QRegisters::current = reg;
+}
+
+void
+QRegisterStack::UndoTokenPush::run(void)
+{
+ SLIST_INSERT_HEAD(&stack->head, entry, entries);
+ entry = NULL;
+}
+
+void
+QRegisterStack::UndoTokenPop::run(void)
+{
+ Entry *entry = SLIST_FIRST(&stack->head);
+
+ SLIST_REMOVE_HEAD(&stack->head, entries);
+ delete entry;
+}
+
+void
+QRegisterStack::push(QRegister *reg)
+{
+ Entry *entry = new Entry();
+
+ entry->set_integer(reg->get_integer());
+ if (reg->string) {
+ gchar *str = reg->get_string();
+ entry->set_string(str);
+ g_free(str);
+ }
+ entry->dot = reg->dot;
+
+ SLIST_INSERT_HEAD(&head, entry, entries);
+ undo.push(new UndoTokenPop(this));
+}
+
+bool
+QRegisterStack::pop(QRegister *reg)
+{
+ Entry *entry = SLIST_FIRST(&head);
+ QRegisterData::document *string;
+
+ if (!entry)
+ return false;
+
+ reg->undo_set_integer();
+ reg->set_integer(entry->get_integer());
+
+ /* exchange document ownership between Stack entry and Q-Register */
+ string = reg->string;
+ if (reg->must_undo)
+ undo.push_var(reg->string);
+ reg->string = entry->string;
+ undo.push_var(entry->string);
+ entry->string = string;
+
+ if (reg->must_undo)
+ undo.push_var(reg->dot);
+ reg->dot = entry->dot;
+
+ SLIST_REMOVE_HEAD(&head, entries);
+ /* pass entry ownership to undo stack */
+ undo.push(new UndoTokenPush(this, entry));
+
+ return true;
+}
+
+QRegisterStack::~QRegisterStack()
+{
+ Entry *entry, *next;
+
+ SLIST_FOREACH_SAFE(entry, &head, entries, next)
+ delete entry;
+}
+
+void
+QRegisters::hook(Hook type)
+{
+ if (!(Flags::ed & Flags::ED_HOOKS))
+ return;
+
+ expressions.push(type);
+ globals["0"]->execute();
+}
+
+/*
+ * Command states
+ */
+
+State *
+StatePushQReg::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ QRegisters::stack.push(reg);
+
+ return &States::start;
+}
+
+State *
+StatePopQReg::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ if (!QRegisters::stack.pop(reg))
+ throw Error("Q-Register stack is empty");
+
+ return &States::start;
+}
+
+State *
+StateEQCommand::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::loadqreg);
+ register_argument = reg;
+ return &States::loadqreg;
+}
+
+State *
+StateLoadQReg::done(const gchar *str) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ if (*str) {
+ register_argument->undo_load();
+ if (!register_argument->load(str))
+ throw Error("Cannot load \"%s\" into Q-Register \"%s\"",
+ str, register_argument->name);
+ } else {
+ if (ring.current)
+ ring.undo_edit();
+ else /* QRegisters::current != NULL */
+ QRegisters::undo_edit();
+ QRegisters::globals.edit(register_argument);
+ }
+
+ return &States::start;
+}
+
+State *
+StateCtlUCommand::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::setqregstring);
+ register_argument = reg;
+ return &States::setqregstring;
+}
+
+State *
+StateSetQRegString::done(const gchar *str) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ register_argument->undo_set_string();
+ register_argument->set_string(str);
+
+ return &States::start;
+}
+
+State *
+StateGetQRegString::got_register(QRegister *reg) throw (Error)
+{
+ gchar *str;
+
+ BEGIN_EXEC(&States::start);
+
+ str = reg->get_string();
+ if (*str) {
+ interface.ssm(SCI_BEGINUNDOACTION);
+ interface.ssm(SCI_ADDTEXT, strlen(str), (sptr_t)str);
+ interface.ssm(SCI_SCROLLCARET);
+ interface.ssm(SCI_ENDUNDOACTION);
+ ring.dirtify();
+
+ undo.push_msg(SCI_UNDO);
+ }
+ g_free(str);
+
+ return &States::start;
+}
+
+State *
+StateGetQRegInteger::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ expressions.eval();
+ expressions.push(reg->get_integer());
+
+ return &States::start;
+}
+
+State *
+StateSetQRegInteger::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ reg->undo_set_integer();
+ reg->set_integer(expressions.pop_num_calc());
+
+ return &States::start;
+}
+
+State *
+StateIncreaseQReg::got_register(QRegister *reg) throw (Error)
+{
+ gint64 res;
+
+ BEGIN_EXEC(&States::start);
+
+ reg->undo_set_integer();
+ res = reg->get_integer() + expressions.pop_num_calc();
+ expressions.push(reg->set_integer(res));
+
+ return &States::start;
+}
+
+State *
+StateMacro::got_register(QRegister *reg) throw (Error)
+{
+ BEGIN_EXEC(&States::start);
+
+ /* don't create new local Q-Registers if colon modifier is given */
+ reg->execute(!eval_colon());
+
+ return &States::start;
+}
+
+State *
+StateCopyToQReg::got_register(QRegister *reg) throw (Error)
+{
+ gint64 from, len;
+ Sci_TextRange tr;
+
+ BEGIN_EXEC(&States::start);
+ expressions.eval();
+
+ if (expressions.args() <= 1) {
+ from = interface.ssm(SCI_GETCURRENTPOS);
+ sptr_t line = interface.ssm(SCI_LINEFROMPOSITION, from) +
+ expressions.pop_num_calc();
+
+ if (!Validate::line(line))
+ throw RangeError("X");
+
+ len = interface.ssm(SCI_POSITIONFROMLINE, line) - from;
+
+ if (len < 0) {
+ from += len;
+ len *= -1;
+ }
+ } else {
+ gint64 to = expressions.pop_num();
+ from = expressions.pop_num();
+
+ if (!Validate::pos(from) || !Validate::pos(to))
+ throw RangeError("X");
+
+ len = to - from;
+ }
+
+ tr.chrg.cpMin = from;
+ tr.chrg.cpMax = from + len;
+ tr.lpstrText = (char *)g_malloc(len + 1);
+ interface.ssm(SCI_GETTEXTRANGE, 0, (sptr_t)&tr);
+
+ if (eval_colon()) {
+ reg->undo_append_string();
+ reg->append_string(tr.lpstrText);
+ } else {
+ reg->undo_set_string();
+ reg->set_string(tr.lpstrText);
+ }
+ g_free(tr.lpstrText);
+
+ return &States::start;
+}
diff --git a/qbuffers.h b/qregisters.h
index d9c1b94..e810b7f 100644
--- a/qbuffers.h
+++ b/qregisters.h
@@ -1,12 +1,10 @@
-#ifndef __QBUFFERS_H
-#define __QBUFFERS_H
+#ifndef __QREGISTERS_H
+#define __QREGISTERS_H
-#include <string.h>
#include <bsd/sys/queue.h>
#include <glib.h>
#include <glib/gprintf.h>
-#include <glib/gstdio.h>
#include <Scintilla.h>
@@ -17,22 +15,6 @@
#include "parser.h"
/*
- * Auxiliary functions
- */
-static inline bool
-is_glob_pattern(const gchar *str)
-{
- return strchr(str, '*') || strchr(str, '?');
-}
-
-/*
- * Get absolute/full version of a possibly relative path.
- * Works with existing and non-existing paths (in the latter case,
- * heuristics may be applied.)
- */
-gchar *get_absolute_path(const gchar *path);
-
-/*
* Classes
*/
@@ -256,196 +238,10 @@ public:
bool pop(QRegister *reg);
};
-class Buffer {
- class UndoTokenClose : public UndoToken {
- Buffer *buffer;
-
- public:
- UndoTokenClose(Buffer *_buffer)
- : UndoToken(), buffer(_buffer) {}
-
- void run(void);
- };
-
-public:
- TAILQ_ENTRY(Buffer) buffers;
-
- gchar *filename;
- gint dot;
-
- gint savepoint_id;
-
- bool dirty;
-
-private:
- typedef void document;
- document *doc;
-
-public:
- Buffer() : filename(NULL), dot(0), savepoint_id(0), dirty(false)
- {
- doc = (document *)interface.ssm(SCI_CREATEDOCUMENT);
- }
- ~Buffer()
- {
- interface.ssm(SCI_RELEASEDOCUMENT, 0, (sptr_t)doc);
- g_free(filename);
- }
-
- inline Buffer *&
- next(void)
- {
- return TAILQ_NEXT(this, buffers);
- }
- inline Buffer *&
- prev(void)
- {
- TAILQ_HEAD(Head, Buffer);
-
- return TAILQ_PREV(this, Head, buffers);
- }
-
- inline void
- set_filename(const gchar *filename)
- {
- gchar *resolved = get_absolute_path(filename);
- g_free(Buffer::filename);
- Buffer::filename = resolved;
- interface.info_update(this);
- }
-
- inline void
- edit(void)
- {
- interface.ssm(SCI_SETDOCPOINTER, 0, (sptr_t)doc);
- interface.ssm(SCI_GOTOPOS, dot);
- interface.info_update(this);
- }
- inline void
- undo_edit(void)
- {
- interface.undo_info_update(this);
- undo.push_msg(SCI_GOTOPOS, dot);
- undo.push_msg(SCI_SETDOCPOINTER, 0, (sptr_t)doc);
- }
-
- bool load(const gchar *filename);
-
- inline void
- undo_close(void)
- {
- undo.push(new UndoTokenClose(this));
- }
-};
-
-extern class Ring {
- /*
- * Emitted after a buffer close
- * The pointer is the only remaining reference to the buffer!
- */
- class UndoTokenEdit : public UndoToken {
- Ring *ring;
- Buffer *buffer;
-
- public:
- UndoTokenEdit(Ring *_ring, Buffer *_buffer)
- : UndoToken(), ring(_ring), buffer(_buffer) {}
- ~UndoTokenEdit()
- {
- if (buffer)
- delete buffer;
- }
-
- void run(void);
- };
-
- class UndoTokenRemoveFile : public UndoToken {
- gchar *filename;
-
- public:
- UndoTokenRemoveFile(const gchar *_filename)
- : filename(g_strdup(_filename)) {}
- ~UndoTokenRemoveFile()
- {
- g_free(filename);
- }
-
- void
- run(void)
- {
- g_unlink(filename);
- }
- };
-
- TAILQ_HEAD(Head, Buffer) head;
-
-public:
- Buffer *current;
-
- Ring() : current(NULL)
- {
- TAILQ_INIT(&head);
- }
- ~Ring();
-
- inline Buffer *
- first(void)
- {
- return TAILQ_FIRST(&head);
- }
- inline Buffer *
- last(void)
- {
- return TAILQ_LAST(&head, Head);
- }
-
- Buffer *find(const gchar *filename);
- Buffer *find(gint64 id);
-
- void dirtify(void);
- bool is_any_dirty(void);
-
- bool edit(gint64 id);
- void edit(const gchar *filename);
- inline void
- undo_edit(void)
- {
- current->dot = interface.ssm(SCI_GETCURRENTPOS);
- undo.push_var(current);
- current->undo_edit();
- }
-
- bool save(const gchar *filename);
-
- void close(Buffer *buffer);
- void close(void);
- inline void
- undo_close(void)
- {
- current->undo_close();
- }
-} ring;
-
/*
* Command states
*/
-class StateEditFile : public StateExpectString {
-private:
- bool allowFilename;
-
- void do_edit(const gchar *filename) throw (Error);
- void do_edit(gint64 id) throw (Error);
-
- void initial(void) throw (Error);
- State *done(const gchar *str) throw (Error);
-};
-
-class StateSaveFile : public StateExpectString {
-private:
- State *done(const gchar *str) throw (Error);
-};
-
class StatePushQReg : public StateExpectQReg {
private:
State *got_register(QRegister *reg) throw (Error);
@@ -509,9 +305,6 @@ private:
};
namespace States {
- extern StateEditFile editfile;
- extern StateSaveFile savefile;
-
extern StatePushQReg pushqreg;
extern StatePopQReg popqreg;
extern StateEQCommand eqcommand;
@@ -529,6 +322,14 @@ namespace States {
namespace QRegisters {
extern QRegisterTable globals;
extern QRegisterTable *locals;
+ extern QRegister *current;
+
+ static inline void
+ undo_edit(void)
+ {
+ current->dot = interface.ssm(SCI_GETCURRENTPOS);
+ undo.push_var(current)->undo_edit();
+ }
enum Hook {
HOOK_ADD = 1,
diff --git a/qbuffers.cpp b/ring.cpp
index 8948f46..f1b051b 100644
--- a/qbuffers.cpp
+++ b/ring.cpp
@@ -14,8 +14,7 @@
#include "undo.h"
#include "parser.h"
#include "expressions.h"
-#include "goto.h"
-#include "qbuffers.h"
+#include "ring.h"
#ifdef G_OS_WIN32
/* here it shouldn't cause conflicts with other headers */
@@ -28,342 +27,12 @@
#endif
namespace States {
- StateEditFile editfile;
- StateSaveFile savefile;
-
- StatePushQReg pushqreg;
- StatePopQReg popqreg;
- StateEQCommand eqcommand;
- StateLoadQReg loadqreg;
- StateCtlUCommand ctlucommand;
- StateSetQRegString setqregstring;
- StateGetQRegString getqregstring;
- StateGetQRegInteger getqreginteger;
- StateSetQRegInteger setqreginteger;
- StateIncreaseQReg increaseqreg;
- StateMacro macro;
- StateCopyToQReg copytoqreg;
+ StateEditFile editfile;
+ StateSaveFile savefile;
}
-namespace QRegisters {
- QRegisterTable globals;
- QRegisterTable *locals = NULL;
- static QRegister *current = NULL;
- static QRegisterStack stack;
-
- static inline void
- undo_edit(void)
- {
- current->dot = interface.ssm(SCI_GETCURRENTPOS);
- undo.push_var(current)->undo_edit();
- }
-}
-
-static QRegister *register_argument = NULL;
-
Ring ring;
-/* FIXME: clean up current_save_dot() usage */
-static inline void
-current_save_dot(void)
-{
- gint dot = interface.ssm(SCI_GETCURRENTPOS);
-
- if (ring.current)
- ring.current->dot = dot;
- else if (QRegisters::current)
- QRegisters::current->dot = dot;
-}
-
-static inline void
-current_edit(void)
-{
- if (ring.current)
- ring.current->edit();
- else if (QRegisters::current)
- QRegisters::current->edit();
-}
-
-void
-QRegisterData::set_string(const gchar *str)
-{
- edit();
- dot = 0;
-
- interface.ssm(SCI_BEGINUNDOACTION);
- interface.ssm(SCI_SETTEXT, 0, (sptr_t)(str ? : ""));
- interface.ssm(SCI_ENDUNDOACTION);
-
- current_edit();
-}
-
-void
-QRegisterData::undo_set_string(void)
-{
- /* set_string() assumes that dot has been saved */
- current_save_dot();
-
- if (!must_undo)
- return;
-
- if (ring.current)
- ring.current->undo_edit();
- else if (QRegisters::current)
- QRegisters::current->undo_edit();
-
- undo.push_var<gint>(dot);
- undo.push_msg(SCI_UNDO);
-
- undo_edit();
-}
-
-void
-QRegisterData::append_string(const gchar *str)
-{
- if (!str)
- return;
-
- edit();
-
- interface.ssm(SCI_BEGINUNDOACTION);
- interface.ssm(SCI_APPENDTEXT, strlen(str), (sptr_t)str);
- interface.ssm(SCI_ENDUNDOACTION);
-
- current_edit();
-}
-
-gchar *
-QRegisterData::get_string(void)
-{
- gint size;
- gchar *str;
-
- current_save_dot();
- edit();
-
- size = interface.ssm(SCI_GETLENGTH) + 1;
- str = (gchar *)g_malloc(size);
- interface.ssm(SCI_GETTEXT, size, (sptr_t)str);
-
- current_edit();
-
- return str;
-}
-
-void
-QRegisterData::edit(void)
-{
- interface.ssm(SCI_SETDOCPOINTER, 0, (sptr_t)get_document());
- interface.ssm(SCI_GOTOPOS, dot);
-}
-
-void
-QRegisterData::undo_edit(void)
-{
- if (!must_undo)
- return;
-
- undo.push_msg(SCI_GOTOPOS, dot);
- undo.push_msg(SCI_SETDOCPOINTER, 0, (sptr_t)get_document());
-}
-
-void
-QRegister::edit(void)
-{
- QRegisterData::edit();
- interface.info_update(this);
-}
-
-void
-QRegister::undo_edit(void)
-{
- if (!must_undo)
- return;
-
- interface.undo_info_update(this);
- QRegisterData::undo_edit();
-}
-
-void
-QRegister::execute(bool locals) throw (State::Error)
-{
- gchar *str = get_string();
-
- try {
- Execute::macro(str, locals);
- } catch (...) {
- g_free(str);
- throw; /* forward */
- }
-
- g_free(str);
-}
-
-bool
-QRegister::load(const gchar *filename)
-{
- gchar *contents;
- gsize size;
-
- /* FIXME: prevent excessive allocations by reading file into buffer */
- if (!g_file_get_contents(filename, &contents, &size, NULL))
- return false;
-
- edit();
- dot = 0;
-
- interface.ssm(SCI_BEGINUNDOACTION);
- interface.ssm(SCI_CLEARALL);
- interface.ssm(SCI_APPENDTEXT, size, (sptr_t)contents);
- interface.ssm(SCI_ENDUNDOACTION);
-
- g_free(contents);
-
- current_edit();
-
- return true;
-}
-
-gint64
-QRegisterBufferInfo::get_integer(void)
-{
- gint64 id = 1;
-
- if (!ring.current)
- return 0;
-
- for (Buffer *buffer = ring.first();
- buffer != ring.current;
- buffer = buffer->next())
- id++;
-
- return id;
-}
-
-gchar *
-QRegisterBufferInfo::get_string(void)
-{
- gchar *filename = ring.current ? ring.current->filename : NULL;
-
- return g_strdup(filename ? : "");
-}
-
-void
-QRegisterBufferInfo::edit(void)
-{
- gchar *filename = ring.current ? ring.current->filename : NULL;
-
- QRegister::edit();
-
- interface.ssm(SCI_BEGINUNDOACTION);
- interface.ssm(SCI_SETTEXT, 0, (sptr_t)(filename ? : ""));
- interface.ssm(SCI_ENDUNDOACTION);
-
- undo.push_msg(SCI_UNDO);
-}
-
-void
-QRegisterTable::initialize(void)
-{
- /* general purpose registers */
- for (gchar q = 'A'; q <= 'Z'; q++)
- initialize(q);
- for (gchar q = '0'; q <= '9'; q++)
- initialize(q);
-}
-
-void
-QRegisterTable::edit(QRegister *reg)
-{
- current_save_dot();
- reg->edit();
-
- ring.current = NULL;
- QRegisters::current = reg;
-}
-
-void
-QRegisterStack::UndoTokenPush::run(void)
-{
- SLIST_INSERT_HEAD(&stack->head, entry, entries);
- entry = NULL;
-}
-
-void
-QRegisterStack::UndoTokenPop::run(void)
-{
- Entry *entry = SLIST_FIRST(&stack->head);
-
- SLIST_REMOVE_HEAD(&stack->head, entries);
- delete entry;
-}
-
-void
-QRegisterStack::push(QRegister *reg)
-{
- Entry *entry = new Entry();
-
- entry->set_integer(reg->get_integer());
- if (reg->string) {
- gchar *str = reg->get_string();
- entry->set_string(str);
- g_free(str);
- }
- entry->dot = reg->dot;
-
- SLIST_INSERT_HEAD(&head, entry, entries);
- undo.push(new UndoTokenPop(this));
-}
-
-bool
-QRegisterStack::pop(QRegister *reg)
-{
- Entry *entry = SLIST_FIRST(&head);
- QRegisterData::document *string;
-
- if (!entry)
- return false;
-
- reg->undo_set_integer();
- reg->set_integer(entry->get_integer());
-
- /* exchange document ownership between Stack entry and Q-Register */
- string = reg->string;
- if (reg->must_undo)
- undo.push_var(reg->string);
- reg->string = entry->string;
- undo.push_var(entry->string);
- entry->string = string;
-
- if (reg->must_undo)
- undo.push_var(reg->dot);
- reg->dot = entry->dot;
-
- SLIST_REMOVE_HEAD(&head, entries);
- /* pass entry ownership to undo stack */
- undo.push(new UndoTokenPush(this, entry));
-
- return true;
-}
-
-QRegisterStack::~QRegisterStack()
-{
- Entry *entry, *next;
-
- SLIST_FOREACH_SAFE(entry, &head, entries, next)
- delete entry;
-}
-
-void
-QRegisters::hook(Hook type)
-{
- if (!(Flags::ed & Flags::ED_HOOKS))
- return;
-
- expressions.push(type);
- globals["0"]->execute();
-}
-
void
Buffer::UndoTokenClose::run(void)
{
@@ -639,6 +308,7 @@ Ring::save(const gchar *filename)
undo.push(new UndoTokenRemoveFile(filename));
}
+ /* FIXME: improve by writing before and after document gap */
buffer = (const gchar *)interface.ssm(SCI_GETCHARACTERPOINTER);
size = interface.ssm(SCI_GETLENGTH);
@@ -867,191 +537,3 @@ StateSaveFile::done(const gchar *str) throw (Error)
return &States::start;
}
-
-State *
-StatePushQReg::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- QRegisters::stack.push(reg);
-
- return &States::start;
-}
-
-State *
-StatePopQReg::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- if (!QRegisters::stack.pop(reg))
- throw Error("Q-Register stack is empty");
-
- return &States::start;
-}
-
-State *
-StateEQCommand::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::loadqreg);
- register_argument = reg;
- return &States::loadqreg;
-}
-
-State *
-StateLoadQReg::done(const gchar *str) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- if (*str) {
- register_argument->undo_load();
- if (!register_argument->load(str))
- throw Error("Cannot load \"%s\" into Q-Register \"%s\"",
- str, register_argument->name);
- } else {
- if (ring.current)
- ring.undo_edit();
- else /* QRegisters::current != NULL */
- QRegisters::undo_edit();
- QRegisters::globals.edit(register_argument);
- }
-
- return &States::start;
-}
-
-State *
-StateCtlUCommand::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::setqregstring);
- register_argument = reg;
- return &States::setqregstring;
-}
-
-State *
-StateSetQRegString::done(const gchar *str) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- register_argument->undo_set_string();
- register_argument->set_string(str);
-
- return &States::start;
-}
-
-State *
-StateGetQRegString::got_register(QRegister *reg) throw (Error)
-{
- gchar *str;
-
- BEGIN_EXEC(&States::start);
-
- str = reg->get_string();
- if (*str) {
- interface.ssm(SCI_BEGINUNDOACTION);
- interface.ssm(SCI_ADDTEXT, strlen(str), (sptr_t)str);
- interface.ssm(SCI_SCROLLCARET);
- interface.ssm(SCI_ENDUNDOACTION);
- ring.dirtify();
-
- undo.push_msg(SCI_UNDO);
- }
- g_free(str);
-
- return &States::start;
-}
-
-State *
-StateGetQRegInteger::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- expressions.eval();
- expressions.push(reg->get_integer());
-
- return &States::start;
-}
-
-State *
-StateSetQRegInteger::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- reg->undo_set_integer();
- reg->set_integer(expressions.pop_num_calc());
-
- return &States::start;
-}
-
-State *
-StateIncreaseQReg::got_register(QRegister *reg) throw (Error)
-{
- gint64 res;
-
- BEGIN_EXEC(&States::start);
-
- reg->undo_set_integer();
- res = reg->get_integer() + expressions.pop_num_calc();
- expressions.push(reg->set_integer(res));
-
- return &States::start;
-}
-
-State *
-StateMacro::got_register(QRegister *reg) throw (Error)
-{
- BEGIN_EXEC(&States::start);
-
- /* don't create new local Q-Registers if colon modifier is given */
- reg->execute(!eval_colon());
-
- return &States::start;
-}
-
-State *
-StateCopyToQReg::got_register(QRegister *reg) throw (Error)
-{
- gint64 from, len;
- Sci_TextRange tr;
-
- BEGIN_EXEC(&States::start);
- expressions.eval();
-
- if (expressions.args() <= 1) {
- from = interface.ssm(SCI_GETCURRENTPOS);
- sptr_t line = interface.ssm(SCI_LINEFROMPOSITION, from) +
- expressions.pop_num_calc();
-
- if (!Validate::line(line))
- throw RangeError("X");
-
- len = interface.ssm(SCI_POSITIONFROMLINE, line) - from;
-
- if (len < 0) {
- from += len;
- len *= -1;
- }
- } else {
- gint64 to = expressions.pop_num();
- from = expressions.pop_num();
-
- if (!Validate::pos(from) || !Validate::pos(to))
- throw RangeError("X");
-
- len = to - from;
- }
-
- tr.chrg.cpMin = from;
- tr.chrg.cpMax = from + len;
- tr.lpstrText = (char *)g_malloc(len + 1);
- interface.ssm(SCI_GETTEXTRANGE, 0, (sptr_t)&tr);
-
- if (eval_colon()) {
- reg->undo_append_string();
- reg->append_string(tr.lpstrText);
- } else {
- reg->undo_set_string();
- reg->set_string(tr.lpstrText);
- }
- g_free(tr.lpstrText);
-
- return &States::start;
-}
diff --git a/ring.h b/ring.h
new file mode 100644
index 0000000..da4f322
--- /dev/null
+++ b/ring.h
@@ -0,0 +1,246 @@
+#ifndef __RING_H
+#define __RING_H
+
+#include <string.h>
+#include <bsd/sys/queue.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include <Scintilla.h>
+
+#include "sciteco.h"
+#include "interface.h"
+#include "undo.h"
+#include "qregisters.h"
+#include "parser.h"
+
+/*
+ * Auxiliary functions
+ */
+static inline bool
+is_glob_pattern(const gchar *str)
+{
+ return strchr(str, '*') || strchr(str, '?');
+}
+
+/*
+ * Get absolute/full version of a possibly relative path.
+ * Works with existing and non-existing paths (in the latter case,
+ * heuristics may be applied.)
+ */
+gchar *get_absolute_path(const gchar *path);
+
+/*
+ * Classes
+ */
+
+class Buffer {
+ class UndoTokenClose : public UndoToken {
+ Buffer *buffer;
+
+ public:
+ UndoTokenClose(Buffer *_buffer)
+ : UndoToken(), buffer(_buffer) {}
+
+ void run(void);
+ };
+
+public:
+ TAILQ_ENTRY(Buffer) buffers;
+
+ gchar *filename;
+ gint dot;
+
+ gint savepoint_id;
+
+ bool dirty;
+
+private:
+ typedef void document;
+ document *doc;
+
+public:
+ Buffer() : filename(NULL), dot(0), savepoint_id(0), dirty(false)
+ {
+ doc = (document *)interface.ssm(SCI_CREATEDOCUMENT);
+ }
+ ~Buffer()
+ {
+ interface.ssm(SCI_RELEASEDOCUMENT, 0, (sptr_t)doc);
+ g_free(filename);
+ }
+
+ inline Buffer *&
+ next(void)
+ {
+ return TAILQ_NEXT(this, buffers);
+ }
+ inline Buffer *&
+ prev(void)
+ {
+ TAILQ_HEAD(Head, Buffer);
+
+ return TAILQ_PREV(this, Head, buffers);
+ }
+
+ inline void
+ set_filename(const gchar *filename)
+ {
+ gchar *resolved = get_absolute_path(filename);
+ g_free(Buffer::filename);
+ Buffer::filename = resolved;
+ interface.info_update(this);
+ }
+
+ inline void
+ edit(void)
+ {
+ interface.ssm(SCI_SETDOCPOINTER, 0, (sptr_t)doc);
+ interface.ssm(SCI_GOTOPOS, dot);
+ interface.info_update(this);
+ }
+ inline void
+ undo_edit(void)
+ {
+ interface.undo_info_update(this);
+ undo.push_msg(SCI_GOTOPOS, dot);
+ undo.push_msg(SCI_SETDOCPOINTER, 0, (sptr_t)doc);
+ }
+
+ bool load(const gchar *filename);
+
+ inline void
+ undo_close(void)
+ {
+ undo.push(new UndoTokenClose(this));
+ }
+};
+
+extern class Ring {
+ /*
+ * Emitted after a buffer close
+ * The pointer is the only remaining reference to the buffer!
+ */
+ class UndoTokenEdit : public UndoToken {
+ Ring *ring;
+ Buffer *buffer;
+
+ public:
+ UndoTokenEdit(Ring *_ring, Buffer *_buffer)
+ : UndoToken(), ring(_ring), buffer(_buffer) {}
+ ~UndoTokenEdit()
+ {
+ if (buffer)
+ delete buffer;
+ }
+
+ void run(void);
+ };
+
+ class UndoTokenRemoveFile : public UndoToken {
+ gchar *filename;
+
+ public:
+ UndoTokenRemoveFile(const gchar *_filename)
+ : filename(g_strdup(_filename)) {}
+ ~UndoTokenRemoveFile()
+ {
+ g_free(filename);
+ }
+
+ void
+ run(void)
+ {
+ g_unlink(filename);
+ }
+ };
+
+ TAILQ_HEAD(Head, Buffer) head;
+
+public:
+ Buffer *current;
+
+ Ring() : current(NULL)
+ {
+ TAILQ_INIT(&head);
+ }
+ ~Ring();
+
+ inline Buffer *
+ first(void)
+ {
+ return TAILQ_FIRST(&head);
+ }
+ inline Buffer *
+ last(void)
+ {
+ return TAILQ_LAST(&head, Head);
+ }
+
+ Buffer *find(const gchar *filename);
+ Buffer *find(gint64 id);
+
+ void dirtify(void);
+ bool is_any_dirty(void);
+
+ bool edit(gint64 id);
+ void edit(const gchar *filename);
+ inline void
+ undo_edit(void)
+ {
+ current->dot = interface.ssm(SCI_GETCURRENTPOS);
+ undo.push_var(current);
+ current->undo_edit();
+ }
+
+ bool save(const gchar *filename);
+
+ void close(Buffer *buffer);
+ void close(void);
+ inline void
+ undo_close(void)
+ {
+ current->undo_close();
+ }
+} ring;
+
+/*
+ * Command states
+ */
+
+class StateEditFile : public StateExpectString {
+private:
+ bool allowFilename;
+
+ void do_edit(const gchar *filename) throw (Error);
+ void do_edit(gint64 id) throw (Error);
+
+ void initial(void) throw (Error);
+ State *done(const gchar *str) throw (Error);
+};
+
+class StateSaveFile : public StateExpectString {
+private:
+ State *done(const gchar *str) throw (Error);
+};
+
+namespace States {
+ extern StateEditFile editfile;
+ extern StateSaveFile savefile;
+}
+
+/* FIXME: clean up current_save_dot() usage */
+static inline void
+current_save_dot(void)
+{
+ gint dot = interface.ssm(SCI_GETCURRENTPOS);
+
+ if (ring.current)
+ ring.current->dot = dot;
+ else if (QRegisters::current)
+ QRegisters::current->dot = dot;
+}
+
+#endif
diff --git a/search.cpp b/search.cpp
index f27e744..701f36c 100644
--- a/search.cpp
+++ b/search.cpp
@@ -6,7 +6,8 @@
#include "sciteco.h"
#include "expressions.h"
#include "undo.h"
-#include "qbuffers.h"
+#include "qregisters.h"
+#include "ring.h"
#include "parser.h"
#include "search.h"
diff --git a/search.h b/search.h
index 12b95db..2bddedd 100644
--- a/search.h
+++ b/search.h
@@ -5,7 +5,7 @@
#include "sciteco.h"
#include "parser.h"
-#include "qbuffers.h"
+#include "ring.h"
/*
* "S" command state and base class for all other search/replace commands