From 630d436e1899f4f3bc02ad19a96118cfc696b178 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 28 Oct 2026 18:32:00 +0800 Subject: [PATCH] fix(editor): Allow selecting and copying text in read-only code previews (#136) Code previews (Find in Files, Usages) are non-editable CodeMirror views, so their text inherited the workbench's user-select: none and had no tab stop: it couldn't be focused, selected with the keyboard or copied. Previews now opt their content back in with the shared selectable-text class and take a tab stop; editing stays blocked. Same root cause as the read-only diff panes (#126). --- src/editor/core/cm/preview.test.ts | 18 ++++++++++++++++++ src/editor/core/cm/preview.ts | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/editor/core/cm/preview.test.ts diff --git a/src/editor/core/cm/preview.test.ts b/src/editor/core/cm/preview.test.ts new file mode 100644 index 000000000..8b4a1b3a0 --- /dev/null +++ b/src/editor/core/cm/preview.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vitest"; +import { EditorState } from "@codemirror/state"; +import { EditorView } from "@codemirror/view"; +import { selectableText } from "@/ui"; +import { previewExtensions } from "./preview"; + +describe("previewExtensions", () => { + it("keeps the read-only preview selectable and focusable", async () => { + const view = new EditorView({ + state: EditorState.create({ doc: "let a = 1;", extensions: await previewExtensions("/p/a.txt", undefined) }), + }); + expect(view.state.readOnly).toBe(true); + expect(view.contentDOM.getAttribute("contenteditable")).toBe("false"); + expect(view.contentDOM.getAttribute("tabindex")).toBe("0"); + expect(view.contentDOM.classList.contains(selectableText)).toBe(true); + view.destroy(); + }); +}); diff --git a/src/editor/core/cm/preview.ts b/src/editor/core/cm/preview.ts index 86fd2fb35..44f0ece8e 100644 --- a/src/editor/core/cm/preview.ts +++ b/src/editor/core/cm/preview.ts @@ -13,6 +13,7 @@ import { openideaTheme } from "./theme"; import { findLanguageDescription, loadSupport, loadedSupport, uiModeForPath } from "./languages"; import { fontExtension } from "./setup"; import { tx } from "@/platform/i18n"; +import { selectableText } from "@/ui"; export async function previewExtensions(path: string, settings: EditorSettings | undefined): Promise { const open = editorsFor(path)[0]?.ctx; @@ -26,7 +27,8 @@ export async function previewExtensions(path: string, settings: EditorSettings | syntaxHighlighting(openideaHighlightStyle), EditorState.readOnly.of(true), EditorView.editable.of(false), - EditorView.contentAttributes.of({ "aria-label": tx`Preview of ${path}` }), + // Not editable, so selection and Copy need the text opted back in and a tab stop. + EditorView.contentAttributes.of({ "aria-label": tx`Preview of ${path}`, class: selectableText, tabindex: "0" }), support ?? [], ]; }