summaryrefslogtreecommitdiff
path: root/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'session.c')
-rw-r--r--session.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/session.c b/session.c
new file mode 100644
index 0000000..cbd84b0
--- /dev/null
+++ b/session.c
@@ -0,0 +1,173 @@
+#define SESSION_FILENAME "session.txt"
+#define SESSION_VERSION "\x7fTED0001"
+
+static void session_write_node(Ted *ted, FILE *fp, u16 node_idx) {
+ Node *node = &ted->nodes[node_idx];
+ write_u16(fp, node_idx);
+ bool is_split = !node->tabs;
+ write_bool(fp, is_split);
+ if (is_split) {
+ write_float(fp, node->split_pos);
+ write_bool(fp, node->split_vertical);
+ write_u16(fp, node->split_a);
+ write_u16(fp, node->split_b);
+ } else {
+ write_u16(fp, node->active_tab); // active tab
+ write_u16(fp, (u16)arr_len(node->tabs)); // ntabs
+ arr_foreach_ptr(node->tabs, u16, tab) {
+ write_u16(fp, *tab);
+ }
+ }
+}
+
+static void session_read_node(Ted *ted, FILE *fp) {
+ u16 node_idx = read_u16(fp);
+ if (node_idx >= TED_MAX_NODES) {
+ debug_println("WARNING: Invalid node index (see %s:%d)!\n", __FILE__, __LINE__);
+ return;
+ }
+ ted->nodes_used[node_idx] = true;
+ Node *node = &ted->nodes[node_idx];
+ bool is_split = read_bool(fp);
+ if (is_split) {
+ node->split_pos = clampf(read_float(fp), 0, 1);
+ node->split_vertical = read_bool(fp);
+ node->split_a = clamp_u16(read_u16(fp), 0, TED_MAX_NODES);
+ node->split_b = clamp_u16(read_u16(fp), 0, TED_MAX_NODES);
+ } else {
+ node->active_tab = read_u16(fp);
+ u16 ntabs = clamp_u16(read_u16(fp), 0, TED_MAX_TABS);
+ for (u16 i = 0; i < ntabs; ++i) {
+ u16 buf_idx = read_u16(fp);
+ if (buf_idx >= TED_MAX_BUFFERS) continue;
+ arr_add(node->tabs, buf_idx);
+ }
+ }
+}
+
+static void session_write_buffer(Ted *ted, FILE *fp, u16 buffer_idx) {
+ write_u16(fp, buffer_idx);
+ TextBuffer *buffer = &ted->buffers[buffer_idx];
+ // some info about the buffer that should be restored
+ if (buffer->filename && !buffer_is_untitled(buffer))
+ write_cstr(fp, buffer->filename);
+ else
+ write_char(fp, 0);
+ write_double(fp, buffer->scroll_x);
+ write_double(fp, buffer->scroll_y);
+ write_bool(fp, buffer->view_only);
+ buffer_pos_write(buffer->cursor_pos, fp);
+ write_bool(fp, buffer->selection);
+ if (buffer->selection)
+ buffer_pos_write(buffer->selection_pos, fp);
+}
+
+static void session_read_buffer(Ted *ted, FILE *fp) {
+ u16 buffer_idx = read_u16(fp);
+ if (buffer_idx >= TED_MAX_BUFFERS) {
+ debug_println("WARNING: Invalid buffer index (see %s:%d)!\n", __FILE__, __LINE__);
+ return;
+ }
+ TextBuffer *buffer = &ted->buffers[buffer_idx];
+ ted->buffers_used[buffer_idx] = true;
+ char filename[TED_PATH_MAX] = {0};
+ read_cstr(fp, filename, sizeof filename);
+ buffer_create(buffer, ted);
+ if (!buffer_haserr(buffer)) {
+ if (*filename) {
+ if (!buffer_load_file(buffer, filename))
+ buffer_new_file(buffer, TED_UNTITLED);
+ } else {
+ buffer_new_file(buffer, TED_UNTITLED);
+ }
+ buffer->scroll_x = read_double(fp);
+ buffer->scroll_y = read_double(fp);
+ buffer->view_only = read_bool(fp);
+ buffer->cursor_pos = buffer_pos_read(buffer, fp);
+ buffer->selection = read_bool(fp);
+ if (buffer->selection)
+ buffer->selection_pos = buffer_pos_read(buffer, fp);
+ }
+}
+
+static void session_write_file(Ted *ted, FILE *fp) {
+ fwrite(SESSION_VERSION, 1, sizeof SESSION_VERSION, fp);
+
+ write_u16(fp, (u16)(ted->active_node - ted->nodes)); // active node idx
+ write_u16(fp, (u16)(ted->active_buffer - ted->buffers)); // active buffer idx
+
+ u16 nnodes = 0;
+ for (u16 i = 0; i < TED_MAX_NODES; ++i)
+ nnodes += ted->nodes_used[i];
+ write_u16(fp, nnodes);
+ for (u16 i = 0; i < TED_MAX_NODES; ++i)
+ if (ted->nodes_used[i])
+ session_write_node(ted, fp, i);
+
+ u16 nbuffers = 0;
+ for (u16 i = 0; i < TED_MAX_BUFFERS; ++i)
+ nbuffers += ted->buffers_used[i];
+ write_u16(fp, nbuffers);
+ for (u16 i = 0; i < TED_MAX_BUFFERS; ++i)
+ if (ted->buffers_used[i])
+ session_write_buffer(ted, fp, i);
+}
+
+static void session_read_file(Ted *ted, FILE *fp) {
+ char version[sizeof SESSION_VERSION] = {0};
+ fread(version, 1, sizeof version, fp);
+ if (memcmp(version, SESSION_VERSION, sizeof version) != 0) {
+ debug_println("WARNING: Session file has wrong version (see %s:%d)!\n", __FILE__, __LINE__);
+ return; // wrong version
+ }
+
+ u16 active_node_idx = clamp_u16(read_u16(fp), 0, TED_MAX_NODES);
+ u16 active_buffer_idx = clamp_u16(read_u16(fp), 0, TED_MAX_BUFFERS);
+
+ u16 nnodes = clamp_u16(read_u16(fp), 0, TED_MAX_NODES);
+ for (u16 i = 0; i < nnodes; ++i) {
+ session_read_node(ted, fp);
+ }
+
+ u16 nbuffers = clamp_u16(read_u16(fp), 0, TED_MAX_BUFFERS);
+ for (u16 i = 0; i < nbuffers; ++i) {
+ session_read_buffer(ted, fp);
+ }
+
+ if (ted->nodes_used[active_node_idx])
+ ted->active_node = &ted->nodes[active_node_idx];
+ if (ted->buffers_used[active_buffer_idx])
+ ted->active_buffer = &ted->buffers[active_buffer_idx];
+}
+
+static void session_write(Ted *ted) {
+ Settings const *settings = &ted->settings;
+ if (!settings->restore_session)
+ return;
+ // first we write to a prefixed file so in case something goes wrong we still have the old session.
+ char filename1[TED_PATH_MAX], filename2[TED_PATH_MAX];
+ strbuf_printf(filename1, "%s/_" SESSION_FILENAME, ted->local_data_dir);
+ strbuf_printf(filename2, "%s/" SESSION_FILENAME, ted->local_data_dir);
+ FILE *fp = fopen(filename1, "wb");
+ if (fp) {
+ session_write_file(ted, fp);
+
+ bool success = !ferror(fp);
+ success &= fclose(fp) == 0;
+ if (success)
+ rename(filename1, filename2); // overwrite old session
+ }
+}
+
+static void session_read(Ted *ted) {
+ Settings const *settings = &ted->settings;
+ if (settings->restore_session) {
+ char filename[TED_PATH_MAX];
+ strbuf_printf(filename, "%s/" SESSION_FILENAME, ted->local_data_dir);
+ FILE *fp = fopen(filename, "rb");
+ if (fp) {
+ session_read_file(ted, fp);
+ fclose(fp);
+ }
+ }
+}