Skip to content

Commit a580d78

Browse files
Added context menu to scope visualizer sidebar to open in browser
1 parent aac06b1 commit a580d78

File tree

14 files changed

+108
-59
lines changed

14 files changed

+108
-59
lines changed

packages/common/src/cursorlessCommandIds.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const cursorlessCommandIds = [
5454
"cursorless.toggleDecorations",
5555
"cursorless.showScopeVisualizer",
5656
"cursorless.hideScopeVisualizer",
57+
"cursorless.scopeVisualizer.openUrl",
5758
"cursorless.tutorial.start",
5859
"cursorless.tutorial.next",
5960
"cursorless.tutorial.previous",
@@ -100,6 +101,7 @@ export const cursorlessCommandDescriptions: Record<
100101
["cursorless.hideScopeVisualizer"]: new VisibleCommand(
101102
"Hide the scope visualizer",
102103
),
104+
["cursorless.scopeVisualizer.openUrl"]: new VisibleCommand("Open in browser"),
103105
["cursorless.analyzeCommandHistory"]: new VisibleCommand(
104106
"Analyze collected command history",
105107
),

packages/common/src/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ export * from "./types/Token";
9292
export * from "./types/TreeSitter";
9393
export * from "./types/tutorial.types";
9494
export * from "./util";
95-
export * from "./util/camelCaseToAllDown";
96-
export * from "./util/capitalize";
9795
export * from "./util/clientSupportsFallback";
9896
export * from "./util/CompositeKeyDefaultMap";
9997
export * from "./util/CompositeKeyMap";
@@ -110,8 +108,8 @@ export * from "./util/regex";
110108
export * from "./util/selectionsEqual";
111109
export * from "./util/serializedMarksToTokenHats";
112110
export * from "./util/serializeScopeType";
113-
export * from "./util/sortRanges";
114111
export * from "./util/splitKey";
112+
export * from "./util/stringUtils";
115113
export * from "./util/toPlainObject";
116114
export * from "./util/type";
117115
export * from "./util/typeUtils";

packages/common/src/util/camelCaseToAllDown.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

packages/common/src/util/capitalize.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/common/src/util/sortRanges.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Converts a camelCase string to a string with spaces between each word, and
3+
* all words in lowercase.
4+
*
5+
* Example: `camelCaseToAllDown("fooBarBaz")` returns `"foo bar baz"`.
6+
*
7+
* @param input A camelCase string
8+
* @returns The same string, but with spaces between each word, and all words
9+
* in lowercase
10+
*/
11+
export function camelCaseToAllDown(input: string): string {
12+
return input
13+
.replace(/([A-Z])/g, " $1")
14+
.split(" ")
15+
.map((word) => word.toLowerCase())
16+
.join(" ");
17+
}
18+
19+
/**
20+
* Capitalizes string
21+
*
22+
* @param input A string
23+
* @returns The same string, but with the first character capitalized
24+
*/
25+
export function capitalize(str: string) {
26+
return str.charAt(0).toUpperCase() + str.slice(1);
27+
}
28+
29+
/**
30+
* Converts a string to a URL-friendly hash ID.
31+
*
32+
* This function takes an input string, converts it to lowercase, replaces spaces
33+
* with hyphens, and removes any characters that are not lowercase letters,
34+
* digits, or hyphens. The result is a string that can be used as a
35+
* URL-friendly hash ID.
36+
*
37+
* @param text The input string to be converted
38+
* @returns A URL-friendly hash ID
39+
*/
40+
export function uriEncodeHashId(text: string): string {
41+
return camelCaseToAllDown(text)
42+
.replaceAll(" ", "-")
43+
.replace(/[^a-z0-9-]/g, "");
44+
}

packages/cursorless-neovim/src/registerCommands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export async function registerCommands(
9898
// Scope visualizer
9999
["cursorless.showScopeVisualizer"]: dummyCommandHandler,
100100
["cursorless.hideScopeVisualizer"]: dummyCommandHandler,
101+
["cursorless.scopeVisualizer.openUrl"]: dummyCommandHandler,
101102

102103
// Command history
103104
["cursorless.analyzeCommandHistory"]: dummyCommandHandler,

packages/cursorless-org-docs/src/docs/user/languages/components/Header.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { uriEncodeHashId } from "@cursorless/common";
12
import React from "react";
23

34
interface Props {
@@ -23,7 +24,7 @@ function renderHeader(
2324
{ className, title, children }: Props,
2425
): React.JSX.Element {
2526
const Tag = `h${level}` as keyof React.JSX.IntrinsicElements;
26-
const href = encodeHash(children);
27+
const href = uriEncodeHashId(children);
2728
return (
2829
<Tag
2930
id={href}
@@ -38,10 +39,3 @@ function renderHeader(
3839
</Tag>
3940
);
4041
}
41-
42-
export function encodeHash(text: string): string {
43-
return text
44-
.toLowerCase()
45-
.replaceAll(" ", "-")
46-
.replace(/[^a-z0-9-]/g, "");
47-
}

packages/cursorless-org-docs/src/docs/user/languages/components/Language.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from "react";
22
import { DynamicTOC } from "./DynamicTOC";
33
import { ScopeSupport } from "./ScopeSupport";
4+
import { ScrollToHash } from "./ScrollToHash";
45

56
interface Props {
67
languageId: string;
@@ -10,6 +11,7 @@ export function Language({ languageId }: Props) {
1011
return (
1112
<>
1213
<DynamicTOC />
14+
<ScrollToHash />
1315

1416
<ScopeSupport languageId={languageId} />
1517
</>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useEffect } from "react";
2+
import { useLocation } from "@docusaurus/router";
3+
4+
/**
5+
* Scrolls to the element with the ID matching the current hash in the URL.
6+
* This is needed when a hash ID is provided in the initial load to scroll to a heading rendered by a react component.
7+
*/
8+
export function ScrollToHash() {
9+
const location = useLocation();
10+
11+
useEffect(() => {
12+
if (location.hash) {
13+
setTimeout(() => {
14+
const id = location.hash.replace("#", "");
15+
const element = document.getElementById(id);
16+
if (element != null) {
17+
element.scrollIntoView();
18+
}
19+
}, 100);
20+
}
21+
}, []);
22+
23+
return null;
24+
}

0 commit comments

Comments
 (0)