From 536fb99ce689ed08bf05e997256f26a74935e8bb Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Sat, 3 Jul 2021 19:42:00 +0100 Subject: [PATCH 01/12] Triangle hats --- images/triangle-hat.svg | 1 + src/core/Decorations.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 images/triangle-hat.svg diff --git a/images/triangle-hat.svg b/images/triangle-hat.svg new file mode 100644 index 0000000000..c4f0fe9d4a --- /dev/null +++ b/images/triangle-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index 4f17dd9831..b1ab5fb6d3 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -124,7 +124,7 @@ export default class Decorations { hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { - const iconPath = join(__dirname, "..", "images", "round-hat.svg"); + const iconPath = join(__dirname, "..", "images", "triangle-hat.svg"); const rawSvg = readFileSync(iconPath, "utf8"); const { originalViewBoxHeight, originalViewBoxWidth } = From a73a667b6acfe3ff6c4d0265fc8d62c8240387a3 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Thu, 26 Aug 2021 16:09:28 +0100 Subject: [PATCH 02/12] Initial triangle hat --- images/triangle-hat.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/triangle-hat.svg b/images/triangle-hat.svg index c4f0fe9d4a..3a24b52dd7 100644 --- a/images/triangle-hat.svg +++ b/images/triangle-hat.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From cb96b96500e771408489cacb4493f29e11c955ed Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Thu, 26 Aug 2021 17:24:01 +0100 Subject: [PATCH 03/12] Lots of hats --- images/bird-hat.svg | 1 + images/curved-hat.svg | 2 +- images/mountain-hat.svg | 1 + images/ninja-hat.svg | 1 + images/north-star-hat.svg | 1 + images/peak-hat.svg | 1 + images/valley-hat.svg | 1 + src/core/Decorations.ts | 2 +- 8 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 images/bird-hat.svg create mode 100644 images/mountain-hat.svg create mode 100644 images/ninja-hat.svg create mode 100644 images/north-star-hat.svg create mode 100644 images/peak-hat.svg create mode 100644 images/valley-hat.svg diff --git a/images/bird-hat.svg b/images/bird-hat.svg new file mode 100644 index 0000000000..1a293316dd --- /dev/null +++ b/images/bird-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/curved-hat.svg b/images/curved-hat.svg index e38e5d5cd8..2fbc7c5ea9 100644 --- a/images/curved-hat.svg +++ b/images/curved-hat.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/mountain-hat.svg b/images/mountain-hat.svg new file mode 100644 index 0000000000..88f70ab101 --- /dev/null +++ b/images/mountain-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/ninja-hat.svg b/images/ninja-hat.svg new file mode 100644 index 0000000000..2a67b50105 --- /dev/null +++ b/images/ninja-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/north-star-hat.svg b/images/north-star-hat.svg new file mode 100644 index 0000000000..1e3986a7df --- /dev/null +++ b/images/north-star-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/peak-hat.svg b/images/peak-hat.svg new file mode 100644 index 0000000000..4a8d6c6dde --- /dev/null +++ b/images/peak-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/valley-hat.svg b/images/valley-hat.svg new file mode 100644 index 0000000000..42239e8c9c --- /dev/null +++ b/images/valley-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index b1ab5fb6d3..bf4983ec64 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -124,7 +124,7 @@ export default class Decorations { hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { - const iconPath = join(__dirname, "..", "images", "triangle-hat.svg"); + const iconPath = join(__dirname, "..", "images", "ninja-hat.svg"); const rawSvg = readFileSync(iconPath, "utf8"); const { originalViewBoxHeight, originalViewBoxWidth } = From 80ad4ff467f9dd5a203a528c3ca71a15f282c5ad Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Thu, 26 Aug 2021 18:55:55 +0100 Subject: [PATCH 04/12] Initial support for multiple hat glyphs --- images/cutout-hat.svg | 1 + images/{round-hat.svg => default-hat.svg} | 0 images/ninja-hat.svg | 2 +- src/core/Decorations.ts | 61 ++++++++++++++++------- src/core/NavigationMap.ts | 10 ++-- src/core/constants.ts | 32 +++++++++++- src/testUtil/extractTargetedMarks.ts | 4 +- src/typings/Types.ts | 4 +- src/util/addDecorationsToEditor.ts | 6 +-- 9 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 images/cutout-hat.svg rename images/{round-hat.svg => default-hat.svg} (100%) diff --git a/images/cutout-hat.svg b/images/cutout-hat.svg new file mode 100644 index 0000000000..56a85fa2fd --- /dev/null +++ b/images/cutout-hat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/round-hat.svg b/images/default-hat.svg similarity index 100% rename from images/round-hat.svg rename to images/default-hat.svg diff --git a/images/ninja-hat.svg b/images/ninja-hat.svg index 2a67b50105..3a08a22c93 100644 --- a/images/ninja-hat.svg +++ b/images/ninja-hat.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index bf4983ec64..df4e24ef2b 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -1,20 +1,37 @@ import * as vscode from "vscode"; import { join } from "path"; -import { COLORS } from "./constants"; -import { SymbolColor } from "./constants"; +import { + HatStyleName, + HatGlyphName, + hatStyleMap, + hatStyleNames, +} from "./constants"; import { readFileSync } from "fs"; import { DecorationColorSetting } from "../typings/Types"; import FontMeasurements from "./FontMeasurements"; -const DEFAULT_HAT_WIDTH_TO_CHARACTER_WITH_RATIO = 0.39; -const DEFAULT_HAT_VERTICAL_OFFSET_EM = -0.05; +interface GlyphMeasurements { + hatWidthToCharacterWidthRatio: number; + verticalOffsetEm: number; +} + +const defaultGlyphMeasurements: Record = { + default: { + hatWidthToCharacterWidthRatio: 0.507, + verticalOffsetEm: -0.05, + }, + ninja: { + hatWidthToCharacterWidthRatio: 0.6825, + verticalOffsetEm: -0.12, + }, +}; export type DecorationMap = { - [k in SymbolColor]?: vscode.TextEditorDecorationType; + [k in HatStyleName]?: vscode.TextEditorDecorationType; }; export interface NamedDecoration { - name: SymbolColor; + name: HatStyleName; decoration: vscode.TextEditorDecorationType; } @@ -43,23 +60,32 @@ export default class Decorations { const hatScaleFactor = 1 + hatSizeAdjustment / 100; - const { svg, svgWidthPx, svgHeightPx } = this.processSvg( - fontMeasurements, - hatScaleFactor * DEFAULT_HAT_WIDTH_TO_CHARACTER_WITH_RATIO, - (DEFAULT_HAT_VERTICAL_OFFSET_EM + userHatVerticalOffsetAdjustment / 100) * - fontMeasurements.fontSize - ); + // TODO: Don't reconstruct svg for each glyph every time + this.decorations = hatStyleNames.map((styleName) => { + const { color, glyphName } = hatStyleMap[styleName]; + const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = + defaultGlyphMeasurements[glyphName]; + + console.log(`color: ${color}`); + console.log(`glyphName: ${glyphName}`); + + const { svg, svgWidthPx, svgHeightPx } = this.processSvg( + fontMeasurements, + glyphName, + hatScaleFactor * hatWidthToCharacterWidthRatio, + (verticalOffsetEm + userHatVerticalOffsetAdjustment / 100) * + fontMeasurements.fontSize + ); - const spanWidthPx = - svgWidthPx + (fontMeasurements.characterWidth - svgWidthPx) / 2; + const spanWidthPx = + svgWidthPx + (fontMeasurements.characterWidth - svgWidthPx) / 2; - this.decorations = COLORS.map((color) => { const colorSetting = vscode.workspace .getConfiguration("cursorless.colors") .get(color)!; return { - name: color, + name: styleName, decoration: vscode.window.createTextEditorDecorationType({ rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed, light: { @@ -121,10 +147,11 @@ export default class Decorations { */ private processSvg( fontMeasurements: FontMeasurements, + glyphName: HatGlyphName, hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { - const iconPath = join(__dirname, "..", "images", "ninja-hat.svg"); + const iconPath = join(__dirname, "..", "images", `${glyphName}-hat.svg`); const rawSvg = readFileSync(iconPath, "utf8"); const { originalViewBoxHeight, originalViewBoxWidth } = diff --git a/src/core/NavigationMap.ts b/src/core/NavigationMap.ts index 3484e80413..8927098557 100644 --- a/src/core/NavigationMap.ts +++ b/src/core/NavigationMap.ts @@ -1,5 +1,5 @@ import { TextDocumentChangeEvent, Range } from "vscode"; -import { SymbolColor } from "./constants"; +import { HatStyleName } from "./constants"; import { SelectionWithEditor, Token } from "../typings/Types"; /** @@ -43,20 +43,20 @@ export default class NavigationMap { [coloredSymbol: string]: Token; } = {}; - static getKey(color: SymbolColor, character: string) { + static getKey(color: HatStyleName, character: string) { return `${color}.${character}`; } static splitKey(key: string) { const [color, character] = key.split("."); - return { color: color as SymbolColor, character }; + return { color: color as HatStyleName, character }; } - public addToken(color: SymbolColor, character: string, token: Token) { + public addToken(color: HatStyleName, character: string, token: Token) { this.map[NavigationMap.getKey(color, character)] = token; } - public getToken(color: SymbolColor, character: string) { + public getToken(color: HatStyleName, character: string) { return this.map[NavigationMap.getKey(color, character)]; } diff --git a/src/core/constants.ts b/src/core/constants.ts index 3489e944f1..ec5d8d143d 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -2,7 +2,7 @@ export const SUBWORD_MATCHER = /[A-Z]?[a-z]+|[A-Z]+(?![a-z])|[0-9]+/g; export const DEBOUNCE_DELAY = 175; -export const COLORS = [ +const HAT_COLORS = [ "default", "blue", "green", @@ -11,4 +11,32 @@ export const COLORS = [ "purple", ] as const; -export type SymbolColor = typeof COLORS[number]; +const HAT_NON_DEFAULT_GLYPHS = ["ninja"] as const; +const HAT_GLYPHS = [...HAT_NON_DEFAULT_GLYPHS, "default"] as const; + +export type HatColor = typeof HAT_COLORS[number]; +export type HatGlyphName = typeof HAT_GLYPHS[number]; +type HatNonDefaultGlyph = typeof HAT_NON_DEFAULT_GLYPHS[number]; +export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultGlyph}`; + +export interface HatStyle { + color: HatColor; + glyphName: HatGlyphName; +} + +export const hatStyleMap = { + ...Object.fromEntries( + HAT_COLORS.map((color) => [color, { color, glyphName: "default" }]) + ), + ...Object.fromEntries( + HAT_COLORS.flatMap((color) => + HAT_NON_DEFAULT_GLYPHS.map((glyphName) => [ + `${color}-${glyphName}`, + { color, glyphName }, + ]) + ) + ), +} as Record; +export const hatStyleNames = Object.keys(hatStyleMap); + +console.log(`hatStyles: ${JSON.stringify(hatStyleMap)}`); diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index 9743585f1d..0e248528c7 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -1,4 +1,4 @@ -import { SymbolColor } from "../core/constants"; +import { HatStyleName } from "../core/constants"; import NavigationMap from "../core/NavigationMap"; import { PrimitiveTarget, Target, Token } from "../typings/Types"; @@ -38,7 +38,7 @@ export function extractTargetedMarks( targetKeys.forEach((key) => { const { color, character } = NavigationMap.splitKey(key); targetedMarks[key] = navigationMap.getToken( - color as SymbolColor, + color as HatStyleName, character ); }); diff --git a/src/typings/Types.ts b/src/typings/Types.ts index ec2779ab37..d4880b4a79 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -1,7 +1,7 @@ import { SyntaxNode } from "web-tree-sitter"; import * as vscode from "vscode"; import { Location } from "vscode"; -import { SymbolColor } from "../core/constants"; +import { HatStyleName } from "../core/constants"; import { EditStyles } from "../core/editStyles"; import NavigationMap from "../core/NavigationMap"; @@ -39,7 +39,7 @@ export interface LastCursorPosition { export interface DecoratedSymbol { type: "decoratedSymbol"; - symbolColor: SymbolColor; + symbolColor: HatStyleName; character: string; } diff --git a/src/util/addDecorationsToEditor.ts b/src/util/addDecorationsToEditor.ts index 17328c388b..2a04295ccf 100644 --- a/src/util/addDecorationsToEditor.ts +++ b/src/util/addDecorationsToEditor.ts @@ -5,7 +5,7 @@ import { getTokenComparator as getTokenComparator } from "./getTokenComparator"; import { getTokensInRange } from "./getTokensInRange"; import { Token } from "../typings/Types"; import Decorations from "../core/Decorations"; -import { COLORS, SymbolColor } from "../core/constants"; +import { hatStyleNames, HatStyleName } from "../core/constants"; import NavigationMap from "../core/NavigationMap"; interface CharacterTokenInfo { @@ -79,7 +79,7 @@ export function addDecorationsToEditors( const decorationRanges: Map< vscode.TextEditor, { - [decorationName in SymbolColor]?: vscode.Range[]; + [decorationName in HatStyleName]?: vscode.Range[]; } > = new Map( editors.map((editor) => [ @@ -150,7 +150,7 @@ export function addDecorationsToEditors( }); decorationRanges.forEach((ranges, editor) => { - COLORS.forEach((color) => { + hatStyleNames.forEach((color) => { editor.setDecorations(decorations.decorationMap[color]!, ranges[color]!); }); }); From 3ad0197926dc647fa3a92d4618254df83bc76dd2 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Thu, 26 Aug 2021 19:00:16 +0100 Subject: [PATCH 05/12] Tweak comment --- src/core/Decorations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index df4e24ef2b..a8a092b1e7 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -60,7 +60,6 @@ export default class Decorations { const hatScaleFactor = 1 + hatSizeAdjustment / 100; - // TODO: Don't reconstruct svg for each glyph every time this.decorations = hatStyleNames.map((styleName) => { const { color, glyphName } = hatStyleMap[styleName]; const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = @@ -69,6 +68,7 @@ export default class Decorations { console.log(`color: ${color}`); console.log(`glyphName: ${glyphName}`); + // TODO: Don't reconstruct svg for each glyph every time const { svg, svgWidthPx, svgHeightPx } = this.processSvg( fontMeasurements, glyphName, From 44382dab52205840ec164f7e2ba95e4c0eb5cf50 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Thu, 26 Aug 2021 19:00:37 +0100 Subject: [PATCH 06/12] Remove debug statements --- src/core/Decorations.ts | 3 --- src/core/constants.ts | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index a8a092b1e7..08009aa094 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -65,9 +65,6 @@ export default class Decorations { const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = defaultGlyphMeasurements[glyphName]; - console.log(`color: ${color}`); - console.log(`glyphName: ${glyphName}`); - // TODO: Don't reconstruct svg for each glyph every time const { svg, svgWidthPx, svgHeightPx } = this.processSvg( fontMeasurements, diff --git a/src/core/constants.ts b/src/core/constants.ts index ec5d8d143d..29f35fd759 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -38,5 +38,3 @@ export const hatStyleMap = { ), } as Record; export const hatStyleNames = Object.keys(hatStyleMap); - -console.log(`hatStyles: ${JSON.stringify(hatStyleMap)}`); From 3ea1f2fab3c38fb216fa0f5b7089396234b65ca3 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Fri, 27 Aug 2021 14:58:20 +0100 Subject: [PATCH 07/12] "glyph" => "shape"; "ninja" => "star" --- images/{bird-hat.svg => hats/bird.svg} | 0 images/{curved-hat.svg => hats/curved.svg} | 0 images/{cutout-hat.svg => hats/cutout.svg} | 0 images/{default-hat.svg => hats/default.svg} | 0 images/{diamond-hat.svg => hats/diamond.svg} | 0 .../{mountain-hat.svg => hats/mountain.svg} | 0 .../north-star.svg} | 0 images/{peak-hat.svg => hats/peak.svg} | 0 images/{ninja-hat.svg => hats/star.svg} | 0 .../{triangle-hat.svg => hats/triangle.svg} | 0 images/{valley-hat.svg => hats/valley.svg} | 0 src/core/Decorations.ts | 20 +++++++++---------- src/core/constants.ts | 20 +++++++++---------- 13 files changed, 20 insertions(+), 20 deletions(-) rename images/{bird-hat.svg => hats/bird.svg} (100%) rename images/{curved-hat.svg => hats/curved.svg} (100%) rename images/{cutout-hat.svg => hats/cutout.svg} (100%) rename images/{default-hat.svg => hats/default.svg} (100%) rename images/{diamond-hat.svg => hats/diamond.svg} (100%) rename images/{mountain-hat.svg => hats/mountain.svg} (100%) rename images/{north-star-hat.svg => hats/north-star.svg} (100%) rename images/{peak-hat.svg => hats/peak.svg} (100%) rename images/{ninja-hat.svg => hats/star.svg} (100%) rename images/{triangle-hat.svg => hats/triangle.svg} (100%) rename images/{valley-hat.svg => hats/valley.svg} (100%) diff --git a/images/bird-hat.svg b/images/hats/bird.svg similarity index 100% rename from images/bird-hat.svg rename to images/hats/bird.svg diff --git a/images/curved-hat.svg b/images/hats/curved.svg similarity index 100% rename from images/curved-hat.svg rename to images/hats/curved.svg diff --git a/images/cutout-hat.svg b/images/hats/cutout.svg similarity index 100% rename from images/cutout-hat.svg rename to images/hats/cutout.svg diff --git a/images/default-hat.svg b/images/hats/default.svg similarity index 100% rename from images/default-hat.svg rename to images/hats/default.svg diff --git a/images/diamond-hat.svg b/images/hats/diamond.svg similarity index 100% rename from images/diamond-hat.svg rename to images/hats/diamond.svg diff --git a/images/mountain-hat.svg b/images/hats/mountain.svg similarity index 100% rename from images/mountain-hat.svg rename to images/hats/mountain.svg diff --git a/images/north-star-hat.svg b/images/hats/north-star.svg similarity index 100% rename from images/north-star-hat.svg rename to images/hats/north-star.svg diff --git a/images/peak-hat.svg b/images/hats/peak.svg similarity index 100% rename from images/peak-hat.svg rename to images/hats/peak.svg diff --git a/images/ninja-hat.svg b/images/hats/star.svg similarity index 100% rename from images/ninja-hat.svg rename to images/hats/star.svg diff --git a/images/triangle-hat.svg b/images/hats/triangle.svg similarity index 100% rename from images/triangle-hat.svg rename to images/hats/triangle.svg diff --git a/images/valley-hat.svg b/images/hats/valley.svg similarity index 100% rename from images/valley-hat.svg rename to images/hats/valley.svg diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index 08009aa094..f073c1e42b 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -2,7 +2,7 @@ import * as vscode from "vscode"; import { join } from "path"; import { HatStyleName, - HatGlyphName, + HatShapeName, hatStyleMap, hatStyleNames, } from "./constants"; @@ -10,17 +10,17 @@ import { readFileSync } from "fs"; import { DecorationColorSetting } from "../typings/Types"; import FontMeasurements from "./FontMeasurements"; -interface GlyphMeasurements { +interface ShapeMeasurements { hatWidthToCharacterWidthRatio: number; verticalOffsetEm: number; } -const defaultGlyphMeasurements: Record = { +const defaultShapeMeasurements: Record = { default: { hatWidthToCharacterWidthRatio: 0.507, verticalOffsetEm: -0.05, }, - ninja: { + star: { hatWidthToCharacterWidthRatio: 0.6825, verticalOffsetEm: -0.12, }, @@ -61,14 +61,14 @@ export default class Decorations { const hatScaleFactor = 1 + hatSizeAdjustment / 100; this.decorations = hatStyleNames.map((styleName) => { - const { color, glyphName } = hatStyleMap[styleName]; + const { color, shapeName } = hatStyleMap[styleName]; const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = - defaultGlyphMeasurements[glyphName]; + defaultShapeMeasurements[shapeName]; - // TODO: Don't reconstruct svg for each glyph every time + // TODO: Don't reconstruct svg for each shape every time const { svg, svgWidthPx, svgHeightPx } = this.processSvg( fontMeasurements, - glyphName, + shapeName, hatScaleFactor * hatWidthToCharacterWidthRatio, (verticalOffsetEm + userHatVerticalOffsetAdjustment / 100) * fontMeasurements.fontSize @@ -144,11 +144,11 @@ export default class Decorations { */ private processSvg( fontMeasurements: FontMeasurements, - glyphName: HatGlyphName, + shapeName: HatShapeName, hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { - const iconPath = join(__dirname, "..", "images", `${glyphName}-hat.svg`); + const iconPath = join(__dirname, "..", "images", `${shapeName}-hat.svg`); const rawSvg = readFileSync(iconPath, "utf8"); const { originalViewBoxHeight, originalViewBoxWidth } = diff --git a/src/core/constants.ts b/src/core/constants.ts index 29f35fd759..4660598e56 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -11,28 +11,28 @@ const HAT_COLORS = [ "purple", ] as const; -const HAT_NON_DEFAULT_GLYPHS = ["ninja"] as const; -const HAT_GLYPHS = [...HAT_NON_DEFAULT_GLYPHS, "default"] as const; +const HAT_NON_DEFAULT_SHAPES = ["star"] as const; +const HAT_SHAPES = [...HAT_NON_DEFAULT_SHAPES, "default"] as const; export type HatColor = typeof HAT_COLORS[number]; -export type HatGlyphName = typeof HAT_GLYPHS[number]; -type HatNonDefaultGlyph = typeof HAT_NON_DEFAULT_GLYPHS[number]; -export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultGlyph}`; +export type HatShapeName = typeof HAT_SHAPES[number]; +type HatNonDefaultShape = typeof HAT_NON_DEFAULT_SHAPES[number]; +export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultShape}`; export interface HatStyle { color: HatColor; - glyphName: HatGlyphName; + shapeName: HatShapeName; } export const hatStyleMap = { ...Object.fromEntries( - HAT_COLORS.map((color) => [color, { color, glyphName: "default" }]) + HAT_COLORS.map((color) => [color, { color, shapeName: "default" }]) ), ...Object.fromEntries( HAT_COLORS.flatMap((color) => - HAT_NON_DEFAULT_GLYPHS.map((glyphName) => [ - `${color}-${glyphName}`, - { color, glyphName }, + HAT_NON_DEFAULT_SHAPES.map((shapeName) => [ + `${color}-${shapeName}`, + { color, shapeName }, ]) ) ), From 065b038f9f3f2546a6e6f655646f829c08ffd441 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Fri, 27 Aug 2021 15:15:37 +0100 Subject: [PATCH 08/12] Remove unused hats --- images/hats/bird.svg | 1 - images/hats/curved.svg | 1 - images/hats/cutout.svg | 1 - images/hats/diamond.svg | 1 - images/hats/mountain.svg | 1 - images/hats/north-star.svg | 1 - images/hats/peak.svg | 1 - images/hats/triangle.svg | 1 - 8 files changed, 8 deletions(-) delete mode 100644 images/hats/bird.svg delete mode 100644 images/hats/curved.svg delete mode 100644 images/hats/cutout.svg delete mode 100644 images/hats/diamond.svg delete mode 100644 images/hats/mountain.svg delete mode 100644 images/hats/north-star.svg delete mode 100644 images/hats/peak.svg delete mode 100644 images/hats/triangle.svg diff --git a/images/hats/bird.svg b/images/hats/bird.svg deleted file mode 100644 index 1a293316dd..0000000000 --- a/images/hats/bird.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/curved.svg b/images/hats/curved.svg deleted file mode 100644 index 2fbc7c5ea9..0000000000 --- a/images/hats/curved.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/cutout.svg b/images/hats/cutout.svg deleted file mode 100644 index 56a85fa2fd..0000000000 --- a/images/hats/cutout.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/diamond.svg b/images/hats/diamond.svg deleted file mode 100644 index 57009204e8..0000000000 --- a/images/hats/diamond.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/mountain.svg b/images/hats/mountain.svg deleted file mode 100644 index 88f70ab101..0000000000 --- a/images/hats/mountain.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/north-star.svg b/images/hats/north-star.svg deleted file mode 100644 index 1e3986a7df..0000000000 --- a/images/hats/north-star.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/peak.svg b/images/hats/peak.svg deleted file mode 100644 index 4a8d6c6dde..0000000000 --- a/images/hats/peak.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/hats/triangle.svg b/images/hats/triangle.svg deleted file mode 100644 index 3a24b52dd7..0000000000 --- a/images/hats/triangle.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From c015bf065c281761b1821fa39fbf2b47096aadab Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Fri, 27 Aug 2021 15:23:32 +0100 Subject: [PATCH 09/12] Add a hat; cleanup --- src/core/Decorations.ts | 47 +++++++++++++++++++++++++++++------------ src/core/constants.ts | 15 +++++++------ src/extension.ts | 2 +- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index f073c1e42b..e2a8ddc0cf 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -5,6 +5,7 @@ import { HatShapeName, hatStyleMap, hatStyleNames, + HAT_SHAPE_NAMES, } from "./constants"; import { readFileSync } from "fs"; import { DecorationColorSetting } from "../typings/Types"; @@ -21,6 +22,10 @@ const defaultShapeMeasurements: Record = { verticalOffsetEm: -0.05, }, star: { + hatWidthToCharacterWidthRatio: 0.6825, + verticalOffsetEm: -0.105, + }, + valley: { hatWidthToCharacterWidthRatio: 0.6825, verticalOffsetEm: -0.12, }, @@ -39,7 +44,10 @@ export default class Decorations { decorations!: NamedDecoration[]; decorationMap!: DecorationMap; - constructor(fontMeasurements: FontMeasurements) { + constructor( + fontMeasurements: FontMeasurements, + private extensionPath: string + ) { this.constructDecorations(fontMeasurements); } @@ -60,19 +68,27 @@ export default class Decorations { const hatScaleFactor = 1 + hatSizeAdjustment / 100; + const hatSvgMap = Object.fromEntries( + HAT_SHAPE_NAMES.map((shapeName) => { + const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = + defaultShapeMeasurements[shapeName]; + + return [ + shapeName, + this.processSvg( + fontMeasurements, + shapeName, + hatScaleFactor * hatWidthToCharacterWidthRatio, + (verticalOffsetEm + userHatVerticalOffsetAdjustment / 100) * + fontMeasurements.fontSize + ), + ]; + }) + ); + this.decorations = hatStyleNames.map((styleName) => { const { color, shapeName } = hatStyleMap[styleName]; - const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = - defaultShapeMeasurements[shapeName]; - - // TODO: Don't reconstruct svg for each shape every time - const { svg, svgWidthPx, svgHeightPx } = this.processSvg( - fontMeasurements, - shapeName, - hatScaleFactor * hatWidthToCharacterWidthRatio, - (verticalOffsetEm + userHatVerticalOffsetAdjustment / 100) * - fontMeasurements.fontSize - ); + const { svg, svgWidthPx, svgHeightPx } = hatSvgMap[shapeName]; const spanWidthPx = svgWidthPx + (fontMeasurements.characterWidth - svgWidthPx) / 2; @@ -148,7 +164,12 @@ export default class Decorations { hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { - const iconPath = join(__dirname, "..", "images", `${shapeName}-hat.svg`); + const iconPath = join( + this.extensionPath, + "images", + "hats", + `${shapeName}.svg` + ); const rawSvg = readFileSync(iconPath, "utf8"); const { originalViewBoxHeight, originalViewBoxWidth } = diff --git a/src/core/constants.ts b/src/core/constants.ts index 4660598e56..c78f5baf31 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -11,13 +11,16 @@ const HAT_COLORS = [ "purple", ] as const; -const HAT_NON_DEFAULT_SHAPES = ["star"] as const; -const HAT_SHAPES = [...HAT_NON_DEFAULT_SHAPES, "default"] as const; +const HAT_NON_DEFAULT_SHAPE_NAMES = ["star", "valley"] as const; +export const HAT_SHAPE_NAMES = [ + ...HAT_NON_DEFAULT_SHAPE_NAMES, + "default", +] as const; export type HatColor = typeof HAT_COLORS[number]; -export type HatShapeName = typeof HAT_SHAPES[number]; -type HatNonDefaultShape = typeof HAT_NON_DEFAULT_SHAPES[number]; -export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultShape}`; +export type HatShapeName = typeof HAT_SHAPE_NAMES[number]; +type HatNonDefaultShapeName = typeof HAT_NON_DEFAULT_SHAPE_NAMES[number]; +export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultShapeName}`; export interface HatStyle { color: HatColor; @@ -30,7 +33,7 @@ export const hatStyleMap = { ), ...Object.fromEntries( HAT_COLORS.flatMap((color) => - HAT_NON_DEFAULT_SHAPES.map((shapeName) => [ + HAT_NON_DEFAULT_SHAPE_NAMES.map((shapeName) => [ `${color}-${shapeName}`, { color, shapeName }, ]) diff --git a/src/extension.ts b/src/extension.ts index ee5abbcffb..1a71b2176f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -23,7 +23,7 @@ import canonicalizeActionName from "./canonicalizeActionName"; export async function activate(context: vscode.ExtensionContext) { const fontMeasurements = new FontMeasurements(context); await fontMeasurements.calculate(); - const decorations = new Decorations(fontMeasurements); + const decorations = new Decorations(fontMeasurements, context.extensionPath); const { getNodeAtLocation } = await getParseTreeApi(); From d2eb8102887c9b2d4c57e5bcf064e9071908642d Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Mon, 30 Aug 2021 17:10:55 +0100 Subject: [PATCH 10/12] Some renaming --- src/core/Decorations.ts | 22 +++++++++++----------- src/core/NavigationMap.ts | 24 ++++++++++++------------ src/core/constants.ts | 23 ++++++++++------------- src/test/suite/recorded.test.ts | 9 ++++++--- src/testUtil/extractTargetedMarks.ts | 9 +++------ src/testUtil/toPlainObject.ts | 4 ++-- src/util/addDecorationsToEditor.ts | 13 ++++++++----- 7 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index e2a8ddc0cf..398b0a35e2 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -2,10 +2,10 @@ import * as vscode from "vscode"; import { join } from "path"; import { HatStyleName, - HatShapeName, + HatShape, hatStyleMap, hatStyleNames, - HAT_SHAPE_NAMES, + HAT_SHAPES, } from "./constants"; import { readFileSync } from "fs"; import { DecorationColorSetting } from "../typings/Types"; @@ -16,7 +16,7 @@ interface ShapeMeasurements { verticalOffsetEm: number; } -const defaultShapeMeasurements: Record = { +const defaultShapeMeasurements: Record = { default: { hatWidthToCharacterWidthRatio: 0.507, verticalOffsetEm: -0.05, @@ -69,15 +69,15 @@ export default class Decorations { const hatScaleFactor = 1 + hatSizeAdjustment / 100; const hatSvgMap = Object.fromEntries( - HAT_SHAPE_NAMES.map((shapeName) => { + HAT_SHAPES.map((shape) => { const { hatWidthToCharacterWidthRatio, verticalOffsetEm } = - defaultShapeMeasurements[shapeName]; + defaultShapeMeasurements[shape]; return [ - shapeName, + shape, this.processSvg( fontMeasurements, - shapeName, + shape, hatScaleFactor * hatWidthToCharacterWidthRatio, (verticalOffsetEm + userHatVerticalOffsetAdjustment / 100) * fontMeasurements.fontSize @@ -87,8 +87,8 @@ export default class Decorations { ); this.decorations = hatStyleNames.map((styleName) => { - const { color, shapeName } = hatStyleMap[styleName]; - const { svg, svgWidthPx, svgHeightPx } = hatSvgMap[shapeName]; + const { color, shape } = hatStyleMap[styleName]; + const { svg, svgWidthPx, svgHeightPx } = hatSvgMap[shape]; const spanWidthPx = svgWidthPx + (fontMeasurements.characterWidth - svgWidthPx) / 2; @@ -160,7 +160,7 @@ export default class Decorations { */ private processSvg( fontMeasurements: FontMeasurements, - shapeName: HatShapeName, + shape: HatShape, hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { @@ -168,7 +168,7 @@ export default class Decorations { this.extensionPath, "images", "hats", - `${shapeName}.svg` + `${shape}.svg` ); const rawSvg = readFileSync(iconPath, "utf8"); diff --git a/src/core/NavigationMap.ts b/src/core/NavigationMap.ts index 8927098557..0b5688e391 100644 --- a/src/core/NavigationMap.ts +++ b/src/core/NavigationMap.ts @@ -3,7 +3,7 @@ import { HatStyleName } from "./constants"; import { SelectionWithEditor, Token } from "../typings/Types"; /** - * Maps from (color, character) pairs to tokens + * Maps from (hatStyle, character) pairs to tokens */ export default class NavigationMap { updateTokenRanges(edit: TextDocumentChangeEvent) { @@ -11,7 +11,7 @@ export default class NavigationMap { // Amount by which to shift ranges const shift = editComponent.text.length - editComponent.rangeLength; - Object.entries(this.map).forEach(([coloredSymbol, token]) => { + Object.entries(this.map).forEach(([decoratedCharacter, token]) => { if (token.editor.document !== edit.document) { return; } @@ -22,7 +22,7 @@ export default class NavigationMap { if (editComponent.range.end.isAfter(token.range.start)) { // If there is overlap, we just delete the token - delete this.map[coloredSymbol]; + delete this.map[decoratedCharacter]; return; } @@ -40,24 +40,24 @@ export default class NavigationMap { } private map: { - [coloredSymbol: string]: Token; + [decoratedCharacter: string]: Token; } = {}; - static getKey(color: HatStyleName, character: string) { - return `${color}.${character}`; + static getKey(hatStyle: HatStyleName, character: string) { + return `${hatStyle}.${character}`; } static splitKey(key: string) { - const [color, character] = key.split("."); - return { color: color as HatStyleName, character }; + const [hatStyle, character] = key.split("."); + return { hatStyle: hatStyle as HatStyleName, character }; } - public addToken(color: HatStyleName, character: string, token: Token) { - this.map[NavigationMap.getKey(color, character)] = token; + public addToken(hatStyle: HatStyleName, character: string, token: Token) { + this.map[NavigationMap.getKey(hatStyle, character)] = token; } - public getToken(color: HatStyleName, character: string) { - return this.map[NavigationMap.getKey(color, character)]; + public getToken(hatStyle: HatStyleName, character: string) { + return this.map[NavigationMap.getKey(hatStyle, character)]; } public clear() { diff --git a/src/core/constants.ts b/src/core/constants.ts index c78f5baf31..270025e491 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -11,31 +11,28 @@ const HAT_COLORS = [ "purple", ] as const; -const HAT_NON_DEFAULT_SHAPE_NAMES = ["star", "valley"] as const; -export const HAT_SHAPE_NAMES = [ - ...HAT_NON_DEFAULT_SHAPE_NAMES, - "default", -] as const; +const HAT_NON_DEFAULT_SHAPES = ["star", "valley"] as const; +export const HAT_SHAPES = [...HAT_NON_DEFAULT_SHAPES, "default"] as const; export type HatColor = typeof HAT_COLORS[number]; -export type HatShapeName = typeof HAT_SHAPE_NAMES[number]; -type HatNonDefaultShapeName = typeof HAT_NON_DEFAULT_SHAPE_NAMES[number]; -export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultShapeName}`; +export type HatShape = typeof HAT_SHAPES[number]; +type HatNonDefaultShape = typeof HAT_NON_DEFAULT_SHAPES[number]; +export type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultShape}`; export interface HatStyle { color: HatColor; - shapeName: HatShapeName; + shape: HatShape; } export const hatStyleMap = { ...Object.fromEntries( - HAT_COLORS.map((color) => [color, { color, shapeName: "default" }]) + HAT_COLORS.map((color) => [color, { color, shape: "default" }]) ), ...Object.fromEntries( HAT_COLORS.flatMap((color) => - HAT_NON_DEFAULT_SHAPE_NAMES.map((shapeName) => [ - `${color}-${shapeName}`, - { color, shapeName }, + HAT_NON_DEFAULT_SHAPES.map((shape) => [ + `${color}-${shape}`, + { color, shape }, ]) ) ), diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 87d4774c00..9b7d9ddc13 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -93,9 +93,12 @@ async function runTest(file: string) { // Assert that recorded decorations are present Object.entries(fixture.marks).forEach(([key, token]) => { - const { color, character } = NavigationMap.splitKey(key); - const currentToken = cursorlessApi.navigationMap.getToken(color, character); - assert(currentToken != null, `Mark "${color} ${character}" not found`); + const { hatStyle, character } = NavigationMap.splitKey(key); + const currentToken = cursorlessApi.navigationMap.getToken( + hatStyle, + character + ); + assert(currentToken != null, `Mark "${hatStyle} ${character}" not found`); assert.deepStrictEqual(rangeToPlainObject(currentToken.range), token); }); diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index 0e248528c7..83a9d81c17 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -33,14 +33,11 @@ export function extractTargetedMarks( targets: Target[], navigationMap: NavigationMap ) { - const targetedMarks: { [coloredSymbol: string]: Token } = {}; + const targetedMarks: { [decoratedCharacter: string]: Token } = {}; const targetKeys = targets.map(extractTargetKeys).flat(); targetKeys.forEach((key) => { - const { color, character } = NavigationMap.splitKey(key); - targetedMarks[key] = navigationMap.getToken( - color as HatStyleName, - character - ); + const { hatStyle, character } = NavigationMap.splitKey(key); + targetedMarks[key] = navigationMap.getToken(hatStyle, character); }); return targetedMarks; } diff --git a/src/testUtil/toPlainObject.ts b/src/testUtil/toPlainObject.ts index 23485b17b3..b5bc745e9b 100644 --- a/src/testUtil/toPlainObject.ts +++ b/src/testUtil/toPlainObject.ts @@ -16,7 +16,7 @@ export type SelectionPlainObject = { active: PositionPlainObject; }; -export type SerializedMarks = { [coloredSymbol: string]: RangePlainObject }; +export type SerializedMarks = { [decoratedCharacter: string]: RangePlainObject }; export function rangeToPlainObject(range: Range): RangePlainObject { return { @@ -38,7 +38,7 @@ export function positionToPlainObject(position: Position): PositionPlainObject { return { line: position.line, character: position.character }; } -export function marksToPlainObject(marks: { [coloredSymbol: string]: Token }) { +export function marksToPlainObject(marks: { [decoratedCharacter: string]: Token }) { const serializedMarks: SerializedMarks = {}; Object.entries(marks).forEach( ([key, value]: [string, Token]) => diff --git a/src/util/addDecorationsToEditor.ts b/src/util/addDecorationsToEditor.ts index 2a04295ccf..a38f5a10ab 100644 --- a/src/util/addDecorationsToEditor.ts +++ b/src/util/addDecorationsToEditor.ts @@ -132,26 +132,29 @@ export function addDecorationsToEditors( const currentDecorationIndex = bestCharacter.decorationIndex; - const colorName = decorations.decorations[currentDecorationIndex].name; + const hatStyleName = decorations.decorations[currentDecorationIndex].name; decorationRanges .get(token.editor)! - [colorName]!.push( + [hatStyleName]!.push( new vscode.Range( token.range.start.translate(undefined, bestCharacter.characterIdx), token.range.start.translate(undefined, bestCharacter.characterIdx + 1) ) ); - navigationMap.addToken(colorName, bestCharacter.character, token); + navigationMap.addToken(hatStyleName, bestCharacter.character, token); characterDecorationIndices[bestCharacter.character] = currentDecorationIndex + 1; }); decorationRanges.forEach((ranges, editor) => { - hatStyleNames.forEach((color) => { - editor.setDecorations(decorations.decorationMap[color]!, ranges[color]!); + hatStyleNames.forEach((hatStyleName) => { + editor.setDecorations( + decorations.decorationMap[hatStyleName]!, + ranges[hatStyleName]! + ); }); }); } From 68577405728b12d369d3b04c9daab74e3064de06 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Tue, 31 Aug 2021 11:31:41 +0100 Subject: [PATCH 11/12] "valley" => "chevron" --- images/hats/{valley.svg => chevron.svg} | 0 src/core/constants.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename images/hats/{valley.svg => chevron.svg} (100%) diff --git a/images/hats/valley.svg b/images/hats/chevron.svg similarity index 100% rename from images/hats/valley.svg rename to images/hats/chevron.svg diff --git a/src/core/constants.ts b/src/core/constants.ts index 270025e491..6f5bc6068b 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -11,7 +11,7 @@ const HAT_COLORS = [ "purple", ] as const; -const HAT_NON_DEFAULT_SHAPES = ["star", "valley"] as const; +const HAT_NON_DEFAULT_SHAPES = ["star", "chevron"] as const; export const HAT_SHAPES = [...HAT_NON_DEFAULT_SHAPES, "default"] as const; export type HatColor = typeof HAT_COLORS[number]; From 09c590c9953a9a04f29d052e7077b368765fe6ec Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Tue, 31 Aug 2021 16:47:45 +0100 Subject: [PATCH 12/12] Fixed chevron --- src/core/Decorations.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/core/Decorations.ts b/src/core/Decorations.ts index 398b0a35e2..4d5ec1545f 100644 --- a/src/core/Decorations.ts +++ b/src/core/Decorations.ts @@ -25,7 +25,7 @@ const defaultShapeMeasurements: Record = { hatWidthToCharacterWidthRatio: 0.6825, verticalOffsetEm: -0.105, }, - valley: { + chevron: { hatWidthToCharacterWidthRatio: 0.6825, verticalOffsetEm: -0.12, }, @@ -164,12 +164,7 @@ export default class Decorations { hatWidthToCharacterWidthRatio: number, hatVerticalOffset: number ) { - const iconPath = join( - this.extensionPath, - "images", - "hats", - `${shape}.svg` - ); + const iconPath = join(this.extensionPath, "images", "hats", `${shape}.svg`); const rawSvg = readFileSync(iconPath, "utf8"); const { originalViewBoxHeight, originalViewBoxWidth } =