1 
2 /******************************************************************************
3 * MODULE     : tm_config.cpp
4 * DESCRIPTION: Configuration routines for TeXmacs server
5 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 
12 #include "tm_config.hpp"
13 #include "analyze.hpp"
14 
15 /******************************************************************************
16 * Constructor and destructor
17 ******************************************************************************/
18 
tm_config_rep()19 tm_config_rep::tm_config_rep ():
20   var_suffix (" tab"), unvar_suffix (" S-tab") {}
21 
~tm_config_rep()22 tm_config_rep::~tm_config_rep () {}
23 
24 /******************************************************************************
25 * Setup TeXmacs fonts
26 ******************************************************************************/
27 
28 void
set_font_rules(scheme_tree rules)29 tm_config_rep::set_font_rules (scheme_tree rules) {
30   int i, n= arity (rules);
31   for (i=0; i<n; i++)
32     if (arity (rules [i]) == 2) {
33       tree l= (tree) rules[i][0];
34       tree r= (tree) rules[i][1];
35       font_rule (l, r);
36     }
37 }
38 
39 /******************************************************************************
40 * Latex and user commands
41 ******************************************************************************/
42 
43 bool
kbd_get_command(string which,string & help,command & cmd)44 tm_config_rep::kbd_get_command (string which, string& help, command& cmd) {
45   object im= call ("kbd-get-command", which);
46   if (im == object (false)) return false;
47   help= as_string (car (im));
48   cmd = as_command (cdr (im));
49   return true;
50 }
51 
52 /******************************************************************************
53 * Wildcards for keyboard bindings
54 ******************************************************************************/
55 
56 static string
apply_wildcards(string s,hashmap<string,tree> w)57 apply_wildcards (string s, hashmap<string,tree> w) {
58   int len, start, end, n= N(s);
59   for (len=n; len>0; len--) {
60     for (start=0; start <= (n-len); start++) {
61       end= start+ len;
62       if ((start>0) && (s[start-1] != ' ') && (s[start-1] != '-')) continue;
63       if ((end<n) && (s[end-1] != ' ') && (s[end-1] != '-')) continue;
64       string ss= s (start, end);
65       if (s[end-1] == ' ') ss= s (start, end-1);
66 
67       // cout << "  " << ss << " => " << w[ss] << LF;
68       if (w->contains (ss)) {
69 	tree t= w[ss];
70 	string rr= t[0]->label;
71 	bool lflag= (t[1]->label != "") || (start == 0);
72 	bool rflag= (t[2]->label != "") || (end == n);
73 	if (lflag && rflag) {
74 	  if ((end<n) && (rr != "") && (rr[N(rr)-1] != '-')) rr= rr * " ";
75 	  string r= s (0, start) * rr * s (end, n);
76 	  return apply_wildcards (r, w);
77 	}
78       }
79     }
80   }
81   return s;
82 }
83 
84 void
insert_kbd_wildcard(string key,string im,bool post,bool l,bool r)85 tm_config_rep::insert_kbd_wildcard (
86   string key, string im, bool post, bool l, bool r)
87 {
88   //cout << "Wildcard " << key << " -> " << im << "\n";
89   tree t= tuple (im,
90 		 l? string ("*"): string (""),
91 		 r? string ("*"): string (""));
92   if (post) post_kbd_wildcards (key)= t;
93   else pre_kbd_wildcards (key)= t;
94 }
95 
96 /******************************************************************************
97 * Variants
98 ******************************************************************************/
99 
100 void
set_variant_keys(string var,string unvar)101 tm_config_rep::set_variant_keys (string var, string unvar) {
102   var_suffix= " " * var;
103   unvar_suffix= " " * unvar;
104 }
105 
106 #define rewrite_find_key_binding(s) \
107   find_key_binding (apply_wildcards (s, post_kbd_wildcards))
108 
109 void
variant_simplification(string & which)110 tm_config_rep::variant_simplification (string& which) {
111   if (ends (which, var_suffix)) {
112     object obj= rewrite_find_key_binding (which);
113     // cout << which << " => " << obj << LF;
114     if (obj == object (false))
115       while (ends (which, var_suffix))
116 	which= which (0, N(which) - N(var_suffix));
117   }
118   if (ends (which, unvar_suffix)) {
119     if (ends (which, var_suffix * unvar_suffix))
120       which= which (0, N(which) - N(var_suffix) - N(unvar_suffix));
121     else {
122       which= which (0, N(which) - N(unvar_suffix));
123       while (true) {
124 	if (rewrite_find_key_binding (which * var_suffix) == object (false))
125 	  break;
126 	which= which * var_suffix;
127       }
128     }
129   }
130 }
131 
132 /******************************************************************************
133 * Server keyboard mappings and shorthands
134 ******************************************************************************/
135 
136 object
find_key_binding(string key)137 tm_config_rep::find_key_binding (string key) {
138   return call ("kbd-find-key-binding", key);
139 }
140 
141 string
kbd_pre_rewrite(string s)142 tm_config_rep::kbd_pre_rewrite (string s) {
143   return apply_wildcards (s, pre_kbd_wildcards);
144 }
145 
146 string
kbd_post_rewrite(string s,bool var_flag)147 tm_config_rep::kbd_post_rewrite (string s, bool var_flag) {
148   if (var_flag) variant_simplification (s);
149   return apply_wildcards (s, post_kbd_wildcards);
150 }
151 
152 void
get_keycomb(string & which,int & status,command & cmd,string & shorth,string & help)153 tm_config_rep::get_keycomb (
154   string& which, int& status, command& cmd, string& shorth, string& help)
155 {
156   string orig= which;
157   if (DEBUG_KEYBOARD) debug_keyboard << which;
158   variant_simplification (which);
159   if (DEBUG_KEYBOARD) debug_keyboard << " -> " << which;
160   string rew= apply_wildcards (which, post_kbd_wildcards);
161   bool no_var= false;
162   if (rew * var_suffix == orig) {
163     no_var= true;
164     rew= var_suffix (1, N(var_suffix));
165   }
166   if (rew * unvar_suffix == orig) {
167     no_var= true;
168     rew= unvar_suffix (1, N(unvar_suffix));
169   }
170   if (DEBUG_KEYBOARD) debug_keyboard << " -> " << rew << LF;
171   object obj= find_key_binding (rew);
172   //cout << rew << " => " << obj << LF;
173   //if (obj == object (false) || (orig != which && !is_string (car (obj)))) {
174   if (obj == object (false)) {
175     status= 0;
176     cmd   = command ();
177     shorth= copy (rew);
178     help  = "";
179   }
180   else if (!is_string (car (obj))) {
181     status= 1;
182     cmd   = as_command (car (obj));
183     shorth= copy (rew);
184     help  = as_string (cadr (obj));
185   }
186   else {
187     status= 2;
188     cmd   = command ();
189     shorth= as_string (car (obj));
190     help  = as_string (cadr (obj));
191   }
192   if (no_var) status += 3;
193 }
194 
195 /******************************************************************************
196 * System dependent rendering of keyboard shortcuts
197 ******************************************************************************/
198 
199 static tree
localize(string s,bool mod_flag=false)200 localize (string s, bool mod_flag= false) {
201   if (mod_flag) return tree (CONCAT, localize (s), "+");
202   else return compound ("localize", s);
203 }
204 
205 tree
mathop(string s)206 mathop (string s) {
207   return compound ("math", compound ("op", s));
208 }
209 
210 static void
system_kbd_initialize(hashmap<string,tree> & h)211 system_kbd_initialize (hashmap<string,tree>& h) {
212   if (N(h) != 0);
213   else if (use_macos_fonts ()) {
214     h ("S-")= "<#21E7>";
215     h ("C-")= "<#2303>";
216     h ("A-")= "<#2325>";
217     h ("M-")= "<#2318>";
218     h ("H-")= localize ("Hyper");
219     h ("windows")= localize ("Windows");
220     h ("capslock")= "<#21EA>";
221     h ("return")= "<#21A9>";
222     h ("delete")= "<#2326>";
223     h ("backspace")= "<#232B>";
224     h ("clear")= "<#2327>";
225     h ("escape")= "<#238B>";
226     h ("space")= "Space";
227     h ("var")= "<#21E5>";
228     h ("tab")= "<#21E5>";
229     h ("left")= "<#2190>";
230     h ("right")= "<#2192>";
231     h ("up")= "<#2191>";
232     h ("down")= "<#2193>";
233     h ("home")= "<#2196>";
234     h ("end")= "<#2198>";
235     h ("pageup")= "<#21DE>";
236     h ("pagedown")= "<#21DF>";
237     h ("<less>")= "<#3C>";
238     h ("<gtr>")= "<#3E>";
239   }
240   else if (gui_is_qt ()) {
241     h ("S-")= localize ("Shift", true);
242     h ("C-")= localize ("Ctrl", true);
243     h ("A-")= localize ("Alt", true);
244     h ("M-")= localize ("Meta", true);
245     h ("H-")= localize ("Hyper", true);
246     h ("windows")= localize ("Windows");
247     h ("capslock")= localize ("Capslock");
248     h ("return")= localize ("Return");
249     h ("delete")= localize ("Delete");
250     h ("backspace")= localize ("Backspace");
251     h ("escape")= localize ("Escape");
252     h ("space")= localize ("Space");
253     h ("var")= localize ("Tab");
254     h ("tab")= localize ("Tab");
255     h ("left")= mathop ("<leftarrow>");
256     h ("right")= mathop ("<rightarrow>");
257     h ("up")= mathop ("<uparrow>");
258     h ("down")= mathop ("<downarrow>");
259     h ("home")= localize ("Home");
260     h ("end")= localize ("End");
261     h ("pageup")= localize ("PageUp");
262     h ("pagedown")= localize ("PageDown");
263   }
264   else {
265     h ("S-")= "S-";
266     h ("C-")= "C-";
267     h ("A-")= "A-";
268     h ("M-")= "M-";
269     h ("H-")= "H-";
270     h ("windows")= localize ("windows");
271     h ("capslock")= localize ("capslock");
272     h ("return")= localize ("return");
273     h ("delete")= localize ("delete");
274     h ("backspace")= localize ("backspace");
275     h ("escape")= localize ("escape");
276     h ("space")= localize ("space");
277     h ("var")= localize ("tab");
278     h ("tab")= localize ("tab");
279     h ("left")= mathop ("<leftarrow>");
280     h ("right")= mathop ("<rightarrow>");
281     h ("up")= mathop ("<uparrow>");
282     h ("down")= mathop ("<downarrow>");
283     h ("home")= localize ("home");
284     h ("end")= localize ("end");
285     h ("pageup")= localize ("pageup");
286     h ("pagedown")= localize ("pagedown");
287   }
288 }
289 
290 static tree
kbd_render(tree t)291 kbd_render (tree t) {
292   if (use_macos_fonts ())
293     t= tree (WITH, "font", "apple-lucida", t);
294   return compound ("render-key", t);
295 }
296 
297 static string
kbd_system_prevails(string s)298 kbd_system_prevails (string s) {
299   string laf= get_preference ("look and feel");
300   bool   mac= os_macos () && (laf == "default" || laf == "macos");
301   if (mac && starts (s, "A-")) {
302     string ss= s (2, N(s));
303     string r = "escape " * ss;
304     if (starts (ss, "S-")) ss= ss (2, N(ss));
305     if (N(ss) == 1) return r;
306     else return s;
307   }
308   else return s;
309 }
310 
311 tree
kbd_system_rewrite(string s)312 tm_config_rep::kbd_system_rewrite (string s) {
313   system_kbd_initialize (system_kbd_decode);
314   int start= 0, i;
315   for (i=0; i <= N(s); i++)
316     if (i == N(s) || s[i] == ' ') {
317       string ss= s (start, i);
318       string rr= kbd_system_prevails (ss);
319       if (rr != ss)
320 	return kbd_system_rewrite (s (0, start) * rr * s (i, N(s)));
321       start= i+1;
322     }
323 
324   tree k (CONCAT);
325   tree r (CONCAT);
326   start= i= 0;
327   while (true)
328     if (i == N(s) || s[i] == '-' || s[i] == ' ') {
329       if (i < N(s) && s[i] == '-') i++;
330       string ss= s (start, i);
331       if (system_kbd_decode->contains (ss)) r << system_kbd_decode[ss];
332       else if (N(ss) == 1 && (use_macos_fonts () || gui_is_qt ())) {
333 	if (is_locase (ss[0])) r << upcase_all (ss);
334 	else if (is_upcase (ss[0])) r << system_kbd_decode ("S-") << ss;
335 	else r << ss;
336       }
337       else r << ss;
338       if (i == N(s) || s[i] == ' ') {
339 	k << kbd_render (simplify_concat (r));
340 	r= tree (CONCAT);
341 	if (i == N(s)) break;
342 	i++;
343       }
344       start= i;
345     }
346     else i++;
347   return simplify_concat (k);
348 }
349