scroll-top-left: fix for xulrunner >= 23
[conkeror.git] / modules / commands.js
blob212336547363f327fd4e1b0cee0a8eaec06081e3
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 () {
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         appStartup.quit(appStartup.eAttemptQuit);
20     }
22 interactive("quit", "Quit Conkeror", quit);
25 function show_conkeror_version (window) {
26     var xulrunner_version = Cc['@mozilla.org/xre/app-info;1']
27         .getService(Ci.nsIXULAppInfo)
28         .platformVersion;
29     window.minibuffer.message("Conkeror "+conkeror.version+
30                               " (XULRunner "+xulrunner_version+
31                               ", "+get_os()+")");
33 interactive("conkeror-version",
34     "Show version information for Conkeror.",
35     function (I) { show_conkeror_version(I.window); });
36 interactive("version",
37     "Show version information for Conkeror.",
38     "conkeror-version");
40 /* FIXME: maybe this should be supported for non-browser buffers */
41 function scroll_horiz_complete (buffer, n) {
42     var w = buffer.focused_frame;
43     w.scrollTo (n > 0 ? w.scrollMaxX : 0, w.scrollY);
45 interactive("scroll-beginning-of-line",
46     "Scroll the current frame all the way to the left.",
47     function (I) { scroll_horiz_complete(I.buffer, -1); });
49 interactive("scroll-end-of-line",
50     "Scroll the current frame all the way to the right.",
51     function (I) { scroll_horiz_complete(I.buffer, 1); });
53 interactive("scroll-top-left",
54     "Scroll the current frame all the way to the top left",
55      function (I) {
56          scroll_horiz_complete(I.buffer, -1);
57          I.buffer.do_command("cmd_scrollTop");
58      });
61 function delete_window (window) {
62     window.window.close();
64 interactive("delete-window",
65     "Delete the current window.",
66     function (I) { delete_window(I.window); });
68 interactive("jsconsole",
69     "Open the JavaScript console.",
70     "find-url-new-buffer",
71     $browser_object = "chrome://global/content/console.xul");
74 function paste_x_primary_selection (field) {
75     modify_region(field, function (str) read_from_x_primary_selection());
77 interactive("paste-x-primary-selection",
78     "Insert the contents of the X primary selection into the selected field or "+
79     "minibuffer. Deactivates the region if it is active, and leaves the point "+
80     "after the inserted text.",
81     function (I) call_on_focused_field(I, paste_x_primary_selection, true));
84 function open_line (field) {
85     modify_region(field, function() ["\n", 0]);
87 interactive("open-line",
88     "If there is an active region, replace is with a newline, otherwise just "+
89     "insert a newline. In both cases leave point before the inserted newline.",
90     function (I) call_on_focused_field(I, open_line, true));
93 interactive("insert-parentheses",
94     "Insert a pair of parentheses, or surround the currently selected text "+
95     "with a pair of parentheses.",
96     function (I) {
97         call_on_focused_field(I, function (field) {
98             modify_region(field,
99                           function (str) {
100                               return ["("+str+")", (str ? str.length+2 : 1)];
101                           });
102         }, true);
103     });
106 function transpose_chars (field) {
107     var value = field.value;
108     var caret = field.selectionStart; // Caret position.
109     var length = value.length;
111     // If we have less than two character in the field or if we are at the
112     // beginning of the field, do nothing.
113     if (length < 2 || caret == 0)
114         return;
116     // If we are at the end of the field, switch places on the two last
117     // characters. TODO: This should happen at the end of every line, not only
118     // at the end of the field.
119     if (caret == length)
120         caret--;
122     // Do the transposing.
123     field.value = switch_subarrays(value, caret - 1, caret, caret, caret + 1);
125     // Increment the caret position. If this is not done, the caret is left at
126     // the end of the field as a result of the replacing of contents.
127     field.selectionStart = caret + 1;
128     field.selectionEnd = caret + 1;
130 interactive("transpose-chars",
131     "Interchange characters around point, moving forward one character.",
132     function (I) call_on_focused_field(I, transpose_chars, true));
135 interactive("execute-extended-command",
136     "Call a command specified in the minibuffer.",
137     function (I) {
138         var prefix = I.P;
139         var boc = I.browser_object;
140         var prompt = "M-x";
141         if (I.key_sequence)
142             prompt = I.key_sequence.join(" ");
143         if (boc)
144             prompt += ' ['+boc.name+']';
145         if (prefix !== null && prefix !== undefined) {
146             if (typeof prefix == "object")
147                 prompt += prefix[0] == 4 ? " C-u" : " "+prefix[0];
148             else
149                 prompt += " "+prefix;
150         }
151         var command = yield I.minibuffer.read_command($prompt = prompt);
152         call_after_timeout(function () {
153             input_handle_command.call(I.window, new command_event(command));
154         }, 0);
155     },
156     $prefix = true);
159 /// built in commands
160 // see: http://www.xulplanet.com/tutorials/xultu/commandupdate.html
162 // Performs a command on a browser buffer content area
165 define_builtin_commands(
166     "",
167     function (I, command) {
168         call_builtin_command(I.window, command);
169     },
170     false
173 define_builtin_commands(
174     "caret-",
175     function (I, command) {
176         var buffer = I.buffer;
177         try {
178             buffer.do_command(command);
179         } catch (e) {
180             /* Ignore exceptions */
181         }
182     },
183     'caret');
185 function get_link_text () {
186     var e = document.commandDispatcher.focusedElement;
187     if (e && e.getAttribute("href")) {
188         return e.getAttribute("href");
189     }
190     return null;
195 function copy_email_address (loc)
197     // Copy the comma-separated list of email addresses only.
198     // There are other ways of embedding email addresses in a mailto:
199     // link, but such complex parsing is beyond us.
200     var qmark = loc.indexOf( "?" );
201     var addresses;
203     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
204         addresses = loc.substring( 7, qmark );
205     } else {
206         addresses = loc.substr( 7 );
207     }
209     //XXX: the original code, which we got from firefox, unescapes the string
210     //     using the current character set.  To do this in conkeror, we
211     //     *should* use an interactive method that gives us the character set,
212     //     rather than fetching it by side-effect.
214     //     // Let's try to unescape it using a character set
215     //     // in case the address is not ASCII.
216     //     try {
217     //         var characterSet = this.target.ownerDocument.characterSet;
218     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
219     //             .getService(Components.interfaces.nsITextToSubURI);
220     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
221     //     }
222     //     catch(ex) {
223     //         // Do nothing.
224     //     }
226     writeToClipboard(addresses);
227     message("Copied '" + addresses + "'");
229 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
232 /* FIXME: fix this command */
234 interactive("source",
235             "Load a JavaScript file.",
236             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
238 function reinit (window) {
239     try {
240         var obs = Cc["@mozilla.org/observer-service;1"]
241             .getService(Ci.nsIObserverService);
242         obs.notifyObservers(null, "startupcache-invalidate", null);
243         var path = load_rc();
244         window.minibuffer.message("Loaded: " + path);
245     } catch (e) {
246         window.minibuffer.message("Failed to load: "+path);
247     }
250 interactive("reinit",
251             "Reload the Conkeror rc file.",
252             function (I) { reinit(I.window); });
254 interactive("help-page", "Open the Conkeror help page.",
255             "find-url-new-buffer",
256             $browser_object = "chrome://conkeror-help/content/help.html");
258 interactive("tutorial", "Open the Conkeror tutorial.",
259             "find-url-new-buffer",
260             $browser_object = "chrome://conkeror-help/content/tutorial.html");
262 function univ_arg_to_number (prefix, default_value) {
263     if (prefix == null) {
264         if (default_value == null)
265             return 1;
266         else
267             return default_value;
268     }
269     if (typeof prefix == "object")
270         return prefix[0];
271     return prefix;
275 interactive("eval-expression",
276     "Evaluate JavaScript statements.",
277     function (I) {
278         var s = yield I.minibuffer.read(
279             $prompt = "Eval:",
280             $history = "eval-expression",
281             $completer = javascript_completer(I.buffer));
282         var result = evaluate(s);
283         if (result !== undefined)
284             I.window.minibuffer.message(String(result));
285     });
288 function show_extension_manager () {
289     return conkeror.window_watcher.openWindow(
290         null,
291         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
292         "ExtensionsWindow",
293         "resizable=yes,dialog=no",
294         null);
296 interactive("extensions",
297     "Open the extensions manager in a new window.",
298     show_extension_manager);
300 function print_buffer (buffer) {
301     buffer.top_frame.print();
304 interactive("print-buffer",
305     "Print the currently loaded page.",
306     function (I) { print_buffer(I.buffer); });
308 function view_partial_source (window, charset, selection) {
309     if (charset)
310         charset = "charset=" + charset;
311     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
312                              "_blank", "scrollbars,resizable,chrome,dialog=no",
313                              null, charset, selection, 'selection');
315 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
318 function  view_mathml_source (window, charset, target) {
319     if (charset)
320         charset = "charset=" + charset;
321     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
322                              "_blank", "scrollbars,resizable,chrome,dialog=no",
323                              null, charset, target, 'mathml');
327 function send_key_as_event (window, element, combo) {
328     var split = unformat_key_combo(combo);
329     var event = window.document.createEvent("KeyboardEvent");
330     event.initKeyEvent(
331         "keypress",
332         true,
333         true,
334         null,
335         split.ctrlKey,
336         split.altKey,
337         split.shiftKey,
338         split.metaKey,
339         split.keyCode,
340         split.charCode);
341     if (element) {
342         return element.dispatchEvent(event);
343     } else {
344         return window.dispatchEvent(event);
345     }
349 function ensure_content_focused (buffer) {
350     var foc = buffer.focused_frame_or_null;
351     if (!foc)
352         buffer.top_frame.focus();
354 interactive("ensure-content-focused", "Ensure that the content document has focus.",
355     function (I) { ensure_content_focused(I.buffer); });
358 function network_set_online_status (status) {
359     const io_service = Cc["@mozilla.org/network/io-service;1"]
360         .getService(Ci.nsIIOService2);
361     status = !status;
362     io_service.manageOfflineStatus = false;
363     io_service.offline = status;
365 interactive("network-go-online", "Work online.",
366     function (I) { network_set_online_status(true); });
368 interactive("network-go-offline", "Work offline.",
369     function (I) { network_set_online_status(false); });
372 interactive("submit-form",
373     "Submit the form to which the focused element belongs.",
374     function (I) {
375         var el = I.buffer.focused_element.parentNode;
376         while (el && el.tagName != "FORM")
377             el = el.parentNode;
378         if (el) {
379             var inputs = el.getElementsByTagName("input");
380             for (var i = 0, ilen = inputs.length; i < ilen; i++) {
381                 if (inputs[i].getAttribute("type") == "submit")
382                     return browser_object_follow(I.buffer, FOLLOW_DEFAULT,
383                                                  inputs[i]);
384             }
385             el.submit();
386         }
387     });
391  * Browser Object Commands
392  */
393 interactive("follow", null,
394     alternates(follow, follow_new_buffer, follow_new_window),
395     $browser_object = browser_object_links);
397 interactive("follow-top", null,
398     alternates(follow_current_buffer, follow_current_frame),
399     $browser_object = browser_object_frames,
400     $prompt = "Follow");
402 interactive("follow-new-buffer",
403     "Follow a link in a new buffer",
404     alternates(follow_new_buffer, follow_new_window),
405     $browser_object = browser_object_links,
406     $prompt = "Follow");
408 interactive("follow-new-buffer-background",
409     "Follow a link in a new buffer in the background",
410     alternates(follow_new_buffer_background, follow_new_window),
411     $browser_object = browser_object_links,
412     $prompt = "Follow");
414 interactive("follow-new-window",
415     "Follow a link in a new window",
416     follow_new_window,
417     $browser_object = browser_object_links,
418     $prompt = "Follow");
420 interactive("find-url", "Open a URL in the current buffer",
421     alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
422     $browser_object = browser_object_url);
424 interactive("find-url-new-buffer",
425     "Open a URL in a new buffer",
426     alternates(follow_new_buffer, follow_new_window),
427     $browser_object = browser_object_url,
428     $prompt = "Find url");
430 interactive("find-url-new-window", "Open a URL in a new window",
431     follow_new_window,
432     $browser_object = browser_object_url,
433     $prompt = "Find url");
435 interactive("find-alternate-url", "Edit the current URL in the minibuffer",
436     "find-url",
437     $browser_object =
438         define_browser_object_class("alternate-url", null,
439             function (I, prompt) {
440                 check_buffer(I.buffer, content_buffer);
441                 var result = yield I.buffer.window.minibuffer.read_url(
442                     $prompt = prompt,
443                     $initial_value = I.buffer.display_uri_string);
444                 yield co_return(result);
445             }),
446     $prompt = "Find url");
449 interactive("up", "Go to the parent directory of the current URL",
450     "find-url",
451     $browser_object = browser_object_up_url);
453 interactive("home",
454     "Go to the homepage in the current buffer.", "follow",
455     $browser_object = function () { return homepage; });
457 interactive("make-window",
458     "Make a new window with the homepage.",
459     follow_new_window,
460     $browser_object = function () { return homepage; });
462 interactive("focus", null,
463     function (I) {
464         var element = yield read_browser_object(I);
465         browser_element_focus(I.buffer, element);
466     },
467     $browser_object = browser_object_frames);
469 interactive("save",
470     "Save a browser object.",
471     function (I) {
472         var element = yield read_browser_object(I);
473         var spec = load_spec(element);
474         var panel;
475         panel = create_info_panel(I.window, "download-panel",
476                                   [["downloading",
477                                     element_get_operation_label(element, "Saving"),
478                                     load_spec_uri_string(spec)],
479                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
480         try {
481             var file = yield I.minibuffer.read_file_check_overwrite(
482                 $prompt = "Save as:",
483                 $initial_value = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer),
484                 $history = "save");
485         } finally {
486             panel.destroy();
487         }
488         save_uri(spec, file,
489                  $buffer = I.buffer,
490                  $use_cache = false);
491     },
492     $browser_object = browser_object_links);
495 interactive("copy", null,
496             alternates(copy_text, copy_text_append),
497             $browser_object = browser_object_links);
499 interactive("paste-url", "Open a URL from the clipboard in the current buffer.",
500             alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
501             $browser_object = browser_object_paste_url);
503 interactive("paste-url-new-buffer", "Open a URL from the clipboard in a new buffer.",
504             alternates(follow_new_buffer, follow_new_window),
505             $browser_object = browser_object_paste_url);
507 interactive("paste-url-new-window", "Open a URL from the clipboard in a new window.",
508             follow_new_window,
509             $browser_object = browser_object_paste_url);
511 interactive("view-source",
512             "Toggle between source and rendered views of a URL.",
513             alternates(view_source, view_source_new_buffer, view_source_new_window),
514             $browser_object = browser_object_frames);
517 interactive("shell-command-on-url",
518     "Run a shell command on the url of a browser object.\n\n"+
519     "If the given shell command contains the string '{}', the "+
520     "url will be substituted in its place, otherwise the url "+
521     "will be added to the end of the command.",
522     function (I) {
523         var cwd = I.local.cwd;
524         var element = yield read_browser_object(I);
525         var spec = load_spec(element);
526         var uri = load_spec_uri_string(spec);
527         var panel;
528         panel = create_info_panel(I.window, "download-panel",
529                                   [["downloading",
530                                     element_get_operation_label(element, "Running on", "URI"),
531                                     load_spec_uri_string(spec)],
532                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
533         try {
534             var cmd = yield I.minibuffer.read_shell_command(
535                 $cwd = cwd,
536                 $initial_value = load_spec_default_shell_command(spec));
537         } finally {
538             panel.destroy();
539         }
540         shell_command_with_argument_blind(cmd, uri, $cwd = cwd);
541     },
542     $browser_object = browser_object_url,
543     $prompt = "Shell command");
546 interactive("shell-command-on-file",
547     "Download a document to a temporary file and run a shell command on it.",
548     function (I) {
549         var cwd = I.local.cwd;
550         var element = yield read_browser_object(I);
551         var spec = load_spec(element);
552         var uri = load_spec_uri_string(spec);
553         var panel;
554         panel = create_info_panel(I.window, "download-panel",
555                                   [["downloading",
556                                     element_get_operation_label(element, "Running on"),
557                                     load_spec_uri_string(spec)],
558                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
559         try {
560             var cmd = yield I.minibuffer.read_shell_command(
561                 $cwd = cwd,
562                 $initial_value = load_spec_default_shell_command(spec));
563         } finally {
564             panel.destroy();
565         }
566         yield browser_element_shell_command(I.buffer, element, cmd, cwd);
567     },
568     $browser_object = browser_object_links,
569     $prompt = "Shell command");
572 interactive("bookmark",
573     "Create a bookmark.",
574     function (I) {
575         var element = yield read_browser_object(I);
576         var spec = load_spec(element);
577         var uri_string = load_spec_uri_string(spec);
578         var panel;
579         panel = create_info_panel(I.window, "bookmark-panel",
580                                   [["bookmarking",
581                                     element_get_operation_label(element, "Bookmarking"),
582                                     uri_string]]);
583         try {
584             var title = yield I.minibuffer.read($prompt = "Bookmark with title:", $initial_value = load_spec_title(spec) || "");
585         } finally {
586             panel.destroy();
587         }
588         add_bookmark(uri_string, title);
589         I.minibuffer.message("Added bookmark: " + uri_string + " - " + title);
590     },
591     $browser_object = browser_object_frames);
594 interactive("save-page",
595     "Save a document, not including any embedded documents such as images "+
596     "and css.",
597     function (I) {
598         check_buffer(I.buffer, content_buffer);
599         var element = yield read_browser_object(I);
600         var spec = load_spec(element);
601         if (!load_spec_document(spec))
602             throw interactive_error("Element is not associated with a document.");
603         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
605         var panel;
606         panel = create_info_panel(I.window, "download-panel",
607                                   [["downloading",
608                                     element_get_operation_label(element, "Saving"),
609                                     load_spec_uri_string(spec)],
610                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
612         try {
613             var file = yield I.minibuffer.read_file_check_overwrite(
614                 $prompt = "Save page as:",
615                 $history = "save",
616                 $initial_value = suggested_path);
617         } finally {
618             panel.destroy();
619         }
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);
637         var panel;
638         panel = create_info_panel(I.window, "download-panel",
639                                   [["downloading",
640                                     element_get_operation_label(element, "Saving", "as text"),
641                                     load_spec_uri_string(spec)],
642                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
644         try {
645             var file = yield I.minibuffer.read_file_check_overwrite(
646                 $prompt = "Save page as text:",
647                 $history = "save",
648                 $initial_value = suggested_path);
649         } finally {
650             panel.destroy();
651         }
653         save_document_as_text(doc, file, $buffer = I.buffer);
654     },
655     $browser_object = browser_object_frames);
658 interactive("save-page-complete",
659     "Save a page and all supporting documents, including images, css, "+
660     "and child frame documents.",
661     function (I) {
662         check_buffer(I.buffer, content_buffer);
663         var element = yield read_browser_object(I);
664         var spec = load_spec(element);
665         var doc;
666         if (!(doc = load_spec_document(spec)))
667             throw interactive_error("Element is not associated with a document.");
668         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
670         var panel;
671         panel = create_info_panel(I.window, "download-panel",
672                                   [["downloading",
673                                     element_get_operation_label(element, "Saving complete"),
674                                     load_spec_uri_string(spec)],
675                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
677         try {
678             var file = yield I.minibuffer.read_file_check_overwrite(
679                 $prompt = "Save page complete:",
680                 $history = "save",
681                 $initial_value = suggested_path);
682             // FIXME: use proper read function
683             var dir = yield I.minibuffer.read_file(
684                 $prompt = "Data Directory:",
685                 $history = "save",
686                 $initial_value = file.path + ".support");
687         } finally {
688             panel.destroy();
689         }
691         save_document_complete(doc, file, dir, $buffer = I.buffer);
692     },
693     $browser_object = browser_object_frames);
696 function view_as_mime_type (I, target) {
697     I.target = target;
698     var element = yield read_browser_object(I);
699     var spec = load_spec(element);
701     if (target == null)
702         target = FOLLOW_CURRENT_FRAME;
704     if (!can_override_mime_type_for_uri(load_spec_uri(spec)))
705         throw interactive_error("Overriding the MIME type is not currently supported for non-HTTP URLs.");
707     var panel;
709     var mime_type = load_spec_mime_type(spec);
710     panel = create_info_panel(I.window, "download-panel",
711                               [["downloading",
712                                 element_get_operation_label(element, "View in browser"),
713                                 load_spec_uri_string(spec)],
714                                ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
717     try {
718         let suggested_type = mime_type;
719         if (viewable_mime_type_list.indexOf(suggested_type) == -1)
720             suggested_type = "text/plain";
721         mime_type = yield I.minibuffer.read_viewable_mime_type(
722             $prompt = "View internally as",
723             $initial_value = suggested_type,
724             $select);
725         yield override_mime_type_for_next_load(load_spec_uri(spec), mime_type);
726         browser_object_follow(I.buffer, target, spec);
727     } finally {
728         panel.destroy();
729     }
732 function view_as_mime_type_new_buffer (I) {
733     yield view_as_mime_type(I, OPEN_NEW_BUFFER);
736 function view_as_mime_type_new_window (I) {
737     yield view_as_mime_type(I, OPEN_NEW_WINDOW);
740 interactive("view-as-mime-type",
741     "Display a browser object in the browser using the specified MIME type.",
742     alternates(view_as_mime_type,
743         view_as_mime_type_new_buffer,
744         view_as_mime_type_new_window),
745     $browser_object = browser_object_frames);
748 interactive("delete",
749     "Delete a DOM node, given as a browser object.",
750     function (I) {
751         var elem = yield read_browser_object(I);
752         if (! (elem instanceof Ci.nsIDOMNode))
753             throw interactive_error("Cannot delete item");
754         elem.parentNode.removeChild(elem);
755     },
756     $browser_object = browser_object_dom_node);
759 interactive("charset-prefix",
760     "A prefix command that prompts for a charset to use in a "+
761     "subsequent navigation command.",
762     function (I) {
763         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
764             .getService(Ci.nsICharsetConverterManager);
765         var decoders = ccman.getDecoderList()
766         var charsets = [];
767         while (decoders.hasMore())
768             charsets.push(decoders.getNext());
769         I.forced_charset = yield I.minibuffer.read(
770             $prompt = "Charset:",
771             $completer = prefix_completer(
772                 $completions = charsets,
773                 $get_string = function (x) x.toLowerCase()),
774             $match_required,
775             $space_completes);
776     },
777     $prefix);
780 interactive("reload-with-charset",
781     "Prompt for a charset, and reload the current page, forcing use "+
782     "of that charset.",
783     function (I) {
784         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
785             .getService(Ci.nsICharsetConverterManager);
786         var decoders = ccman.getDecoderList()
787         var charsets = [];
788         while (decoders.hasMore())
789             charsets.push(decoders.getNext());
790         var forced_charset = yield I.minibuffer.read(
791             $prompt = "Charset:",
792             $completer = prefix_completer(
793                 $completions = charsets,
794                 $get_string = function (x) x.toLowerCase()),
795             $match_required,
796             $space_completes);
797         reload(I.buffer, false, null, forced_charset);
798     });
801 interactive("yank",
802     "Paste the contents of the clipboard",
803     function (I) {
804         call_builtin_command(I.window, "cmd_paste", true);
805     });
807 interactive("kill-region",
808     "Kill (\"cut\") the selected text.",
809     function (I) {
810         call_builtin_command(I.window, "cmd_cut", true);
811     });
813 interactive("kill-ring-save",
814     "Save the region as if killed, but don't kill it.",
815     function (I) {
816         call_builtin_command(I.window, "cmd_copy", true);
817     });
819 interactive("password-manager",
820     "Open the password manager.",
821     "find-url-new-buffer",
822     $browser_object = "chrome://passwordmgr/content/passwordManager.xul");
825 interactive("toggle-full-screen",
826     "Toggle full screen mode for the current window.",
827     function (I) {
828         window_set_full_screen(I.window);
829         if (I.window.fullScreen)
830             I.minibuffer.message("Fullscreen mode on");
831         else
832             I.minibuffer.message("Fullscreen mode off");
833     });
836 interactive("image-toggle-zoom-to-fit",
837     "Toggle zoom-to-fit (viewport) on an image document.",
838     function (I) {
839         try {
840             var doc = I.buffer.document
841                 .QueryInterface(Ci.nsIImageDocument);
842             doc.toggleImageSize();
843             zoom_hook.run(I.buffer);
844         } catch (e) {
845             I.minibuffer.message("Not an image document");
846         }
847     });
850 provide("commands");