diff --git a/registry/cell/CodeCell.tsx b/registry/cell/CodeCell.tsx
index 3b6b216..7ce8b88 100644
--- a/registry/cell/CodeCell.tsx
+++ b/registry/cell/CodeCell.tsx
@@ -9,6 +9,7 @@ import {
type CodeMirrorEditorRef,
} from "@/registry/editor/codemirror-editor";
import type { SupportedLanguage } from "@/registry/editor/languages";
+import { searchHighlight } from "@/registry/editor/search-highlight";
import { CellContainer } from "./CellContainer";
import { CompactExecutionButton } from "./CompactExecutionButton";
import type { JupyterOutput } from "./OutputArea";
@@ -84,6 +85,18 @@ interface CodeCellProps {
* Whether this is the last cell (affects Enter behavior)
*/
isLastCell?: boolean;
+ /**
+ * Search query for highlighting matches in editor and outputs
+ */
+ searchQuery?: string;
+ /**
+ * Character offset of the active search match in the editor (-1 for none)
+ */
+ searchActiveOffset?: number;
+ /**
+ * Callback when search match count changes (from outputs)
+ */
+ onSearchMatchCount?: (count: number) => void;
/**
* Additional CodeMirror extensions
*/
@@ -147,6 +160,9 @@ export function CodeCell({
onInsertCellAfter,
onFormat,
isLastCell = false,
+ searchQuery,
+ searchActiveOffset = -1,
+ onSearchMatchCount,
extensions,
className,
}: CodeCellProps) {
@@ -199,6 +215,15 @@ export function CodeCell({
[navigationKeyMap],
);
+ // Combine user extensions with search highlighting
+ const editorExtensions = useMemo(
+ () => [
+ ...(extensions ?? []),
+ ...searchHighlight(searchQuery ?? "", searchActiveOffset),
+ ],
+ [extensions, searchQuery, searchActiveOffset],
+ );
+
const handleExecute = useCallback(() => {
onExecute?.();
}, [onExecute]);
@@ -240,14 +265,21 @@ export function CodeCell({
language={language}
onValueChange={onUpdateSource}
keyMap={keyMap}
- extensions={extensions}
+ extensions={editorExtensions}
placeholder="Enter code..."
className="min-h-[2rem]"
autoFocus={isFocused}
/>
}
- outputContent={}
+ outputContent={
+
+ }
hideOutput={cell.outputs.length === 0}
/>
);
diff --git a/registry/cell/MarkdownCell.tsx b/registry/cell/MarkdownCell.tsx
index 2a95d15..96f73de 100644
--- a/registry/cell/MarkdownCell.tsx
+++ b/registry/cell/MarkdownCell.tsx
@@ -9,6 +9,7 @@ import {
CodeMirrorEditor,
type CodeMirrorEditorRef,
} from "@/registry/editor/codemirror-editor";
+import { searchHighlight } from "@/registry/editor/search-highlight";
import {
IsolatedFrame,
type IsolatedFrameHandle,
@@ -63,6 +64,10 @@ interface MarkdownCellProps {
* Whether this is the last cell (affects Enter behavior)
*/
isLastCell?: boolean;
+ /**
+ * Search query for highlighting matches in editor (edit mode) and rendered content (view mode)
+ */
+ searchQuery?: string;
/**
* Additional class name for the container
*/
@@ -114,6 +119,7 @@ export function MarkdownCell({
onFocusNext,
onInsertCellAfter,
isLastCell = false,
+ searchQuery,
className,
}: MarkdownCellProps) {
// Start in edit mode if cell is empty
@@ -252,6 +258,19 @@ export function MarkdownCell({
[navigationKeyMap, cell.source],
);
+ // Search highlighting for edit mode
+ const editorExtensions = useMemo(
+ () => searchHighlight(searchQuery ?? ""),
+ [searchQuery],
+ );
+
+ // Sync search to iframe when searchQuery changes (view mode)
+ useEffect(() => {
+ if (!editing && frameRef.current?.isReady) {
+ frameRef.current.search(searchQuery ?? "");
+ }
+ }, [searchQuery, editing]);
+
// Focus editor when entering edit mode (after initial mount)
const initialMountRef = useRef(true);
useEffect(() => {
@@ -309,6 +328,7 @@ export function MarkdownCell({
onValueChange={onUpdateSource}
onBlur={handleBlur}
keyMap={keyMap}
+ extensions={editorExtensions}
placeholder="Enter markdown..."
className="min-h-[2rem]"
autoFocus={editing}