]> git.lyx.org Git - lyx.git/blob - src/kbmap.C
lyxfunc.h #included frontends/LyXKeySym.h for a typedef only. No more.
[lyx.git] / src / kbmap.C
1 /**
2  * \file kbmap.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author John Levon
9  * \author André Pönitz
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "kbmap.h"
17
18 #include "debug.h"
19 #include "kbsequence.h"
20 #include "LyXAction.h"
21 #include "lyxlex.h"
22
23 #include "frontends/LyXKeySym.h"
24
25 #include "support/filetools.h"
26
27 using std::endl;
28 using lyx::support::i18nLibFileSearch;
29
30 string const kb_keymap::printKeysym(LyXKeySymPtr key,
31                                     key_modifier::state mod)
32 {
33         string buf;
34
35         string const s = key->getSymbolName();
36
37         if (mod & key_modifier::shift)
38                 buf += "S-";
39         if (mod & key_modifier::ctrl)
40                 buf += "C-";
41         if (mod & key_modifier::alt)
42                 buf += "M-";
43
44         buf += s;
45         return buf;
46 }
47
48
49 string const kb_keymap::printKey(kb_key const & key) const
50 {
51         return printKeysym(key.code, key.mod.first);
52 }
53
54
55 string::size_type kb_keymap::bind(string const & seq, int action)
56 {
57         if (lyxerr.debugging(Debug::KBMAP)) {
58                 lyxerr << "BIND: Sequence `"
59                        << seq << "' Action `"
60                        << action << '\'' << endl;
61         }
62
63         kb_sequence k(0, 0);
64
65         string::size_type const res = k.parse(seq);
66         if (res == string::npos) {
67                 defkey(&k, action);
68         } else {
69                 lyxerr[Debug::KBMAP] << "Parse error at position " << res
70                                      << " in key sequence '" << seq << "'."
71                                      << endl;
72         }
73
74         return res;
75 }
76
77
78 namespace {
79
80 enum BindTags {
81         BN_BIND,
82         BN_BINDFILE
83 };
84
85 keyword_item bindTags[] = {
86         { "\\bind", BN_BIND },
87         { "\\bind_file", BN_BINDFILE }
88 };
89
90 }
91
92
93 bool kb_keymap::read(string const & bind_file) 
94 {
95         const int bindCount = sizeof(bindTags) / sizeof(keyword_item);
96
97         LyXLex lexrc(bindTags, bindCount);
98         if (lyxerr.debugging(Debug::PARSER))
99                 lexrc.printTable(lyxerr);
100
101         string const tmp = i18nLibFileSearch("bind", bind_file, "bind");
102         lexrc.setFile(tmp);
103         if (!lexrc.isOK()) {
104                 lyxerr << "kb_keymap::read: cannot open bind file:" 
105                        << tmp << endl;
106                 return false;
107         }
108
109         lyxerr[Debug::KBMAP] << "Reading bind file:" << tmp << endl;
110
111         bool error = false;
112         while (!error && lexrc.isOK()) {
113                 switch (lexrc.lex()) {
114                 case LyXLex::LEX_UNDEF:
115                         lexrc.printError("Unknown tag `$$Token'");
116                         error = true;
117                         continue;
118                 case LyXLex::LEX_FEOF:
119                         continue;
120                 case BN_BIND:
121                 {
122                         string seq, cmd;
123                         
124                         if (lexrc.next()) {
125                                 seq = lexrc.getString();
126                         } else {
127                                 lexrc.printError("BN_BIND: Missing key sequence");
128                                 error = true;
129                                 break;
130                         }
131                         
132                         if (lexrc.next(true)) {
133                                 cmd = lexrc.getString();
134                         } else {
135                                 lexrc.printError("BN_BIND: missing command");
136                                 error = true;
137                                 break;
138                         }
139                         
140                         int action = lyxaction.LookupFunc(cmd);
141                         if (!action == LFUN_UNKNOWN_ACTION) {
142                                 lexrc.printError("BN_BIND: Unknown LyX"
143                                                  " function `$$Token'");
144                                 error = true;
145                                 break;
146                         }
147                         
148                         bind(seq, kb_action(action));
149                         break;
150                 }
151                 case BN_BINDFILE:
152                         if (lexrc.next()) {
153                                 string const tmp(lexrc.getString());
154                                 error = !read(tmp);
155                         } else {
156                                 lexrc.printError("BN_BINDFILE: Missing file name");
157                                 error = true;
158                                 break;
159
160                         }
161                         break;
162                 }
163         }
164
165         if (error)
166                 lyxerr << "kb_keymap::read: error while reading bind file:" 
167                        << tmp << endl;
168         return !error;
169 }
170
171
172 int kb_keymap::lookup(LyXKeySymPtr key,
173                       key_modifier::state mod, kb_sequence * seq) const
174 {
175         if (table.empty()) {
176                 seq->curmap = seq->stdmap;
177                 seq->mark_deleted();
178                 return LFUN_UNKNOWN_ACTION;
179         }
180
181         Table::const_iterator end = table.end();
182         for (Table::const_iterator cit = table.begin(); cit != end; ++cit) {
183                 key_modifier::state mask(cit->mod.second);
184                 key_modifier::state check =
185                         static_cast<key_modifier::state>(mod & ~mask);
186
187                 if (*(cit->code) == *key && cit->mod.first == check) {
188                         // match found
189                         if (cit->table.get()) {
190                                 // this is a prefix key - set new map
191                                 seq->curmap = cit->table.get();
192                                 return LFUN_PREFIX;
193                         } else {
194                                 // final key - reset map
195                                 seq->curmap = seq->stdmap;
196                                 seq->mark_deleted();
197                                 return cit->action;
198                         }
199                 }
200         }
201
202         // error - key not found:
203         seq->curmap = seq->stdmap;
204         seq->mark_deleted();
205         return LFUN_UNKNOWN_ACTION;
206 }
207
208
209 string const kb_keymap::print() const
210 {
211         string buf;
212         Table::const_iterator end = table.end();
213         for (Table::const_iterator cit = table.begin(); cit != end; ++cit) {
214                 buf += printKey((*cit));
215                 buf += ' ';
216         }
217         return buf;
218 }
219
220
221 void kb_keymap::defkey(kb_sequence * seq, int action, unsigned int r)
222 {
223         LyXKeySymPtr code = seq->sequence[r];
224         if (!code->isOK())
225                 return;
226
227         key_modifier::state const mod1 = seq->modifiers[r].first;
228         key_modifier::state const mod2 = seq->modifiers[r].second;
229
230         // check if key is already there
231         Table::iterator end = table.end();
232         for (Table::iterator it = table.begin(); it != end; ++it) {
233                 if (*(code) == *(it->code)
234                     && mod1 == it->mod.first
235                     && mod2 == it->mod.second) {
236                         // overwrite binding
237                         if (r + 1 == seq->length()) {
238                                 lyxerr[Debug::KBMAP]
239                                         << "Warning: New binding for '"
240                                         << seq->print()
241                                         << "' is overriding old binding..."
242                                         << endl;
243                                 if (it->table.get()) {
244                                         it->table.reset();
245                                 }
246                                 it->action = action;
247                                 return;
248                         } else if (!it->table.get()) {
249                                 lyxerr << "Error: New binding for '" << seq->print()
250                                        << "' is overriding old binding..."
251                                                << endl;
252                                 return;
253                         } else {
254                                 it->table->defkey(seq, action, r + 1);
255                                 return;
256                         }
257                 }
258         }
259
260         Table::iterator newone = table.insert(table.end(), kb_key());
261         newone->code = code;
262         newone->mod = seq->modifiers[r];
263         if (r + 1 == seq->length()) {
264                 newone->action = action;
265                 newone->table.reset();
266                 return;
267         } else {
268                 newone->table.reset(new kb_keymap);
269                 newone->table->defkey(seq, action, r + 1);
270                 return;
271         }
272 }
273
274
275 string const kb_keymap::findbinding(int act, string const & prefix) const
276 {
277         string res;
278         if (table.empty()) return res;
279
280         Table::const_iterator end = table.end();
281         for (Table::const_iterator cit = table.begin();
282             cit != end; ++cit) {
283                 if (cit->table.get()) {
284                         res += cit->table->findbinding(act,
285                                                        prefix
286                                                        + printKey((*cit))
287                                                        + ' ');
288                 } else if (cit->action == act) {
289                         res += '[';
290                         res += prefix + printKey((*cit));
291                         res += "] ";
292                 }
293         }
294         return res;
295 }