2 * (C) Copyright 2004-2007 Shawn Betts
3 * (C) Copyright 2007-2008 John J. Foerch
4 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
5 * (C) Copyright 2011 Peter Lunicks
7 * Use, modification, and distribution are subject to the terms specified in the
11 define_variable("webjump_separator", ' ',
12 "The separator character between a webjump name "+
13 "and its arguments.");
17 define_keywords("$completer", "$description", "$argument", "$alternative",
19 function define_webjump (key, handler) {
21 var argument = arguments.$argument;
22 let alternative = arguments.$alternative;
23 var post_data = arguments.$post_data;
25 // handler may be a function or a string. An alternative url may
26 // be passed using the $alternative keyword; it is used in place
27 // of the handler when no arguments are supplied by the user when
28 // invoking the webjump (see get_webjump). For string webjumps
29 // that contain %s and for which no alternative is provided, an
30 // alternative is autogenerated by trimming the path from the url.
31 // A webjump can thus function both as a way to invoke a search
34 // When the handler is a string and post_data is given the webjump
35 // will result in a POST. A '%s' element in post_data will be
36 // replaced by the webjump argument and the alternative is the
37 // same as the handler (but as a GET).
39 // The argument property may be false (no arguments will be
40 // accepted for the webjump), true (arguments are required for the
41 // webjump) or 'optional' (arguments are accepted but not
42 // required). If the property is not specified, a sensible default
43 // is chosen depending on the type of the handler and whether an
44 // alternative is specified. If the property is false, then
45 // completing on the name of the webjump in the minibuffer will
46 // not result in a space being appended.
48 if (typeof(handler) == "function") {
49 if (argument == null && alternative == null)
51 } else if (typeof(handler) == "string") {
52 if (post_data && alternative == null)
53 alternative = handler;
54 else if (handler.indexOf('%s') == -1)
56 else if (alternative == null)
57 alternative = url_path_trim(handler);
59 if (alternative && argument == null)
60 argument = 'optional';
62 function make_string_handler (template) {
63 var b = template.indexOf('%s');
64 return function (arg) {
66 // Just return the same string if it doesn't contain a %s
69 return template.substr(0,b) + encodeURIComponent(arg) + template.substring(a);
73 function make_post_handler (uri, post_data) {
74 return function (arg) {
77 post_data: make_post_data(post_data.map(function (pair) {
79 return [pair[0], arg];
87 if (typeof(handler) == "string") {
89 handler = make_post_handler(handler, post_data);
91 handler = make_string_handler(handler);
94 webjumps[key] = { key: key,
96 completer: arguments.$completer,
97 description: arguments.$description,
99 alternative: alternative};
102 function define_delicious_webjumps (username) {
103 define_webjump("delicious", "http://www.delicious.com/" + username + "/%s",
104 $alternative = "http://www.delicious.com/" + username);
105 define_webjump("adelicious", "javascript:location.href='http://www.delicious.com/save"+
106 "?v=2&url='+encodeURIComponent(location.href)+'&title='+"+
107 "encodeURIComponent(document.title);");
108 define_webjump("sdelicious", "http://www.delicious.com/search?p=%s&u="+username+
109 "&chk=&context=userposts&fr=del_icio_us&lc=1");
110 define_webjump("sadelicious", "http://www.delicious.com/search/all?search=%s");
113 add_delicious_webjumps = define_delicious_webjumps;
115 function define_lastfm_webjumps (username) {
116 if (! username) username = "";
117 define_webjump("lastfm", "http://www.last.fm/user/"+username);
118 define_webjump("lastfm-user", "http://www.last.fm/user/%s");
119 define_webjump("lastfm-music", "http://www.last.fm/search?m=all&q=%s");
120 define_webjump("lastfm-group", "http://www.last.fm/users/groups?s_bio=%s");
121 define_webjump("lastfm-tag", "http://www.last.fm/search?m=tag&q=%s");
122 define_webjump("lastfm-label", "http://www.last.fm/search?m=label&q=%s");
123 define_webjump("lastfm-event", "http://www.last.fm/events?by=artists&q=%s");
126 add_lastfm_webjumps = define_lastfm_webjumps;
128 function clear_webjumps () {
132 // Some built in web jumps
133 function define_default_webjumps () {
134 define_webjump("conkerorwiki",
135 "http://conkeror.org/?action=fullsearch&context=60&value=%s&fullsearch=Text");
136 define_webjump("lucky", "http://www.google.com/search?q=%s&btnI=I'm Feeling Lucky");
137 define_webjump("maps", "http://maps.google.com/?q=%s");
138 define_webjump("scholar", "http://scholar.google.com/scholar?q=%s");
139 define_webjump("slang", "http://www.urbandictionary.com/define.php?term=%s");
140 define_webjump("dictionary", "http://dictionary.reference.com/search?q=%s");
141 define_webjump("image", "http://images.google.com/images?q=%s");
142 define_webjump("clhs",
143 "http://www.xach.com/clhs?q=%s",
144 $alternative = "http://www.lispworks.com/documentation/HyperSpec/Front/index.htm");
145 define_webjump("cliki", "http://www.cliki.net/admin/search?words=%s");
146 define_webjump("ratpoisonwiki", "http://ratpoison.antidesktop.net/?search=%s");
147 define_webjump("stumpwmwiki", "http://stumpwm.antidesktop.net/wiki?search=%s");
148 define_webjump("savannah",
149 "http://savannah.gnu.org/search/?words=%s&type_of_search=soft&Search=Search&exact=1");
150 define_webjump("sourceforge", "http://sourceforge.net/search/?words=%s");
151 define_webjump("freshmeat", "http://freshmeat.net/search/?q=%s");
152 define_webjump("slashdot", "http://slashdot.org/search.pl?query=%s");
153 define_webjump("kuro5hin", "http://www.kuro5hin.org/?op=search&string=%s");
156 define_variable("webjump_partial_match", true,
157 "When entering a url, if the input is not a webjump, " +
158 "but would uniquely complete to a webjump, then accept " +
159 "that webjump only if this is true.");
161 function match_webjump (str) {
162 var sp = str.indexOf(webjump_separator);
169 key = str.substring(0, sp);
170 arg = str.substring(sp + 1);
171 if (/^\s*$/.test(arg))
175 // Look for an exact match
176 var match = webjumps[key];
178 // Look for a partial match
179 if (!match && webjump_partial_match) {
180 for (let [k,v] in Iterator(webjumps)) {
181 if (String(k).substring(0, key.length) == key) {
183 // key is not a unique prefix, as there are multiple partial matches
192 if (arg == null && match.argument == true)
193 throw interactive_error('Webjump '+key+' requires an argument.');
194 return [match, key, arg];
200 function get_webjump (value) {
201 var res = match_webjump(value);
204 let [match,key,arg] = res;
205 if (arg == null && match.alternative)
206 return match.alternative;
207 return match.handler(arg);
210 function get_url_or_webjump (input) {
211 var url = get_webjump(input);
218 define_default_webjumps();
220 function webjump_completer () {
221 let base_completer = prefix_completer(
222 $completions = [ v for ([k,v] in Iterator(webjumps)) ],
223 $get_string = function (x) { return x.key + (x.argument ? webjump_separator : ""); },
224 $get_description = function (x) { return x.description || ""; });
225 return function (input, pos, conservative) {
226 let str = input.substring(0,pos);
228 try { res = match_webjump(str); }
229 catch (e) { res = null; }
231 let [match, key, arg] = res;
232 if (arg != null) { // If there is no argument yet, we use the base completer
233 if (match.completer) {
234 let c = yield match.completer.call(null, arg, pos - key.length - 1, conservative);
235 yield co_return(nest_completions(c, match.key + webjump_separator));
237 yield co_return(null);
240 yield co_return(base_completer(input, pos, conservative));