Debian package: Declare compliance with Debian Policy 4.3.0
[conkeror.git] / modules / commands.js
blobe4c03661ff4fcac2320e7b3982a6fc823e2d50ad
1 /**
2  * (C) Copyright 2004-2007 Shawn Betts
3  * (C) Copyright 2007-2010 John J. Foerch
4  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
5  *
6  * Use, modification, and distribution are subject to the terms specified in the
7  * COPYING file.
8 **/
10 define_coroutine_hook("before_quit_hook", RUN_HOOK_UNTIL_FAILURE);
11 define_hook("quit_hook");
13 function quit (I, restart) {
14     var res = yield before_quit_hook.run();
15     if (res) {
16         quit_hook.run();
17         var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
18             .getService(Ci.nsIAppStartup);
19         if (restart) {
20             appStartup.quit(appStartup.eRestart | appStartup.eAttemptQuit);
21         } else {
22             appStartup.quit(appStartup.eAttemptQuit);
23         }
24     }
26 interactive("quit", "Quit Conkeror", quit);
28 interactive("restart",
29     "Restart Conkeror",
30     function (I) {
31         yield quit(I, true);
32     });
34 function show_conkeror_version (window) {
35     var xulrunner_version = Cc['@mozilla.org/xre/app-info;1']
36         .getService(Ci.nsIXULAppInfo)
37         .platformVersion;
38     window.minibuffer.message("Conkeror "+conkeror.version+
39                               " (XULRunner "+xulrunner_version+
40                               ", "+get_os()+")");
42 interactive("conkeror-version",
43     "Show version information for Conkeror.",
44     function (I) { show_conkeror_version(I.window); });
45 interactive("version",
46     "Show version information for Conkeror.",
47     "conkeror-version");
49 /* FIXME: maybe this should be supported for non-browser buffers */
50 function scroll_horiz_complete (buffer, n) {
51     var w = buffer.focused_frame;
52     w.scrollTo (n > 0 ? w.scrollMaxX : 0, w.scrollY);
54 interactive("scroll-beginning-of-line",
55     "Scroll the current frame all the way to the left.",
56     function (I) { scroll_horiz_complete(I.buffer, -1); });
58 interactive("scroll-end-of-line",
59     "Scroll the current frame all the way to the right.",
60     function (I) { scroll_horiz_complete(I.buffer, 1); });
62 interactive("scroll-top-left",
63     "Scroll the current frame all the way to the top left",
64     function (I) {
65         scroll_horiz_complete(I.buffer, -1);
66         I.buffer.do_command("cmd_scrollTop");
67     });
70 function delete_window (window) {
71     window.window.close();
73 interactive("delete-window",
74     "Delete the current window.",
75     function (I) { delete_window(I.window); });
77 interactive("jsconsole",
78     "Open the JavaScript console.",
79     "find-url-new-buffer",
80     $browser_object = "chrome://global/content/console.xul");
83 function paste_x_primary_selection (field) {
84     modify_region(field, function (str) read_from_x_primary_selection());
86 interactive("paste-x-primary-selection",
87     "Insert the contents of the X primary selection into the selected field or "+
88     "minibuffer. Deactivates the region if it is active, and leaves the point "+
89     "after the inserted text.",
90     function (I) call_on_focused_field(I, paste_x_primary_selection, true));
93 function open_line (field) {
94     modify_region(field, function() ["\n", 0]);
96 interactive("open-line",
97     "If there is an active region, replace is with a newline, otherwise just "+
98     "insert a newline. In both cases leave point before the inserted newline.",
99     function (I) call_on_focused_field(I, open_line, true));
102 interactive("insert-parentheses",
103     "Insert a pair of parentheses, or surround the currently selected text "+
104     "with a pair of parentheses.",
105     function (I) {
106         call_on_focused_field(I, function (field) {
107             modify_region(field,
108                           function (str) {
109                               return ["("+str+")", (str ? str.length+2 : 1)];
110                           });
111         }, true);
112     });
115 function transpose_chars (field) {
116     var value = field.value;
117     var caret = field.selectionStart; // Caret position.
118     var length = value.length;
120     // If we have less than two character in the field or if we are at the
121     // beginning of the field, do nothing.
122     if (length < 2 || caret == 0)
123         return;
125     // If we are at the end of the field, switch places on the two last
126     // characters. TODO: This should happen at the end of every line, not only
127     // at the end of the field.
128     if (caret == length)
129         caret--;
131     // Do the transposing.
132     field.value = switch_subarrays(value, caret - 1, caret, caret, caret + 1);
134     // Increment the caret position. If this is not done, the caret is left at
135     // the end of the field as a result of the replacing of contents.
136     field.selectionStart = caret + 1;
137     field.selectionEnd = caret + 1;
139 interactive("transpose-chars",
140     "Interchange characters around point, moving forward one character.",
141     function (I) call_on_focused_field(I, transpose_chars, true));
144 interactive("execute-extended-command",
145     "Call a command specified in the minibuffer.",
146     function (I) {
147         var prefix = I.P;
148         var boc = I.browser_object;
149         var prompt = "M-x";
150         if (I.key_sequence)
151             prompt = I.key_sequence.join(" ");
152         if (boc)
153             prompt += ' ['+boc.name+']';
154         if (prefix !== null && prefix !== undefined) {
155             if (typeof prefix == "object")
156                 prompt += prefix[0] == 4 ? " C-u" : " "+prefix[0];
157             else
158                 prompt += " "+prefix;
159         }
160         var command = yield I.minibuffer.read_command($prompt = prompt);
161         call_after_timeout(function () {
162             input_handle_command.call(I.window, new command_event(command));
163         }, 0);
164     },
165     $prefix = true);
168 /// built in commands
169 // see: http://www.xulplanet.com/tutorials/xultu/commandupdate.html
171 // Performs a command on a browser buffer content area
174 define_builtin_commands("",
175     function (I, command) {
176         call_builtin_command(I.window, command);
177     },
178     false);
180 define_builtin_commands("caret-",
181     function (I, command) {
182         var buffer = I.buffer;
183         try {
184             buffer.do_command(command);
185         } catch (e) {
186             /* Ignore exceptions */
187         }
188     },
189     'caret');
191 function get_link_text () {
192     var e = document.commandDispatcher.focusedElement;
193     if (e && e.getAttribute("href")) {
194         return e.getAttribute("href");
195     }
196     return null;
201 function copy_email_address (loc)
203     // Copy the comma-separated list of email addresses only.
204     // There are other ways of embedding email addresses in a mailto:
205     // link, but such complex parsing is beyond us.
206     var qmark = loc.indexOf( "?" );
207     var addresses;
209     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
210         addresses = loc.substring( 7, qmark );
211     } else {
212         addresses = loc.substr( 7 );
213     }
215     //XXX: the original code, which we got from firefox, unescapes the string
216     //     using the current character set.  To do this in conkeror, we
217     //     *should* use an interactive method that gives us the character set,
218     //     rather than fetching it by side-effect.
220     //     // Let's try to unescape it using a character set
221     //     // in case the address is not ASCII.
222     //     try {
223     //         var characterSet = this.target.ownerDocument.characterSet;
224     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
225     //             .getService(Components.interfaces.nsITextToSubURI);
226     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
227     //     }
228     //     catch(ex) {
229     //         // Do nothing.
230     //     }
232     writeToClipboard(addresses);
233     message("Copied '" + addresses + "'");
235 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
238 /* FIXME: fix this command */
240 interactive("source",
241             "Load a JavaScript file.",
242             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
244 function reinit (window) {
245     try {
246         var obs = Cc["@mozilla.org/observer-service;1"]
247             .getService(Ci.nsIObserverService);
248         obs.notifyObservers(null, "startupcache-invalidate", null);
249         var path = load_rc();
250         window.minibuffer.message("Loaded: " + path);
251     } catch (e) {
252         window.minibuffer.message("Failed to load: "+path);
253     }
256 interactive("reinit",
257     "Reload the Conkeror rc file.",
258     function (I) { reinit(I.window); });
260 interactive("help-page",
261     "Open the Conkeror help page.",
262     "find-url-new-buffer",
263     $browser_object = "chrome://conkeror-help/content/help.html");
265 interactive("tutorial",
266     "Open the Conkeror tutorial.",
267     "find-url-new-buffer",
268     $browser_object = "chrome://conkeror-help/content/tutorial.html");
270 function univ_arg_to_number (prefix, default_value) {
271     if (prefix == null) {
272         if (default_value == null)
273             return 1;
274         else
275             return default_value;
276     }
277     if (typeof prefix == "object")
278         return prefix[0];
279     return prefix;
283 interactive("eval-expression",
284     "Evaluate JavaScript statements.",
285     function (I) {
286         var s = yield I.minibuffer.read(
287             $prompt = "Eval:",
288             $history = "eval-expression",
289             $completer = new javascript_completer(conkeror));
290         var result = evaluate(s);
291         if (result !== undefined)
292             I.window.minibuffer.message(String(result));
293     });
296 function show_extension_manager () {
297     return conkeror.window_watcher.openWindow(
298         null,
299         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
300         "ExtensionsWindow",
301         "resizable=yes,dialog=no",
302         null);
304 interactive("extensions",
305     "Open the extensions manager in a new window.",
306     show_extension_manager);
308 function print_buffer (buffer) {
309     buffer.top_frame.print();
312 interactive("print-buffer",
313     "Print the currently loaded page.",
314     function (I) { print_buffer(I.buffer); });
316 function view_partial_source (window, charset, selection) {
317     if (charset)
318         charset = "charset=" + charset;
319     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
320                              "_blank", "scrollbars,resizable,chrome,dialog=no",
321                              null, charset, selection, 'selection');
323 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
326 function view_mathml_source (window, charset, target) {
327     if (charset)
328         charset = "charset=" + charset;
329     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
330                              "_blank", "scrollbars,resizable,chrome,dialog=no",
331                              null, charset, target, 'mathml');
335 function send_key_as_event (window, element, combo) {
336     var split = unformat_key_combo(combo);
337     var event = window.document.createEvent("KeyboardEvent");
338     event.initKeyEvent(
339         "keypress",
340         true,
341         true,
342         null,
343         split.ctrlKey,
344         split.altKey,
345         split.shiftKey,
346         split.metaKey,
347         split.keyCode,
348         split.charCode);
349     if (element)
350         return element.dispatchEvent(event);
351     else
352         return window.dispatchEvent(event);
356 function ensure_content_focused (buffer) {
357     var foc = buffer.focused_frame_or_null;
358     if (!foc)
359         buffer.top_frame.focus();
361 interactive("ensure-content-focused", "Ensure that the content document has focus.",
362     function (I) { ensure_content_focused(I.buffer); });
365 function network_set_online_status (status) {
366     const io_service = Cc["@mozilla.org/network/io-service;1"]
367         .getService(Ci.nsIIOService2);
368     status = !status;
369     io_service.manageOfflineStatus = false;
370     io_service.offline = status;
372 interactive("network-go-online", "Work online.",
373     function (I) { network_set_online_status(true); });
375 interactive("network-go-offline", "Work offline.",
376     function (I) { network_set_online_status(false); });
379 interactive("submit-form",
380     "Submit the form to which the focused element belongs.",
381     function (I) {
382         var el = I.buffer.focused_element.parentNode;
383         while (el && el.tagName != "FORM")
384             el = el.parentNode;
385         if (el) {
386             var inputs = el.getElementsByTagName("input");
387             for (var i = 0, ilen = inputs.length; i < ilen; i++) {
388                 if (inputs[i].getAttribute("type") == "submit")
389                     return browser_object_follow(I.buffer, FOLLOW_DEFAULT,
390                                                  inputs[i]);
391             }
392             el.submit();
393         }
394     });
398  * Browser Object Commands
399  */
400 interactive("follow", null,
401     alternates(follow, follow_new_buffer, follow_new_window),
402     $browser_object = browser_object_links);
404 interactive("follow-top", null,
405     alternates(follow_current_buffer, follow_current_frame),
406     $browser_object = browser_object_frames,
407     $prompt = "Follow");
409 interactive("follow-new-buffer",
410     "Follow a link in a new buffer",
411     alternates(follow_new_buffer, follow_new_window),
412     $browser_object = browser_object_links,
413     $prompt = "Follow");
415 interactive("follow-new-buffer-background",
416     "Follow a link in a new buffer in the background",
417     alternates(follow_new_buffer_background, follow_new_window),
418     $browser_object = browser_object_links,
419     $prompt = "Follow");
421 interactive("follow-new-window",
422     "Follow a link in a new window",
423     follow_new_window,
424     $browser_object = browser_object_links,
425     $prompt = "Follow");
427 interactive("find-url", "Open a URL in the current buffer",
428     alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
429     $browser_object = browser_object_url);
431 interactive("find-url-new-buffer",
432     "Open a URL in a new buffer",
433     alternates(follow_new_buffer, follow_new_window),
434     $browser_object = browser_object_url,
435     $prompt = "Find url");
437 interactive("find-url-new-window", "Open a URL in a new window",
438     follow_new_window,
439     $browser_object = browser_object_url,
440     $prompt = "Find url");
442 interactive("find-alternate-url", "Edit the current URL in the minibuffer",
443     "find-url",
444     $browser_object =
445         define_browser_object_class("alternate-url", null,
446             function (I, prompt) {
447                 check_buffer(I.buffer, content_buffer);
448                 var result = yield I.buffer.window.minibuffer.read_url(
449                     $prompt = prompt,
450                     $initial_value = I.buffer.display_uri_string);
451                 yield co_return(result);
452             }),
453     $prompt = "Find url");
456 interactive("up", "Go to the parent directory of the current URL",
457     "find-url",
458     $browser_object = browser_object_up_url);
460 interactive("home",
461     "Go to the homepage in the current buffer.", "follow",
462     $browser_object = function () { return homepage; });
464 interactive("make-window",
465     "Make a new window with the homepage.",
466     follow_new_window,
467     $browser_object = function () { return homepage; });
469 interactive("focus", null,
470     function (I) {
471         var element = yield read_browser_object(I);
472         browser_element_focus(I.buffer, element);
473     },
474     $browser_object = browser_object_frames);
476 interactive("save",
477     "Save a browser object.",
478     function (I) {
479         var element = yield read_browser_object(I);
480         var spec = load_spec(element);
481         var panel;
482         panel = create_info_panel(I.window, "download-panel",
483                                   [["downloading",
484                                     element_get_operation_label(element, "Saving"),
485                                     load_spec_uri_string(spec)],
486                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
487         try {
488             var file = yield I.minibuffer.read_file_check_overwrite(
489                 $prompt = "Save as:",
490                 $initial_value = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer),
491                 $history = "save");
492         } finally {
493             panel.destroy();
494         }
495         save_uri(spec, file,
496                  $buffer = I.buffer,
497                  $use_cache = false);
498     },
499     $browser_object = browser_object_links);
502 interactive("copy", null,
503     alternates(copy_text, copy_text_append),
504     $browser_object = browser_object_links);
506 interactive("paste-url", "Open a URL from the clipboard in the current buffer.",
507     alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
508     $browser_object = browser_object_paste_url);
510 interactive("paste-url-new-buffer", "Open a URL from the clipboard in a new buffer.",
511     alternates(follow_new_buffer, follow_new_window),
512     $browser_object = browser_object_paste_url);
514 interactive("paste-url-new-window", "Open a URL from the clipboard in a new window.",
515     follow_new_window,
516     $browser_object = browser_object_paste_url);
518 interactive("view-source",
519     "Toggle between source and rendered views of a URL.",
520     alternates(view_source, view_source_new_buffer, view_source_new_window),
521     $browser_object = browser_object_frames);
524 interactive("shell-command-on-url",
525     "Run a shell command on the url of a browser object.\n\n"+
526     "If the given shell command contains the string '{}', the "+
527     "url will be substituted in its place, otherwise the url "+
528     "will be added to the end of the command.",
529     function (I) {
530         var cwd = I.local.cwd;
531         var element = yield read_browser_object(I);
532         var spec = load_spec(element);
533         var uri = load_spec_uri_string(spec);
534         var panel = create_info_panel(I.window, "download-panel",
535                                       [["downloading",
536                                         element_get_operation_label(element, "Running on", "URI"),
537                                         load_spec_uri_string(spec)],
538                                        ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
539         try {
540             var cmd = yield I.minibuffer.read_shell_command(
541                 $cwd = cwd,
542                 $initial_value = load_spec_default_shell_command(spec));
543         } finally {
544             panel.destroy();
545         }
546         shell_command_with_argument_blind(cmd, uri, $cwd = cwd);
547     },
548     $browser_object = browser_object_url,
549     $prompt = "Shell command");
552 interactive("shell-command-on-file",
553     "Download a document to a temporary file and run a shell command on it.",
554     function (I) {
555         var cwd = I.local.cwd;
556         var element = yield read_browser_object(I);
557         var spec = load_spec(element);
558         var uri = load_spec_uri_string(spec);
559         var panel = create_info_panel(I.window, "download-panel",
560                                       [["downloading",
561                                         element_get_operation_label(element, "Running on"),
562                                         load_spec_uri_string(spec)],
563                                        ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
564         try {
565             var cmd = yield I.minibuffer.read_shell_command(
566                 $cwd = cwd,
567                 $initial_value = load_spec_default_shell_command(spec));
568         } finally {
569             panel.destroy();
570         }
571         yield browser_element_shell_command(I.buffer, element, cmd, cwd);
572     },
573     $browser_object = browser_object_links,
574     $prompt = "Shell command");
577 interactive("bookmark",
578     "Create a bookmark.",
579     function (I) {
580         var element = yield read_browser_object(I);
581         var spec = load_spec(element);
582         var uri_string = load_spec_uri_string(spec);
583         var panel = create_info_panel(I.window, "bookmark-panel",
584                                       [["bookmarking",
585                                         element_get_operation_label(element, "Bookmarking"),
586                                         uri_string]]);
587         try {
588             var title = yield I.minibuffer.read($prompt = "Bookmark with title:", $initial_value = load_spec_title(spec) || "");
589         } finally {
590             panel.destroy();
591         }
592         add_bookmark(uri_string, title);
593         I.minibuffer.message("Added bookmark: " + uri_string + " - " + title);
594     },
595     $browser_object = browser_object_frames);
598 interactive("save-page",
599     "Save a document, not including any embedded documents such as images "+
600     "and css.",
601     function (I) {
602         check_buffer(I.buffer, content_buffer);
603         var element = yield read_browser_object(I);
604         var spec = load_spec(element);
605         if (!load_spec_document(spec))
606             throw interactive_error("Element is not associated with a document.");
607         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
608         var panel = create_info_panel(I.window, "download-panel",
609                                       [["downloading",
610                                         element_get_operation_label(element, "Saving"),
611                                         load_spec_uri_string(spec)],
612                                        ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
613         try {
614             var file = yield I.minibuffer.read_file_check_overwrite(
615                 $prompt = "Save page as:",
616                 $history = "save",
617                 $initial_value = suggested_path);
618         } finally {
619             panel.destroy();
620         }
621         save_uri(spec, file, $buffer = I.buffer);
622     },
623     $browser_object = browser_object_frames);
626 interactive("save-page-as-text",
627     "Save a page as plain text.",
628     function (I) {
629         check_buffer(I.buffer, content_buffer);
630         var element = yield read_browser_object(I);
631         var spec = load_spec(element);
632         var doc;
633         if (!(doc = load_spec_document(spec)))
634             throw interactive_error("Element is not associated with a document.");
635         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec, "txt"), I.buffer);
636         var panel = create_info_panel(I.window, "download-panel",
637                                       [["downloading",
638                                         element_get_operation_label(element, "Saving", "as text"),
639                                         load_spec_uri_string(spec)],
640                                        ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
641         try {
642             var file = yield I.minibuffer.read_file_check_overwrite(
643                 $prompt = "Save page as text:",
644                 $history = "save",
645                 $initial_value = suggested_path);
646         } finally {
647             panel.destroy();
648         }
649         save_document_as_text(doc, file, $buffer = I.buffer);
650     },
651     $browser_object = browser_object_frames);
654 interactive("save-page-complete",
655     "Save a page and all supporting documents, including images, css, "+
656     "and child frame documents.",
657     function (I) {
658         check_buffer(I.buffer, content_buffer);
659         var element = yield read_browser_object(I);
660         var spec = load_spec(element);
661         var doc;
662         if (!(doc = load_spec_document(spec)))
663             throw interactive_error("Element is not associated with a document.");
664         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
665         var panel = create_info_panel(I.window, "download-panel",
666                                       [["downloading",
667                                         element_get_operation_label(element, "Saving complete"),
668                                         load_spec_uri_string(spec)],
669                                        ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
670         try {
671             var file = yield I.minibuffer.read_file_check_overwrite(
672                 $prompt = "Save page complete:",
673                 $history = "save",
674                 $initial_value = suggested_path);
675             // FIXME: use proper read function
676             var dir = yield I.minibuffer.read_file(
677                 $prompt = "Data Directory:",
678                 $history = "save",
679                 $initial_value = file.path + ".support");
680         } finally {
681             panel.destroy();
682         }
683         save_document_complete(doc, file, dir, $buffer = I.buffer);
684     },
685     $browser_object = browser_object_frames);
688 function view_as_mime_type (I, target) {
689     I.target = target;
690     var element = yield read_browser_object(I);
691     var spec = load_spec(element);
693     if (target == null)
694         target = FOLLOW_CURRENT_FRAME;
696     if (!can_override_mime_type_for_uri(load_spec_uri(spec)))
697         throw interactive_error("Overriding the MIME type is not currently supported for non-HTTP URLs.");
699     var mime_type = load_spec_mime_type(spec);
700     var panel = create_info_panel(I.window, "download-panel",
701                                   [["downloading",
702                                     element_get_operation_label(element, "View in browser"),
703                                     load_spec_uri_string(spec)],
704                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
705     try {
706         let suggested_type = mime_type;
707         if (viewable_mime_type_list.indexOf(suggested_type) == -1)
708             suggested_type = "text/plain";
709         mime_type = yield I.minibuffer.read_viewable_mime_type(
710             $prompt = "View internally as",
711             $initial_value = suggested_type,
712             $select);
713         yield override_mime_type_for_next_load(load_spec_uri(spec), mime_type);
714         browser_object_follow(I.buffer, target, spec);
715     } finally {
716         panel.destroy();
717     }
720 function view_as_mime_type_new_buffer (I) {
721     yield view_as_mime_type(I, OPEN_NEW_BUFFER);
724 function view_as_mime_type_new_window (I) {
725     yield view_as_mime_type(I, OPEN_NEW_WINDOW);
728 interactive("view-as-mime-type",
729     "Display a browser object in the browser using the specified MIME type.",
730     alternates(view_as_mime_type,
731                view_as_mime_type_new_buffer,
732                view_as_mime_type_new_window),
733     $browser_object = browser_object_frames);
736 interactive("delete",
737     "Delete a DOM node, given as a browser object.",
738     function (I) {
739         var elem = yield read_browser_object(I);
740         if (! (elem instanceof Ci.nsIDOMNode))
741             throw interactive_error("Cannot delete item");
742         elem.parentNode.removeChild(elem);
743     },
744     $browser_object = browser_object_dom_node);
747 interactive("charset-prefix",
748     "A prefix command that prompts for a charset to use in a "+
749     "subsequent navigation command.",
750     function (I) {
751         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
752             .getService(Ci.nsICharsetConverterManager);
753         var decoders = ccman.getDecoderList()
754         var charsets = [];
755         while (decoders.hasMore())
756             charsets.push(decoders.getNext());
757         I.forced_charset = yield I.minibuffer.read(
758             $prompt = "Charset:",
759             $completer = new prefix_completer(
760                 $completions = charsets,
761                 $get_string = function (x) x.toLowerCase()),
762             $require_match,
763             $space_completes);
764     },
765     $prefix);
768 interactive("reload-with-charset",
769     "Prompt for a charset, and reload the current page, forcing use "+
770     "of that charset.",
771     function (I) {
772         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
773             .getService(Ci.nsICharsetConverterManager);
774         var decoders = ccman.getDecoderList()
775         var charsets = [];
776         while (decoders.hasMore())
777             charsets.push(decoders.getNext());
778         var forced_charset = yield I.minibuffer.read(
779             $prompt = "Charset:",
780             $completer = new prefix_completer(
781                 $completions = charsets,
782                 $get_string = function (x) x.toLowerCase()),
783             $require_match,
784             $space_completes);
785         reload(I.buffer, false, null, forced_charset);
786     });
789 interactive("yank",
790     "Paste the contents of the clipboard",
791     function (I) {
792         call_builtin_command(I.window, "cmd_paste", true);
793     });
795 interactive("kill-region",
796     "Kill (\"cut\") the selected text.",
797     function (I) {
798         call_builtin_command(I.window, "cmd_cut", true);
799     });
801 interactive("kill-ring-save",
802     "Save the region as if killed, but don't kill it.",
803     function (I) {
804         call_builtin_command(I.window, "cmd_copy", true);
805     });
807 interactive("password-manager",
808     "Open the password manager.",
809     "find-url-new-buffer",
810     $browser_object = "chrome://passwordmgr/content/passwordManager.xul");
813 interactive("toggle-full-screen",
814     "Toggle full screen mode for the current window.",
815     function (I) {
816         window_set_full_screen(I.window);
817         if (I.window.fullScreen)
818             I.minibuffer.message("Fullscreen mode on");
819         else
820             I.minibuffer.message("Fullscreen mode off");
821     });
824 interactive("image-toggle-zoom-to-fit",
825     "Toggle zoom-to-fit (viewport) on an image document.",
826     function (I) {
827         try {
828             var doc = I.buffer.document
829                 .QueryInterface(Ci.nsIImageDocument);
830             doc.toggleImageSize();
831             zoom_hook.run(I.buffer);
832         } catch (e) {
833             I.minibuffer.message("Not an image document");
834         }
835     });
838 provide("commands");