]> git.lyx.org Git - lyx.git/blob - src/trans.C
Fix the keymap bug!
[lyx.git] / src / trans.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation "trans.h"
5 #endif
6
7 #include "LyXView.h"
8 #include "trans.h"
9 #include "support/filetools.h"
10 #include "tex-strings.h"
11 #include "lyxlex.h"
12 #include "debug.h"
13 #include "trans_mgr.h"
14
15 using std::endl;
16
17
18 // KmodInfo
19 KmodInfo::KmodInfo()
20 {
21         exception_list = 0;
22 }
23
24
25 // Default Trans
26 bool DefaultTrans::init_ = false;
27
28
29 DefaultTrans::DefaultTrans()
30 {
31         if (init_ == false) {
32                 // Do initialization
33                 init_ = true;
34         }
35 }
36
37
38 string const DefaultTrans::process(char c, TransManager & k)
39 {
40         char dummy[2] = "?";
41         dummy[0] = c;
42     
43         return k.normalkey(c, dummy);
44 }
45
46
47 // Trans class
48
49 Trans::Trans()
50 {
51         for (int i = 0; i < TEX_MAX_ACCENT + 1; ++i)
52                 kmod_list_[i] = 0;
53 }
54
55
56 Trans::~Trans()
57 {
58         FreeKeymap();
59 }
60
61
62 void Trans::InsertException(Trans::keyexc & exclist, char c,
63                             string const & data, bool flag, tex_accent accent)
64 {
65         keyexc p = new Keyexc; 
66         p->next = exclist;
67         p->c = c;
68
69         p->data = data;
70         p->combined = flag;
71         p->accent = accent;
72
73         exclist = p;
74 }
75
76
77 void Trans::FreeException(Trans::keyexc & exclist)
78 {
79         Trans::keyexc p = exclist;
80         while (p) {
81                 p = exclist->next;
82                 delete exclist;
83                 exclist = p;
84         }
85 }
86
87
88 void Trans::FreeKeymap()
89 {
90         for (int i = 0; i < 256; ++i)
91                 if (!keymap_[i].empty()) {
92                         keymap_[i].erase();
93                 }
94         for (int i = 0; i < TEX_MAX_ACCENT + 1; ++i)
95                 if (kmod_list_[i]) {
96                         FreeException(kmod_list_[i]->exception_list);
97                         delete kmod_list_[i];
98                         kmod_list_[i] = 0;
99                 }
100 }
101
102
103 bool Trans::IsDefined() const
104 {
105         return !name_.empty();
106 }
107
108
109 string const & Trans::GetName() const
110 {
111         return name_;
112 }
113
114
115 enum kmaptags_ {
116         KCOMB = 1,
117         KMOD,
118         KMAP,
119         KXMOD,
120         K_LAST
121 };
122
123
124 struct keyword_item kmapTags[K_LAST - 1] = {
125         {"\\kcomb", KCOMB },
126         { "\\kmap", KMAP },
127         { "\\kmod", KMOD },
128         { "\\kxmod", KXMOD }
129 };
130
131
132 tex_accent getkeymod(string const &);
133
134
135 void Trans::AddDeadkey(tex_accent accent, string const & keys,
136                        string const & allowed)
137 {
138         if (kmod_list_[accent]) {
139                 FreeException(kmod_list_[accent]->exception_list);
140                 
141                 delete kmod_list_[accent];
142         }
143         
144         kmod_list_[accent] = new kmod_list_decl;
145         kmod_list_[accent]->data = keys;
146         kmod_list_[accent]->accent = accent;
147         if (allowed == "native") { 
148                 kmod_list_[accent]->allowed= lyx_accent_table[accent].native;
149         } else { 
150                 kmod_list_[accent]->allowed = allowed;
151         }
152         
153         for (string::size_type i = 0; i < keys.length(); ++i) {
154                 string & temp =
155                         keymap_[static_cast<unsigned char>(keys[i])];
156                 if (!temp.empty())
157                         temp.erase();
158
159                 // But the question remains: "Should we be allowed
160                 // to change bindings, without unbinding first?"
161                 // Lgb
162                 temp += char(0);
163                 temp += char(accent);
164         }
165         kmod_list_[accent]->exception_list = 0;
166 }
167
168
169 int Trans::Load(LyXLex & lex)
170 {
171         bool error = false;
172
173         while (lex.IsOK() && !error) {
174                 switch (lex.lex()) {
175                 case KMOD:
176                 {
177                         if (lyxerr.debugging(Debug::KBMAP))
178                                 lyxerr << "KMOD:\t" << lex.text() << endl;
179                         if (lex.next(true)) {
180                                 if (lyxerr.debugging(Debug::KBMAP))
181                                         lyxerr << "key\t`" << lex.text()
182                                                << "'" << endl;
183                         } else
184                                 return -1;
185                         
186                         string keys = lex.GetString();
187
188                         if (lex.next(true)) {
189                                 if (lyxerr.debugging(Debug::KBMAP))
190                                         lyxerr << "accent\t`" << lex.text()
191                                                << "'" << endl;
192                         } else
193                                 return -1;
194
195                         tex_accent accent = getkeymod(lex.GetString());
196
197                         if (accent == TEX_NOACCENT)
198                                 return -1;
199
200                         if (lex.next(true)) {
201                                 if (lyxerr.debugging(Debug::KBMAP))
202                                         lyxerr << "allowed\t`" << lex.text()
203                                                << "'" << endl;
204                         } else
205                                 return -1;
206
207                         string allowed = lex.GetString();
208
209                         AddDeadkey(accent, keys, allowed);
210                         break;
211                 }       
212                 case KCOMB: {
213                         string str;
214
215                         lyxerr[Debug::KBMAP] << "KCOMB:" << endl;
216                         if (lex.next(true)) {
217                                 str= lex.text();
218                                 lyxerr[Debug::KBMAP] << str << endl;
219                         } else
220                                 return -1;
221                         
222                         tex_accent accent_1 = getkeymod(str);
223                         if (accent_1 == TEX_NOACCENT) return -1;
224
225                         if (lex.next(true)) {
226                                 str = lex.text();
227                                 lyxerr[Debug::KBMAP] << str << endl;
228                         } else
229                                 return -1;
230
231                         tex_accent accent_2= getkeymod(str);
232                         if (accent_2 == TEX_NOACCENT) return -1;
233
234                         if (kmod_list_[accent_1] == 0
235                             || kmod_list_[accent_2] == 0)
236                                 return -1;
237
238                         // Find what key accent_2 is on - should
239                         // check about accent_1 also
240                         int key = 0;
241                         for (; key < 256; ++key) {
242                                 if (!keymap_[key].empty()
243                                     && keymap_[key][0] == 0
244                                     && keymap_[key][1] == accent_2)
245                                         break;
246                         }
247                         string allowed;
248
249                         if (lex.next()) {
250                                 allowed = lex.GetString();
251                                 lyxerr[Debug::KBMAP] << "allowed: "
252                                                      << allowed << endl;
253                         } else
254                                 return -1;
255
256                         InsertException(kmod_list_[accent_1]->exception_list,
257                                         static_cast<char>(key), allowed,
258                                         true, accent_2);
259                 }
260                 break;
261                 case KMAP: {
262                         unsigned char key_from;
263
264                         if (lyxerr.debugging(Debug::KBMAP))
265                                 lyxerr << "KMAP:\t" << lex.text() << endl;
266                         if (lex.next(true)) {
267                                 key_from = lex.text()[0];
268                                 if (lyxerr.debugging(Debug::KBMAP))
269                                         lyxerr << "\t`" << lex.text() << "'"
270                                                << endl;
271                         } else
272                                 return -1;
273
274                         if (lex.next(true)) {
275                                 string string_to = lex.text();
276                                 //char * string_to =
277                                 //      strcpy(new char[strlen(t)+1], t);
278                                 keymap_[key_from] = string_to;
279                                 if (lyxerr.debugging(Debug::KBMAP))
280                                         lyxerr << "\t`" << string_to << "'"
281                                                << endl;
282                         } else
283                                 return -1;
284
285                         break;
286                 }
287                 case KXMOD: {
288                         tex_accent accent;
289                         char key;
290                         string str;
291
292                         if (lyxerr.debugging(Debug::KBMAP))
293                                 lyxerr << "KXMOD:\t" << lex.text() << endl;
294                         if (lex.next(true)) {
295                                 if (lyxerr.debugging(Debug::KBMAP))
296                                         lyxerr << "\t`" << lex.text() << "'"
297                                                << endl;
298                                 accent = getkeymod(lex.GetString());
299                         } else
300                                 return -1;
301
302                         if (lex.next(true)) {
303                                 if (lyxerr.debugging(Debug::KBMAP))
304                                         lyxerr << "\t`" << lex.text() << "'"
305                                                << endl;
306                                 key = lex.text()[0];
307                         } else
308                                 return -1;
309
310                         if (lex.next(true)) {
311                                 if (lyxerr.debugging(Debug::KBMAP))
312                                         lyxerr << "\t`" << lex.text() << "'"
313                                                << endl;
314                                 str = lex.text();
315                         } else
316                                 return -1;
317
318                         InsertException(kmod_list_[accent]->exception_list,
319                                         key, str);
320                         break;
321                 }
322                 case LyXLex::LEX_FEOF:
323                         lyxerr[Debug::PARSER] << "End of parsing" << endl;
324                         break;
325                 default:
326                         lex.printError("ParseKeymapFile: "
327                                        "Unknown tag: `$$Token'");
328                         return -1;
329                 }
330         }
331         return 0;
332 }
333
334
335 bool Trans::isAccentDefined(tex_accent accent, KmodInfo & i) const
336 {
337         if (kmod_list_[accent] != 0) {
338                 i = *kmod_list_[accent];
339                 return true;
340         }
341         return false;
342 }
343
344
345 string const Trans::process(char c, TransManager & k)
346 {
347         string dummy("?");
348         string dt = dummy;
349         string const t = Match(static_cast<unsigned char>(c));
350
351         if (t.empty() && c != 0) {
352                 dt[0] = c;
353                 return k.normalkey(c, dt);
354         } else if (!t.empty() && t[0] != char(0)) {
355                 dt = t;
356                 return k.normalkey(c, dt);
357         } else {
358                 return k.deadkey(c,
359                                  *kmod_list_[static_cast<tex_accent>(t[1])]);
360         }
361 }
362
363
364 int Trans::Load(string const & language)
365 {
366         string const filename = LibFileSearch("kbd", language, "kmap");
367         if (filename.empty())
368                 return -1;
369
370         FreeKeymap();
371         LyXLex lex(kmapTags, K_LAST-1);
372         lex.setFile(filename);
373         
374         int const res = Load(lex);
375
376         if (res == 0) {
377                 name_ = language;
378         } else
379                 name_.erase();
380
381         return res;
382 }
383
384
385 tex_accent getkeymod(string const & p)
386         /* return modifier - decoded from p and update p */
387 {
388         for (int i = 1; i <= TEX_MAX_ACCENT; ++i) {
389                 if (lyxerr.debugging(Debug::KBMAP))
390                         lyxerr << "p = " << p
391                                << ", lyx_accent_table[" << i
392                                << "].name = `" << lyx_accent_table[i].name
393                                << "'" << endl;
394                 
395                 if (lyx_accent_table[i].name
396                      && contains(p, lyx_accent_table[i].name)) {
397                         lyxerr[Debug::KBMAP] << "Found it!" << endl;
398                         return static_cast<tex_accent>(i);
399                 }
400         }
401         return TEX_NOACCENT;
402 }