diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | main.cpp | 12 | ||||
-rw-r--r-- | parser.cpp | 1 | ||||
-rw-r--r-- | parser.h | 2 | ||||
-rw-r--r-- | qbuffers.cpp | 144 | ||||
-rw-r--r-- | qbuffers.h | 122 |
6 files changed, 277 insertions, 6 deletions
@@ -10,7 +10,7 @@ LDFLAGS:=$(GTK_LDFLAGS) $(SCI_LDFLAGS) all : sciteco -sciteco : main.o cmdline.o undo.o expressions.o \ +sciteco : main.o cmdline.o undo.o expressions.o qbuffers.o \ parser.o goto.o $(CXX) -o $@ $^ $(LDFLAGS) @@ -13,6 +13,9 @@ #include <ScintillaWidget.h> #include "sciteco.h" +#include "parser.h" +#include "qbuffers.h" +#include "undo.h" static GtkWidget *editor_widget; static GtkWidget *cmdline_widget; @@ -143,11 +146,10 @@ main(int argc, char **argv) editor_msg(SCI_STYLESETFORE, SCE_C_WORD, 0x800000); editor_msg(SCI_STYLESETFORE, SCE_C_STRING, 0x800080); editor_msg(SCI_STYLESETBOLD, SCE_C_OPERATOR, 1); - editor_msg(SCI_INSERTTEXT, 0, (sptr_t) - "int main(int argc, char **argv) {\n" - " // Start up the gnome\n" - " gnome_init(\"stest\", \"1.0\", argc, argv);\n}" - ); + + ring.edit(NULL); + + undo.enabled = true; cmdline_display("*"); gtk_widget_grab_focus(cmdline_widget); @@ -556,6 +556,7 @@ StateControl::custom(gchar chr) StateECommand::StateECommand() : State() { transitions['\0'] = this; + transitions['B'] = &states.file; } State * @@ -92,6 +92,7 @@ private: }; #include "goto.h" +#include "qbuffers.h" extern gint macro_pc; @@ -100,6 +101,7 @@ extern struct States { StateLabel label; StateControl control; StateECommand ecommand; + StateFile file; StateInsert insert; } states; diff --git a/qbuffers.cpp b/qbuffers.cpp new file mode 100644 index 0000000..03f9562 --- /dev/null +++ b/qbuffers.cpp @@ -0,0 +1,144 @@ +#include <bsd/sys/queue.h> + +#include <glib.h> +#include <glib/gprintf.h> +#include <glib/gstdio.h> + +#include <Scintilla.h> + +#include "sciteco.h" +#include "undo.h" +#include "parser.h" +#include "qbuffers.h" + +Ring ring; + +bool +Buffer::load(const gchar *filename) +{ + gchar *contents; + gsize size; + + edit(); + editor_msg(SCI_CLEARALL); + + /* FIXME: prevent excessive allocations by reading file into buffer */ + if (!g_file_get_contents(filename, &contents, &size, NULL)) + return false; + editor_msg(SCI_APPENDTEXT, size, (sptr_t)contents); + g_free(contents); + + editor_msg(SCI_GOTOPOS, 0); + editor_msg(SCI_SETSAVEPOINT); + + set_filename(filename); + + return true; +} + +void +Buffer::close(void) +{ + LIST_REMOVE(this, buffers); + + if (filename) + message_display(GTK_MESSAGE_INFO, + "Removed file \"%s\" from the ring", + filename); + else + message_display(GTK_MESSAGE_INFO, + "Removed unnamed file from the ring."); +} + +Buffer * +Ring::find(const gchar *filename) +{ + Buffer *cur; + + LIST_FOREACH(cur, &head, buffers) + if (!g_strcmp0(cur->filename, filename)) + return cur; + + return NULL; +} + +bool +Ring::edit(const gchar *filename) +{ + bool new_in_ring = false; + Buffer *buffer = find(filename); + + if (current) + current->dot = editor_msg(SCI_GETCURRENTPOS); + + if (buffer) { + buffer->edit(); + } else { + new_in_ring = true; + + buffer = new Buffer(); + LIST_INSERT_HEAD(&head, buffer, buffers); + + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { + buffer->load(filename); + + message_display(GTK_MESSAGE_INFO, + "Added file \"%s\" to ring", filename); + } else { + buffer->edit(); + buffer->set_filename(filename); + + if (filename) + message_display(GTK_MESSAGE_INFO, + "Added new file \"%s\" to ring", + filename); + else + message_display(GTK_MESSAGE_INFO, + "Added new unnamed file to ring."); + } + } + + current = buffer; + + return new_in_ring; +} + +void +Ring::close(void) +{ + Buffer *buffer = current; + + buffer->close(); + current = LIST_NEXT(buffer, buffers) ? : LIST_FIRST(&head); + if (!current) + edit(NULL); + + delete buffer; +} + +Ring::~Ring() +{ + Buffer *buffer, *next; + + LIST_FOREACH_SAFE(buffer, &head, buffers, next) + delete buffer; +} + +/* + * Command states + */ + +State * +StateFile::done(const gchar *str) +{ + bool new_in_ring; + + BEGIN_EXEC(&states.start); + + ring.undo_edit(); + new_in_ring = ring.edit(*str ? str : NULL); + if (new_in_ring) + ring.undo_close(); + + return &states.start; +} diff --git a/qbuffers.h b/qbuffers.h new file mode 100644 index 0000000..88e5f8f --- /dev/null +++ b/qbuffers.h @@ -0,0 +1,122 @@ +#ifndef __QBUFFERS_H +#define __QBUFFERS_H + +#include <bsd/sys/queue.h> + +#include <glib.h> +#include <glib/gprintf.h> + +#include <Scintilla.h> + +#include "sciteco.h" +#include "undo.h" +#include "parser.h" + +class Buffer { + class UndoTokenClose : public UndoToken { + Buffer *buffer; + + public: + UndoTokenClose(Buffer *_buffer) + : UndoToken(), buffer(_buffer) {} + + void + run(void) + { + buffer->close(); + delete buffer; + } + }; + +public: + LIST_ENTRY(Buffer) buffers; + + gchar *filename; + gint dot; + +private: + typedef void document; + document *doc; + +public: + Buffer() : filename(NULL), dot(0) + { + doc = (document *)editor_msg(SCI_CREATEDOCUMENT); + } + ~Buffer() + { + editor_msg(SCI_RELEASEDOCUMENT, 0, (sptr_t)doc); + g_free(filename); + } + + inline void + set_filename(const gchar *filename) + { + g_free(Buffer::filename); + Buffer::filename = filename ? g_strdup(filename) : NULL; + } + + inline void + edit(void) + { + editor_msg(SCI_SETDOCPOINTER, 0, (sptr_t)doc); + editor_msg(SCI_GOTOPOS, dot); + } + inline void + undo_edit(void) + { + undo.push_msg(SCI_GOTOPOS, dot); + undo.push_msg(SCI_SETDOCPOINTER, 0, (sptr_t)doc); + } + + bool load(const gchar *filename); + + void close(void); + inline void + undo_close(void) + { + undo.push(new UndoTokenClose(this)); + } +}; + +extern class Ring { + LIST_HEAD(Head, Buffer) head; + Buffer *current; + +public: + Ring() : current(NULL) + { + LIST_INIT(&head); + } + ~Ring(); + + Buffer *find(const gchar *filename); + + bool edit(const gchar *filename); + inline void + undo_edit(void) + { + current->dot = editor_msg(SCI_GETCURRENTPOS); + + undo.push_var<Buffer*>(current); + current->undo_edit(); + } + + void close(void); + inline void + undo_close(void) + { + current->undo_close(); + } +} ring; + +/* + * Command states + */ + +class StateFile : public StateExpectString { +private: + State *done(const gchar *str); +}; + +#endif |