keywords.js: make write_keywords public and more flexible
[conkeror.git] / modules / interactive.js
bloba55a8f2f472e9f4b5d0c5759131e1f2e1fc93a6c
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");
24 function interactive(name, doc, handler)
26     keywords(arguments);
27     var cmd = {
28         name: name,
29         handler: handler,
30         prefix: arguments.$prefix,
31         doc: doc,
32         shortdoc: get_shortdoc_string(doc),
33         source_code_reference: get_caller_source_code_reference() };
35     interactive_commands.put(name, cmd);
38 function interactive_error(str) {
39     var e = new Error(str);
40     e.__proto__ = interactive_error.prototype;
41     return e;
43 interactive_error.prototype.__proto__ = Error.prototype;
45 function interactive_context() {}
46 interactive_context.prototype = {
48     get P () this.prefix_argument,
50     get p () univ_arg_to_number(this.prefix_argument),
52     set p (default_value) univ_arg_to_number(this.prefix_argument, default_value),
54     get minibuffer () this.window.minibuffer,
56     get : function (x) this.buffer.get(x)
59 function handle_interactive_error(window, e) {
60     if (e instanceof interactive_error)
61         window.minibuffer.message(e.message);
62     else if (e instanceof abort)
63         window.minibuffer.message("Quit");
64     else {
65         dump_error(e);
66         window.minibuffer.message("call interactively: " + e);
67     }
70 // Any additional arguments specify "given" arguments to the function.
71 function call_interactively(I, command)
73     var handler;
74     var top_args;
76     I.__proto__ = interactive_context.prototype;
78     if (I.buffer == null)
79         I.buffer = I.window.buffers.current;
80     else if (I.window == null)
81         I.window = I.buffer.window;
83     var window = I.window;
85     if (typeof(command) == "function") {
86         // Special interactive command
87         command(I);
88         return;
89     }
91     var cmd = interactive_commands.get(command);
92     if (!cmd)
93     {
94         window.minibuffer.message("Invalid command: " + command);
95         return;
96     }
98     I.command = command;
100     var handler = cmd.handler;
102     try {
103         var result = handler(I);
104         if (is_coroutine(result)) {
105             co_call(function() {
106                 try {
107                     yield result;
108                 } catch (e) {
109                     handle_interactive_error(window, e);
110                 }
111             }());
112         }
113     } catch (e)
114     {
115         handle_interactive_error(window, e);
116     }
120 I.f = interactive_method(
121     $doc = "Existing file",
122     $async = function (ctx, cont) {
123         keywords(arguments, $prompt = "File:", $initial_value = default_directory.path,
124                  $history = "file");
125         ctx.window.minibuffer.read(
126             $prompt = arguments.$prompt,
127             $initial_value = arguments.$initial_value,
128             $history = arguments.$history,
129             $callback = function(s) {
130                 var f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
131                 f.initWithPath(s);
132                 cont(f);
133             });
134     });
136 // FIXME: eventually they will differ, when completion for files is added
137 I.F = I.f;