diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-12-04 17:29:01 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-12-04 22:07:08 +0100 |
commit | d8a316514c03d85b771a9dce4a8a51b875d955b3 (patch) | |
tree | 8966c29db767a155848f6d90f76771ce5b9de32e /src/qregisters.cpp | |
parent | b120616b6da52e951097f69ad267de06081d218a (diff) | |
download | sciteco-d8a316514c03d85b771a9dce4a8a51b875d955b3.tar.gz |
autoconf preparation: move everything into src/ subdir
Diffstat (limited to 'src/qregisters.cpp')
-rw-r--r-- | src/qregisters.cpp | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/src/qregisters.cpp b/src/qregisters.cpp new file mode 100644 index 0000000..06947f7 --- /dev/null +++ b/src/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; +} |