tridactyl/src/controller.ts

118 lines
3.9 KiB
TypeScript
Raw Normal View History

2017-10-06 03:28:14 +01:00
import {MsgSafeKeyboardEvent, MsgSafeNode} from './msgsafe'
import {isTextEditable} from './dom'
import {isSimpleKey} from './keyseq'
import state from "./state"
import {repeat} from './excmds_background'
2017-12-30 00:46:26 +00:00
import Logger from "./logging"
import {parser as exmode_parser} from './parsers/exmode'
import {parser as hintmode_parser} from './hinting_background'
import * as normalmode from "./parsers/normalmode"
import * as insertmode from "./parsers/insertmode"
2017-11-15 00:03:34 +00:00
import * as ignoremode from "./parsers/ignoremode"
import * as gobblemode from './parsers/gobblemode'
import * as inputmode from './parsers/inputmode'
2017-12-30 00:46:26 +00:00
const logger = new Logger('controller')
/** Accepts keyevents, resolves them to maps, maps to exstrs, executes exstrs */
function *ParserController () {
const parsers = {
normal: normalmode.parser,
insert: insertmode.parser,
2017-11-15 00:03:34 +00:00
ignore: ignoremode.parser,
hint: hintmode_parser,
gobble: gobblemode.parser,
input: inputmode.parser,
}
while (true) {
let ex_str = ""
let keys = []
try {
while (true) {
2017-10-06 03:28:14 +01:00
let keyevent: MsgSafeKeyboardEvent = yield
let keypress = keyevent.key
2017-11-08 23:20:41 +00:00
// TODO: think about if this is robust
if (state.mode != "ignore" && state.mode != "hint" && state.mode != "input") {
2017-11-15 00:03:34 +00:00
if (isTextEditable(keyevent.target)) {
state.mode = "insert"
} else if (state.mode === 'insert') {
state.mode = "normal"
}
}
2017-12-30 00:46:26 +00:00
logger.debug(keyevent, state.mode)
// Special keys (e.g. Backspace) are not handled properly
// yet. So drop them. This also drops all modifier keys.
// When we put in handling for other special keys, remember
// to continue to ban modifiers.
if (state.mode === 'normal' && ! isSimpleKey(keyevent)) {
continue
}
keys.push(keypress)
let response = undefined
switch (state.mode) {
2017-11-09 21:01:57 +00:00
case 'normal':
response = (parsers[state.mode] as any)(keys)
break
default:
2017-11-09 21:01:57 +00:00
response = (parsers[state.mode] as any)([keyevent])
break
}
2017-12-30 00:46:26 +00:00
logger.debug(keys, response)
if (response.ex_str){
ex_str = response.ex_str
break
} else {
keys = response.keys
}
}
acceptExCmd(ex_str)
} catch (e) {
// Rumsfeldian errors are caught here
console.error("Tridactyl ParserController fatally wounded:", e)
}
}
}
let generator = ParserController() // var rather than let stops weirdness in repl.
generator.next()
/** Feed keys to the ParserController */
2017-10-06 03:28:14 +01:00
export function acceptKey(keyevent: MsgSafeKeyboardEvent) {
generator.next(keyevent)
}
/** Parse and execute ExCmds */
export function acceptExCmd(ex_str: string) {
// TODO: Errors should go to CommandLine.
try {
let [func, args] = exmode_parser(ex_str)
// Stop the repeat excmd from recursing.
if (func !== repeat)
state.last_ex_str = ex_str
try {
func(...args)
} catch (e) {
// Errors from func are caught here (e.g. no next tab)
console.error(e)
}
} catch (e) {
// Errors from parser caught here
console.error(e)
}
}
import {activeTabId} from './lib/webext'
browser.webNavigation.onBeforeNavigate.addListener(async function (details) {
2017-12-11 13:17:11 +00:00
if (details.frameId === 0 && details.tabId === await activeTabId()) {
state.mode = 'normal'
}
})
browser.tabs.onActivated.addListener(()=>state.mode = 'normal')