Skip to content
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

Dispose of decorations #307

Merged
merged 3 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions src/core/Decorations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DEFAULT_HAT_HEIGHT_EM,
DEFAULT_VERTICAL_OFFSET_EM,
} from "./shapeAdjustments";
import { Graph } from "../typings/Types";

export type DecorationMap = {
[k in HatStyleName]?: vscode.TextEditorDecorationType;
Expand All @@ -35,11 +36,9 @@ export default class Decorations {
hatStyleMap!: Record<HatStyleName, HatStyle>;
hatStyleNames!: HatStyleName[];

constructor(
fontMeasurements: FontMeasurements,
private extensionPath: string
) {
this.constructDecorations(fontMeasurements);
constructor(private graph: Graph) {
this.constructDecorations(graph.fontMeasurements);
graph.extensionContext.subscriptions.push(this);
}

destroyDecorations() {
Expand Down Expand Up @@ -209,7 +208,12 @@ export default class Decorations {
scaleFactor: number,
hatVerticalOffsetEm: number
) {
const iconPath = join(this.extensionPath, "images", "hats", `${shape}.svg`);
const iconPath = join(
this.graph.extensionContext.extensionPath,
"images",
"hats",
`${shape}.svg`
);
const rawSvg = readFileSync(iconPath, "utf8");
const { characterWidth, characterHeight, fontSize } = fontMeasurements;

Expand Down Expand Up @@ -272,4 +276,8 @@ export default class Decorations {

return { originalViewBoxHeight, originalViewBoxWidth };
}

dispose() {
this.destroyDecorations();
}
}
9 changes: 5 additions & 4 deletions src/core/FontMeasurements.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as vscode from "vscode";
import { Graph } from "../typings/Types";

/**
* Contains measurements for the user's font
Expand All @@ -17,24 +18,24 @@ export default class FontMeasurements {
*/
characterHeight!: number;

constructor(private context: vscode.ExtensionContext) {}
constructor(private graph: Graph) {}

clearCache() {
this.context.globalState.update("fontRatios", undefined);
this.graph.extensionContext.globalState.update("fontRatios", undefined);
}

async calculate() {
const fontFamily = getFontFamily();
let widthRatio, heightRatio;
let fontRatiosCache = this.context.globalState.get<{
let fontRatiosCache = this.graph.extensionContext.globalState.get<{
widthRatio: number;
heightRatio: number;
fontFamily: string;
}>("fontRatios");

if (fontRatiosCache == null || fontRatiosCache.fontFamily !== fontFamily) {
const fontRatios = await getFontRatios();
this.context.globalState.update("fontRatios", {
this.graph.extensionContext.globalState.update("fontRatios", {
...fontRatios,
fontFamily,
});
Expand Down
51 changes: 37 additions & 14 deletions src/core/editStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import {
DecorationRangeBehavior,
window,
} from "vscode";
import { Graph } from "../typings/Types";

export class EditStyle {
token: TextEditorDecorationType;
line: TextEditorDecorationType;

constructor(colorName: string) {
constructor(colorName: EditStyleThemeColorName) {
const options = {
backgroundColor: new ThemeColor(`cursorless.${colorName}`),
rangeBehavior: DecorationRangeBehavior.ClosedClosed,
Expand All @@ -20,20 +21,42 @@ export class EditStyle {
isWholeLine: true,
});
}

dispose() {
this.token.dispose();
this.line.dispose();
}
}

export class EditStyles {
pendingDelete: EditStyle;
referenced: EditStyle;
pendingModification0: EditStyle;
pendingModification1: EditStyle;
justAdded: EditStyle;

constructor() {
this.pendingDelete = new EditStyle("pendingDeleteBackground");
this.justAdded = new EditStyle("justAddedBackground");
this.referenced = new EditStyle("referencedBackground");
this.pendingModification0 = new EditStyle("pendingModification0Background");
this.pendingModification1 = new EditStyle("pendingModification1Background");
const EDIT_STYLE_NAMES = [
"pendingDelete",
"referenced",
"pendingModification0",
"pendingModification1",
"justAdded",
] as const;

type EditStyleName = typeof EDIT_STYLE_NAMES[number];
type EditStyleThemeColorName = `${EditStyleName}Background`;

export class EditStyles implements Record<EditStyleName, EditStyle> {
pendingDelete!: EditStyle;
referenced!: EditStyle;
pendingModification0!: EditStyle;
pendingModification1!: EditStyle;
justAdded!: EditStyle;

constructor(graph: Graph) {
EDIT_STYLE_NAMES.forEach((editStyleName) => {
this[editStyleName] = new EditStyle(`${editStyleName}Background`);
});

graph.extensionContext.subscriptions.push(this);
}

dispose() {
EDIT_STYLE_NAMES.forEach((editStyleName) => {
this[editStyleName].dispose();
});
}
}
28 changes: 9 additions & 19 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,34 @@
import * as vscode from "vscode";
import { addDecorationsToEditors } from "./util/addDecorationsToEditor";
import { DECORATION_DEBOUNCE_DELAY } from "./core/constants";
import Decorations from "./core/Decorations";
import graphFactories from "./util/graphFactories";
import inferFullTargets from "./core/inferFullTargets";
import processTargets from "./processTargets";
import FontMeasurements from "./core/FontMeasurements";
import {
ActionType,
Graph,
PartialTarget,
ProcessedTargetsContext,
} from "./typings/Types";
import { Graph, PartialTarget, ProcessedTargetsContext } from "./typings/Types";
import makeGraph, { FactoryMap } from "./util/makeGraph";
import { logBranchTypes } from "./util/debug";
import { TestCase } from "./testUtil/TestCase";
import { ThatMark } from "./core/ThatMark";
import { TestCaseRecorder } from "./testUtil/TestCaseRecorder";
import { getParseTreeApi } from "./util/getExtensionApi";
import { canonicalizeAndValidateCommand } from "./util/canonicalizeAndValidateCommand";
import canonicalizeActionName from "./util/canonicalizeActionName";

export async function activate(context: vscode.ExtensionContext) {
const fontMeasurements = new FontMeasurements(context);
await fontMeasurements.calculate();
const decorations = new Decorations(fontMeasurements, context.extensionPath);

const { getNodeAtLocation } = await getParseTreeApi();

var isActive = vscode.workspace
.getConfiguration("cursorless")
.get<boolean>("showOnStart")!;

function clearEditorDecorations(editor: vscode.TextEditor) {
decorations.decorations.forEach(({ decoration }) => {
graph.decorations.decorations.forEach(({ decoration }) => {
editor.setDecorations(decoration, []);
});
}

function addDecorations() {
if (isActive) {
addDecorationsToEditors(graph.navigationMap, decorations);
addDecorationsToEditors(graph.navigationMap, graph.decorations);
} else {
vscode.window.visibleTextEditors.forEach(clearEditorDecorations);
graph.navigationMap.clear();
Expand Down Expand Up @@ -72,7 +60,7 @@ export async function activate(context: vscode.ExtensionContext) {
const recomputeDecorationStylesDisposable = vscode.commands.registerCommand(
"cursorless.recomputeDecorationStyles",
() => {
fontMeasurements.clearCache();
graph.fontMeasurements.clearCache();
recomputeDecorationStyles();
}
);
Expand All @@ -82,6 +70,8 @@ export async function activate(context: vscode.ExtensionContext) {
extensionContext: () => context,
} as FactoryMap<Graph>);
graph.snippets.init();
await graph.fontMeasurements.calculate();

const thatMark = new ThatMark();
const sourceMark = new ThatMark();
const testCaseRecorder = new TestCaseRecorder(context);
Expand Down Expand Up @@ -248,9 +238,9 @@ export async function activate(context: vscode.ExtensionContext) {
}

const recomputeDecorationStyles = async () => {
decorations.destroyDecorations();
await fontMeasurements.calculate();
decorations.constructDecorations(fontMeasurements);
graph.decorations.destroyDecorations();
await graph.fontMeasurements.calculate();
graph.decorations.constructDecorations(graph.fontMeasurements);
addDecorations();
};

Expand Down
23 changes: 23 additions & 0 deletions src/typings/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import NavigationMap from "../core/NavigationMap";
import { Snippets } from "../core/Snippets";
import { RangeUpdater } from "../core/updateSelections/RangeUpdater";
import { FullRangeInfo } from "./updateSelections";
import Decorations from "../core/Decorations";
import FontMeasurements from "../core/FontMeasurements";

/**
* A token within a text editor, including the current display line of the token
Expand Down Expand Up @@ -46,6 +48,7 @@ export interface LineNumberPosition {
lineNumber: number;
isRelative: boolean;
}

export interface LineNumber {
type: "lineNumber";
anchor: LineNumberPosition;
Expand All @@ -60,6 +63,7 @@ export type Mark =
// | LastCursorPosition Not implemented yet
| DecoratedSymbol
| LineNumber;

export type Delimiter =
| "angleBrackets"
| "backtickQuotes"
Expand Down Expand Up @@ -97,19 +101,22 @@ export type ScopeType =
| "xmlElement"
| "xmlEndTag"
| "xmlStartTag";

export type SubTokenType = "word" | "character";

export interface SurroundingPairModifier {
type: "surroundingPair";
delimiter: Delimiter | null;
delimitersOnly: boolean;
}

export interface ContainingScopeModifier {
type: "containingScope";
scopeType: ScopeType;
valueOnly?: boolean;
includeSiblings?: boolean;
}

export interface SubTokenModifier {
type: "subpiece";
pieceType: SubTokenType;
Expand All @@ -118,15 +125,19 @@ export interface SubTokenModifier {
excludeAnchor?: boolean;
excludeActive?: boolean;
}

export interface MatchingPairSymbolModifier {
type: "matchingPairSymbol";
}

export interface IdentityModifier {
type: "identity";
}

export interface HeadModifier {
type: "head";
}

export interface TailModifier {
type: "tail";
}
Expand All @@ -143,7 +154,9 @@ export type Modifier =
export type SelectionType =
// | "character" Not implemented
"token" | "line" | "notebookCell" | "paragraph" | "document";

export type Position = "before" | "after" | "contents";

export type InsideOutsideType = "inside" | "outside" | null;

export interface PartialPrimitiveTarget {
Expand Down Expand Up @@ -354,6 +367,16 @@ export interface Graph {
* as the document changes
*/
readonly rangeUpdater: RangeUpdater;

/**
* Responsible for all the hat styles
*/
readonly decorations: Decorations;

/**
* Takes measurements of the user's font
*/
readonly fontMeasurements: FontMeasurements;
}

export type NodeMatcherValue = {
Expand Down
27 changes: 21 additions & 6 deletions src/util/graphFactories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@ import { FactoryMap } from "./makeGraph";
import NavigationMap from "../core/NavigationMap";
import { Snippets } from "../core/Snippets";
import { RangeUpdater } from "../core/updateSelections/RangeUpdater";
import Decorations from "../core/Decorations";
import FontMeasurements from "../core/FontMeasurements";

const graphFactories: Partial<FactoryMap<Graph>> = {
actions: (graph: Graph) => new Actions(graph),
editStyles: () => new EditStyles(),
navigationMap: (graph: Graph) => new NavigationMap(graph),
snippets: (graph: Graph) => new Snippets(graph),
rangeUpdater: (graph: Graph) => new RangeUpdater(graph),
type ConstructorMap<T> = {
[P in keyof T]: new (t: T) => T[P];
};

const graphConstructors: Partial<ConstructorMap<Graph>> = {
actions: Actions,
editStyles: EditStyles,
navigationMap: NavigationMap,
decorations: Decorations,
fontMeasurements: FontMeasurements,
snippets: Snippets,
rangeUpdater: RangeUpdater,
};

const graphFactories: Partial<FactoryMap<Graph>> = Object.fromEntries(
Object.entries(graphConstructors).map(([key, constructor]) => [
key,
(graph: Graph) => new constructor(graph),
])
);

export default graphFactories;