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