Merge branch 'shifthints'

This commit is contained in:
Oliver Blanthorn 2020-05-05 16:34:31 +01:00
commit 5fa256a568
No known key found for this signature in database
GPG key ID: 2BB8C36BB504BFF3
2 changed files with 78 additions and 1 deletions

View file

@ -253,6 +253,61 @@ class HintState {
this.focusedHint = nextFocusedHint
this.focusedHint.focused = true
}
// Attempt to make the next hint the same as the previous one
shiftHints() {
// Pages often have their "interesting" hints separated by the same
// amount of "uninteresting" hints. We can use this to try to predict
// what the next interesting hint will be and provide the same hint
// name as the previous one, so that the user can keep on pressing the
// same key in order to select all interesting hints.
// To do this, compute the number of hints between the last selected
// hint and the hint selected before it
const lastIndex = this.hints.indexOf(this.selectedHints[this.selectedHints.length - 1])
const prevIndex = this.hints.indexOf(this.selectedHints[this.selectedHints.length - 2])
const distance = lastIndex - prevIndex
if (distance > 0) {
// Then, shift the hint names "forward". This requires saving the
// last N hints (the ones that will end up at the beginning of the
// hint array).
const savedNames = []
for (let i = 0; i < distance; ++i) {
savedNames.push(this.hints[this.hints.length - 1 - i].name)
}
// Actually shift the names.
for (let i = this.hints.length - 1; i >= distance; --i) {
this.hints[i].setName(this.hints[i - distance].name)
}
// Set the names that should go at the beginning
for (let i = savedNames.length - 1; i >= 0; --i) {
this.hints[i].setName(savedNames[i])
}
} else if (distance < 0) {
// Then, shift the hint names "backward". This requires saving the
// first N hints (the ones that will end up at the end of the hint
// array).
const savedNames = []
for (let i = 0; i < Math.abs(distance); ++i) {
savedNames.push(this.hints[i].name)
}
// Actually shift the names.
for (let i = 0; i < this.hints.length + distance; ++i) {
this.hints[i].setName(this.hints[i - distance].name)
}
// Set the names that should go at the end
for (let i = 0; i < savedNames.length; ++i) {
this.hints[this.hints.length + distance + i].setName(savedNames[i])
}
}
// All done!
}
}
/** @hidden*/
@ -284,6 +339,9 @@ export function hintPage(
buildHints(hintableElements, hint => {
hint.result = onSelect(hint.target)
modeState.selectedHints.push(hint)
if (modeState.selectedHints.length > 1 && (config.get("hintshift") === "true")) {
modeState.shiftHints();
}
})
}
@ -461,7 +519,7 @@ class Hint {
constructor(
public readonly target: Element,
public readonly name: string,
public name: string,
public readonly filterData: any,
private readonly onSelect: HintSelectedCallback,
) {
@ -514,6 +572,11 @@ class Hint {
this.hidden = false
}
setName(n: string) {
this.name = n
this.flag.textContent = this.name
}
// These styles would be better with pseudo selectors. Can we do custom ones?
// If not, do a state machine.
set hidden(hide: boolean) {

View file

@ -675,6 +675,20 @@ export class default_config {
*/
hintdelay = 300
/**
* Controls whether hints should be shifted in quick-hints mode.
*
* Here's what it means: let's say you have hints from a to z but are only
* interested in every second hint. You first press `a`, then `c`.
* Tridactyl will realize that you skipped over `b`, and so that the next
* hint you're going to trigger is probably `e`. Tridactyl will shift all
* hint names so that `e` becomes `c`, `d` becomes `b`, `c` becomes `a` and
* so on.
* This means that once you pressed `c`, you can keep on pressing `c` to
* trigger every second hint. Only makes sense with hintnames = short.
*/
hintshift: "true" | "false" = "false"
/**
* Controls whether the page can focus elements for you via js
*