diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | cmdline.cpp | 3 | ||||
-rw-r--r-- | interface-gtk.cpp | 3 | ||||
-rw-r--r-- | interface-ncurses.cpp | 3 | ||||
-rw-r--r-- | main.cpp | 3 | ||||
-rw-r--r-- | parser.cpp | 3 | ||||
-rw-r--r-- | qregisters.cpp | 522 | ||||
-rw-r--r-- | qregisters.h (renamed from qbuffers.h) | 219 | ||||
-rw-r--r-- | ring.cpp (renamed from qbuffers.cpp) | 526 | ||||
-rw-r--r-- | ring.h | 246 | ||||
-rw-r--r-- | search.cpp | 3 | ||||
-rw-r--r-- | search.h | 2 |
12 files changed, 796 insertions, 739 deletions
@@ -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" @@ -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 @@ -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, @@ -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; -} @@ -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 @@ -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" @@ -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 |