-
-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hat snapshots #318
Merged
Merged
Hat snapshots #318
Changes from all commits
Commits
Show all changes
55 commits
Select commit
Hold shift + click to select a range
d3edc76
Initial attempt to at snapshots
pokey 4ff14be
Switch to unnamed snapshots
pokey 134685c
A kind of workign attempt
pokey 3626b29
A kind of workign attempt
pokey 79f5759
Use command server signal API
pokey e81cf2d
More error robustness
pokey a72d6b7
Working version
pokey cb60d9d
Have navigation map return snapshot
pokey 9c813da
Attempt at big refactor
pokey 87b5e1f
Fixes to get it running
pokey b063d7c
Rename
pokey 4c71e5e
Bind function
pokey 6b69e22
Remove unnecessary field
pokey 56bb24f
Add docstring
pokey aeb1786
snapshot => prePhraseSnapshot
pokey 55ce1c4
Clean yaml
pokey 759aa3c
Do disposal in hat allocator
pokey 0b1b9ab
navigationMap => hatTokenMap
pokey 94bb3d8
Add tests
pokey f1c60ee
Make isTesting into function
pokey ac4df71
Set testing env var
pokey ea5760d
Try to change env var
pokey 5e98e7f
Initial cleanup work for edits outside viewport
pokey 1717dec
More cleanup
pokey e5c80ee
Fix yarn lockfile
pokey ddd3022
Fix yarn
pokey fc4dd8c
refactoring
pokey 8a7ae4b
Fixes; add tests
pokey f2c2e11
File rename
pokey c6062c5
Finish merging
pokey 6c85e37
Some cleanup
pokey 95ac8f9
Create command runner class
pokey ef8624e
Working backwards compatible command runner
pokey e2440fc
More backward compatibility fixes
pokey e888bbf
Rejects stale snapshots
pokey a17d90d
Add link
pokey 65bc4b9
A bunch of refactoring
pokey 12694fb
Test fixes
pokey e5de4da
Revert change
pokey 7358f3b
Improved canonicalization
pokey 0f9cfd6
Add comment
pokey c01bd09
Fix ci
pokey f609c7c
Rollback decoration test change
pokey 006681b
Attempt to fix decorations
pokey 4b13d06
Normalize hat enablement during testing
pokey c90e810
Fix recorded tests
pokey 66c8195
Fix tests
pokey f98ae49
Cleanup test recording
pokey fbd8531
Add docs
pokey 3e75772
Fix creating nested recorded test directories
pokey 30d60bc
Cleanup test case bulk transformer
pokey c577831
More transform script fixes
pokey 4b56a1d
More transform stuff
pokey 333e02a
Merge branch 'main' into hat-snapshots
pokey b74cf8d
Upgrade a test
pokey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Hat snapshots | ||
|
||
In order to allow long chained command phrases, we take a snapshot of the hat token map at the start of a phrase and continue to use this map during the course of the entire phrase. This way you can be sure that any commands issued during the course of a single phrase that refer to a decorated token will continue to refer to the same logical token no matter what happens in the document during phrase execution. Note that the ranges of tokens will be kept current as the document changes so that they refer to the same logical range, but the same logical token will keep the same key in the hat token map over the course of a phrase. | ||
|
||
To make this work, first the voice engine touches a file within the signals subdirectory of the command server communication directory after the phrase has been parsed but right before execution begins. Then cursorless will check the version of the signal file via the command server signal API. If the signal has been emitted since the last time cursorless took a snapshot of the hat token map, it will take a new snapshot and continue to use that snapshot of the hats until the next time the signal is emitted. Note that the signal transmission is asynchronous so cursorless just needs to make sure to check the version of the signal before it either updates or reads the map. | ||
|
||
![flow diagram](hat-token-map-snapshots.png) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ import { | |
} from "./constants"; | ||
import { readFileSync } from "fs"; | ||
import FontMeasurements from "./FontMeasurements"; | ||
import { sortBy } from "lodash"; | ||
import { pull, sortBy } from "lodash"; | ||
import getHatThemeColors from "./getHatThemeColors"; | ||
import { | ||
IndividualHatAdjustmentMap, | ||
|
@@ -20,6 +20,7 @@ import { | |
DEFAULT_VERTICAL_OFFSET_EM, | ||
} from "./shapeAdjustments"; | ||
import { Graph } from "../typings/Types"; | ||
import isTesting from "../testUtil/isTesting"; | ||
|
||
export type DecorationMap = { | ||
[k in HatStyleName]?: vscode.TextEditorDecorationType; | ||
|
@@ -30,24 +31,66 @@ export interface NamedDecoration { | |
decoration: vscode.TextEditorDecorationType; | ||
} | ||
|
||
type DecorationChangeListener = () => void; | ||
|
||
export default class Decorations { | ||
decorations!: NamedDecoration[]; | ||
decorationMap!: DecorationMap; | ||
hatStyleMap!: Record<HatStyleName, HatStyle>; | ||
private hatStyleMap!: Record<HatStyleName, HatStyle>; | ||
hatStyleNames!: HatStyleName[]; | ||
private decorationChangeListeners: DecorationChangeListener[] = []; | ||
private disposables: vscode.Disposable[] = []; | ||
|
||
constructor(private graph: Graph) { | ||
this.constructDecorations(graph.fontMeasurements); | ||
graph.extensionContext.subscriptions.push(this); | ||
|
||
this.recomputeDecorationStyles = this.recomputeDecorationStyles.bind(this); | ||
|
||
this.disposables.push( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note how graph components do their own registration now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good really clean things up |
||
vscode.commands.registerCommand( | ||
"cursorless.recomputeDecorationStyles", | ||
() => { | ||
graph.fontMeasurements.clearCache(); | ||
this.recomputeDecorationStyles(); | ||
} | ||
), | ||
|
||
vscode.workspace.onDidChangeConfiguration(this.recomputeDecorationStyles) | ||
); | ||
} | ||
|
||
async init() { | ||
await this.graph.fontMeasurements.calculate(); | ||
this.constructDecorations(this.graph.fontMeasurements); | ||
} | ||
|
||
destroyDecorations() { | ||
/** | ||
* Register to be notified when decoration styles are updated, for example if | ||
* the user enables a new hat style | ||
* @param listener A function to be called when decoration styles are updated | ||
* @returns A function that can be called to unsubscribe from notifications | ||
*/ | ||
registerDecorationChangeListener(listener: DecorationChangeListener) { | ||
this.decorationChangeListeners.push(listener); | ||
|
||
return () => { | ||
pull(this.decorationChangeListeners, listener); | ||
}; | ||
} | ||
|
||
private destroyDecorations() { | ||
this.decorations.forEach(({ decoration }) => { | ||
decoration.dispose(); | ||
}); | ||
} | ||
|
||
constructDecorations(fontMeasurements: FontMeasurements) { | ||
private async recomputeDecorationStyles() { | ||
this.destroyDecorations(); | ||
await this.graph.fontMeasurements.calculate(); | ||
this.constructDecorations(this.graph.fontMeasurements); | ||
} | ||
|
||
private constructDecorations(fontMeasurements: FontMeasurements) { | ||
this.constructHatStyleMap(); | ||
|
||
const userSizeAdjustment = vscode.workspace | ||
|
@@ -125,6 +168,8 @@ export default class Decorations { | |
this.decorationMap = Object.fromEntries( | ||
this.decorations.map(({ name, decoration }) => [name, decoration]) | ||
); | ||
|
||
this.decorationChangeListeners.forEach((listener) => listener()); | ||
} | ||
|
||
private constructHatStyleMap() { | ||
|
@@ -146,9 +191,10 @@ export default class Decorations { | |
shapePenalties.default = 0; | ||
colorPenalties.default = 0; | ||
|
||
const activeHatColors = HAT_COLORS.filter( | ||
(color) => colorEnablement[color] | ||
); | ||
// So that unit tests don't fail locally if you have some colors disabled | ||
const activeHatColors = isTesting() | ||
? HAT_COLORS | ||
: HAT_COLORS.filter((color) => colorEnablement[color]); | ||
pokey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const activeNonDefaultHatShapes = HAT_NON_DEFAULT_SHAPES.filter( | ||
(shape) => shapeEnablement[shape] | ||
); | ||
|
@@ -279,5 +325,6 @@ export default class Decorations { | |
|
||
dispose() { | ||
this.destroyDecorations(); | ||
this.disposables.forEach(({ dispose }) => dispose()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import * as vscode from "vscode"; | ||
import { addDecorationsToEditors } from "../util/addDecorationsToEditor"; | ||
import { DECORATION_DEBOUNCE_DELAY } from "../core/constants"; | ||
import { Graph } from "../typings/Types"; | ||
import { Disposable } from "vscode"; | ||
import { IndividualHatMap } from "./IndividualHatMap"; | ||
|
||
interface Context { | ||
getActiveMap(): Promise<IndividualHatMap>; | ||
} | ||
|
||
export class HatAllocator { | ||
private timeoutHandle: NodeJS.Timeout | null = null; | ||
private isActive: boolean; | ||
private disposables: Disposable[] = []; | ||
private disposalFunctions: (() => void)[] = []; | ||
|
||
constructor(private graph: Graph, private context: Context) { | ||
graph.extensionContext.subscriptions.push(this); | ||
|
||
this.isActive = vscode.workspace | ||
.getConfiguration("cursorless") | ||
.get<boolean>("showOnStart")!; | ||
|
||
this.addDecorationsDebounced = this.addDecorationsDebounced.bind(this); | ||
this.toggleDecorations = this.toggleDecorations.bind(this); | ||
this.clearEditorDecorations = this.clearEditorDecorations.bind(this); | ||
|
||
this.disposalFunctions.push( | ||
graph.decorations.registerDecorationChangeListener( | ||
this.addDecorationsDebounced | ||
) | ||
); | ||
|
||
this.disposables.push( | ||
vscode.commands.registerCommand( | ||
"cursorless.toggleDecorations", | ||
this.toggleDecorations | ||
), | ||
|
||
vscode.window.onDidChangeTextEditorVisibleRanges( | ||
this.addDecorationsDebounced | ||
), | ||
vscode.window.onDidChangeActiveTextEditor(this.addDecorationsDebounced), | ||
vscode.window.onDidChangeVisibleTextEditors(this.addDecorationsDebounced), | ||
vscode.window.onDidChangeTextEditorSelection( | ||
this.addDecorationsDebounced | ||
), | ||
vscode.workspace.onDidChangeTextDocument(this.addDecorationsDebounced) | ||
); | ||
} | ||
|
||
private clearEditorDecorations(editor: vscode.TextEditor) { | ||
this.graph.decorations.decorations.forEach(({ decoration }) => { | ||
editor.setDecorations(decoration, []); | ||
}); | ||
} | ||
|
||
async addDecorations() { | ||
const activeMap = await this.context.getActiveMap(); | ||
|
||
if (this.isActive) { | ||
addDecorationsToEditors(activeMap, this.graph.decorations); | ||
} else { | ||
vscode.window.visibleTextEditors.forEach(this.clearEditorDecorations); | ||
activeMap.clear(); | ||
} | ||
} | ||
|
||
addDecorationsDebounced() { | ||
if (this.timeoutHandle != null) { | ||
clearTimeout(this.timeoutHandle); | ||
} | ||
|
||
this.timeoutHandle = setTimeout(() => { | ||
this.addDecorations(); | ||
|
||
this.timeoutHandle = null; | ||
}, DECORATION_DEBOUNCE_DELAY); | ||
} | ||
|
||
private toggleDecorations() { | ||
this.isActive = !this.isActive; | ||
this.addDecorationsDebounced(); | ||
} | ||
|
||
dispose() { | ||
this.disposables.forEach(({ dispose }) => dispose()); | ||
this.disposalFunctions.forEach((dispose) => dispose()); | ||
|
||
if (this.timeoutHandle != null) { | ||
clearTimeout(this.timeoutHandle); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with local unit testing, where this variable is set by
launch.json