buffer.override_keymaps: dealt with privately inside buffer
[conkeror.git] / modules / commands.js
blobf64b88be8675529d12141b46efdd966a9427e7cf
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         var buffer = I.buffer;
171         try {
172             buffer.do_command(command);
173         } catch (e) {
174             /* Ignore exceptions */
175         }
176     },
177     function (I) {
178         I.buffer.mark_active = !I.buffer.mark_active;
179     },
180     function (I) I.buffer.mark_active,
181     false
184 define_builtin_commands(
185     "caret-",
186     function (I, command) {
187         var buffer = I.buffer;
188         try {
189             buffer.do_command(command);
190         } catch (e) {
191             /* Ignore exceptions */
192         }
193     },
194     function (I) {
195         I.buffer.mark_active = !I.buffer.mark_active;
196     },
197     function (I) I.buffer.mark_active,
198     'caret');
200 function get_link_text () {
201     var e = document.commandDispatcher.focusedElement;
202     if (e && e.getAttribute("href")) {
203         return e.getAttribute("href");
204     }
205     return null;
210 function copy_email_address (loc)
212     // Copy the comma-separated list of email addresses only.
213     // There are other ways of embedding email addresses in a mailto:
214     // link, but such complex parsing is beyond us.
215     var qmark = loc.indexOf( "?" );
216     var addresses;
218     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
219         addresses = loc.substring( 7, qmark );
220     } else {
221         addresses = loc.substr( 7 );
222     }
224     //XXX: the original code, which we got from firefox, unescapes the string
225     //     using the current character set.  To do this in conkeror, we
226     //     *should* use an interactive method that gives us the character set,
227     //     rather than fetching it by side-effect.
229     //     // Let's try to unescape it using a character set
230     //     // in case the address is not ASCII.
231     //     try {
232     //         var characterSet = this.target.ownerDocument.characterSet;
233     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
234     //             .getService(Components.interfaces.nsITextToSubURI);
235     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
236     //     }
237     //     catch(ex) {
238     //         // Do nothing.
239     //     }
241     writeToClipboard(addresses);
242     message("Copied '" + addresses + "'");
244 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
247 /* FIXME: fix this command */
249 interactive("source",
250             "Load a JavaScript file.",
251             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
253 function reinit (window) {
254     var path;
255     try {
256         path = load_rc();
257         window.minibuffer.message("Loaded: " + path);
258     } catch (e) {
259         window.minibuffer.message("Failed to load: "+path);
260     }
263 interactive("reinit",
264             "Reload the Conkeror rc file.",
265             function (I) { reinit(I.window); });
267 interactive("help-page", "Open the Conkeror help page.",
268             "find-url-new-buffer",
269             $browser_object = "chrome://conkeror-help/content/help.html");
271 interactive("tutorial", "Open the Conkeror tutorial.",
272             "find-url-new-buffer",
273             $browser_object = "chrome://conkeror-help/content/tutorial.html");
275 function univ_arg_to_number (prefix, default_value) {
276     if (prefix == null) {
277         if (default_value == null)
278             return 1;
279         else
280             return default_value;
281     }
282     if (typeof prefix == "object")
283         return prefix[0];
284     return prefix;
287 function eval_expression (window, s) {
288     // eval in the global scope.
290     // In addition, the following variables are available:
291     // var window;
292     var buffer = window.buffers.current;
293     var result = eval(s);
294     if (result !== undefined) {
295         window.minibuffer.message(String(result));
296     }
298 interactive("eval-expression",
299     "Evaluate JavaScript statements.",
300     function (I) {
301         eval_expression(
302             I.window,
303             (yield I.minibuffer.read($prompt = "Eval:",
304                                      $history = "eval-expression",
305                                      $completer = javascript_completer(I.buffer))));
306     });
308 function show_extension_manager () {
309     return conkeror.window_watcher.openWindow(
310         null,
311         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
312         "ExtensionsWindow",
313         "resizable=yes,dialog=no",
314         null);
316 interactive("extensions",
317     "Open the extensions manager in a new window.",
318     show_extension_manager);
320 function print_buffer (buffer) {
321     buffer.top_frame.print();
324 interactive("print-buffer",
325     "Print the currently loaded page.",
326     function (I) { print_buffer(I.buffer); });
328 function view_partial_source (window, charset, selection) {
329     if (charset)
330         charset = "charset=" + charset;
331     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
332                              "_blank", "scrollbars,resizable,chrome,dialog=no",
333                              null, charset, selection, 'selection');
335 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
338 function  view_mathml_source (window, charset, target) {
339     if (charset)
340         charset = "charset=" + charset;
341     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
342                              "_blank", "scrollbars,resizable,chrome,dialog=no",
343                              null, charset, target, 'mathml');
347 function send_key_as_event (window, element, combo) {
348     var split = unformat_key_combo(combo);
349     var event = window.document.createEvent("KeyboardEvent");
350     event.initKeyEvent(
351         "keypress",
352         true,
353         true,
354         null,
355         split.ctrlKey,
356         split.altKey,
357         split.shiftKey,
358         split.metaKey,
359         split.keyCode,
360         split.charCode);
361     if (element) {
362         return element.dispatchEvent(event);
363     } else {
364         return window.dispatchEvent(event);
365     }
369 function ensure_content_focused (buffer) {
370     var foc = buffer.focused_frame_or_null;
371     if (!foc)
372         buffer.top_frame.focus();
374 interactive("ensure-content-focused", "Ensure that the content document has focus.",
375     function (I) { ensure_content_focused(I.buffer); });
378 function network_set_online_status (status) {
379     const io_service = Cc["@mozilla.org/network/io-service;1"]
380         .getService(Ci.nsIIOService2);
381     status = !status;
382     io_service.manageOfflineStatus = false;
383     io_service.offline = status;
385 interactive("network-go-online", "Work online.",
386     function (I) { network_set_online_status(true); });
388 interactive("network-go-offline", "Work offline.",
389     function (I) { network_set_online_status(false); });
392 interactive("submit-form",
393     "Submit the form to which the focused element belongs.",
394     function (I) {
395         var el = I.buffer.focused_element.parentNode;
396         while (el && el.tagName != "FORM")
397             el = el.parentNode;
398         if (el) {
399             var inputs = el.getElementsByTagName("input");
400             for (var i = 0, ilen = inputs.length; i < ilen; i++) {
401                 if (inputs[i].getAttribute("type") == "submit")
402                     return browser_object_follow(I.buffer, FOLLOW_DEFAULT,
403                                                  inputs[i]);
404             }
405             el.submit();
406         }
407     });
411  * Browser Object Commands
412  */
413 interactive("follow", null,
414     alternates(follow, follow_new_buffer, follow_new_window),
415     $browser_object = browser_object_links);
417 interactive("follow-top", null,
418     alternates(follow_current_buffer, follow_current_frame),
419     $browser_object = browser_object_frames,
420     $prompt = "Follow");
422 interactive("follow-new-buffer",
423     "Follow a link in a new buffer",
424     alternates(follow_new_buffer, follow_new_window),
425     $browser_object = browser_object_links,
426     $prompt = "Follow");
428 interactive("follow-new-buffer-background",
429     "Follow a link in a new buffer in the background",
430     alternates(follow_new_buffer_background, follow_new_window),
431     $browser_object = browser_object_links,
432     $prompt = "Follow");
434 interactive("follow-new-window",
435     "Follow a link in a new window",
436     follow_new_window,
437     $browser_object = browser_object_links,
438     $prompt = "Follow");
440 interactive("find-url", "Open a URL in the current buffer",
441     alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
442     $browser_object = browser_object_url);
444 interactive("find-url-new-buffer",
445     "Open a URL in a new buffer",
446     alternates(follow_new_buffer, follow_new_window),
447     $browser_object = browser_object_url,
448     $prompt = "Find url");
450 interactive("find-url-new-window", "Open a URL in a new window",
451     follow_new_window,
452     $browser_object = browser_object_url,
453     $prompt = "Find url");
455 interactive("find-alternate-url", "Edit the current URL in the minibuffer",
456     "find-url",
457     $browser_object =
458         define_browser_object_class("alternate-url", null,
459             function (I, prompt) {
460                 check_buffer(I.buffer, content_buffer);
461                 var result = yield I.buffer.window.minibuffer.read_url(
462                     $prompt = prompt,
463                     $initial_value = I.buffer.display_uri_string);
464                 yield co_return(result);
465             }),
466     $prompt = "Find url");
469 interactive("up", "Go to the parent directory of the current URL",
470     "find-url",
471     $browser_object = browser_object_up_url);
473 interactive("home",
474     "Go to the homepage in the current buffer.", "follow",
475     $browser_object = function () { return homepage; });
477 interactive("make-window",
478     "Make a new window with the homepage.",
479     follow_new_window,
480     $browser_object = function () { return homepage; });
482 interactive("focus", null,
483     function (I) {
484         var element = yield read_browser_object(I);
485         browser_element_focus(I.buffer, element);
486     },
487     $browser_object = browser_object_frames);
489 interactive("save",
490     "Save a browser object.",
491     function (I) {
492         var element = yield read_browser_object(I);
493         var spec = load_spec(element);
494         var panel;
495         panel = create_info_panel(I.window, "download-panel",
496                                   [["downloading",
497                                     element_get_operation_label(element, "Saving"),
498                                     load_spec_uri_string(spec)],
499                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
500         try {
501             var file = yield I.minibuffer.read_file_check_overwrite(
502                 $prompt = "Save as:",
503                 $initial_value = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer),
504                 $history = "save");
505         } finally {
506             panel.destroy();
507         }
508         save_uri(spec, file,
509                  $buffer = I.buffer,
510                  $use_cache = false);
511     },
512     $browser_object = browser_object_links);
515 interactive("copy", null,
516     function (I) {
517         var element = yield read_browser_object(I);
518         browser_element_copy(I.buffer, element);
519     },
520     $browser_object = browser_object_links);
522 interactive("paste-url", "Open a URL from the clipboard in the current buffer.",
523             alternates(follow_current_buffer, follow_new_buffer, follow_new_window),
524             $browser_object = browser_object_paste_url);
526 interactive("paste-url-new-buffer", "Open a URL from the clipboard in a new buffer.",
527             alternates(follow_new_buffer, follow_new_window),
528             $browser_object = browser_object_paste_url);
530 interactive("paste-url-new-window", "Open a URL from the clipboard in a new window.",
531             follow_new_window,
532             $browser_object = browser_object_paste_url);
534 interactive("view-source",
535             "Toggle between source and rendered views of a URL.",
536             alternates(view_source, view_source_new_buffer, view_source_new_window),
537             $browser_object = browser_object_frames);
540 interactive("shell-command-on-url",
541     "Run a shell command on the url of a browser object.",
542     function (I) {
543         var cwd = I.local.cwd;
544         var element = yield read_browser_object(I);
545         var spec = load_spec(element);
546         var uri = load_spec_uri_string(spec);
547         var panel;
548         panel = create_info_panel(I.window, "download-panel",
549                                   [["downloading",
550                                     element_get_operation_label(element, "Running on", "URI"),
551                                     load_spec_uri_string(spec)],
552                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
553         try {
554             var cmd = yield I.minibuffer.read_shell_command(
555                 $cwd = cwd,
556                 $initial_value = load_spec_default_shell_command(spec));
557         } finally {
558             panel.destroy();
559         }
560         shell_command_with_argument_blind(cmd, uri, $cwd = cwd);
561     },
562     $browser_object = browser_object_url,
563     $prompt = "Shell command");
566 interactive("shell-command-on-file",
567     "Download a document to a temporary file and run a shell command on it.",
568     function (I) {
569         var cwd = I.local.cwd;
570         var element = yield read_browser_object(I);
571         var spec = load_spec(element);
572         var uri = load_spec_uri_string(spec);
573         var panel;
574         panel = create_info_panel(I.window, "download-panel",
575                                   [["downloading",
576                                     element_get_operation_label(element, "Running on"),
577                                     load_spec_uri_string(spec)],
578                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
579         try {
580             var cmd = yield I.minibuffer.read_shell_command(
581                 $cwd = cwd,
582                 $initial_value = load_spec_default_shell_command(spec));
583         } finally {
584             panel.destroy();
585         }
586         yield browser_element_shell_command(I.buffer, element, cmd, cwd);
587     },
588     $browser_object = browser_object_links,
589     $prompt = "Shell command");
592 interactive("bookmark",
593     "Create a bookmark.",
594     function (I) {
595         var element = yield read_browser_object(I);
596         var spec = load_spec(element);
597         var uri_string = load_spec_uri_string(spec);
598         var panel;
599         panel = create_info_panel(I.window, "bookmark-panel",
600                                   [["bookmarking",
601                                     element_get_operation_label(element, "Bookmarking"),
602                                     uri_string]]);
603         try {
604             var title = yield I.minibuffer.read($prompt = "Bookmark with title:", $initial_value = load_spec_title(spec) || "");
605         } finally {
606             panel.destroy();
607         }
608         add_bookmark(uri_string, title);
609         I.minibuffer.message("Added bookmark: " + uri_string + " - " + title);
610     },
611     $browser_object = browser_object_frames);
614 interactive("save-page",
615     "Save a document, not including any embedded documents such as images "+
616     "and css.",
617     function (I) {
618         check_buffer(I.buffer, content_buffer);
619         var element = yield read_browser_object(I);
620         var spec = load_spec(element);
621         if (!load_spec_document(spec))
622             throw interactive_error("Element is not associated with a document.");
623         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
625         var panel;
626         panel = create_info_panel(I.window, "download-panel",
627                                   [["downloading",
628                                     element_get_operation_label(element, "Saving"),
629                                     load_spec_uri_string(spec)],
630                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
632         try {
633             var file = yield I.minibuffer.read_file_check_overwrite(
634                 $prompt = "Save page as:",
635                 $history = "save",
636                 $initial_value = suggested_path);
637         } finally {
638             panel.destroy();
639         }
641         save_uri(spec, file, $buffer = I.buffer);
642     },
643     $browser_object = browser_object_frames);
646 interactive("save-page-as-text",
647     "Save a page as plain text.",
648     function (I) {
649         check_buffer(I.buffer, content_buffer);
650         var element = yield read_browser_object(I);
651         var spec = load_spec(element);
652         var doc;
653         if (!(doc = load_spec_document(spec)))
654             throw interactive_error("Element is not associated with a document.");
655         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec, "txt"), I.buffer);
657         var panel;
658         panel = create_info_panel(I.window, "download-panel",
659                                   [["downloading",
660                                     element_get_operation_label(element, "Saving", "as text"),
661                                     load_spec_uri_string(spec)],
662                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
664         try {
665             var file = yield I.minibuffer.read_file_check_overwrite(
666                 $prompt = "Save page as text:",
667                 $history = "save",
668                 $initial_value = suggested_path);
669         } finally {
670             panel.destroy();
671         }
673         save_document_as_text(doc, file, $buffer = I.buffer);
674     },
675     $browser_object = browser_object_frames);
678 interactive("save-page-complete",
679     "Save a page and all supporting documents, including images, css, "+
680     "and child frame documents.",
681     function (I) {
682         check_buffer(I.buffer, content_buffer);
683         var element = yield read_browser_object(I);
684         var spec = load_spec(element);
685         var doc;
686         if (!(doc = load_spec_document(spec)))
687             throw interactive_error("Element is not associated with a document.");
688         var suggested_path = suggest_save_path_from_file_name(suggest_file_name(spec), I.buffer);
690         var panel;
691         panel = create_info_panel(I.window, "download-panel",
692                                   [["downloading",
693                                     element_get_operation_label(element, "Saving complete"),
694                                     load_spec_uri_string(spec)],
695                                    ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
697         try {
698             var file = yield I.minibuffer.read_file_check_overwrite(
699                 $prompt = "Save page complete:",
700                 $history = "save",
701                 $initial_value = suggested_path);
702             // FIXME: use proper read function
703             var dir = yield I.minibuffer.read_file(
704                 $prompt = "Data Directory:",
705                 $history = "save",
706                 $initial_value = file.path + ".support");
707         } finally {
708             panel.destroy();
709         }
711         save_document_complete(doc, file, dir, $buffer = I.buffer);
712     },
713     $browser_object = browser_object_frames);
716 function view_as_mime_type (I, target) {
717     I.target = target;
718     var element = yield read_browser_object(I);
719     var spec = load_spec(element);
721     if (target == null)
722         target = FOLLOW_CURRENT_FRAME;
724     if (!can_override_mime_type_for_uri(load_spec_uri(spec)))
725         throw interactive_error("Overriding the MIME type is not currently supported for non-HTTP URLs.");
727     var panel;
729     var mime_type = load_spec_mime_type(spec);
730     panel = create_info_panel(I.window, "download-panel",
731                               [["downloading",
732                                 element_get_operation_label(element, "View in browser"),
733                                 load_spec_uri_string(spec)],
734                                ["mime-type", "Mime type:", load_spec_mime_type(spec)]]);
737     try {
738         let suggested_type = mime_type;
739         if (viewable_mime_type_list.indexOf(suggested_type) == -1)
740             suggested_type = "text/plain";
741         mime_type = yield I.minibuffer.read_viewable_mime_type(
742             $prompt = "View internally as",
743             $initial_value = suggested_type,
744             $select);
745         override_mime_type_for_next_load(load_spec_uri(spec), mime_type);
746         browser_object_follow(I.buffer, target, spec);
747     } finally {
748         panel.destroy();
749     }
752 function view_as_mime_type_new_buffer (I) {
753     yield view_as_mime_type(I, OPEN_NEW_BUFFER);
756 function view_as_mime_type_new_window (I) {
757     yield view_as_mime_type(I, OPEN_NEW_WINDOW);
760 interactive("view-as-mime-type",
761     "Display a browser object in the browser using the specified MIME type.",
762     alternates(view_as_mime_type,
763         view_as_mime_type_new_buffer,
764         view_as_mime_type_new_window),
765     $browser_object = browser_object_frames);
768 interactive("delete",
769     "Delete a DOM node, given as a browser object.",
770     function (I) {
771         var elem = yield read_browser_object(I);
772         elem.parentNode.removeChild(elem);
773     },
774     $browser_object = browser_object_dom_node);
777 interactive("charset-prefix",
778     "A prefix command that prompts for a charset to use in a "+
779     "subsequent navigation command.",
780     function (I) {
781         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
782             .getService(Ci.nsICharsetConverterManager);
783         var decoders = ccman.getDecoderList()
784         var charsets = [];
785         while (decoders.hasMore())
786             charsets.push(decoders.getNext());
787         I.forced_charset = yield I.minibuffer.read(
788             $prompt = "Charset:",
789             $completer = prefix_completer(
790                 $completions = charsets,
791                 $get_string = function (x) x.toLowerCase()),
792             $match_required);
793     },
794     $prefix);
797 interactive("reload-with-charset",
798     "Prompt for a charset, and reload the current page, forcing use "+
799     "of that charset.",
800     function (I) {
801         var ccman = Cc["@mozilla.org/charset-converter-manager;1"]
802             .getService(Ci.nsICharsetConverterManager);
803         var decoders = ccman.getDecoderList()
804         var charsets = [];
805         while (decoders.hasMore())
806             charsets.push(decoders.getNext());
807         var forced_charset = yield I.minibuffer.read(
808             $prompt = "Charset:",
809             $completer = prefix_completer(
810                 $completions = charsets,
811                 $get_string = function (x) x.toLowerCase()),
812             $match_required);
813         reload(I.buffer, false, null, forced_charset);
814     });
817 interactive("yank",
818     "Paste the contents of the clipboard",
819     function (I) {
820         I.buffer.mark_active = false;
821         I.buffer.do_command("cmd_paste");
822     });
824 interactive("kill-region",
825     "Kill (\"cut\") the selected text.",
826     function (I) {
827         I.buffer.mark_active = false;
828         I.buffer.do_command("cmd_cut");
829     });
831 interactive("kill-ring-save",
832     "Save the region as if killed, but don't kill it.",
833     function (I) {
834          I.buffer.mark_active = false;
835          I.buffer.do_command("cmd_copy");
836     });
838 provide("commands");