Skip to content

Conversation

@Yazaven
Copy link

@Yazaven Yazaven commented Oct 22, 2025

Feature Preview

This PR adds LaTeX paste support to AppFlowy, allowing users to paste mathematical equations from ChatGPT and other sources directly into documents with proper rendering.

Fixes #8177

Summary

This PR implements comprehensive LaTeX equation parsing when pasting mathematical content into AppFlowy documents. Users can now copy LaTeX equations from ChatGPT, Gemini, or any other source and paste them directly into AppFlowy with correct rendering.

What this PR adds:

  • Automatic detection and parsing of LaTeX equations in pasted content
  • Support for piecewise functions with \begin{cases} environments
  • Support for aligned equations with \begin{aligned} environments
  • Support for array environments with \begin{array}
  • Proper handling of integrals, limits, series, and differential equations
  • Automatic line break conversion (single \ to double \\) for multi-line equations
  • Correct spacing for differential notation (, dx\, dx)
  • Smart detection of \text{...} blocks to preserve inline text formatting

Before:

beforef.mp4

After:

after.mp4

PR Checklist

  • My code adheres to AppFlowy's Conventions
  • I've listed at least one issue that this PR fixes in the description above.
  • I've added a test(s) to validate changes in this PR, or this PR only contains semantic changes.
  • All existing tests are passing.

Summary by Sourcery

Enable users to paste LaTeX equations directly into the editor by parsing and rendering mathematical content in both markdown and HTML paste flows.

New Features:

  • Add LaTeX paste support with a custom MarkdownMathEquationParser and preprocessing to detect and convert math blocks (including custom brackets) into rendered equations, handling cases, aligned, array environments, spacing normalization, and line breaks
  • Extend HTML paste workflow to detect mathematical and list content and route such content through markdown conversion for accurate structure and LaTeX rendering

Enables users to paste LaTeX-formatted content (e.g. =mc^2$, \[\int x dx\]) directly into the editor

Detects inline ($...$) and display (\[\]) LaTeX syntax on paste

Enhances usability for users working with mathematical or scientific content

Integrated into the existing paste handler logic

 Feature Preview

Paste ^2 + y^2 = z^2$  handled as LaTeX inline math

Paste \[\frac{a}{b}\]  handled as LaTeX display math

Plain text pastes remain unaffected

 PR Checklist

 My code adheres to AppFlowys conventions

 I've listed at least one issue that this PR fixes in the description above

 I've added a test(s) to validate changes in this PR, or this PR only contains semantic changes

 All existing tests are passing
@CLAassistant
Copy link

CLAassistant commented Oct 22, 2025

CLA assistant check
All committers have signed the CLA.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 22, 2025

Reviewer's Guide

Implements LaTeX paste support by adding preprocessing for bracketed LaTeX blocks, integrating a custom MarkdownMathEquationParser into the markdown-to-document flow, and updating HTML paste logic to detect math and list structures and route rich content through markdown conversion for proper rendering.

Sequence diagram for LaTeX paste processing in the editor

sequenceDiagram
    actor User
    participant EditorState
    participant MarkdownMathEquationParser
    participant Document
    User->>EditorState: Paste LaTeX content
    EditorState->>EditorState: Detect math/list structures in HTML
    EditorState->>MarkdownMathEquationParser: Parse Markdown for LaTeX blocks
    MarkdownMathEquationParser->>Document: Convert LaTeX to mathEquationNode
    Document->>EditorState: Render equation in document
Loading

Class diagram for MarkdownMathEquationParser and related changes

classDiagram
    class MarkdownMathEquationParser {
        +transform(element, parsers, listType, startNumber)
        -_looksLikeLaTeX(content)
        -_fixLatexSpacing(latex)
        -_fixLatexLineBreaks(latex)
    }
    class CustomMarkdownParser {
        <<abstract>>
        +transform(...)
    }
    MarkdownMathEquationParser --|> CustomMarkdownParser
    class Document {
        +root
        +customMarkdownToDocument(markdown, tableWidth)
    }
    class EditorState {
        +convertHtmlToNodes(html)
    }
    EditorState --> Document
    Document --> MarkdownMathEquationParser
Loading

Flow diagram for HTML paste handling with LaTeX detection

flowchart TD
    A["User pastes HTML content"] --> B["EditorState.convertHtmlToNodes"]
    B --> C{"Contains math/list structures?"}
    C -- Yes --> D["Convert HTML to Markdown"]
    D --> E["customMarkdownToDocument (with MarkdownMathEquationParser)"]
    E --> F["Document nodes with mathEquationNode"]
    C -- No --> G["htmlToDocument"]
    G --> H["Remove empty lines, convert tables"]
    H --> I{"Nodes empty or contains table?"}
    I -- Yes --> D
    I -- No --> F
Loading

File-Level Changes

Change Details Files
Integrate LaTeX preprocessing and parser into markdown-to-document conversion
  • Imported MarkdownMathEquationParser and added it to markdownParsers
  • Wrapped input with _preprocessLatexBlocks to detect and convert bracketed LaTeX into $$…$$
  • Implemented _preprocessLatexBlocks plus helper functions (_containsLaTeX, _fixLatexSpacing, _fixLatexLineBreaks)
  • Refactored customDocumentToMarkdown for explicit type annotations and minor formatting cleanup
frontend/appflowy_flutter/lib/shared/markdown_to_document.dart
Enhance HTML paste logic to detect math and lists and route through markdown conversion
  • Introduced heuristics (containsListStructures, containsMathContent) to identify rich content
  • Added shouldUseMarkdownConverter branching: use html2md.convert + customMarkdownToDocument for math/lists, else fallback to htmlToDocument
  • Preserved Apple Notes exception and existing table fallback within the new branching structure
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/copy_and_paste/paste_from_html.dart
Add MarkdownMathEquationParser to transform LaTeX blocks into mathEquationNode
  • Created MarkdownMathEquationParser with regex-based detection for $$…$$, […], plain [ ], and (…) delimiters
  • Implemented transform logic that applies _fixLatexLineBreaks and _fixLatexSpacing before emitting nodes
  • Added helper methods (_looksLikeLaTeX, _fixLatexSpacing, _fixLatexLineBreaks) to normalize formulas
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_math_equation_parser.dart

Assessment against linked issues

Issue Objective Addressed Explanation
#8177 Enable users to paste LaTeX mathematical equations into the editor and have them rendered correctly.
#8177 Support parsing and rendering of advanced LaTeX environments (e.g., piecewise functions, aligned equations, arrays) when pasted.
#8177 Improve readability of pasted notes containing LaTeX by handling line breaks, spacing, and inline text formatting appropriately.

Possibly linked issues

  • [FR] Paste with LaTex support #8177: The PR adds comprehensive LaTeX equation parsing, including support for various environments and formatting, directly addressing the issue's request for LaTeX paste support.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • There’s a lot of duplicated LaTeX logic (_fixLatexSpacing and _fixLatexLineBreaks) in both the preprocessor and the parser—consider moving those into a shared helper to keep the behavior in sync and reduce code duplication.
  • Many RegExp objects (e.g. the LaTeX detection and parsing patterns) are recreated on each call; extracting them as static final constants would improve performance and readability.
  • The fallback decision tree in paste_from_html is fairly complex—consider encapsulating that logic into a well-named helper or adding clarifying comments so future maintainers can follow when you switch between htmlToDocument vs. markdown conversion.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There’s a lot of duplicated LaTeX logic (_fixLatexSpacing and _fixLatexLineBreaks) in both the preprocessor and the parser—consider moving those into a shared helper to keep the behavior in sync and reduce code duplication.
- Many RegExp objects (e.g. the LaTeX detection and parsing patterns) are recreated on each call; extracting them as static final constants would improve performance and readability.
- The fallback decision tree in paste_from_html is fairly complex—consider encapsulating that logic into a well-named helper or adding clarifying comments so future maintainers can follow when you switch between htmlToDocument vs. markdown conversion.

## Individual Comments

### Comment 1
<location> `frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_math_equation_parser.dart:96-105` </location>
<code_context>
+  /// Ensure common spacing in LaTeX (e.g. `\, dx`).
+  String _fixLatexSpacing(String latex) {
+    String result = latex;
+    result = result.replaceAll(', dx', r'\, dx');
+    result = result.replaceAll(', dy', r'\, dy');
+    result = result.replaceAll(', dz', r'\, dz');
+    result = result.replaceAll(', dt', r'\, dt');
+    result = result.replaceAll(', dV', r'\, dV');
+    result = result.replaceAll(', dA', r'\, dA');
+    result = result.replaceAll(', ds', r'\, ds');
+    result = result.replaceAll(', du', r'\, du');
+    result = result.replaceAll(', dv', r'\, dv');
+    result = result.replaceAll(', dw', r'\, dw');
+    return result;
+  }
</code_context>

<issue_to_address>
**suggestion:** The _fixLatexSpacing function duplicates logic from markdown_to_document.dart.

Refactor the spacing logic into a shared utility to reduce duplication and maintain consistency.

Suggested implementation:

```
import 'package:appflowy_flutter/plugins/document/presentation/editor_plugins/parsers/markdown_latex_utils.dart';

  /// Ensure common spacing in LaTeX (e.g. `\, dx`).
  String _fixLatexSpacing(String latex) {
    return fixLatexSpacing(latex);
  }

```

You must also:
1. Create a new file `frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_latex_utils.dart` (if it doesn't exist).
2. Move the LaTeX spacing logic into a public function, e.g.:
```dart
String fixLatexSpacing(String latex) {
  String result = latex;
  result = result.replaceAll(', dx', r'\, dx');
  result = result.replaceAll(', dy', r'\, dy');
  result = result.replaceAll(', dz', r'\, dz');
  result = result.replaceAll(', dt', r'\, dt');
  result = result.replaceAll(', dV', r'\, dV');
  result = result.replaceAll(', dA', r'\, dA');
  result = result.replaceAll(', ds', r'\, ds');
  result = result.replaceAll(', du', r'\, du');
  result = result.replaceAll(', dv', r'\, dv');
  result = result.replaceAll(', dw', r'\, dw');
  return result;
}
```
3. Update any other files (e.g., `markdown_to_document.dart`) to use this shared utility instead of duplicating the logic.
</issue_to_address>

### Comment 2
<location> `frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_math_equation_parser.dart:119-120` </location>
<code_context>
+      return latex;
+    }
+
+    // Avoid sequences like " \-" being treated poorly.
+    String result = latex.replaceAll(RegExp(r'(?<!\\)\\-'), r'\\ -');
+
+    // Replace single backslash followed by spaces and a letter/digit with a double
</code_context>

<issue_to_address>
**suggestion:** The line break fixer may introduce unintended formatting changes.

The current replacement logic could unintentionally alter valid LaTeX. Please clarify the intent with comments or refine the checks to avoid modifying correct syntax.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Yazaven Yazaven closed this Oct 22, 2025
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.

[FR] Paste with LaTex support

2 participants