Merge branch 'main' of github.com:getpaseo/paseo
This commit is contained in:
@@ -140,6 +140,7 @@ function parseLineFragment(value: string): Pick<InlinePathTarget, "lineStart" |
|
|||||||
*
|
*
|
||||||
* Supported:
|
* Supported:
|
||||||
* - `filename:linenumber`
|
* - `filename:linenumber`
|
||||||
|
* - `filename:linenumber:columnnumber` as a line target
|
||||||
* - `filename:lineStart-lineEnd`
|
* - `filename:lineStart-lineEnd`
|
||||||
*
|
*
|
||||||
* Not supported (by design):
|
* Not supported (by design):
|
||||||
|
|||||||
@@ -256,6 +256,12 @@ describe("splitHtmlishMarkdown", () => {
|
|||||||
expect(splitHtmlishMarkdown(source)).toEqual([{ kind: "markdown", text: source }]);
|
expect(splitHtmlishMarkdown(source)).toEqual([{ kind: "markdown", text: source }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("terminates when an unmatched backtick follows a closed inline code span", () => {
|
||||||
|
const source = "Use `<details><summary>Example</summary>Body</details>` before `dangling";
|
||||||
|
|
||||||
|
expect(splitHtmlishMarkdown(source)).toEqual([{ kind: "markdown", text: source }]);
|
||||||
|
});
|
||||||
|
|
||||||
it("still parses normal details outside code", () => {
|
it("still parses normal details outside code", () => {
|
||||||
expect(splitHtmlishMarkdown("`code`\n<details><summary>Real</summary>Body</details>")).toEqual([
|
expect(splitHtmlishMarkdown("`code`\n<details><summary>Real</summary>Body</details>")).toEqual([
|
||||||
{ kind: "markdown", text: "`code`\n" },
|
{ kind: "markdown", text: "`code`\n" },
|
||||||
|
|||||||
@@ -651,8 +651,13 @@ function getInlineCodeRanges(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const marker = open[0];
|
const marker = open[0];
|
||||||
const close = findClosingBacktickRun(source, BACKTICK_RUN_RE.lastIndex, marker, fencedRanges);
|
const afterOpen = BACKTICK_RUN_RE.lastIndex;
|
||||||
|
const close = findClosingBacktickRun(source, afterOpen, marker, fencedRanges);
|
||||||
if (!close) {
|
if (!close) {
|
||||||
|
// Unmatched backtick run — skip past it so the loop doesn't restart from 0.
|
||||||
|
// findClosingBacktickRun exhausts the global regex, which resets lastIndex
|
||||||
|
// to 0 when exec() returns null (ECMAScript §22.2.7.2).
|
||||||
|
BACKTICK_RUN_RE.lastIndex = afterOpen;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
type ChordState,
|
type ChordState,
|
||||||
resolveKeyboardShortcut,
|
resolveKeyboardShortcut,
|
||||||
buildEffectiveBindings,
|
buildEffectiveBindings,
|
||||||
|
getWorkspaceIndexJumpModifierKey,
|
||||||
} from "@/keyboard/keyboard-shortcuts";
|
} from "@/keyboard/keyboard-shortcuts";
|
||||||
import { resolveKeyboardFocusScope } from "@/keyboard/focus-scope";
|
import { resolveKeyboardFocusScope } from "@/keyboard/focus-scope";
|
||||||
import {
|
import {
|
||||||
@@ -73,6 +74,20 @@ export function useKeyboardShortcuts({
|
|||||||
const isDesktopApp = getIsElectronRuntime();
|
const isDesktopApp = getIsElectronRuntime();
|
||||||
const isMac = getShortcutOs() === "mac";
|
const isMac = getShortcutOs() === "mac";
|
||||||
|
|
||||||
|
// Only the modifier that actually performs the workspace-index jump on this
|
||||||
|
// runtime should reveal the sidebar number badges (Alt on web, Cmd on
|
||||||
|
// desktop Mac, Ctrl on desktop non-Mac). The store ORs altDown/cmdOrCtrlDown
|
||||||
|
// to drive badge visibility, so we set the flag matching this runtime.
|
||||||
|
const badgeModifierKey = getWorkspaceIndexJumpModifierKey({ isMac, isDesktop: isDesktopApp });
|
||||||
|
const setBadgeModifierDown = (down: boolean) => {
|
||||||
|
const state = useKeyboardShortcutsStore.getState();
|
||||||
|
if (isDesktopApp) {
|
||||||
|
state.setCmdOrCtrlDown(down);
|
||||||
|
} else {
|
||||||
|
state.setAltDown(down);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const shouldHandle = () => {
|
const shouldHandle = () => {
|
||||||
if (typeof document === "undefined") return false;
|
if (typeof document === "undefined") return false;
|
||||||
if (document.visibilityState !== "visible") return false;
|
if (document.visibilityState !== "visible") return false;
|
||||||
@@ -156,11 +171,8 @@ export function useKeyboardShortcuts({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const key = event.key ?? "";
|
const key = event.key ?? "";
|
||||||
if (key === "Alt" && !event.shiftKey) {
|
if (key === badgeModifierKey && !event.shiftKey) {
|
||||||
useKeyboardShortcutsStore.getState().setAltDown(true);
|
setBadgeModifierDown(true);
|
||||||
}
|
|
||||||
if (isDesktopApp && (key === "Meta" || key === "Control") && !event.shiftKey) {
|
|
||||||
useKeyboardShortcutsStore.getState().setCmdOrCtrlDown(true);
|
|
||||||
}
|
}
|
||||||
if (key === "Shift") {
|
if (key === "Shift") {
|
||||||
const state = useKeyboardShortcutsStore.getState();
|
const state = useKeyboardShortcutsStore.getState();
|
||||||
@@ -231,11 +243,8 @@ export function useKeyboardShortcuts({
|
|||||||
|
|
||||||
const handleKeyUp = (event: KeyboardEvent) => {
|
const handleKeyUp = (event: KeyboardEvent) => {
|
||||||
const key = event.key ?? "";
|
const key = event.key ?? "";
|
||||||
if (key === "Alt") {
|
if (key === badgeModifierKey) {
|
||||||
useKeyboardShortcutsStore.getState().setAltDown(false);
|
setBadgeModifierDown(false);
|
||||||
}
|
|
||||||
if (isDesktopApp && (key === "Meta" || key === "Control")) {
|
|
||||||
useKeyboardShortcutsStore.getState().setCmdOrCtrlDown(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
buildKeyboardShortcutHelpSections,
|
buildKeyboardShortcutHelpSections,
|
||||||
buildEffectiveBindings,
|
buildEffectiveBindings,
|
||||||
getBindingIdForAction,
|
getBindingIdForAction,
|
||||||
|
getWorkspaceIndexJumpModifierKey,
|
||||||
resolveKeyboardShortcut,
|
resolveKeyboardShortcut,
|
||||||
type ChordState,
|
type ChordState,
|
||||||
type KeyboardShortcutContext,
|
type KeyboardShortcutContext,
|
||||||
@@ -638,3 +639,18 @@ describe("keyboard-shortcut help sections", () => {
|
|||||||
).toBeNull();
|
).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getWorkspaceIndexJumpModifierKey", () => {
|
||||||
|
it("uses Alt on web, regardless of OS", () => {
|
||||||
|
expect(getWorkspaceIndexJumpModifierKey({ isMac: true, isDesktop: false })).toBe("Alt");
|
||||||
|
expect(getWorkspaceIndexJumpModifierKey({ isMac: false, isDesktop: false })).toBe("Alt");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses Cmd (Meta) on desktop Mac, not Control or Alt", () => {
|
||||||
|
expect(getWorkspaceIndexJumpModifierKey({ isMac: true, isDesktop: true })).toBe("Meta");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses Ctrl on desktop non-Mac, not Meta or Alt", () => {
|
||||||
|
expect(getWorkspaceIndexJumpModifierKey({ isMac: false, isDesktop: true })).toBe("Control");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1344,6 +1344,21 @@ export function getDefaultKeysForAction(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `KeyboardEvent.key` whose hold reveals the sidebar workspace-jump number
|
||||||
|
* badges. It must match the modifier of the active `workspace.navigate.index`
|
||||||
|
* binding for this runtime, otherwise the badges appear for a modifier that
|
||||||
|
* does not actually jump: Alt on web, Cmd (Meta) on desktop Mac, Ctrl on
|
||||||
|
* desktop non-Mac.
|
||||||
|
*/
|
||||||
|
export function getWorkspaceIndexJumpModifierKey(platform: {
|
||||||
|
isMac: boolean;
|
||||||
|
isDesktop: boolean;
|
||||||
|
}): "Alt" | "Meta" | "Control" {
|
||||||
|
if (!platform.isDesktop) return "Alt";
|
||||||
|
return platform.isMac ? "Meta" : "Control";
|
||||||
|
}
|
||||||
|
|
||||||
export function buildKeyboardShortcutHelpSections(
|
export function buildKeyboardShortcutHelpSections(
|
||||||
input: KeyboardShortcutPlatformContext,
|
input: KeyboardShortcutPlatformContext,
|
||||||
bindings: readonly ParsedShortcutBinding[] = DEFAULT_BINDINGS,
|
bindings: readonly ParsedShortcutBinding[] = DEFAULT_BINDINGS,
|
||||||
|
|||||||
Reference in New Issue
Block a user