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