mirror of
https://github.com/stablyai/orca.git
synced 2026-10-26 16:02:42 +00:00
Preserve inline-code link labels in rich markdown
This commit is contained in:
@@ -20,6 +20,35 @@ function roundTripMarkdown(content: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function markdownAfterTextReplace(content: string, search: string, replacement: string): string {
|
||||
const editor = new Editor({
|
||||
element: null,
|
||||
extensions: createRichMarkdownExtensions(),
|
||||
content: encodeRawMarkdownHtmlForRichEditor(content),
|
||||
contentType: 'markdown'
|
||||
})
|
||||
|
||||
try {
|
||||
let from: number | null = null
|
||||
editor.state.doc.descendants((node, pos) => {
|
||||
if (from !== null || !node.isText || !node.text) {
|
||||
return
|
||||
}
|
||||
const index = node.text.indexOf(search)
|
||||
if (index !== -1) {
|
||||
from = pos + index
|
||||
}
|
||||
})
|
||||
if (from === null) {
|
||||
throw new Error(`Missing text: ${search}`)
|
||||
}
|
||||
editor.view.dispatch(editor.state.tr.insertText(replacement, from, from + search.length))
|
||||
return editor.getMarkdown().trimEnd()
|
||||
} finally {
|
||||
editor.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
function slashCommandMarkdown(commandId: SlashCommandId): string {
|
||||
const editor = new Editor({
|
||||
element: null,
|
||||
@@ -158,6 +187,36 @@ describe('rich markdown round trip', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves links whose label is inline code', () => {
|
||||
expect(roundTripMarkdown('Link to [`foo.md`](./foo.md) here\n')).toBe(
|
||||
'Link to [`foo.md`](./foo.md) here'
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves links whose label is inline code after an editor transaction', () => {
|
||||
expect(
|
||||
markdownAfterTextReplace('Link to [`foo.md`](./foo.md) here\n', 'here', 'here saved')
|
||||
).toBe('Link to [`foo.md`](./foo.md) here saved')
|
||||
})
|
||||
|
||||
it('preserves links when editing inside an inline-code label', () => {
|
||||
expect(markdownAfterTextReplace('Link to [`foo.md`](./foo.md) here\n', 'foo', 'bar')).toBe(
|
||||
'Link to [`bar.md`](./foo.md) here'
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves titled links whose label is inline code', () => {
|
||||
expect(roundTripMarkdown('Link to [`foo.md`](./foo.md "Foo") here\n')).toBe(
|
||||
'Link to [`foo.md`](./foo.md "Foo") here'
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves bold link labels as formatted link text', () => {
|
||||
expect(roundTripMarkdown('Link to [**bold**](./foo.md) here\n')).toBe(
|
||||
'Link to [**bold**](./foo.md) here'
|
||||
)
|
||||
})
|
||||
|
||||
it('does not surface Linear issue reference definitions as description text', () => {
|
||||
const input = [
|
||||
'- [x] [H-279]',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { AnyExtension } from '@tiptap/core'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import { Code } from '@tiptap/extension-code'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
@@ -28,6 +29,18 @@ import { createRichMarkdownAnnotationHighlightExtension } from './rich-markdown-
|
||||
|
||||
const lowlight = createLowlight(common)
|
||||
|
||||
const RichMarkdownLink = Link.extend({
|
||||
// Why: link's priority must stay below code's default 100 so Markdown
|
||||
// serializes code-styled labels as [`label`](href).
|
||||
priority: 90
|
||||
})
|
||||
|
||||
const RichMarkdownCode = Code.extend({
|
||||
// Why: Markdown supports linked code labels, so code cannot exclude the link
|
||||
// mark even though it should still stay exclusive with emphasis marks.
|
||||
excludes: 'code bold italic strike underline'
|
||||
})
|
||||
|
||||
export function createRichMarkdownExtensions({
|
||||
includePlaceholder = false
|
||||
}: {
|
||||
@@ -39,8 +52,10 @@ export function createRichMarkdownExtensions({
|
||||
// preview and then still lose syntax on save.
|
||||
StarterKit.configure({
|
||||
link: false,
|
||||
code: false,
|
||||
codeBlock: false
|
||||
}),
|
||||
RichMarkdownCode,
|
||||
CodeBlockLowlight.extend({
|
||||
addNodeView() {
|
||||
return safeReactNodeViewRenderer(RichMarkdownCodeBlock)
|
||||
@@ -49,7 +64,7 @@ export function createRichMarkdownExtensions({
|
||||
lowlight,
|
||||
defaultLanguage: null
|
||||
}),
|
||||
Link.configure({
|
||||
RichMarkdownLink.configure({
|
||||
openOnClick: false,
|
||||
autolink: true,
|
||||
linkOnPaste: true
|
||||
|
||||
Reference in New Issue
Block a user