Skip to content

Commit

Permalink
Convert VscodeHatRendered to use vscode.workspace.fs (#2194)
Browse files Browse the repository at this point in the history
This is part of porting Cursorless to work in the web environment.

This is a re-roll of
#2153 which I messed up
with bad git-fu.

## Checklist

- [ ] I have added
[tests](https://www.cursorless.org/docs/contributing/test-case-recorder/)
- [ ] I have updated the
[docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and
[cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet)
- [ ] I have not broken the cheatsheet

---------

Co-authored-by: Barry Jaspan <[email protected]>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: David Vo <[email protected]>
  • Loading branch information
4 people authored Jan 25, 2024
1 parent 08abb7f commit aa95401
Showing 1 changed file with 51 additions and 35 deletions.
86 changes: 51 additions & 35 deletions packages/cursorless-vscode/src/ide/vscode/hats/VscodeHatRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@cursorless/common";
import { VscodeApi } from "@cursorless/vscode-common";
import { cloneDeep, isEqual } from "lodash";
import * as fs from "node:fs";
import * as fs from "fs/promises";
import * as path from "node:path";
import * as vscode from "vscode";
import { vscodeGetConfigurationString } from "../VscodeConfiguration";
Expand All @@ -24,6 +24,7 @@ import {
defaultShapeAdjustments,
} from "./shapeAdjustments";
import { performPr1868ShapeUpdateInit } from "./performPr1868ShapeUpdateInit";
import { TextDecoder } from "util";

const CURSORLESS_HAT_SHAPES_SUFFIX = ".svg";

Expand Down Expand Up @@ -65,7 +66,8 @@ export default class VscodeHatRenderer {
private notifier: Notifier<[]> = new Notifier();
private lastSeenEnabledHatStyles: ExtendedHatStyleMap = {};
private hatsDirWatcherDisposable?: vscode.Disposable;
private hatShapeOverrides: Record<string, string> = {};
private hatShapeOverrides: Record<string, vscode.Uri> = {};
private decoder: TextDecoder = new TextDecoder("utf-8");

constructor(
private vscodeApi: VscodeApi,
Expand Down Expand Up @@ -133,10 +135,13 @@ export default class VscodeHatRenderer {
if (hatsDir) {
await this.updateShapeOverrides(hatsDir);

if (fs.existsSync(hatsDir)) {
try {
await fs.access(hatsDir);
this.hatsDirWatcherDisposable = watchDir(hatsDir, () =>
this.updateShapeOverrides(hatsDir),
);
} catch (e) {
console.error("cannot watch hatsDir", hatsDir, e);
}
} else {
this.hatShapeOverrides = {};
Expand All @@ -150,7 +155,10 @@ export default class VscodeHatRenderer {

for (const file of files) {
const name = path.basename(file, CURSORLESS_HAT_SHAPES_SUFFIX);
this.hatShapeOverrides[name] = file;
this.hatShapeOverrides[name] = vscode.Uri.from({
scheme: "file",
path: file,
});
}

await this.recomputeDecorations();
Expand Down Expand Up @@ -207,35 +215,41 @@ export default class VscodeHatRenderer {
);

const hatSvgMap = Object.fromEntries(
HAT_SHAPES.map((shape) => {
const { sizeAdjustment = 0, verticalOffset = 0 } =
defaultShapeAdjustments[shape];

const {
sizeAdjustment: userIndividualSizeAdjustment = 0,
verticalOffset: userIndividualVerticalOffset = 0,
} = userIndividualAdjustments[shape] ?? {};

const scaleFactor =
1 +
(sizeAdjustment + userSizeAdjustment + userIndividualSizeAdjustment) /
await Promise.all(
HAT_SHAPES.map(async (shape) => {
const { sizeAdjustment = 0, verticalOffset = 0 } =
defaultShapeAdjustments[shape];

const {
sizeAdjustment: userIndividualSizeAdjustment = 0,
verticalOffset: userIndividualVerticalOffset = 0,
} = userIndividualAdjustments[shape] ?? {};

const scaleFactor =
1 +
(sizeAdjustment +
userSizeAdjustment +
userIndividualSizeAdjustment) /
100;

const finalVerticalOffsetEm =
(verticalOffset +
userVerticalOffset +
userIndividualVerticalOffset) /
100;

const finalVerticalOffsetEm =
(verticalOffset + userVerticalOffset + userIndividualVerticalOffset) /
100;

return [
shape,
this.processSvg(
this.fontMeasurements,
return [
shape,
scaleFactor,
defaultShapeAdjustments[shape].strokeFactor ?? 1,
finalVerticalOffsetEm,
),
];
}),
await this.processSvg(
this.fontMeasurements,
shape,
scaleFactor,
defaultShapeAdjustments[shape].strokeFactor ?? 1,
finalVerticalOffsetEm,
),
];
}),
),
);

this.decorationMap = Object.fromEntries(
Expand Down Expand Up @@ -373,22 +387,24 @@ export default class VscodeHatRenderer {
* @param hatVerticalOffsetEm How far off top of characters should hats be
* @returns An object with the new SVG and its measurements
*/
private processSvg(
private async processSvg(
fontMeasurements: FontMeasurements,
shape: HatShape,
scaleFactor: number,
strokeFactor: number,
hatVerticalOffsetEm: number,
): SvgInfo | null {
): Promise<SvgInfo | null> {
const iconPath =
this.hatShapeOverrides[shape] ??
path.join(
this.extensionContext.extensionPath,
vscode.Uri.joinPath(
this.extensionContext.extensionUri,
"images",
"hats",
`${shape}.svg`,
);
const rawSvg = fs.readFileSync(iconPath, "utf8");
const rawSvg = this.decoder.decode(
await vscode.workspace.fs.readFile(iconPath),
);
const { characterWidth, characterHeight, fontSize } = fontMeasurements;

if (!this.checkSvg(shape, rawSvg)) {
Expand Down

0 comments on commit aa95401

Please sign in to comment.