annotate .cms/lib/codemirror/src/input/keymap.js @ 0:78edf6b517a0 draft

24.10
author Coffee CMS <info@coffee-cms.ru>
date Fri, 11 Oct 2024 22:40:23 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
1 import { flipCtrlCmd, mac, presto } from "../util/browser.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
2 import { map } from "../util/misc.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
3
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
4 import { keyNames } from "./keynames.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
5
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
6 export let keyMap = {}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
7
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
8 keyMap.basic = {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
9 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
10 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
11 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
12 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
13 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
14 "Esc": "singleSelection"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
15 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
16 // Note that the save and find-related commands aren't defined by
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
17 // default. User code or addons can define them. Unknown commands
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
18 // are simply ignored.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
19 keyMap.pcDefault = {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
20 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
21 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
22 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
23 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
24 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
25 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
26 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
27 "fallthrough": "basic"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
28 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
29 // Very basic readline/emacs-style bindings, which are standard on Mac.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
30 keyMap.emacsy = {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
31 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
32 "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
33 "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
34 "Ctrl-T": "transposeChars", "Ctrl-O": "openLine"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
35 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
36 keyMap.macDefault = {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
37 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
38 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
39 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
40 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
41 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
42 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
43 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
44 "fallthrough": ["basic", "emacsy"]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
45 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
46 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
47
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
48 // KEYMAP DISPATCH
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
49
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
50 function normalizeKeyName(name) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
51 let parts = name.split(/-(?!$)/)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
52 name = parts[parts.length - 1]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
53 let alt, ctrl, shift, cmd
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
54 for (let i = 0; i < parts.length - 1; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
55 let mod = parts[i]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
56 if (/^(cmd|meta|m)$/i.test(mod)) cmd = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
57 else if (/^a(lt)?$/i.test(mod)) alt = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
58 else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
59 else if (/^s(hift)?$/i.test(mod)) shift = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
60 else throw new Error("Unrecognized modifier name: " + mod)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
61 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
62 if (alt) name = "Alt-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
63 if (ctrl) name = "Ctrl-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
64 if (cmd) name = "Cmd-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
65 if (shift) name = "Shift-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
66 return name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
67 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
68
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
69 // This is a kludge to keep keymaps mostly working as raw objects
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
70 // (backwards compatibility) while at the same time support features
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
71 // like normalization and multi-stroke key bindings. It compiles a
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
72 // new normalized keymap, and then updates the old object to reflect
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
73 // this.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
74 export function normalizeKeyMap(keymap) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
75 let copy = {}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
76 for (let keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
77 let value = keymap[keyname]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
78 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
79 if (value == "...") { delete keymap[keyname]; continue }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
80
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
81 let keys = map(keyname.split(" "), normalizeKeyName)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
82 for (let i = 0; i < keys.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
83 let val, name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
84 if (i == keys.length - 1) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
85 name = keys.join(" ")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
86 val = value
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
87 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
88 name = keys.slice(0, i + 1).join(" ")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
89 val = "..."
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
90 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
91 let prev = copy[name]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
92 if (!prev) copy[name] = val
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
93 else if (prev != val) throw new Error("Inconsistent bindings for " + name)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
94 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
95 delete keymap[keyname]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
96 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
97 for (let prop in copy) keymap[prop] = copy[prop]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
98 return keymap
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
99 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
100
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
101 export function lookupKey(key, map, handle, context) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
102 map = getKeyMap(map)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
103 let found = map.call ? map.call(key, context) : map[key]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
104 if (found === false) return "nothing"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
105 if (found === "...") return "multi"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
106 if (found != null && handle(found)) return "handled"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
107
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
108 if (map.fallthrough) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
109 if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
110 return lookupKey(key, map.fallthrough, handle, context)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
111 for (let i = 0; i < map.fallthrough.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
112 let result = lookupKey(key, map.fallthrough[i], handle, context)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
113 if (result) return result
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
114 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
115 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
116 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
117
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
118 // Modifier key presses don't count as 'real' key presses for the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
119 // purpose of keymap fallthrough.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
120 export function isModifierKey(value) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
121 let name = typeof value == "string" ? value : keyNames[value.keyCode]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
122 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
123 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
124
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
125 export function addModifierNames(name, event, noShift) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
126 let base = name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
127 if (event.altKey && base != "Alt") name = "Alt-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
128 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
129 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") name = "Cmd-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
130 if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
131 return name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
132 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
133
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
134 // Look up the name of a key as indicated by an event object.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
135 export function keyName(event, noShift) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
136 if (presto && event.keyCode == 34 && event["char"]) return false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
137 let name = keyNames[event.keyCode]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
138 if (name == null || event.altGraphKey) return false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
139 // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
140 // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
141 if (event.keyCode == 3 && event.code) name = event.code
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
142 return addModifierNames(name, event, noShift)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
143 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
144
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
145 export function getKeyMap(val) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
146 return typeof val == "string" ? keyMap[val] : val
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
147 }