2 * (C) Copyright 2009 Nicholas A. Zigarovich
4 * Use, modification, and distribution are subject to the terms specified in the
12 * - A session-load-window-replace command which is like
13 * window-current-replace, but which also recycles existing windows.
14 * - A session-load-window-current-flatten command which loads all buffers in a
15 * multi-window section in the current window.
16 * - Session files should be more human readable.
17 * - Ability to store arbitrary session data, for example, a buffer's history.
18 * - The previous two features depend on a parser/generator for retroj's
19 * structured plaintext format.
23 * - This module does not work correctly with daemon mode.
27 * - Inhibit loading of the homepage in windows' initial buffers when auto-
29 * - Auto-save the session when the last conkeror window is closed by a
30 * window manager event. Currently no session is saved.
31 * - Consider how and which errors should be handled. Too often we silently
32 * fail and return without telling the user why we are doing so.
36 //// Manual sessions. ////
39 let _session_dir_default = Cc["@mozilla.org/file/directory_service;1"]
40 .getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
41 _session_dir_default.append("sessions");
42 if (! _session_dir_default.exists())
43 _session_dir_default.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
45 define_variable("session_dir", _session_dir_default,
46 "Default directory for save/load interactive commands.");
48 let _json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
50 function session_get() {
53 for_each_window(function (w) {
56 w.buffers.for_each(function (b) {
57 if (! b.browser || ! b instanceof content_buffer) return;
58 buffers[y] = b.browser.contentDocument.location.href;
68 function session_load(session, window, buffer_idx) {
69 if (! (session[0] && session[0][0]))
70 throw new Error("Invalid 'session' argument.");
73 let bi = buffer_idx != undefined ?
74 buffer_idx : window.buffers.count;
75 for (let i = 0; session[s][i]; ++i, ++bi) {
76 let b = window.buffers.get_buffer(bi);
77 if (! b instanceof content_buffer) continue;
78 if (b) b.load(session[s][i]);
80 let c = buffer_creator(content_buffer, $load = session[s][i]);
81 create_buffer(window, c, OPEN_NEW_BUFFER_BACKGROUND);
84 for (let b = window.buffers.get_buffer(bi); b;
85 b = window.buffers.get_buffer(bi)) {
86 if (b instanceof content_buffer) kill_buffer(b, true);
92 function make_init_hook(session) {
93 function init_hook(window) {
94 for (let i = 1; session[i]; ++i) {
95 let c = buffer_creator(content_buffer, $load = session[i]);
96 create_buffer(window, c, OPEN_NEW_BUFFER_BACKGROUND);
102 for (; session[s]; ++s) {
103 let w = make_window(buffer_creator(content_buffer,
104 $load = session[s][0]));
105 add_hook.call(w, "window_initialize_late_hook",
106 make_init_hook(session[s]));
110 function session_load_window_new(session) {
111 session_load(session);
114 function session_load_window_current(session, window) {
115 let w = window ? window : get_recent_conkeror_window();
116 session_load(session, w);
119 function session_load_window_current_replace(session, window) {
120 let w = window ? window : get_recent_conkeror_window();
121 session_load(session, w, 0);
124 function session_write(path, session) {
125 if (! (path instanceof Ci.nsIFile))
126 path = make_file(path);
127 if (! session) session = session_get();
128 write_text_file(path, _json.encode(session));
131 function session_read(path) {
132 if (! (path instanceof Ci.nsIFile))
133 path = make_file(path);
134 return _json.decode(read_text_file(path));
137 function session_remove(path) {
138 if (! (path instanceof Ci.nsIFile))
139 path = make_file(path);
143 let _session_prompt_file = function (I) {
145 yield I.minibuffer.read_file_path(
146 $prompt = "Session file:",
147 $initial_value = session_dir.path,
153 let _session_file_not_found = function (I, file) {
154 let mb = I ? I.minibuffer : get_recent_conkeror_window().minibuffer;
155 let msg = "Session file not found: " + file.path;
160 interactive("session-save", "Save the current session.", function (I) {
161 session_write(make_file(yield _session_prompt_file(I)), session_get());
164 interactive("session-load-window-new", "Load a session in a new window.",
166 let file = make_file(yield _session_prompt_file(I));
167 if (! file.exists()) _session_file_not_found(I, file);
168 else session_load_window_new(session_read(file));
171 interactive("session-load-window-current",
172 "Load a session in new buffers in the current window.",
174 let file = make_file(yield _session_prompt_file(I));
175 if (! file.exists()) _session_file_not_found(I, file);
176 else session_load_window_current(session_read(file), I.window);
179 interactive("session-load-window-current-replace",
180 "Replace all buffers in the current window with buffers in the saved session.",
182 let file = make_file(yield _session_prompt_file(I));
183 if (! file.exists()) _session_file_not_found(I, file);
184 else session_load_window_current_replace(session_read(file), I.window, 0)
187 interactive("session-remove", "Remove a session file.", function (I) {
188 let file = make_file(yield _session_prompt_file(I));
189 if (! file.exists()) _session_file_not_found(I, file);
190 else session_remove(file);
194 //// Auto-save sessions. ////
197 define_variable("session_auto_save_file", "auto-save",
198 "Default filename for the auto-save session.");
200 define_variable("session_auto_save_auto_load", false,
201 'Whether to load the auto-saved session when the browser is started. ' +
202 'May be true, false, or "prompt".');
204 function session_auto_save_load_window_new() {
205 session_load_window_new(_session_auto_save_cached);
208 function session_auto_save_load_window_current(window) {
209 session_load_window_current(_session_auto_save_cached, window);
212 function session_auto_save_load_window_current_replace(window) {
213 session_load_window_current_replace(_session_auto_save_cached, window);
216 define_variable("session_auto_save_auto_load_fn",
218 "Function to be called to load the auto-saved session at start-up " +
219 "when URLs are given on the command-line. May be " +
220 "session_auto_save_load_window_new, " +
221 "session_auto_save_load_window_current, or null. If null, the" +
222 "session will not be auto-loaded when URLs are given.");
225 // undefined - we have not tried to cache the auto-save.
226 // null - we have tried to cache the auto-save, but it didn't exist.
227 // object - the cached session object for the auto-save.
228 let _session_auto_save_cached = undefined;
230 let _session_auto_save_file_get = function () {
231 if (session_auto_save_file instanceof Ci.nsIFile)
232 return session_auto_save_file;
233 let f = session_dir.clone();
234 f.append(session_auto_save_file);
238 function session_auto_save_save() {
239 let f = _session_auto_save_file_get();
240 let s = session_get();
241 if (s[0]) session_write(f, s);
242 else if (f.exists()) f.remove(false);
245 function session_auto_save_remove() {
246 let f = _session_auto_save_file_get();
247 if (f.exists()) f.remove(false);
250 let _session_auto_save_auto_load = function (user_gave_urls) {
251 if (! session_auto_save_auto_load) return;
252 if (! _session_auto_save_cached) {
253 _session_file_not_found(null, _session_auto_save_file_get());
257 let window = get_recent_conkeror_window();
258 if (session_auto_save_auto_load == true) do_load = true;
259 else if (session_auto_save_auto_load == "prompt" && !user_gave_urls) {
260 do_load = (yield window.minibuffer.read_single_character_option(
261 $prompt = "Load auto-saved session? (y/n)",
262 $options = ["y", "n"]
266 throw new Error("Invalid value for session_auto_save_auto_load: " +
267 session_auto_save_auto_load);
268 if (! do_load) return;
269 if (user_gave_urls) {
270 if (session_auto_save_auto_load_fn)
271 session_auto_save_auto_load_fn(window);
273 else session_auto_save_load_window_current_replace(window);
276 interactive("session-auto-save-load-window-new",
277 "Load the auto-save session in a new window.",
279 if (_session_auto_save_cached == null)
280 _session_file_not_found(I, _session_auto_save_file_get());
281 else session_auto_save_load_window_new();
284 interactive("session-auto-save-load-window-current",
285 "Load the auto-save session in new buffers in the current window.",
287 if (_session_auto_save_cached == null)
288 _session_file_not_found(I, session_auto_save_file_get());
289 else session_auto_save_load_window_current(I.window);
292 interactive("session-auto-save-load-window-current-replace",
293 "Replace all buffers in the current window with buffers in the auto-saved session.",
295 if (_session_auto_save_cached == null)
296 _session_file_not_found(I, session_auto_save_file_get());
297 else session_auto_save_load_window_current_replace(I.window);
300 interactive("session-auto-save-remove", "Remove the auto-save session",
301 session_auto_save_remove);
304 //// auto-save-session-mode ////
307 let _session_auto_save_mode_bootstrap = function (b) {
308 remove_hook("window_initialize_late_hook", _session_auto_save_mode_bootstrap);
309 add_hook("create_buffer_hook", session_auto_save_save);
310 add_hook("kill_buffer_hook", session_auto_save_save);
311 add_hook("content_buffer_location_change_hook", session_auto_save_save);
312 let user_gave_urls = false;
313 for (let i = 0; i < command_line.length; ++i) {
314 if (command_line[i][0] != '-') {
315 user_gave_urls = true;
319 co_call(_session_auto_save_auto_load(user_gave_urls));
322 let _session_auto_save_mode_enable = function () {
323 if (_session_auto_save_cached == undefined) {
324 let f = _session_auto_save_file_get();
325 _session_auto_save_cached = f.exists() ? session_read(f) : null;
327 if (conkeror_started) {
328 add_hook("create_buffer_hook", session_auto_save_save);
329 add_hook("kill_buffer_hook", session_auto_save_save);
330 add_hook("content_buffer_location_change_hook", session_auto_save_save);
333 add_hook("window_initialize_late_hook", _session_auto_save_mode_bootstrap);
336 let _session_auto_save_mode_disable = function () {
337 remove_hook("create_buffer_hook", session_auto_save_save);
338 remove_hook("kill_buffer_hook", session_auto_save_save);
339 remove_hook("content_buffer_location_change_hook", session_auto_save_save);
341 remove_hook("window_initialize_late_hook", _session_auto_save_mode_bootstrap);
344 define_global_mode("session_auto_save_mode",
345 _session_auto_save_mode_enable,
346 _session_auto_save_mode_disable);
348 session_auto_save_mode(true);