commit - fff512aae8ab52742cc4622c2c069b80485b47e3
commit + 6c74799d01bfb8706f1972917da936fc2eee66da
blob - 34787152d2da79894284b909dec383aa033e419e
blob + e328ac9f7af797b1c7ef58320f2ff30a7d1ccef1
--- ChangeLog
+++ ChangeLog
+2022-01-05 Omar Polo <op@omarpolo.com>
+
+ * defaults.c (load_default_keys): bind `u' to tab-undo-close.
+ (config_setvari): add "max-killed-tabs" to control the maximum number of killed tabs to keep.
+
+ * cmd.c (cmd_tab_undo_close): allow to re-open closed tabs.
+
+ * session.c (kill_tab): save killed tabs into a queue.
+
2022-01-02 Omar Polo <op@omarpolo.com>
* telescope.c (handle_imsg_session): implement persistent tab history
blob - adbdf3b9d75a5755f48b67d2e0a8137838d20c24
blob + 3d737a1f4f8e1e94d14ea6b63705227c91b032d6
--- cmd.c
+++ cmd.c
if ((t = TAILQ_NEXT(tab, tabs)) != NULL ||
(t = TAILQ_PREV(tab, tabshead, tabs)) != NULL) {
switch_to_tab(t);
- free_tab(tab);
+ kill_tab(tab);
} else
message("Can't close the only tab.");
if (t == current_tab)
continue;
- free_tab(t);
+ kill_tab(t);
}
}
void
+cmd_tab_undo_close(struct buffer *buffer)
+{
+ struct tab *t;
+
+ if ((t = unkill_tab()) == NULL) {
+ message("No recently-closed tabs");
+ return;
+ }
+
+ switch_to_tab(t);
+}
+
+void
cmd_tab_new(struct buffer *buffer)
{
const char *url;
blob - d3e8e03401973d0af7f6105aa76cd809ea4dee79
blob + 3a94d6f4dfe7251a846e41b3996fbfdfa3da85bf
--- cmd.h
+++ cmd.h
CMD(cmd_swiper, "Jump to a line using the minibuffer.");
CMD(cmd_tab_close, "Close the current tab.");
CMD(cmd_tab_close_other, "Close all tabs but the current one.");
+CMD(cmd_tab_undo_close, "Reopen last closed tab.");
CMD(cmd_tab_move, "Move the current tab to the right.");
CMD(cmd_tab_move_to, "Move the current tab to the left.");
CMD(cmd_tab_new, "Open a new tab.");
blob - e20b1fc63a211b1bdf2509f5b9bbd54f6f9b1787
blob + 76189e2e1a837c7a98b1f43edda5c47f0433399b
--- defaults.c
+++ defaults.c
int hide_pre_blocks = 0;
int hide_pre_closing_line = 0;
int hide_pre_context = 0;
+int max_killed_tabs = 10;
int olivetti_mode = 1;
int set_title = 1;
int tab_bar_show = 1;
global_set_key("H", cmd_previous_page);
global_set_key("L", cmd_next_page);
+
+ global_set_key("u", cmd_tab_undo_close);
/* tmp */
global_set_key("q", cmd_kill_telescope);
tab_bar_show = 0;
else
tab_bar_show = 1;
+ } else if (!strcmp(var, "max-killed-tabs")) {
+ if (val >= 0)
+ max_killed_tabs = val;
} else {
return 0;
}
blob - d6f309f1e81cbc284fc8df38ac3bbe09c1926ad1
blob + 177c8b83606b33ad09561dae2b66e7d0413a05db
--- defaults.h
+++ defaults.h
extern int hide_pre_blocks;
extern int hide_pre_closing_line;
extern int hide_pre_context;
+extern int max_killed_tabs;
extern int olivetti_mode;
extern int set_title;
extern int tab_bar_show;
blob - 00c622fa9fc5ec86cc0db1acca0159e026fe9a1a
blob + 62b6b4f265d04a920df1f6b96c644d498c7b6ea5
--- fs.c
+++ fs.c
fprintf(session, "%s", tab.uri);
- if (tab.flags & TAB_CURRENT)
- fprintf(session, " current ");
- else
+ if (tab.flags == 0)
fprintf(session, " - ");
+ else {
+ fprintf(session, " ");
+ if (tab.flags & TAB_CURRENT)
+ fprintf(session, "current,");
+ if (tab.flags & TAB_KILLED)
+ fprintf(session, "killed,");
+ fprintf(session, " ");
+ }
fprintf(session, "%s\n", tab.title);
}
while ((ap = strsep(&s, ",")) != NULL) {
if (!strcmp(ap, "current"))
*flags |= TAB_CURRENT;
+ else if (!strcmp(ap, "killed"))
+ *flags |= TAB_KILLED;
}
}
blob - c3b8bf4d957d13e5a94dc793b4a5a7a47613696d
blob + 41ca7dcb1df7409e3b89e2e685af4c7d26be107a
--- session.c
+++ session.c
}
/*
- * Free every resource linked to the tab, including the tab itself.
- * Removes the tab from the tablist, but doesn't update the
- * current_tab though.
+ * Move a tab from the tablist to the killed tab list and erase its
+ * contents. NB: doesn't update the current_tab.
*/
void
-free_tab(struct tab *tab)
+kill_tab(struct tab *tab)
{
+ int count;
+
stop_tab(tab);
+ erase_buffer(&tab->buffer);
+ TAILQ_REMOVE(&tabshead, tab, tabs);
ui_schedule_redraw();
autosave_hook();
if (evtimer_pending(&tab->loadingev, NULL))
evtimer_del(&tab->loadingev);
- TAILQ_REMOVE(&tabshead, tab, tabs);
+ TAILQ_INSERT_HEAD(&ktabshead, tab, tabs);
+
+ /* gc closed tabs */
+ count = 0;
+ TAILQ_FOREACH(tab, &ktabshead, tabs)
+ count++;
+ while (count > max_killed_tabs) {
+ count--;
+ free_tab(TAILQ_LAST(&ktabshead, tabshead));
+ }
+}
+
+/*
+ * Resurrects the lastest killed tab and returns it. The tab is already
+ * added to the tab list with the TAB_LAZY flag set. NB: this doesn't
+ * update current_tab.
+ */
+struct tab *
+unkill_tab(void)
+{
+ struct tab *t;
+
+ if (TAILQ_EMPTY(&ktabshead))
+ return NULL;
+
+ autosave_hook();
+
+ t = TAILQ_FIRST(&ktabshead);
+ TAILQ_REMOVE(&ktabshead, t, tabs);
+ TAILQ_INSERT_TAIL(&tabshead, t, tabs);
+ t->flags |= TAB_LAZY;
+ return t;
+}
+
+/*
+ * Free every resource linked to the tab, including the tab itself.
+ * Removes the tab from the *killed* tablist, but doesn't update the
+ * current_tab though.
+ */
+void
+free_tab(struct tab *tab)
+{
+ /* TODO: free the history */
+ TAILQ_REMOVE(&ktabshead, tab, tabs);
free(tab);
}
ui_send_net(IMSG_STOP, tab->id, NULL, 0);
}
-void
-save_session(void)
+static inline void
+sendtab(struct tab *tab, int killed)
{
struct session_tab st;
struct session_tab_hist sth;
- struct tab *tab;
struct hist *h;
int future;
- if (safe_mode)
- return;
+ memset(&st, 0, sizeof(st));
- ui_send_fs(IMSG_SESSION_START, 0, NULL, 0);
+ if (tab == current_tab)
+ st.flags |= TAB_CURRENT;
+ if (killed)
+ st.flags |= TAB_KILLED;
- TAILQ_FOREACH(tab, &tabshead, tabs) {
- memset(&st, 0, sizeof(st));
+ strlcpy(st.uri, tab->hist_cur->h, sizeof(st.uri));
+ strlcpy(st.title, tab->buffer.page.title, sizeof(st.title));
+ ui_send_fs(IMSG_SESSION_TAB, 0, &st, sizeof(st));
- if (tab == current_tab)
- st.flags = TAB_CURRENT;
+ future = 0;
+ TAILQ_FOREACH(h, &tab->hist.head, entries) {
+ if (h == tab->hist_cur) {
+ future = 1;
+ continue;
+ }
- strlcpy(st.uri, tab->hist_cur->h, sizeof(st.uri));
- strlcpy(st.title, tab->buffer.page.title, sizeof(st.title));
- ui_send_fs(IMSG_SESSION_TAB, 0, &st, sizeof(st));
+ memset(&sth, 0, sizeof(sth));
+ strlcpy(sth.uri, h->h, sizeof(sth.uri));
+ sth.future = future;
+ ui_send_fs(IMSG_SESSION_TAB_HIST, 0, &sth, sizeof(sth));
+ }
- future = 0;
- TAILQ_FOREACH(h, &tab->hist.head, entries) {
- if (h == tab->hist_cur) {
- future = 1;
- continue;
- }
+}
- memset(&sth, 0, sizeof(sth));
- strlcpy(sth.uri, h->h, sizeof(sth.uri));
- sth.future = future;
- ui_send_fs(IMSG_SESSION_TAB_HIST, 0, &sth, sizeof(sth));
- }
- }
+void
+save_session(void)
+{
+ struct tab *tab;
+ if (safe_mode)
+ return;
+
+ ui_send_fs(IMSG_SESSION_START, 0, NULL, 0);
+
+ TAILQ_FOREACH(tab, &tabshead, tabs)
+ sendtab(tab, 0);
+ TAILQ_FOREACH(tab, &ktabshead, tabs)
+ sendtab(tab, 1);
+
ui_send_fs(IMSG_SESSION_END, 0, NULL, 0);
}
blob - 6d2ba716953cd94537053699950aa11304f5a8c8
blob + 27af81e3dc4e84f9178b54b4636499d516f6cc25
--- session.h
+++ session.h
void switch_to_tab(struct tab *);
unsigned int tab_new_id(void);
struct tab *new_tab(const char *, const char *base, struct tab *);
+void kill_tab(struct tab *);
+struct tab *unkill_tab(void);
void free_tab(struct tab *);
void stop_tab(struct tab*);
blob - 9c81b8fbd2cbbad08aa49c3f9bdd02cc73516ecf
blob + 7dac83364bc3bc2eea62d67b52a8b09862b41ec4
--- telescope.c
+++ telescope.c
static struct imsgev *iev_fs, *iev_net;
struct tabshead tabshead = TAILQ_HEAD_INITIALIZER(tabshead);
+struct tabshead ktabshead = TAILQ_HEAD_INITIALIZER(ktabshead);
struct proxylist proxies = TAILQ_HEAD_INITIALIZER(proxies);
enum telescope_process {
sizeof(tab->buffer.page.title));
if (st.flags & TAB_CURRENT)
curr = tab;
+ if (st.flags & TAB_KILLED)
+ kill_tab(tab);
break;
case IMSG_SESSION_TAB_HIST:
blob - 1cb51617e81908a9f7c4f87713bf8de8bc19c253
blob + 927d3cb37b29dd04e0d0c3970be303617229a575
--- telescope.h
+++ telescope.h
};
#define TAB_CURRENT 0x1 /* only for save_session */
-#define TAB_URGENT 0x2
-#define TAB_LAZY 0x4 /* to lazy load tabs */
+#define TAB_KILLED 0x2 /* only for save_session */
+#define TAB_URGENT 0x4
+#define TAB_LAZY 0x8 /* to lazy load tabs */
#define NEW_TAB_URL "about:new"
-extern TAILQ_HEAD(tabshead, tab) tabshead;
+TAILQ_HEAD(tabshead, tab);
+extern struct tabshead tabshead;
+extern struct tabshead ktabshead;
struct tab {
TAILQ_ENTRY(tab) tabs;
uint32_t id;