Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ import type { MarkdownNode } from "react-native-nitro-markdown/headless";

import { CopyTextButton } from "./CopyTextButton";
import { MarkdownTextPrimitive } from "./MarkdownTextPrimitive";
import {
nativeMarkdownDocumentRuns,
nativeMarkdownListItemBlocks,
nativeMarkdownTextRuns,
} from "./nativeMarkdownText";
import { nativeMarkdownDocumentRuns, nativeMarkdownListItemBlocks } from "./nativeMarkdownText";
import { NativeMarkdownSelectableText } from "./NativeMarkdownSelectableText.ios";
import type {
MarkdownCodeHighlighter,
MarkdownHighlightedToken,
NativeMarkdownTextStyle,
SelectableMarkdownSkill,
} from "./SelectableMarkdownText.types";

type HighlightedCode = ReadonlyArray<ReadonlyArray<MarkdownHighlightedToken>>;
Expand Down Expand Up @@ -48,12 +45,13 @@ function documentFor(node: MarkdownNode): MarkdownNode {

function SelectableNode(props: {
readonly node: MarkdownNode;
readonly skills: ReadonlyArray<SelectableMarkdownSkill>;
readonly textStyle: NativeMarkdownTextStyle;
readonly onLinkPress?: (href: string) => void;
}) {
return (
<NativeMarkdownSelectableText
runs={nativeMarkdownDocumentRuns(documentFor(props.node))}
runs={nativeMarkdownDocumentRuns(documentFor(props.node), props.skills)}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand Down Expand Up @@ -322,6 +320,7 @@ function collectTableRows(node: MarkdownNode): MarkdownNode[] {

function NativeTable(props: {
readonly node: MarkdownNode;
readonly skills: ReadonlyArray<SelectableMarkdownSkill>;
readonly textStyle: NativeMarkdownTextStyle;
readonly onLinkPress?: (href: string) => void;
}) {
Expand Down Expand Up @@ -359,7 +358,7 @@ function NativeTable(props: {
}}
>
<NativeMarkdownSelectableText
runs={nativeMarkdownTextRuns(cell).map((run) =>
runs={nativeMarkdownDocumentRuns(documentFor(cell), props.skills).map((run) =>
rowIndex === 0 || cell.isHeader ? { ...run, bold: true } : run,
)}
textStyle={props.textStyle}
Expand All @@ -376,6 +375,7 @@ function NativeTable(props: {

function NativeMarkdownImage(props: {
readonly node: MarkdownNode;
readonly skills: ReadonlyArray<SelectableMarkdownSkill>;
readonly textStyle: NativeMarkdownTextStyle;
readonly onLinkPress?: (href: string) => void;
}) {
Expand All @@ -384,6 +384,7 @@ function NativeMarkdownImage(props: {
return (
<SelectableNode
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand Down Expand Up @@ -445,6 +446,7 @@ function inlineGroups(nodes: ReadonlyArray<MarkdownNode>): MarkdownNode[] {

function NativeMixedParagraph(props: {
readonly node: MarkdownNode;
readonly skills: ReadonlyArray<SelectableMarkdownSkill>;
readonly textStyle: NativeMarkdownTextStyle;
readonly onLinkPress?: (href: string) => void;
}) {
Expand All @@ -455,13 +457,15 @@ function NativeMixedParagraph(props: {
<NativeMarkdownImage
key={nodeKey(child, index)}
node={child}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
) : (
<SelectableNode
key={nodeKey(child, index)}
node={child}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand All @@ -473,6 +477,7 @@ function NativeMixedParagraph(props: {

function NativeList(props: {
readonly node: MarkdownNode;
readonly skills: ReadonlyArray<SelectableMarkdownSkill>;
readonly textStyle: NativeMarkdownTextStyle;
readonly highlightCode: MarkdownCodeHighlighter;
readonly onLinkPress?: (href: string) => void;
Expand Down Expand Up @@ -534,6 +539,7 @@ function NativeList(props: {
<NativeMarkdownBlock
key={nodeKey(child, childIndex)}
node={child}
skills={props.skills}
textStyle={props.textStyle}
highlightCode={props.highlightCode}
onLinkPress={props.onLinkPress}
Expand All @@ -551,6 +557,7 @@ function NativeList(props: {

export function NativeMarkdownBlock(props: {
readonly node: MarkdownNode;
readonly skills: ReadonlyArray<SelectableMarkdownSkill>;
readonly textStyle: NativeMarkdownTextStyle;
readonly highlightCode: MarkdownCodeHighlighter;
readonly onLinkPress?: (href: string) => void;
Expand All @@ -566,6 +573,7 @@ export function NativeMarkdownBlock(props: {
<NativeMarkdownBlock
key={nodeKey(child, index)}
node={child}
skills={props.skills}
textStyle={props.textStyle}
highlightCode={props.highlightCode}
onLinkPress={props.onLinkPress}
Expand All @@ -587,6 +595,7 @@ export function NativeMarkdownBlock(props: {
return (
<NativeTable
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand All @@ -595,6 +604,7 @@ export function NativeMarkdownBlock(props: {
return (
<NativeMarkdownImage
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand Down Expand Up @@ -624,6 +634,7 @@ export function NativeMarkdownBlock(props: {
<NativeMarkdownBlock
key={nodeKey(child, index)}
node={child}
skills={props.skills}
textStyle={props.textStyle}
highlightCode={props.highlightCode}
onLinkPress={props.onLinkPress}
Expand All @@ -637,6 +648,7 @@ export function NativeMarkdownBlock(props: {
return (
<NativeList
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
highlightCode={props.highlightCode}
onLinkPress={props.onLinkPress}
Expand All @@ -647,12 +659,14 @@ export function NativeMarkdownBlock(props: {
return (props.node.children ?? []).some((child) => child.type === "image") ? (
<NativeMixedParagraph
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
) : (
<SelectableNode
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand All @@ -673,6 +687,7 @@ export function NativeMarkdownBlock(props: {
>
<SelectableNode
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand All @@ -690,6 +705,7 @@ export function NativeMarkdownBlock(props: {
<NativeMarkdownBlock
key={nodeKey(child, index)}
node={child}
skills={props.skills}
textStyle={props.textStyle}
highlightCode={props.highlightCode}
onLinkPress={props.onLinkPress}
Expand All @@ -703,6 +719,7 @@ export function NativeMarkdownBlock(props: {
return (
<SelectableNode
node={props.node}
skills={props.skills}
textStyle={props.textStyle}
onLinkPress={props.onLinkPress}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function SelectableMarkdownText({
chunk.kind === "rich" ? (
<NativeMarkdownBlock
node={chunk.node}
skills={skills}
textStyle={textStyle}
highlightCode={highlightCode}
onLinkPress={onLinkPress}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ function appendDocumentBlock(
function containsRichBlock(node: MarkdownNode): boolean {
if (
node.type === "code_block" ||
node.type === "blockquote" ||
Comment thread
chrisdeeming marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
node.type === "table" ||
node.type === "image" ||
node.type === "horizontal_rule" ||
Expand Down
54 changes: 53 additions & 1 deletion apps/mobile/src/lib/nativeMarkdownText.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,25 @@ describe("nativeMarkdownDocumentRuns", () => {
]);
});

it("decorates known skill references inside blockquotes", () => {
const node: MarkdownNode = {
type: "blockquote",
children: [
{
type: "paragraph",
children: [{ type: "text", content: "Use $ui for this." }],
},
],
};

expect(nativeMarkdownDocumentRuns(node, [{ name: "ui", displayName: "UI" }])).toContainEqual({
text: "$ui",
role: "body",
skillName: "ui",
skillLabel: "UI",
});
});

it("leaves unknown skill-like text unchanged", () => {
const node: MarkdownNode = {
type: "document",
Expand Down Expand Up @@ -328,7 +347,7 @@ describe("nativeMarkdownDocumentRuns", () => {
]);
});

it("includes quotes and fenced code in the same selectable string", () => {
it("preserves quotes and fenced code in document runs", () => {
const node: MarkdownNode = {
type: "document",
children: [
Expand Down Expand Up @@ -414,6 +433,39 @@ describe("nativeMarkdownListItemBlocks", () => {
});

describe("nativeMarkdownDocumentChunks", () => {
it("renders plain blockquotes as rich blocks so their marker spans wrapped lines", () => {
const blockquote: MarkdownNode = {
type: "blockquote",
beg: 0,
end: 120,
children: [
{
type: "paragraph",
children: [
{
type: "text",
content:
"Persistent random per-result keys are the strongest design, even when this text wraps.",
},
],
},
],
};

expect(
nativeMarkdownDocumentChunks({
type: "document",
children: [blockquote],
}),
).toEqual([
{
kind: "rich",
key: "rich:blockquote:0:120",
node: blockquote,
},
]);
});

it("keeps headings and plain lists in one selectable document", () => {
const document: MarkdownNode = {
type: "document",
Expand Down
Loading