support XULRunner 2.0
[conkeror.git] / modules / commands.js
blob843992994b8418c9badf6a821f3715164cae88bb
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 in_module(null);
12 define_coroutine_hook("before_quit_hook", RUN_HOOK_UNTIL_FAILURE);
13 define_hook("quit_hook");
15 function quit () {
16     var res = yield before_quit_hook.run();
17     if (res) {
18         quit_hook.run();
19         var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
20             .getService(Ci.nsIAppStartup);
21         appStartup.quit(appStartup.eAttemptQuit);
22     }
24 interactive("quit",
25     "Quit Conkeror",
26     quit);
29 function show_conkeror_version (window) {
30     var xulrunner_version = Cc['@mozilla.org/xre/app-info;1']
31         .getService(Ci.nsIXULAppInfo)
32         .platformVersion;
33     window.minibuffer.message("Conkeror "+conkeror.version+
34                               " (XULRunner "+xulrunner_version+
35                               ", "+get_os()+")");
37 interactive("conkeror-version",
38     "Show version information for Conkeror.",
39     function (I) { show_conkeror_version(I.window); });
40 interactive("version",
41     "Show version information for Conkeror.",
42     "conkeror-version");
44 /* FIXME: maybe this should be supported for non-browser buffers */
45 function scroll_horiz_complete (buffer, n) {
46     var w = buffer.focused_frame;
47     w.scrollTo (n > 0 ? w.scrollMaxX : 0, w.scrollY);
49 interactive("scroll-beginning-of-line",
50     "Scroll the current frame all the way to the left.",
51     function (I) { scroll_horiz_complete(I.buffer, -1); });
53 interactive("scroll-end-of-line",
54     "Scroll the current frame all the way to the right.",
55     function (I) { scroll_horiz_complete(I.buffer, 1); });
57 interactive("scroll-top-left",
58     "Scroll the current frame all the way to the top left",
59      function (I) { I.buffer.do_command("cmd_scrollTop");
60                     scroll_horiz_complete(I.buffer, -1); });
63 function delete_window (window) {
64     window.window.close();
66 interactive("delete-window",
67     "Delete the current window.",
68     function (I) { delete_window(I.window); });
70 interactive("jsconsole",
71     "Open the JavaScript console.",
72     "find-url-new-buffer",
73     $browser_object = "chrome://global/content/console.xul");
76 function paste_x_primary_selection (field) {
77     modify_region(field, function (str) read_from_x_primary_selection());
79 interactive("paste-x-primary-selection",
80     "Insert the contents of the X primary selection into the selected field or "+
81     "minibuffer. Deactivates the region if it is active, and leaves the point "+
82     "after the inserted text.",
83     function (I) call_on_focused_field(I, paste_x_primary_selection, true));
86 function open_line (field) {
87     modify_region(field, function() ["\n", 0]);
89 interactive("open-line",
90     "If there is an active region, replace is with a newline, otherwise just "+
91     "insert a newline. In both cases leave point before the inserted newline.",
92     function (I) call_on_focused_field(I, open_line, true));
95 interactive("insert-parentheses",
96     "Insert a pair of parentheses, or surround the currently selected text "+
97     "with a pair of parentheses.",
98     function (I) {
99         call_on_focused_field(I, function (field) {
100             modify_region(field,
101                           function (str) {
102                               return ["("+str+")", (str ? str.length+2 : 1)];
103                           });
104         }, true);
105     });
108 function transpose_chars (field) {
109     var value = field.value;
110     var caret = field.selectionStart; // Caret position.
111     var length = value.length;
113     // If we have less than two character in the field or if we are at the
114     // beginning of the field, do nothing.
115     if (length < 2 || caret == 0)
116         return;
118     // If we are at the end of the field, switch places on the two last
119     // characters. TODO: This should happen at the end of every line, not only
120     // at the end of the field.
121     if (caret == length)
122         caret--;
124     // Do the transposing.
125     field.value = switch_subarrays(value, caret - 1, caret, caret, caret + 1);
127     // Increment the caret position. If this is not done, the caret is left at
128     // the end of the field as a result of the replacing of contents.
129     field.selectionStart = caret + 1;
130     field.selectionEnd = caret + 1;
132 interactive("transpose-chars",
133     "Interchange characters around point, moving forward one character.",
134     function (I) call_on_focused_field(I, transpose_chars, true));
137 interactive("execute-extended-command",
138     "Call a command specified in the minibuffer.",
139     function (I) {
140         var prefix = I.P;
141         var boc = I.browser_object;
142         var prompt = "M-x";
143         if (I.key_sequence)
144             prompt = I.key_sequence.join(" ");
145         if (boc)
146             prompt += ' ['+boc.name+']';
147         if (prefix !== null && prefix !== undefined) {
148             if (typeof prefix == "object")
149                 prompt += prefix[0] == 4 ? " C-u" : " "+prefix[0];
150             else
151                 prompt += " "+prefix;
152         }
153         var command = yield I.minibuffer.read_command($prompt = prompt);
154         call_after_timeout(function () {
155             input_handle_command.call(I.window, new command_event(command));
156         }, 0);
157     },
158     $prefix = true);
161 /// built in commands
162 // see: http://www.xulplanet.com/tutorials/xultu/commandupdate.html
164 // Performs a command on a browser buffer content area
167 define_builtin_commands(
168     "",
169     function (I, command) {
170         call_builtin_command(I.window, command);
171     },
172     false
175 define_builtin_commands(
176     "caret-",
177     function (I, command) {
178         var buffer = I.buffer;
179         try {
180             buffer.do_command(command);
181         } catch (e) {
182             /* Ignore exceptions */
183         }
184     },
185     'caret');
187 function get_link_text () {
188     var e = document.commandDispatcher.focusedElement;
189     if (e && e.getAttribute("href")) {
190         return e.getAttribute("href");
191     }
192     return null;
197 function copy_email_address (loc)
199     // Copy the comma-separated list of email addresses only.
200     // There are other ways of embedding email addresses in a mailto:
201     // link, but such complex parsing is beyond us.
202     var qmark = loc.indexOf( "?" );
203     var addresses;
205     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
206         addresses = loc.substring( 7, qmark );
207     } else {
208         addresses = loc.substr( 7 );
209     }
211     //XXX: the original code, which we got from firefox, unescapes the string
212     //     using the current character set.  To do this in conkeror, we
213     //     *should* use an interactive method that gives us the character set,
214     //     rather than fetching it by side-effect.
216     //     // Let's try to unescape it using a character set
217     //     // in case the address is not ASCII.
218     //     try {
219     //         var characterSet = this.target.ownerDocument.characterSet;
220     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
221     //             .getService(Components.interfaces.nsITextToSubURI);
222     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
223     //     }
224     //     catch(ex) {
225     //         // Do nothing.
226     //     }
228     writeToClipboard(addresses);
229     message("Copied '" + addresses + "'");
231 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
234 /* FIXME: fix this command */
236 interactive("source",
237             "Load a JavaScript file.",
238             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
240 function reinit (window) {
241     var path;
242     try {
243         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;
274 function eval_expression (window, s) {
275     // eval in the global scope.
277     // In addition, the following variables are available:
278     // var window;
279     var buffer = window.buffers.current;
280     var result = eval(s);
281     if (result !== undefined) {
282         window.minibuffer.message(String(result));
283     }
285 interactive("eval-expression",
286     "Evaluate JavaScript statements.",
287     function (I) {
288         eval_expression(
289             I.window,
290             (yield I.minibuffer.read($prompt = "Eval:",
291                                      $history = "eval-expression",
292                                      $completer = javascript_completer(I.buffer))));
293     });
295 function show_extension_manager () {
296     return conkeror.window_watcher.openWindow(
297         null,
298         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
299         "ExtensionsWindow",
300         "resizable=yes,dialog=no",
301         null);
303 interactive("extensions",
304     "Open the extensions manager in a new window.",
305     show_extension_manager);
307 function print_buffer (buffer) {
308     buffer.top_frame.print();
311 interactive("print-buffer",
312     "Print the currently loaded page.",
313     function (I) { print_buffer(I.buffer); });
315 function view_partial_source (window, charset, selection) {
316     if (charset)
317         charset = "charset=" + charset;
318     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
319                              "_blank", "scrollbars,resizable,chrome,dialog=no",
320                              null, charset, selection, 'selection');
322 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
325 function  view_mathml_source (window, charset, target) {
326     if (charset)
327         charset = "charset=" + charset;
328     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
329                              "_blank", "scrollbars,resizable,chrome,dialog=no",
330                              null, charset, target, 'mathml');
334 function send_key_as_event (window, element, combo) {
335     var split = unformat_key_combo(combo);
336     var event = window.document.createEvent("KeyboardEvent");
337     event.initKeyEvent(
338         "keypress",
339         true,
340         true,
341         null,
342         split.ctrlKey,
343         split.altKey,
344         split.shiftKey,
345         split.metaKey,
346         split.keyCode,
347         split.charCode);
348     if (element) {
349         return element.dispatchEvent(event);
350     } else {
351         return window.dispatchEvent(event);
352     }
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     function (I) {
504         var element = yield read_browser_object(I);
505         browser_element_copy(I.buffer, element);
506     },
507     $browser_object = browser_object_links);
509 interactive("paste-url", "Open a URL from the clipboard in the current buffer.",
510             alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
511             $browser_object = browser_object_paste_url);
513 interactive("paste-url-new-buffer", "Open a URL from the clipboard in a new buffer.",
514             alternates(follow_new_buffer, follow_new_window),
515             $browser_object = browser_object_paste_url);
517 interactive("paste-url-new-window", "Open a URL from the clipboard in a new window.",
518             follow_new_window,
519             $browser_object = browser_object_paste_url);
521 interactive("view-source",
522             "Toggle between source and rendered views of a URL.",
523             alternates(view_source, view_source_new_buffer, view_source_new_window),
524             $browser_object = browser_object_frames);
527 interactive("shell-command-on-url",
528     "Run a shell command on the url of a browser object.",
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;
535         panel = create_info_panel(I.window, "download-panel",
536                                   [["downloading",
537                                     element_get_operation_label(element, "Running on", "URI"),
538                                     load_spec_uri_string(spec)],
539                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
540         try {
541             var cmd = yield I.minibuffer.read_shell_command(
542                 $cwd = cwd,
543                 $initial_value = load_spec_default_shell_command(spec));
544         } finally {
545             panel.destroy();
546         }
547         shell_command_with_argument_blind(cmd, uri, $cwd = cwd);
548     },
549     $browser_object = browser_object_url,
550     $prompt = "Shell command");
553 interactive("shell-command-on-file",
554     "Download a document to a temporary file and run a shell command on it.",
555     function (I) {
556         var cwd = I.local.cwd;
557         var element = yield read_browser_object(I);
558         var spec = load_spec(element);
559         var uri = load_spec_uri_string(spec);
560         var panel;
561         panel = create_info_panel(I.window, "download-panel",
562                                   [["downloading",
563                                     element_get_operation_label(element, "Running on"),
564                                     load_spec_uri_string(spec)],
565                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
566         try {
567             var cmd = yield I.minibuffer.read_shell_command(
568                 $cwd = cwd,
569                 $initial_value = load_spec_default_shell_command(spec));
570         } finally {
571             panel.destroy();
572         }
573         yield browser_element_shell_command(I.buffer, element, cmd, cwd);
574     },
575     $browser_object = browser_object_links,
576     $prompt = "Shell command");
579 interactive("bookmark",
580     "Create a bookmark.",
581     function (I) {
582         var element = yield read_browser_object(I);
583         var spec = load_spec(element);
584         var uri_string = load_spec_uri_string(spec);
585         var panel;
586         panel = create_info_panel(I.window, "bookmark-panel",
587                                   [["bookmarking",
588                                     element_get_operation_label(element, "Bookmarking"),
589                                     uri_string]]);
590         try {
591             var title = yield I.minibuffer.read($prompt = "Bookmark with title:", $initial_value = load_spec_title(spec) || "");
592         } finally {
593             panel.destroy();
594         }
595         add_bookmark(uri_string, title);
596         I.minibuffer.message("Added bookmark: " + uri_string + " - " + title);
597     },
598     $browser_object = browser_object_frames);
601 interactive("save-page",
602     "Save a document, not including any embedded documents such as images "+
603     "and css.",
604     function (I) {
605         check_buffer(I.buffer, content_buffer);
606         var element = yield read_browser_object(I);
607         var spec = load_spec(element);
608         if (!load_spec_document(spec))
609             throw interactive_error("Element is not associated with a document.");
610         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
612         var panel;
613         panel = create_info_panel(I.window, "download-panel",
614                                   [["downloading",
615                                     element_get_operation_label(element, "Saving"),
616                                     load_spec_uri_string(spec)],
617                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
619         try {
620             var file = yield I.minibuffer.read_file_check_overwrite(
621                 $prompt = "Save page as:",
622                 $history = "save",
623                 $initial_value = suggested_path);
624         } finally {
625             panel.destroy();
626         }
628         save_uri(spec, file, $buffer = I.buffer);
629     },
630     $browser_object = browser_object_frames);
633 interactive("save-page-as-text",
634     "Save a page as plain text.",
635     function (I) {
636         check_buffer(I.buffer, content_buffer);
637         var element = yield read_browser_object(I);
638         var spec = load_spec(element);
639         var doc;
640         if (!(doc = load_spec_document(spec)))
641             throw interactive_error("Element is not associated with a document.");
642         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec, "txt"), I.buffer);
644         var panel;
645         panel = create_info_panel(I.window, "download-panel",
646                                   [["downloading",
647                                     element_get_operation_label(element, "Saving", "as text"),
648                                     load_spec_uri_string(spec)],
649                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
651         try {
652             var file = yield I.minibuffer.read_file_check_overwrite(
653                 $prompt = "Save page as text:",
654                 $history = "save",
655                 $initial_value = suggested_path);
656         } finally {
657             panel.destroy();
658         }
660         save_document_as_text(doc, file, $buffer = I.buffer);
661     },
662     $browser_object = browser_object_frames);
665 interactive("save-page-complete",
666     "Save a page and all supporting documents, including images, css, "+
667     "and child frame documents.",
668     function (I) {
669         check_buffer(I.buffer, content_buffer);
670         var element = yield read_browser_object(I);
671         var spec = load_spec(element);
672         var doc;
673         if (!(doc = load_spec_document(spec)))
674             throw interactive_error("Element is not associated with a document.");
675         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
677         var panel;
678         panel = create_info_panel(I.window, "download-panel",
679                                   [["downloading",
680                                     element_get_operation_label(element, "Saving complete"),
681                                     load_spec_uri_string(spec)],
682                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
684         try {
685             var file = yield I.minibuffer.read_file_check_overwrite(
686                 $prompt = "Save page complete:",
687                 $history = "save",
688                 $initial_value = suggested_path);
689             // FIXME: use proper read function
690             var dir = yield I.minibuffer.read_file(
691                 $prompt = "Data Directory:",
692                 $history = "save",
693                 $initial_value = file.path + ".support");
694         } finally {
695             panel.destroy();
696         }
698         save_document_complete(doc, file, dir, $buffer = I.buffer);
699     },
700     $browser_object = browser_object_frames);
703 function view_as_mime_type (I, target) {
704     I.target = target;
705     var element = yield read_browser_object(I);
706     var spec = load_spec(element);
708     if (target == null)
709         target = FOLLOW_CURRENT_FRAME;
711     if (!can_override_mime_type_for_uri(load_spec_uri(spec)))
712         throw interactive_error("Overriding the MIME type is not currently supported for non-HTTP URLs.");
714     var panel;
716     var mime_type = load_spec_mime_type(spec);
717     panel = create_info_panel(I.window, "download-panel",
718                               [["downloading",
719                                 element_get_operation_label(element, "View in browser"),
720                                 load_spec_uri_string(spec)],
721                                ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
724     try {
725         let suggested_type = mime_type;
726         if (viewable_mime_type_list.indexOf(suggested_type) == -1)
727             suggested_type = "text/plain";
728         mime_type = yield I.minibuffer.read_viewable_mime_type(
729             $prompt = "View internally as",
730             $initial_value = suggested_type,
731             $select);
732         override_mime_type_for_next_load(load_spec_uri(spec), mime_type);
733         browser_object_follow(I.buffer, target, spec);
734     } finally {
735         panel.destroy();
736     }
739 function view_as_mime_type_new_buffer (I) {
740     yield view_as_mime_type(I, OPEN_NEW_BUFFER);
743 function view_as_mime_type_new_window (I) {
744     yield view_as_mime_type(I, OPEN_NEW_WINDOW);
747 interactive("view-as-mime-type",
748     "Display a browser object in the browser using the specified MIME type.",
749     alternates(view_as_mime_type,
750         view_as_mime_type_new_buffer,
751         view_as_mime_type_new_window),
752     $browser_object = browser_object_frames);
755 interactive("delete",
756     "Delete a DOM node, given as a browser object.",
757     function (I) {
758         var elem = yield read_browser_object(I);
759         elem.parentNode.removeChild(elem);
760     },
761     $browser_object = browser_object_dom_node);
764 interactive("charset-prefix",
765     "A prefix command that prompts for a charset to use in a "+
766     "subsequent navigation command.",
767     function (I) {
768         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
769             .getService(Ci.nsICharsetConverterManager);
770         var decoders = ccman.getDecoderList()
771         var charsets = [];
772         while (decoders.hasMore())
773             charsets.push(decoders.getNext());
774         I.forced_charset = yield I.minibuffer.read(
775             $prompt = "Charset:",
776             $completer = prefix_completer(
777                 $completions = charsets,
778                 $get_string = function (x) x.toLowerCase()),
779             $match_required,
780             $space_completes);
781     },
782     $prefix);
785 interactive("reload-with-charset",
786     "Prompt for a charset, and reload the current page, forcing use "+
787     "of that charset.",
788     function (I) {
789         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
790             .getService(Ci.nsICharsetConverterManager);
791         var decoders = ccman.getDecoderList()
792         var charsets = [];
793         while (decoders.hasMore())
794             charsets.push(decoders.getNext());
795         var forced_charset = yield I.minibuffer.read(
796             $prompt = "Charset:",
797             $completer = prefix_completer(
798                 $completions = charsets,
799                 $get_string = function (x) x.toLowerCase()),
800             $match_required,
801             $space_completes);
802         reload(I.buffer, false, null, forced_charset);
803     });
806 interactive("yank",
807     "Paste the contents of the clipboard",
808     function (I) {
809         call_builtin_command(I.window, "cmd_paste", true);
810     });
812 interactive("kill-region",
813     "Kill (\"cut\") the selected text.",
814     function (I) {
815         call_builtin_command(I.window, "cmd_cut", true);
816     });
818 interactive("kill-ring-save",
819     "Save the region as if killed, but don't kill it.",
820     function (I) {
821         call_builtin_command(I.window, "cmd_copy", true);
822     });
824 provide("commands");