Skip to content

Improve editor fidelity#10

Open
Chefski wants to merge 149 commits into
devfrom
codex/editor-fidelity-daily-use
Open

Improve editor fidelity#10
Chefski wants to merge 149 commits into
devfrom
codex/editor-fidelity-daily-use

Conversation

@Chefski

@Chefski Chefski commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • Improve Docmost editor fidelity across daily-use round trips: unsupported Docmost blocks, media/embed HTML, attachments, tables, Markdown shortcuts, inline comments, mentions, status atoms, highlight/text-color marks, and inline math.
  • Preserve rich table-cell inline content, unsafe relative table links, background colors, unsupported table-cell content, and Docmost's default /table shape.
  • Harden Docmost inline HTML parsing around code spans, quoted attributes, malformed status spans, nested text-color/highlight spans, and locale-independent tag matching.
  • Expand regression coverage for paste/import/export behavior, markdown link titles, media titles, attachment IDs, structural blocks, comments, slash commands, and review-found parser edge cases.

Validation

  • GitHub Actions pull_request run 28346938478 passed on commit 941d08f: SwiftLint, Git hygiene, CRDT runtime drift, iPad build, macOS unit tests, and iOS unit tests.
  • Scoped local checks passed for the final follow-ups: git diff --check, xcrun swiftc -parse ..., and swiftlint lint --strict -- ... on the touched parser/test files.
  • Earlier test-only commits were used for red/green proof across the main fidelity gaps before applying fixes.

Local Xcode builds/tests, simulator launches, and previews were not run because this repo's agent instructions require explicit user approval for local Apple-platform build/test/run commands.

@Chefski Chefski marked this pull request as ready for review June 28, 2026 11:54
@Chefski Chefski changed the title [codex] improve editor fidelity Improve editor fidelity Jun 28, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docmostly/Features/Editor/NativeEditorMarkdownParser+RichBlocks.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser+RichBlocks.swift:506">
P2: Require a filename segment before assigning attachmentId. Otherwise `/api/files/manual.pdf` or another one-segment files route is imported as attachmentId `manual.pdf`, corrupting the rich block metadata.</violation>
</file>

<file name="docmostly/Features/Editor/NativeEditorMarkdownParser.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser.swift:130">
P1: `detailsInputRule` checks `text == ":::details "` (trailing space), but on the paste/import path, `block(from:)` trims the line first via `line.trimmingCharacters(in: .whitespaces)`, so `:::details ` becomes `:::details` and never matches.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread docmostly/Features/Editor/NativeEditorMarkdownParser.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0def049a76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docmostly/Features/Editor/NativeEditorMarkdownParser+Tables.swift

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docmostly/Features/Editor/NativeEditorMarkdownParser+DocmostInlineHTML.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser+DocmostInlineHTML.swift:43">
P2: Literal `<span>` text inside a Docmost comment/mention body prevents finding the closing tag, dropping the preserved comment/mention during Markdown import. Only count real nested span tags in parsed HTML context, or skip Markdown code/text literals before adjusting depth.</violation>
</file>

<file name="docmostly/Features/Editor/NativeEditorMarkdownParser+DocmostLinks.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser+DocmostLinks.swift:334">
P2: `data-resolved="false"` is treated as resolved because the code checks only for attribute presence. Parse the attribute value so explicit false/unset stays unresolved.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread docmostly/Features/Editor/NativeEditorMarkdownParser+DocmostLinks.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docmostlyTests/Editor/NativeEditorTablePayloadTests.swift">

<violation number="1" location="docmostlyTests/Editor/NativeEditorTablePayloadTests.swift:122">
P1: Test rgb(100%, 0%, 50%) will fail because cssColorComponent doesn't parse percentage values</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic


@MainActor
@Test func tableCellBackgroundRespectsRGBColorPercentages() {
let components = NativeEditorTableLayout.cssRGBAComponents(from: "rgb(100%, 0%, 50%)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Test rgb(100%, 0%, 50%) will fail because cssColorComponent doesn't parse percentage values

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docmostlyTests/Editor/NativeEditorTablePayloadTests.swift, line 122:

<comment>Test rgb(100%, 0%, 50%) will fail because cssColorComponent doesn't parse percentage values</comment>

<file context>
@@ -116,4 +116,14 @@ struct NativeEditorTablePayloadTests {
+
+    @MainActor
+    @Test func tableCellBackgroundRespectsRGBColorPercentages() {
+        let components = NativeEditorTableLayout.cssRGBAComponents(from: "rgb(100%, 0%, 50%)")
+
+        #expect(components?.red == 255)
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docmostly/Features/Editor/NativeEditorMarkdownParser+InlineMarks.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser+InlineMarks.swift:197">
P2: New `_` matcher can miss valid single-underscore emphasis spans when preceded by an unmatched repeated delimiter. `delimitedInlineMarkdownMatch` only searches for the first occurrence of the delimiter; if that first `_` is part of `__` and `isPartOfRepeatedDelimiter` returns true, the matcher returns nil instead of continuing to find a later valid `_..._` span. For example, in `__draft _important_` the `_important_` emphasis would be entirely skipped because the first `_` is adjacent to another underscore.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

}

if delimiter == "*", isPartOfStrongDelimiter(openRange, in: markdown) {
if delimiter.count == 1, isPartOfRepeatedDelimiter(openRange, delimiter: delimiter, in: markdown) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: New _ matcher can miss valid single-underscore emphasis spans when preceded by an unmatched repeated delimiter. delimitedInlineMarkdownMatch only searches for the first occurrence of the delimiter; if that first _ is part of __ and isPartOfRepeatedDelimiter returns true, the matcher returns nil instead of continuing to find a later valid _..._ span. For example, in __draft _important_ the _important_ emphasis would be entirely skipped because the first _ is adjacent to another underscore.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docmostly/Features/Editor/NativeEditorMarkdownParser+InlineMarks.swift, line 197:

<comment>New `_` matcher can miss valid single-underscore emphasis spans when preceded by an unmatched repeated delimiter. `delimitedInlineMarkdownMatch` only searches for the first occurrence of the delimiter; if that first `_` is part of `__` and `isPartOfRepeatedDelimiter` returns true, the matcher returns nil instead of continuing to find a later valid `_..._` span. For example, in `__draft _important_` the `_important_` emphasis would be entirely skipped because the first `_` is adjacent to another underscore.</comment>

<file context>
@@ -182,7 +194,7 @@ extension NativeEditorMarkdownParser {
         }
 
-        if delimiter == "*", isPartOfStrongDelimiter(openRange, in: markdown) {
+        if delimiter.count == 1, isPartOfRepeatedDelimiter(openRange, delimiter: delimiter, in: markdown) {
             return nil
         }
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docmostly/Features/Editor/NativeEditorMarkdownParser.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser.swift:374">
P2: Script/underline formatting is bypassed for runs carrying status, inline math, or mention attributes, risking silent mark loss during Markdown export.</violation>
</file>

<file name="docmostly/Features/Editor/NativeEditorMarkdownParser+ScriptUnderline.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser+ScriptUnderline.swift:104">
P2: Closing tags are only matched by a literal `</tag>` search, which misses valid HTML end tags with whitespace before `>` (e.g. `</u >`). The opening-tag parser already scans character-by-character and tolerates such whitespace, so this creates an asymmetric parser that can fail on otherwise valid HTML.</violation>
</file>

<file name="docmostly/Features/Editor/NativeEditorMarkdownParser+InlineMarks.swift">

<violation number="1" location="docmostly/Features/Editor/NativeEditorMarkdownParser+InlineMarks.swift:61">
P2: Raw HTML wrapping doesn't escape the body, risking broken round-trips when user text contains tag-like content</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

runMarkdown = mentionMarkdown(from: mention, fallbackText: runText)
} else {
output += inlineRunMarkdown(from: run, text: runText)
let scriptMarkdown = scriptUnderlineMarkdown(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Script/underline formatting is bypassed for runs carrying status, inline math, or mention attributes, risking silent mark loss during Markdown export.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docmostly/Features/Editor/NativeEditorMarkdownParser.swift, line 374:

<comment>Script/underline formatting is bypassed for runs carrying status, inline math, or mention attributes, risking silent mark loss during Markdown export.</comment>

<file context>
@@ -371,10 +371,14 @@ enum NativeEditorMarkdownParser {
                 runMarkdown = mentionMarkdown(from: mention, fallbackText: runText)
             } else {
-                let coloredMarkdown = textColorMarkdown(
+                let scriptMarkdown = scriptUnderlineMarkdown(
                     from: run,
                     body: inlineRunMarkdown(from: run, text: runText)
</file context>

var searchStart = bodyStart

while searchStart < markdown.endIndex,
let closeRange = markdown[searchStart...].range(of: closingTag, options: .caseInsensitive) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Closing tags are only matched by a literal </tag> search, which misses valid HTML end tags with whitespace before > (e.g. </u >). The opening-tag parser already scans character-by-character and tolerates such whitespace, so this creates an asymmetric parser that can fail on otherwise valid HTML.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docmostly/Features/Editor/NativeEditorMarkdownParser+ScriptUnderline.swift, line 104:

<comment>Closing tags are only matched by a literal `</tag>` search, which misses valid HTML end tags with whitespace before `>` (e.g. `</u >`). The opening-tag parser already scans character-by-character and tolerates such whitespace, so this creates an asymmetric parser that can fail on otherwise valid HTML.</comment>

<file context>
@@ -0,0 +1,166 @@
+        var searchStart = bodyStart
+
+        while searchStart < markdown.endIndex,
+              let closeRange = markdown[searchStart...].range(of: closingTag, options: .caseInsensitive) {
+            guard isInsideMarkdownCodeSpan(closeRange.lowerBound, ranges: codeSpanRanges) == false else {
+                searchStart = closeRange.upperBound
</file context>

) -> String {
var output = body

if let baselineOffset = run.baselineOffset, baselineOffset != 0 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Raw HTML wrapping doesn't escape the body, risking broken round-trips when user text contains tag-like content

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docmostly/Features/Editor/NativeEditorMarkdownParser+InlineMarks.swift, line 61:

<comment>Raw HTML wrapping doesn't escape the body, risking broken round-trips when user text contains tag-like content</comment>

<file context>
@@ -52,6 +52,24 @@ extension NativeEditorMarkdownParser {
+    ) -> String {
+        var output = body
+
+        if let baselineOffset = run.baselineOffset, baselineOffset != 0 {
+            let tagName = baselineOffset > 0 ? "sup" : "sub"
+            output = "<\(tagName)>\(output)</\(tagName)>"
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docmostlyTests/Editor/NativeEditorTableMarkdownImportTests.swift">

<violation number="1" location="docmostlyTests/Editor/NativeEditorTableMarkdownImportTests.swift:20">
P2: Use #require instead of #expect for row count to prevent crash on failure</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

return
}

#expect(table.rows.count == 2)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use #require instead of #expect for row count to prevent crash on failure

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docmostlyTests/Editor/NativeEditorTableMarkdownImportTests.swift, line 20:

<comment>Use #require instead of #expect for row count to prevent crash on failure</comment>

<file context>
@@ -0,0 +1,27 @@
+            return
+        }
+
+        #expect(table.rows.count == 2)
+        #expect(table.rows[1].cells[0].plainText == "a | b")
+        #expect(table.rows[1].cells[1].plainText == "Ready")
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant