Allow to unbind without specifying the lfun

When unbinding a shortcut, it may happen that the exact definition of
the request is not known. A typical example it Tab, which is bound to
a complex command sequence.

In this case it is convenient to use the syntax
\unbind "Tab" "*"

To make this word, the special "*" value is translated to the
FuncRequest::unknown lfun and this value is considered specially in
several places.
This commit is contained in:
Jean-Marc Lasgouttes 2022-07-27 11:52:50 +02:00
parent 11d5e31c65
commit 1dedd39864
2 changed files with 32 additions and 28 deletions

View File

@ -160,29 +160,30 @@ void KeyMap::unbind(KeySequence * seq, FuncRequest const & func, unsigned int r)
KeyModifier const mod2 = seq->modifiers[r].second; KeyModifier const mod2 = seq->modifiers[r].second;
// check if key is already there // check if key is already there
vector <Table::iterator> removes;
Table::iterator end = table.end(); Table::iterator end = table.end();
Table::iterator remove = end;
for (Table::iterator it = table.begin(); it != end; ++it) { for (Table::iterator it = table.begin(); it != end; ++it) {
if (code == it->code if (code == it->code
&& mod1 == it->mod.first && mod1 == it->mod.first
&& mod2 == it->mod.second) { && mod2 == it->mod.second) {
// remove // remove
if (r + 1 == seq->length()) { if (r + 1 == seq->length()) {
if (it->func == func) { if (it->func == func || func == FuncRequest::unknown) {
remove = it; removes.push_back(it);
if (it->prefixes) if (it->prefixes)
it->prefixes.reset(); it->prefixes.reset();
} }
} else if (it->prefixes) { } else if (it->prefixes) {
it->prefixes->unbind(seq, func, r + 1); it->prefixes->unbind(seq, func, r + 1);
if (it->prefixes->empty()) if (it->prefixes->empty())
remove = it; removes.push_back(it);
return; return;
} }
} }
} }
if (remove != end)
table.erase(remove); for (unsigned i = removes.size(); i > 0; --i)
table.erase(removes[i-1]);
} }
@ -333,7 +334,7 @@ KeyMap::ReturnValues KeyMap::readWithoutConv(FileName const & bind_file, KeyMap
string cmd = lexrc.getString(); string cmd = lexrc.getString();
FuncRequest func = lyxaction.lookupFunc(cmd); FuncRequest func = lyxaction.lookupFunc(cmd);
if (func.action() == LFUN_UNKNOWN_ACTION) { if (func == FuncRequest::unknown) {
lexrc.printError("BN_BIND: Unknown LyX function `$$Token'"); lexrc.printError("BN_BIND: Unknown LyX function `$$Token'");
error = true; error = true;
break; break;
@ -357,14 +358,17 @@ KeyMap::ReturnValues KeyMap::readWithoutConv(FileName const & bind_file, KeyMap
break; break;
} }
string cmd = lexrc.getString(); string cmd = lexrc.getString();
FuncRequest func;
FuncRequest func = lyxaction.lookupFunc(cmd); if (cmd == "*")
if (func.action() == LFUN_UNKNOWN_ACTION) { func = FuncRequest::unknown;
lexrc.printError("BN_UNBIND: Unknown LyX" else {
" function `$$Token'"); func = lyxaction.lookupFunc(cmd);
if (func == FuncRequest::unknown) {
lexrc.printError("BN_UNBIND: Unknown LyX function `$$Token'");
error = true; error = true;
break; break;
} }
}
if (unbind_map) if (unbind_map)
unbind_map->bind(seq, func); unbind_map->bind(seq, func);
@ -409,17 +413,17 @@ void KeyMap::write(string const & bind_file, bool append, bool unbind) const
<< "Format " << LFUN_FORMAT << "\n\n"; << "Format " << LFUN_FORMAT << "\n\n";
string tag = unbind ? "\\unbind" : "\\bind"; string tag = unbind ? "\\unbind" : "\\bind";
BindingList const list = listBindings(false); for (auto const & bnd : listBindings(false)) {
BindingList::const_iterator it = list.begin(); FuncCode const action = bnd.request.action();
BindingList::const_iterator it_end = list.end(); string const arg = to_utf8(bnd.request.argument());
for (; it != it_end; ++it) {
FuncCode action = it->request.action();
string arg = to_utf8(it->request.argument());
string const cmd = lyxaction.getActionName(action) string cmd;
+ (arg.empty() ? string() : " " + arg) ; if (unbind && bnd.request == FuncRequest::unknown)
cmd = "*";
else
cmd = lyxaction.getActionName(action) + (arg.empty() ? string() : " " + arg);
os << tag << " \"" os << tag << " \""
<< to_utf8(it->sequence.print(KeySequence::BindFile)) << to_utf8(bnd.sequence.print(KeySequence::BindFile))
<< "\" " << Lexer::quoteString(cmd) << "\" " << Lexer::quoteString(cmd)
<< "\n"; << "\n";
} }

View File

@ -3087,10 +3087,10 @@ QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
QTreeWidgetItem * newItem = nullptr; QTreeWidgetItem * newItem = nullptr;
// for unbind items, try to find an existing item in the system bind list // for unbind items, try to find an existing item in the system bind list
if (tag == KeyMap::UserUnbind) { if (tag == KeyMap::UserUnbind) {
QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(lfun_name, QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0); Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
for (auto const & item : items) { for (auto const & item : items) {
if (item->text(1) == shortcut) { if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
newItem = item; newItem = item;
break; break;
} }
@ -3125,10 +3125,10 @@ QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
// this should not happen // this should not happen
newItem = new QTreeWidgetItem(shortcutsTW); newItem = new QTreeWidgetItem(shortcutsTW);
} }
}
newItem->setText(0, lfun_name); newItem->setText(0, lfun_name);
newItem->setText(1, shortcut); newItem->setText(1, shortcut);
}
// record BindFile representation to recover KeySequence when needed. // record BindFile representation to recover KeySequence when needed.
newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile))); newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
setItemType(newItem, tag); setItemType(newItem, tag);