kludge issue 513
[conkeror.git] / modules / interactive.js
blob8eec0b0fd7813ea0ee14968ea318cedcabc4eb54
1 /**
2 * (C) Copyright 2007-2009 John J. Foerch
3 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
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 = {};
13 /**
14 * name: string name of the command.
16 * doc: Documentation string, may be null.
18 * handler: A function to handle the command.
20 * The $prefix keyword, when true, means that the command
21 * is a prefix-command.
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() };
35 interactive_commands[name] = cmd;
36 return name;
39 function interactive_error (str) {
40 var e = new Error(str);
41 e.__proto__ = interactive_error.prototype;
42 return e;
44 interactive_error.prototype.__proto__ = Error.prototype;
47 function interactive_context (buffer) {
48 this.local = conkeror;
49 this.buffer = buffer;
50 if (buffer) {
51 this.window = this.buffer.window;
52 if (buffer.page) {
53 this.local = buffer.page.local;
54 } else {
55 this.local = buffer.local;
59 interactive_context.prototype = {
60 constructor: interactive_context,
61 toString: function () "#<interactive_context>",
62 get P () this.prefix_argument,
63 get p () univ_arg_to_number(this.prefix_argument),
64 set p (default_value) univ_arg_to_number(this.prefix_argument, default_value),
65 get minibuffer () this.window.minibuffer,
66 prefix_argument: null,
67 repeat: null
71 function handle_interactive_error (window, e) {
72 if (! window)
73 throw e;
74 if (e instanceof interactive_error) {
75 window.minibuffer.message(e.message);
76 } else if (e instanceof abort) {
77 window.minibuffer.message("Quit");
78 } else {
79 dump_error(e);
80 window.minibuffer.message("call interactively: " + e);
84 function call_interactively (I, command) {
85 var handler;
86 var window = I.window;
88 if (typeof command == "function") {
89 // Special interactive command
90 command(I);
91 yield co_return();
94 var cmd = interactive_commands[command];
95 if (!cmd) {
96 handle_interactive_error(
97 window,
98 interactive_error("Invalid command: " + command));
99 yield co_return();
102 I.command = cmd;
103 handler = cmd.handler;
105 try {
106 while (typeof handler == "string") {
107 let parent = interactive_commands[handler];
108 handler = parent.handler;
109 if (handler == command) {
110 throw (interactive_error("circular command alias, "+command));
114 try {
115 yield handler(I);
116 } catch (e) {
117 handle_interactive_error(window, e);
119 } catch (e) {
120 handle_interactive_error(window, e);
125 function alternates () {
126 let alts = Array.prototype.slice.call(arguments, 0);
127 return function (I) {
128 var index = 0;
129 if (array_p(I.prefix_argument)) {
130 let num = I.prefix_argument = I.prefix_argument[0];
131 while (num >= 4 && index + 1 < alts.length) {
132 num = num / 4;
133 index++;
136 yield alts[index](I);
142 * Utility functions for use in the rc to alter the behavior
143 * of interactive commands.
145 function set_handler (name, handler) {
146 var cmd = interactive_commands[name];
147 cmd.handler = handler;
150 function set_default_browser_object (name, browser_object) {
151 var cmd = interactive_commands[name];
152 cmd.browser_object = browser_object;
155 provide("interactive");