#define SESSION_FILENAME "session.txt" #define SESSION_VERSION "\x7fTED0002" 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); if (node->active_tab >= ntabs) node->active_tab = 0; 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_cstr(fp, ted->cwd); write_u16(fp, ted->active_node ? (u16)(ted->active_node - ted->nodes) : U16_MAX); // active node idx write_u16(fp, ted->active_buffer ? (u16)(ted->active_buffer - ted->buffers) : U16_MAX); // 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 } read_cstr(fp, ted->cwd, sizeof ted->cwd); u16 active_node_idx = read_u16(fp); u16 active_buffer_idx = read_u16(fp); 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 (active_node_idx == U16_MAX) { ted->active_node = NULL; } else { active_node_idx = clamp_u16(active_node_idx, 0, TED_MAX_NODES); if (ted->nodes_used[active_node_idx]) ted->active_node = &ted->nodes[active_node_idx]; } if (active_buffer_idx == U16_MAX) { ted->active_buffer = NULL; } else { active_buffer_idx = clamp_u16(active_buffer_idx, 0, TED_MAX_BUFFERS); if (ted->buffers_used[active_buffer_idx]) ted->active_buffer = &ted->buffers[active_buffer_idx]; } if (nbuffers && !ted->active_buffer) { // set active buffer to something for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) { if (ted->buffers_used[i]) { ted_switch_to_buffer(ted, &ted->buffers[i]); break; } } } } 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) { remove(filename2); 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); } } }