gmane page-mode: binding for browser-object-links
[conkeror.git] / modules / interactive.js
blob61815fbac336396d626f6294ae2c7faffa09a2d4
1 /**
2  * (C) Copyright 2007-2008 John J. Foerch
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 require("utils.js");
11 var interactive_commands = new string_hashmap();
13 /**
14  * name: string name of the command.
15  *
16  * doc: Documentation string, may be null.
17  *
18  * handler: A function to handle the command.
19  *
20  * The $prefix keyword, when true, means that the command
21  * is a prefix-command.
22  */
23 define_keywords("$prefix", "$browser_object", "$prompt");
24 function interactive(name, doc, handler)
26     keywords(arguments);
27     var cmd = {
28         name: name,
29         handler: handler,
30         browser_object: arguments.$browser_object,
31         prefix: arguments.$prefix,
32         doc: doc,
33         shortdoc: get_shortdoc_string(doc),
34         prompt: arguments.$prompt,
35         source_code_reference: get_caller_source_code_reference() };
37     interactive_commands.put(name, cmd);
38     return name;
41 function interactive_error(str) {
42     var e = new Error(str);
43     e.__proto__ = interactive_error.prototype;
44     return e;
46 interactive_error.prototype.__proto__ = Error.prototype;
48 function interactive_context() {}
49 interactive_context.prototype = {
51     get P () this.prefix_argument,
53     get p () univ_arg_to_number(this.prefix_argument),
55     set p (default_value) univ_arg_to_number(this.prefix_argument, default_value),
57     get minibuffer () this.window.minibuffer,
59     get : function (x) this.buffer.get(x)
62 function handle_interactive_error(window, e) {
63     if (! window)
64         throw e;
65     if (e instanceof interactive_error) {
66         window.minibuffer.message(e.message);
67     } else if (e instanceof abort) {
68         window.minibuffer.message("Quit");
69     } else {
70         dump_error(e);
71         window.minibuffer.message("call interactively: " + e);
72     }
75 function call_interactively(I, command)
77     var handler;
78     var top_args;
80     I.__proto__ = interactive_context.prototype;
82     if (I.window) {
83         if (I.buffer == null)
84             I.buffer = I.window.buffers.current;
85     } else if (I.buffer) {
86         I.window = I.buffer.window;
87     }
89     var window = I.window;
91     if (typeof(command) == "function") {
92         // Special interactive command
93         command(I);
94         return;
95     }
97     var cmd = interactive_commands.get(command);
98     if (!cmd) {
99         handle_interactive_error(
100             window,
101             interactive_error("Invalid command: " + command));
102         return;
103     }
105     I.command = cmd;
107     // if the default is a non-null literal, it always overrides.
108     if (cmd.browser_object != null &&
109         (! (cmd.browser_object instanceof browser_object_class)))
110     {
111         I.browser_object = cmd.browser_object;
112     }
114     // if no browser-object was specified interactively, use a
115     // default, possibly specified by the page-mode.
116     if (I.browser_object == null) {
117         I.browser_object =
118             (I.buffer && I.buffer.default_browser_object_classes[command]) ||
119             cmd.browser_object;
120     }
122     handler = cmd.handler;
124     try {
125         while (typeof(handler) == "string") {
126             let parent = interactive_commands.get(handler);
127             handler = parent.handler;
128             if (handler == command) {
129                 throw (interactive_error("circular command alias, "+command));
130             }
131         }
133         var result = handler(I);
134         if (is_coroutine(result)) {
135             co_call(function() {
136                 try {
137                     yield result;
138                 } catch (e) {
139                     handle_interactive_error(window, e);
140                 }
141             }());
142         }
143     } catch (e)
144     {
145         handle_interactive_error(window, e);
146     }
150 function alternates () {
151     let alts = Array.prototype.slice.call(arguments, 0);
152     return function (I) {
153         var index = 0;
154         if (I.prefix_argument instanceof Array) {
155             let num = I.prefix_argument = I.prefix_argument[0];
156             while (num >= 4 && index + 1 < alts.length) {
157                 num = num / 4;
158                 index++;
159             }
160         }
161         yield alts[index](I);
162     };
167  * Utility functions for use in the rc to alter the behavior
168  * of interactive commands.
169  */
170 function set_handler (name, handler) {
171     var cmd = interactive_commands.get(name);
172     cmd.handler = handler;
175 function set_default_browser_object (name, browser_object) {
176     var cmd = interactive_commands.get(name);
177     cmd.browser_object = browser_object;