ketmar string patch

This commit is contained in:
Adam D. Ruppe 2017-04-19 21:47:27 -04:00
parent 5f7dcb8e44
commit b9614e483d
1 changed files with 91 additions and 89 deletions

View File

@ -3653,14 +3653,25 @@ struct KeyEvent {
if (!this.key) return null; if (!this.key) return null;
// put modifiers // put modifiers
if (this.modifierState&ModifierState.ctrl) put("C-"); if (this.modifierState&ModifierState.ctrl) put("Ctrl+");
if (this.modifierState&ModifierState.alt) put("M-"); if (this.modifierState&ModifierState.alt) put("Alt+");
if (this.modifierState&ModifierState.windows) put("H-"); if (this.modifierState&ModifierState.windows) put("Win+");
if (this.modifierState&ModifierState.shift) put("S-"); if (this.modifierState&ModifierState.shift) put("Shift+");
foreach (string kn; __traits(allMembers, Key)) { foreach (string kn; __traits(allMembers, Key)) {
if (this.key == __traits(getMember, Key, kn)) { if (this.key == __traits(getMember, Key, kn)) {
put(kn); // HACK!
static if (kn == "N0") put("0");
else static if (kn == "N1") put("1");
else static if (kn == "N2") put("2");
else static if (kn == "N3") put("3");
else static if (kn == "N4") put("4");
else static if (kn == "N5") put("5");
else static if (kn == "N6") put("6");
else static if (kn == "N7") put("7");
else static if (kn == "N8") put("8");
else static if (kn == "N9") put("9");
else put(kn);
return dest[0..dpos]; return dest[0..dpos];
} }
} }
@ -3671,101 +3682,92 @@ struct KeyEvent {
string toStr() () { return cast(string)toStrBuf!true(null); } // it is safe to cast here string toStr() () { return cast(string)toStrBuf!true(null); } // it is safe to cast here
// sorry for pasta, but i don't want to create new struct in `opEquals()` /** Parse string into key name with modifiers. It accepts things like:
*
* C-H-1 -- emacs style (ctrl, and windows, and 1)
*
* Ctrl+Win+1 -- windows style
*
* Ctrl-Win-1 -- '-' is a valid delimiter too
*
* Ctrl Win 1 -- and space
*
* and even "Win + 1 + Ctrl".
*/
static KeyEvent parse (const(char)[] name) nothrow @trusted @nogc { static KeyEvent parse (const(char)[] name) nothrow @trusted @nogc {
KeyEvent res; auto nanchor = name; // keep it anchored, 'cause `name` may have NO_INTERIOR set
while (name.length && name.ptr[0] <= ' ') name = name[1..$];
// remove trailing spaces
while (name.length && name[$-1] <= ' ') name = name[0..$-1]; while (name.length && name[$-1] <= ' ') name = name[0..$-1];
uint mods = 0;
while (name.length > 1 && name.ptr[1] == '-') { // tokens delimited by blank, '+', or '-'
switch (name.ptr[0]) { // null on eol
case 'C': case 'c': mods |= ModifierState.ctrl; break; const(char)[] getToken () nothrow @trusted @nogc {
case 'M': case 'm': mods |= ModifierState.alt; break; // remove leading spaces and delimiters
case 'H': case 'h': mods |= ModifierState.windows; break; while (name.length && (name[0] <= ' ' || name[0] == '+' || name[0] == '-')) name = name[1..$];
case 'S': case 's': mods |= ModifierState.shift; break; if (name.length == 0) return null; // oops, no more tokens
default: return res; // alas // get token
} size_t epos = 0;
name = name[2..$]; while (epos < name.length && name[epos] > ' ' && name[epos] != '+' && name[epos] != '-') ++epos;
assert(epos > 0 && epos <= name.length);
auto res = name[0..epos];
name = name[epos..$];
return res;
} }
if (name.length == 0) return res;
res.modifierState = mods; static bool strEquCI (const(char)[] s0, const(char)[] s1) pure nothrow @trusted @nogc {
//HACK if (s0.length != s1.length) return false;
if (name.length == 1 && name.ptr[0] >= '0' && name.ptr[0] <= '9') { foreach (immutable ci, char c0; s0) {
final switch (name.ptr[0]) { if (c0 >= 'A' && c0 <= 'Z') c0 += 32; // poor man's tolower
case '0': name = "N0"; break; char c1 = s1[ci];
case '1': name = "N1"; break; if (c1 >= 'A' && c1 <= 'Z') c1 += 32; // poor man's tolower
case '2': name = "N2"; break; if (c0 != c1) return false;
case '3': name = "N3"; break;
case '4': name = "N4"; break;
case '5': name = "N5"; break;
case '6': name = "N6"; break;
case '7': name = "N7"; break;
case '8': name = "N8"; break;
case '9': name = "N9"; break;
} }
return true;
} }
foreach (string kn; __traits(allMembers, Key)) {
if (kn.length == name.length) { KeyEvent res;
// case-insensitive comapre res.key = cast(Key)0; // just in case
bool ok = true; tokenloop: for (;;) {
foreach (immutable ci, char c0; kn) { auto tk = getToken();
if (c0 >= 'A' && c0 <= 'Z') c0 += 32; // poor man's tolower if (tk is null) break;
char c1 = name.ptr[ci]; if (strEquCI(tk, "C") || strEquCI(tk, "Ctrl")) { res.modifierState |= ModifierState.ctrl; continue tokenloop; }
if (c1 >= 'A' && c1 <= 'Z') c1 += 32; // poor man's tolower if (strEquCI(tk, "M") || strEquCI(tk, "Alt")) { res.modifierState |= ModifierState.alt; continue tokenloop; }
if (c0 != c1) { ok = false; break; } if (strEquCI(tk, "H") || strEquCI(tk, "Win") || strEquCI(tk, "Windows")) { res.modifierState |= ModifierState.windows; continue tokenloop; }
if (strEquCI(tk, "S") || strEquCI(tk, "Shift")) { res.modifierState |= ModifierState.shift; continue tokenloop; }
// try key name
if (res.key == 0) {
// little hack
if (tk.length == 1 && tk[0] >= '0' && tk[0] <= '9') {
final switch (tk[0]) {
case '0': tk = "N0"; break;
case '1': tk = "N1"; break;
case '2': tk = "N2"; break;
case '3': tk = "N3"; break;
case '4': tk = "N4"; break;
case '5': tk = "N5"; break;
case '6': tk = "N6"; break;
case '7': tk = "N7"; break;
case '8': tk = "N8"; break;
case '9': tk = "N9"; break;
}
}
foreach (string kn; __traits(allMembers, Key)) {
if (strEquCI(tk, kn)) { res.key = __traits(getMember, Key, kn); continue tokenloop; }
} }
if (ok) { res.key = __traits(getMember, Key, kn); return res; }
} }
// unknown or duplicate key name, get out of here
break;
} }
return res; // at least modifier state, lol return res; // something
} }
bool opEquals() (const(char)[] name) const nothrow @trusted @nogc { bool opEquals() (const(char)[] name) const nothrow @trusted @nogc {
while (name.length && name.ptr[0] <= ' ') name = name[1..$]; auto ke = KeyEvent.parse(name);
while (name.length && name[$-1] <= ' ') name = name[0..$-1]; if (this.key != ke.key) return false;
if (!this.key) return (name.length == 0); // check modifiers
uint mods = 0; ke.modifierState &= (ModifierState.ctrl|ModifierState.alt|ModifierState.shift|ModifierState.windows);
while (name.length > 1 && name.ptr[1] == '-') { return ((this.modifierState&(ModifierState.ctrl|ModifierState.alt|ModifierState.shift|ModifierState.windows)) == ke.modifierState);
switch (name.ptr[0]) {
case 'C': case 'c': mods |= ModifierState.ctrl; break;
case 'M': case 'm': mods |= ModifierState.alt; break;
case 'H': case 'h': mods |= ModifierState.windows; break;
case 'S': case 's': mods |= ModifierState.shift; break;
default: return false; // alas
}
name = name[2..$];
}
if (name.length == 0) return false;
if ((this.modifierState&(ModifierState.ctrl|ModifierState.alt|ModifierState.shift|ModifierState.windows)) != mods) return false;
//HACK
if (name.length == 1 && name.ptr[0] >= '0' && name.ptr[0] <= '9') {
final switch (name.ptr[0]) {
case '0': name = "N0"; break;
case '1': name = "N1"; break;
case '2': name = "N2"; break;
case '3': name = "N3"; break;
case '4': name = "N4"; break;
case '5': name = "N5"; break;
case '6': name = "N6"; break;
case '7': name = "N7"; break;
case '8': name = "N8"; break;
case '9': name = "N9"; break;
}
}
foreach (string kn; __traits(allMembers, Key)) {
if (kn.length == name.length) {
// case-insensitive comapre
bool ok = true;
foreach (immutable ci, char c0; kn) {
if (c0 >= 'A' && c0 <= 'Z') c0 += 32; // poor man's tolower
char c1 = name.ptr[ci];
if (c1 >= 'A' && c1 <= 'Z') c1 += 32; // poor man's tolower
if (c0 != c1) { ok = false; break; }
}
if (ok && this.key == __traits(getMember, Key, kn)) return true;
}
}
return false;
} }
} }