whitespace
[conkeror.git] / modules / interactive.js
blob834f96a2a4f00a49939130cf771dd07dcd53e948
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) {
25     keywords(arguments);
26     var cmd = {
27         name: name,
28         handler: handler,
29         browser_object: arguments.$browser_object,
30         prefix: arguments.$prefix,
31         doc: doc,
32         shortdoc: get_shortdoc_string(doc),
33         prompt: arguments.$prompt,
34         source_code_reference: get_caller_source_code_reference() };
36     interactive_commands.put(name, cmd);
37     return name;
40 function interactive_error (str) {
41     var e = new Error(str);
42     e.__proto__ = interactive_error.prototype;
43     return e;
45 interactive_error.prototype.__proto__ = Error.prototype;
48 function interactive_context (buffer) {
49     this.local = conkeror;
50     this.buffer = buffer;
51     if (buffer) {
52         this.window = this.buffer.window;
53         if (buffer.page) {
54             this.local = buffer.page.local;
55         } else {
56             this.local = buffer.local;
57         }
58     }
60 interactive_context.prototype = {
62     get P () this.prefix_argument,
64     get p () univ_arg_to_number(this.prefix_argument),
66     set p (default_value) univ_arg_to_number(this.prefix_argument, default_value),
68     get minibuffer () this.window.minibuffer,
72 function handle_interactive_error (window, e) {
73     if (! window)
74         throw e;
75     if (e instanceof interactive_error) {
76         window.minibuffer.message(e.message);
77     } else if (e instanceof abort) {
78         window.minibuffer.message("Quit");
79     } else {
80         dump_error(e);
81         window.minibuffer.message("call interactively: " + e);
82     }
85 function call_interactively (I, command) {
86     var handler;
87     var top_args;
88     var window = I.window;
90     if (typeof(command) == "function") {
91         // Special interactive command
92         command(I);
93         return;
94     }
96     var cmd = interactive_commands.get(command);
97     if (!cmd) {
98         handle_interactive_error(
99             window,
100             interactive_error("Invalid command: " + command));
101         return;
102     }
104     I.command = cmd;
107     // if there was no interactive browser-object,
108     // binding_browser_object becomes the default.
109     if (I.browser_object == null) {
110         I.browser_object = I.binding_browser_object;
111     }
112     // if the command's default browser object is a non-null literal,
113     // it overrides an interactive browser-object, but not a binding
114     // browser object.
115     if (cmd.browser_object != null &&
116         (! (cmd.browser_object instanceof browser_object_class)) &&
117         (I.binding_browser_object == null))
118     {
119         I.browser_object = cmd.browser_object;
120     }
121     // if we still have no browser-object, look for a page-mode
122     // default, or finally the command default.
123     if (I.browser_object == null) {
124         I.browser_object =
125             (I.buffer && I.buffer.default_browser_object_classes[command]) ||
126             cmd.browser_object;
127     }
129     handler = cmd.handler;
131     try {
132         while (typeof(handler) == "string") {
133             let parent = interactive_commands.get(handler);
134             handler = parent.handler;
135             if (handler == command) {
136                 throw (interactive_error("circular command alias, "+command));
137             }
138         }
140         var result = handler(I);
141         if (is_coroutine(result)) {
142             co_call(function() {
143                 try {
144                     yield result;
145                 } catch (e) {
146                     handle_interactive_error(window, e);
147                 }
148             }());
149         }
150     } catch (e) {
151         handle_interactive_error(window, e);
152     }
156 function alternates () {
157     let alts = Array.prototype.slice.call(arguments, 0);
158     return function (I) {
159         var index = 0;
160         if (I.prefix_argument instanceof Array) {
161             let num = I.prefix_argument = I.prefix_argument[0];
162             while (num >= 4 && index + 1 < alts.length) {
163                 num = num / 4;
164                 index++;
165             }
166         }
167         yield alts[index](I);
168     };
173  * Utility functions for use in the rc to alter the behavior
174  * of interactive commands.
175  */
176 function set_handler (name, handler) {
177     var cmd = interactive_commands.get(name);
178     cmd.handler = handler;
181 function set_default_browser_object (name, browser_object) {
182     var cmd = interactive_commands.get(name);
183     cmd.browser_object = browser_object;