dd4221465aee7d26f9f8c31a46362c6c18cb5d31
[conkeror.git] / modules / commands.js
blobdd4221465aee7d26f9f8c31a46362c6c18cb5d31
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) { I.buffer.do_command("cmd_scrollTop");
56                     scroll_horiz_complete(I.buffer, -1); });
59 function delete_window (window) {
60     window.window.close();
62 interactive("delete-window",
63     "Delete the current window.",
64     function (I) { delete_window(I.window); });
66 interactive("jsconsole",
67     "Open the JavaScript console.",
68     "find-url-new-buffer",
69     $browser_object = "chrome://global/content/console.xul");
72 function paste_x_primary_selection (field) {
73     modify_region(field, function (str) read_from_x_primary_selection());
75 interactive("paste-x-primary-selection",
76     "Insert the contents of the X primary selection into the selected field or "+
77     "minibuffer. Deactivates the region if it is active, and leaves the point "+
78     "after the inserted text.",
79     function (I) call_on_focused_field(I, paste_x_primary_selection, true));
82 function open_line (field) {
83     modify_region(field, function() ["\n", 0]);
85 interactive("open-line",
86     "If there is an active region, replace is with a newline, otherwise just "+
87     "insert a newline. In both cases leave point before the inserted newline.",
88     function (I) call_on_focused_field(I, open_line, true));
91 interactive("insert-parentheses",
92     "Insert a pair of parentheses, or surround the currently selected text "+
93     "with a pair of parentheses.",
94     function (I) {
95         call_on_focused_field(I, function (field) {
96             modify_region(field,
97                           function (str) {
98                               return ["("+str+")", (str ? str.length+2 : 1)];
99                           });
100         }, true);
101     });
104 function transpose_chars (field) {
105     var value = field.value;
106     var caret = field.selectionStart; // Caret position.
107     var length = value.length;
109     // If we have less than two character in the field or if we are at the
110     // beginning of the field, do nothing.
111     if (length < 2 || caret == 0)
112         return;
114     // If we are at the end of the field, switch places on the two last
115     // characters. TODO: This should happen at the end of every line, not only
116     // at the end of the field.
117     if (caret == length)
118         caret--;
120     // Do the transposing.
121     field.value = switch_subarrays(value, caret - 1, caret, caret, caret + 1);
123     // Increment the caret position. If this is not done, the caret is left at
124     // the end of the field as a result of the replacing of contents.
125     field.selectionStart = caret + 1;
126     field.selectionEnd = caret + 1;
128 interactive("transpose-chars",
129     "Interchange characters around point, moving forward one character.",
130     function (I) call_on_focused_field(I, transpose_chars, true));
133 interactive("execute-extended-command",
134     "Call a command specified in the minibuffer.",
135     function (I) {
136         var prefix = I.P;
137         var boc = I.browser_object;
138         var prompt = "M-x";
139         if (I.key_sequence)
140             prompt = I.key_sequence.join(" ");
141         if (boc)
142             prompt += ' ['+boc.name+']';
143         if (prefix !== null && prefix !== undefined) {
144             if (typeof prefix == "object")
145                 prompt += prefix[0] == 4 ? " C-u" : " "+prefix[0];
146             else
147                 prompt += " "+prefix;
148         }
149         var command = yield I.minibuffer.read_command($prompt = prompt);
150         call_after_timeout(function () {
151             input_handle_command.call(I.window, new command_event(command));
152         }, 0);
153     },
154     $prefix = true);
157 /// built in commands
158 // see: http://www.xulplanet.com/tutorials/xultu/commandupdate.html
160 // Performs a command on a browser buffer content area
163 define_builtin_commands(
164     "",
165     function (I, command) {
166         call_builtin_command(I.window, command);
167     },
168     false
171 define_builtin_commands(
172     "caret-",
173     function (I, command) {
174         var buffer = I.buffer;
175         try {
176             buffer.do_command(command);
177         } catch (e) {
178             /* Ignore exceptions */
179         }
180     },
181     'caret');
183 function get_link_text () {
184     var e = document.commandDispatcher.focusedElement;
185     if (e && e.getAttribute("href")) {
186         return e.getAttribute("href");
187     }
188     return null;
193 function copy_email_address (loc)
195     // Copy the comma-separated list of email addresses only.
196     // There are other ways of embedding email addresses in a mailto:
197     // link, but such complex parsing is beyond us.
198     var qmark = loc.indexOf( "?" );
199     var addresses;
201     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
202         addresses = loc.substring( 7, qmark );
203     } else {
204         addresses = loc.substr( 7 );
205     }
207     //XXX: the original code, which we got from firefox, unescapes the string
208     //     using the current character set.  To do this in conkeror, we
209     //     *should* use an interactive method that gives us the character set,
210     //     rather than fetching it by side-effect.
212     //     // Let's try to unescape it using a character set
213     //     // in case the address is not ASCII.
214     //     try {
215     //         var characterSet = this.target.ownerDocument.characterSet;
216     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
217     //             .getService(Components.interfaces.nsITextToSubURI);
218     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
219     //     }
220     //     catch(ex) {
221     //         // Do nothing.
222     //     }
224     writeToClipboard(addresses);
225     message("Copied '" + addresses + "'");
227 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
230 /* FIXME: fix this command */
232 interactive("source",
233             "Load a JavaScript file.",
234             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
236 function reinit (window) {
237     var path;
238     try {
239         path = load_rc();
240         window.minibuffer.message("Loaded: " + path);
241     } catch (e) {
242         window.minibuffer.message("Failed to load: "+path);
243     }
246 interactive("reinit",
247             "Reload the Conkeror rc file.",
248             function (I) { reinit(I.window); });
250 interactive("help-page", "Open the Conkeror help page.",
251             "find-url-new-buffer",
252             $browser_object = "chrome://conkeror-help/content/help.html");
254 interactive("tutorial", "Open the Conkeror tutorial.",
255             "find-url-new-buffer",
256             $browser_object = "chrome://conkeror-help/content/tutorial.html");
258 function univ_arg_to_number (prefix, default_value) {
259     if (prefix == null) {
260         if (default_value == null)
261             return 1;
262         else
263             return default_value;
264     }
265     if (typeof prefix == "object")
266         return prefix[0];
267     return prefix;
271 interactive("eval-expression",
272     "Evaluate JavaScript statements.",
273     function (I) {
274         var s = yield I.minibuffer.read(
275             $prompt = "Eval:",
276             $history = "eval-expression",
277             $completer = javascript_completer(I.buffer));
278         var result = evaluate(s);
279         if (result !== undefined)
280             I.window.minibuffer.message(String(result));
281     });
284 function show_extension_manager () {
285     return conkeror.window_watcher.openWindow(
286         null,
287         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
288         "ExtensionsWindow",
289         "resizable=yes,dialog=no",
290         null);
292 interactive("extensions",
293     "Open the extensions manager in a new window.",
294     show_extension_manager);
296 function print_buffer (buffer) {
297     buffer.top_frame.print();
300 interactive("print-buffer",
301     "Print the currently loaded page.",
302     function (I) { print_buffer(I.buffer); });
304 function view_partial_source (window, charset, selection) {
305     if (charset)
306         charset = "charset=" + charset;
307     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
308                              "_blank", "scrollbars,resizable,chrome,dialog=no",
309                              null, charset, selection, 'selection');
311 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
314 function  view_mathml_source (window, charset, target) {
315     if (charset)
316         charset = "charset=" + charset;
317     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
318                              "_blank", "scrollbars,resizable,chrome,dialog=no",
319                              null, charset, target, 'mathml');
323 function send_key_as_event (window, element, combo) {
324     var split = unformat_key_combo(combo);
325     var event = window.document.createEvent("KeyboardEvent");
326     event.initKeyEvent(
327         "keypress",
328         true,
329         true,
330         null,
331         split.ctrlKey,
332         split.altKey,
333         split.shiftKey,
334         split.metaKey,
335         split.keyCode,
336         split.charCode);
337     if (element) {
338         return element.dispatchEvent(event);
339     } else {
340         return window.dispatchEvent(event);
341     }
345 function ensure_content_focused (buffer) {
346     var foc = buffer.focused_frame_or_null;
347     if (!foc)
348         buffer.top_frame.focus();
350 interactive("ensure-content-focused", "Ensure that the content document has focus.",
351     function (I) { ensure_content_focused(I.buffer); });
354 function network_set_online_status (status) {
355     const io_service = Cc["@mozilla.org/network/io-service;1"]
356         .getService(Ci.nsIIOService2);
357     status = !status;
358     io_service.manageOfflineStatus = false;
359     io_service.offline = status;
361 interactive("network-go-online", "Work online.",
362     function (I) { network_set_online_status(true); });
364 interactive("network-go-offline", "Work offline.",
365     function (I) { network_set_online_status(false); });
368 interactive("submit-form",
369     "Submit the form to which the focused element belongs.",
370     function (I) {
371         var el = I.buffer.focused_element.parentNode;
372         while (el && el.tagName != "FORM")
373             el = el.parentNode;
374         if (el) {
375             var inputs = el.getElementsByTagName("input");
376             for (var i = 0, ilen = inputs.length; i < ilen; i++) {
377                 if (inputs[i].getAttribute("type") == "submit")
378                     return browser_object_follow(I.buffer, FOLLOW_DEFAULT,
379                                                  inputs[i]);
380             }
381             el.submit();
382         }
383     });
387  * Browser Object Commands
388  */
389 interactive("follow", null,
390     alternates(follow, follow_new_buffer, follow_new_window),
391     $browser_object = browser_object_links);
393 interactive("follow-top", null,
394     alternates(follow_current_buffer, follow_current_frame),
395     $browser_object = browser_object_frames,
396     $prompt = "Follow");
398 interactive("follow-new-buffer",
399     "Follow a link in a new buffer",
400     alternates(follow_new_buffer, follow_new_window),
401     $browser_object = browser_object_links,
402     $prompt = "Follow");
404 interactive("follow-new-buffer-background",
405     "Follow a link in a new buffer in the background",
406     alternates(follow_new_buffer_background, follow_new_window),
407     $browser_object = browser_object_links,
408     $prompt = "Follow");
410 interactive("follow-new-window",
411     "Follow a link in a new window",
412     follow_new_window,
413     $browser_object = browser_object_links,
414     $prompt = "Follow");
416 interactive("find-url", "Open a URL in the current buffer",
417     alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
418     $browser_object = browser_object_url);
420 interactive("find-url-new-buffer",
421     "Open a URL in a new buffer",
422     alternates(follow_new_buffer, follow_new_window),
423     $browser_object = browser_object_url,
424     $prompt = "Find url");
426 interactive("find-url-new-window", "Open a URL in a new window",
427     follow_new_window,
428     $browser_object = browser_object_url,
429     $prompt = "Find url");
431 interactive("find-alternate-url", "Edit the current URL in the minibuffer",
432     "find-url",
433     $browser_object =
434         define_browser_object_class("alternate-url", null,
435             function (I, prompt) {
436                 check_buffer(I.buffer, content_buffer);
437                 var result = yield I.buffer.window.minibuffer.read_url(
438                     $prompt = prompt,
439                     $initial_value = I.buffer.display_uri_string);
440                 yield co_return(result);
441             }),
442     $prompt = "Find url");
445 interactive("up", "Go to the parent directory of the current URL",
446     "find-url",
447     $browser_object = browser_object_up_url);
449 interactive("home",
450     "Go to the homepage in the current buffer.", "follow",
451     $browser_object = function () { return homepage; });
453 interactive("make-window",
454     "Make a new window with the homepage.",
455     follow_new_window,
456     $browser_object = function () { return homepage; });
458 interactive("focus", null,
459     function (I) {
460         var element = yield read_browser_object(I);
461         browser_element_focus(I.buffer, element);
462     },
463     $browser_object = browser_object_frames);
465 interactive("save",
466     "Save a browser object.",
467     function (I) {
468         var element = yield read_browser_object(I);
469         var spec = load_spec(element);
470         var panel;
471         panel = create_info_panel(I.window, "download-panel",
472                                   [["downloading",
473                                     element_get_operation_label(element, "Saving"),
474                                     load_spec_uri_string(spec)],
475                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
476         try {
477             var file = yield I.minibuffer.read_file_check_overwrite(
478                 $prompt = "Save as:",
479                 $initial_value = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer),
480                 $history = "save");
481         } finally {
482             panel.destroy();
483         }
484         save_uri(spec, file,
485                  $buffer = I.buffer,
486                  $use_cache = false);
487     },
488     $browser_object = browser_object_links);
491 interactive("copy", null,
492             alternates(copy_text, copy_text_append),
493             $browser_object = browser_object_links);
495 interactive("paste-url", "Open a URL from the clipboard in the current buffer.",
496             alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
497             $browser_object = browser_object_paste_url);
499 interactive("paste-url-new-buffer", "Open a URL from the clipboard in a new buffer.",
500             alternates(follow_new_buffer, follow_new_window),
501             $browser_object = browser_object_paste_url);
503 interactive("paste-url-new-window", "Open a URL from the clipboard in a new window.",
504             follow_new_window,
505             $browser_object = browser_object_paste_url);
507 interactive("view-source",
508             "Toggle between source and rendered views of a URL.",
509             alternates(view_source, view_source_new_buffer, view_source_new_window),
510             $browser_object = browser_object_frames);
513 interactive("shell-command-on-url",
514     "Run a shell command on the url of a browser object.",
515     function (I) {
516         var cwd = I.local.cwd;
517         var element = yield read_browser_object(I);
518         var spec = load_spec(element);
519         var uri = load_spec_uri_string(spec);
520         var panel;
521         panel = create_info_panel(I.window, "download-panel",
522                                   [["downloading",
523                                     element_get_operation_label(element, "Running on", "URI"),
524                                     load_spec_uri_string(spec)],
525                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
526         try {
527             var cmd = yield I.minibuffer.read_shell_command(
528                 $cwd = cwd,
529                 $initial_value = load_spec_default_shell_command(spec));
530         } finally {
531             panel.destroy();
532         }
533         shell_command_with_argument_blind(cmd, uri, $cwd = cwd);
534     },
535     $browser_object = browser_object_url,
536     $prompt = "Shell command");
539 interactive("shell-command-on-file",
540     "Download a document to a temporary file and run a shell command on it.",
541     function (I) {
542         var cwd = I.local.cwd;
543         var element = yield read_browser_object(I);
544         var spec = load_spec(element);
545         var uri = load_spec_uri_string(spec);
546         var panel;
547         panel = create_info_panel(I.window, "download-panel",
548                                   [["downloading",
549                                     element_get_operation_label(element, "Running on"),
550                                     load_spec_uri_string(spec)],
551                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
552         try {
553             var cmd = yield I.minibuffer.read_shell_command(
554                 $cwd = cwd,
555                 $initial_value = load_spec_default_shell_command(spec));
556         } finally {
557             panel.destroy();
558         }
559         yield browser_element_shell_command(I.buffer, element, cmd, cwd);
560     },
561     $browser_object = browser_object_links,
562     $prompt = "Shell command");
565 interactive("bookmark",
566     "Create a bookmark.",
567     function (I) {
568         var element = yield read_browser_object(I);
569         var spec = load_spec(element);
570         var uri_string = load_spec_uri_string(spec);
571         var panel;
572         panel = create_info_panel(I.window, "bookmark-panel",
573                                   [["bookmarking",
574                                     element_get_operation_label(element, "Bookmarking"),
575                                     uri_string]]);
576         try {
577             var title = yield I.minibuffer.read($prompt = "Bookmark with title:", $initial_value = load_spec_title(spec) || "");
578         } finally {
579             panel.destroy();
580         }
581         add_bookmark(uri_string, title);
582         I.minibuffer.message("Added bookmark: " + uri_string + " - " + title);
583     },
584     $browser_object = browser_object_frames);
587 interactive("save-page",
588     "Save a document, not including any embedded documents such as images "+
589     "and css.",
590     function (I) {
591         check_buffer(I.buffer, content_buffer);
592         var element = yield read_browser_object(I);
593         var spec = load_spec(element);
594         if (!load_spec_document(spec))
595             throw interactive_error("Element is not associated with a document.");
596         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
598         var panel;
599         panel = create_info_panel(I.window, "download-panel",
600                                   [["downloading",
601                                     element_get_operation_label(element, "Saving"),
602                                     load_spec_uri_string(spec)],
603                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
605         try {
606             var file = yield I.minibuffer.read_file_check_overwrite(
607                 $prompt = "Save page as:",
608                 $history = "save",
609                 $initial_value = suggested_path);
610         } finally {
611             panel.destroy();
612         }
614         save_uri(spec, file, $buffer = I.buffer);
615     },
616     $browser_object = browser_object_frames);
619 interactive("save-page-as-text",
620     "Save a page as plain text.",
621     function (I) {
622         check_buffer(I.buffer, content_buffer);
623         var element = yield read_browser_object(I);
624         var spec = load_spec(element);
625         var doc;
626         if (!(doc = load_spec_document(spec)))
627             throw interactive_error("Element is not associated with a document.");
628         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec, "txt"), I.buffer);
630         var panel;
631         panel = create_info_panel(I.window, "download-panel",
632                                   [["downloading",
633                                     element_get_operation_label(element, "Saving", "as text"),
634                                     load_spec_uri_string(spec)],
635                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
637         try {
638             var file = yield I.minibuffer.read_file_check_overwrite(
639                 $prompt = "Save page as text:",
640                 $history = "save",
641                 $initial_value = suggested_path);
642         } finally {
643             panel.destroy();
644         }
646         save_document_as_text(doc, file, $buffer = I.buffer);
647     },
648     $browser_object = browser_object_frames);
651 interactive("save-page-complete",
652     "Save a page and all supporting documents, including images, css, "+
653     "and child frame documents.",
654     function (I) {
655         check_buffer(I.buffer, content_buffer);
656         var element = yield read_browser_object(I);
657         var spec = load_spec(element);
658         var doc;
659         if (!(doc = load_spec_document(spec)))
660             throw interactive_error("Element is not associated with a document.");
661         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
663         var panel;
664         panel = create_info_panel(I.window, "download-panel",
665                                   [["downloading",
666                                     element_get_operation_label(element, "Saving complete"),
667                                     load_spec_uri_string(spec)],
668                                    ["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         }
684         save_document_complete(doc, file, dir, $buffer = I.buffer);
685     },
686     $browser_object = browser_object_frames);
689 function view_as_mime_type (I, target) {
690     I.target = target;
691     var element = yield read_browser_object(I);
692     var spec = load_spec(element);
694     if (target == null)
695         target = FOLLOW_CURRENT_FRAME;
697     if (!can_override_mime_type_for_uri(load_spec_uri(spec)))
698         throw interactive_error("Overriding the MIME type is not currently supported for non-HTTP URLs.");
700     var panel;
702     var mime_type = load_spec_mime_type(spec);
703     panel = create_info_panel(I.window, "download-panel",
704                               [["downloading",
705                                 element_get_operation_label(element, "View in browser"),
706                                 load_spec_uri_string(spec)],
707                                ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
710     try {
711         let suggested_type = mime_type;
712         if (viewable_mime_type_list.indexOf(suggested_type) == -1)
713             suggested_type = "text/plain";
714         mime_type = yield I.minibuffer.read_viewable_mime_type(
715             $prompt = "View internally as",
716             $initial_value = suggested_type,
717             $select);
718         override_mime_type_for_next_load(load_spec_uri(spec), mime_type);
719         browser_object_follow(I.buffer, target, spec);
720     } finally {
721         panel.destroy();
722     }
725 function view_as_mime_type_new_buffer (I) {
726     yield view_as_mime_type(I, OPEN_NEW_BUFFER);
729 function view_as_mime_type_new_window (I) {
730     yield view_as_mime_type(I, OPEN_NEW_WINDOW);
733 interactive("view-as-mime-type",
734     "Display a browser object in the browser using the specified MIME type.",
735     alternates(view_as_mime_type,
736         view_as_mime_type_new_buffer,
737         view_as_mime_type_new_window),
738     $browser_object = browser_object_frames);
741 interactive("delete",
742     "Delete a DOM node, given as a browser object.",
743     function (I) {
744         var elem = yield read_browser_object(I);
745         if (! (elem instanceof Ci.nsIDOMNode))
746             throw interactive_error("Cannot delete item");
747         elem.parentNode.removeChild(elem);
748     },
749     $browser_object = browser_object_dom_node);
752 interactive("charset-prefix",
753     "A prefix command that prompts for a charset to use in a "+
754     "subsequent navigation command.",
755     function (I) {
756         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
757             .getService(Ci.nsICharsetConverterManager);
758         var decoders = ccman.getDecoderList()
759         var charsets = [];
760         while (decoders.hasMore())
761             charsets.push(decoders.getNext());
762         I.forced_charset = yield I.minibuffer.read(
763             $prompt = "Charset:",
764             $completer = prefix_completer(
765                 $completions = charsets,
766                 $get_string = function (x) x.toLowerCase()),
767             $match_required,
768             $space_completes);
769     },
770     $prefix);
773 interactive("reload-with-charset",
774     "Prompt for a charset, and reload the current page, forcing use "+
775     "of that charset.",
776     function (I) {
777         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
778             .getService(Ci.nsICharsetConverterManager);
779         var decoders = ccman.getDecoderList()
780         var charsets = [];
781         while (decoders.hasMore())
782             charsets.push(decoders.getNext());
783         var forced_charset = yield I.minibuffer.read(
784             $prompt = "Charset:",
785             $completer = prefix_completer(
786                 $completions = charsets,
787                 $get_string = function (x) x.toLowerCase()),
788             $match_required,
789             $space_completes);
790         reload(I.buffer, false, null, forced_charset);
791     });
794 interactive("yank",
795     "Paste the contents of the clipboard",
796     function (I) {
797         call_builtin_command(I.window, "cmd_paste", true);
798     });
800 interactive("kill-region",
801     "Kill (\"cut\") the selected text.",
802     function (I) {
803         call_builtin_command(I.window, "cmd_cut", true);
804     });
806 interactive("kill-ring-save",
807     "Save the region as if killed, but don't kill it.",
808     function (I) {
809         call_builtin_command(I.window, "cmd_copy", true);
810     });
812 interactive("password-manager",
813     "Open the password manager.",
814     "find-url-new-buffer",
815     $browser_object = "chrome://passwordmgr/content/passwordManager.xul");
818 interactive("toggle-full-screen",
819     "Toggle full screen mode for the current window.",
820     function (I) {
821         window_set_full_screen(I.window);
822         if (I.window.fullScreen)
823             I.minibuffer.message("Fullscreen mode on");
824         else
825             I.minibuffer.message("Fullscreen mode off");
826     });
829 interactive("image-toggle-zoom-to-fit",
830     "Toggle zoom-to-fit (viewport) on an image document.",
831     function (I) {
832         try {
833             var doc = I.buffer.document
834                 .QueryInterface(Ci.nsIImageDocument);
835             doc.toggleImageSize();
836             zoom_hook.run(I.buffer);
837         } catch (e) {
838             I.minibuffer.message("Not an image document");
839         }
840     });
843 provide("commands");