Skip to content

Add inline diff highlighting and side by side rendering with bulk actions#517

Open
LavaTiger99 wants to merge 5 commits intoglowingjade:mainfrom
LavaTiger99:Add-inline-diff-highlighting-and-side-by-side-rendering-with-bulk-actions
Open

Add inline diff highlighting and side by side rendering with bulk actions#517
LavaTiger99 wants to merge 5 commits intoglowingjade:mainfrom
LavaTiger99:Add-inline-diff-highlighting-and-side-by-side-rendering-with-bulk-actions

Conversation

@LavaTiger99
Copy link

@LavaTiger99 LavaTiger99 commented Jan 23, 2026

Description

This PR enhances the Apply view diff experience with several user-facing improvements: inline word/character highlighting for edits (with smarter similarity handling to avoid odd partial highlights), side‑by‑side diff rendering that collapses responsively in narrow panes, and clearer bulk actions that let you Accept All or Reject All remaining changes while preserving previously accepted/rejected blocks. It also refines the visual presentation with adjusted diff block styling and action placement, and ensures paragraph spacing is preserved when applying or rejecting changes.

Feat:
#478

image

Checklist before requesting a review

  • [X ] I have reviewed the guidelines for contributing to this repository.
  • [X ] I have performed a self-review of my code
  • [X ] I have performed a code linting check and type check (by running npm run lint:check and npm run type:check)
  • [X ] I have run the test suite (by running npm run test)
  • [X ] I have tested the functionality manually

Summary by CodeRabbit

  • New Features

    • Added bulk action buttons to Accept All Remaining Changes or Reject All Remaining Changes at once
    • Introduced inline diff highlighting that displays character and word-level modifications with clear visual distinction
  • Style

    • Refined diff block appearance with improved backgrounds and visual hierarchy
    • Enhanced responsive layout for optimal display across all device sizes

✏️ Tip: You can customize this high-level summary in your review settings.

-add inline diff tokens with word + char-level refinement and size guards
-render inline token spans in Apply View modified blocks
-style inline add/remove highlights
-add inline diff unit tests
-render modified blocks in a two-column grid
-add responsive stacking and empty-side spacing styles
-gate char-level diff by word similarity to avoid odd partial highlights
-merge added/removed tokens across whitespace for cleaner word-group highlights
-add padding/rounding to diff blocks and soften background intensity
-add block spacing to prevent action overlap
-pin accept badges inside block container
-change header actions to Accept All / Reject All with detailed tooltips
-apply remaining changes correctly for accept/reject
-keep paragraph spacing by tracking line counts in diff blocks
@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

This PR introduces inline token-level diff rendering with a new tokenization system using longest common subsequence (LCS) and optional character-level diffs. The apply view's acceptance mechanism is refactored to replace single accept/reject actions with "Accept All Remaining" and "Reject All Remaining" options. DiffBlock types are extended with line counts and inline token arrays for both original and modified sides. CSS updates enable responsive grid layouts and container queries.

Changes

Cohort / File(s) Summary
Diff Algorithm & Types
src/utils/chat/diff.ts
Introduces inline tokenization system with InlineToken type; adds LCS-based diffSequence algorithm, Levenshtein distance computation, and shouldUseCharDiff heuristic for character-level vs. word-level diff selection. Expands DiffBlock with lineCount (unchanged), originalLineCount/modifiedLineCount (modified), and optional originalTokens/modifiedTokens arrays. Refactors createDiffBlocks to populate inline tokens and normalize missing values.
Diff Testing
src/utils/chat/diff.test.ts
New test suite verifying inline tokenization for insertions, replacements, character-level highlights (e.g., "color" vs. "colour"), and word-level replacements with dissimilar substitutions. Uses getFirstModifiedBlock helper to extract modified blocks from createDiffBlocks output.
Apply View UI
src/components/apply-view/ApplyViewRoot.tsx
Replaces single-accept/single-reject with "Accept All Remaining" and "Reject All Remaining" actions via new buildContentFromDiff helper. Adds renderInlineTokens and renderSide helpers for inline token rendering with per-token styling. Adjusts diff-part handling to use lineCount fields with safe defaults and normalize missing values. Updates ARIA labels and UI text for multi-block semantics.
Styling
styles.css
Adds container-type: inline-size to input[type='text'] and #smtcmp-apply-view for container queries. Introduces grid-based layout for diff blocks (two-column at wide widths, one-column below 700px). Adds classes for inline diff rendering (.smtcmp-diff-block-grid, .smtcmp-diff-empty, .smtcmp-diff-inline-added, .smtcmp-diff-inline-removed). Reduces diff block background opacity (0.3 → 0.18), adjusts padding/border-radius, repositions diff block actions, and increases z-index for stacking context.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Improve Diff View #325: Both PRs modify the diff machinery (createDiffBlocks / src/utils/chat/diff.ts) and DiffBlock shape, with this PR building on that foundation by adding inline-token generation and rendering.
  • chore: Resolve minor issues #365: Both refactor ApplyViewRoot.tsx's per-block acceptance semantics, replacing the original accept/reject flow with new multi-action accept behaviors.

Poem

🐰 With tokens fine-tuned, line by line,
Diffs now shine with colors divine—
LCS hops through the word-dance floor,
Accept All, Reject All—choices galore!
Grid layouts bend, container queries bend,
Our diffs evolve, again and again!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main changes: inline diff highlighting, side-by-side rendering, and bulk actions.
Description check ✅ Passed The description covers all template sections: detailed summary of changes, feature reference, screenshot, and completed checklist items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@styles.css`:
- Around line 688-691: Empty diff placeholders are being coloured because
.smtcmp-diff-block.added/.removed override .smtcmp-diff-empty; change the rule
to a more specific selector so it wins when an element has both classes — e.g.
add a rule targeting .smtcmp-diff-block.added.smtcmp-diff-empty and
.smtcmp-diff-block.removed.smtcmp-diff-empty and set background: transparent
(avoid using !important).
🧹 Nitpick comments (1)
src/utils/chat/diff.ts (1)

176-193: Avoid UTF‑16 splitting in char-level diff.

split('') operates on UTF‑16 code units, which can split emoji/combining sequences and produce broken highlights. Consider Array.from (code points) or Intl.Segmenter (graphemes) for safer splitting.

♻️ Suggested tweak (code points)
-      const charOps = diffSequence(deletes.split(''), inserts.split(''))
+      const charOps = diffSequence(Array.from(deletes), Array.from(inserts))

Comment on lines +688 to +691
.smtcmp-diff-empty {
background: transparent;
min-height: var(--size-4-8);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "styles.css" -type f

Repository: glowingjade/obsidian-smart-composer

Length of output: 91


🏁 Script executed:

wc -l ./styles.css

Repository: glowingjade/obsidian-smart-composer

Length of output: 96


🏁 Script executed:

sed -n '680,700p' ./styles.css

Repository: glowingjade/obsidian-smart-composer

Length of output: 456


🏁 Script executed:

rg '\.smtcmp-diff-block\.(added|removed)' ./styles.css -A 5

Repository: glowingjade/obsidian-smart-composer

Length of output: 330


🏁 Script executed:

find . -type f \( -name "*.jsx" -o -name "*.js" -o -name "*.tsx" -o -name "*.ts" -o -name "*.html" \) | head -20

Repository: glowingjade/obsidian-smart-composer

Length of output: 877


🏁 Script executed:

rg 'smtcmp-diff-empty' ./src --type ts --type tsx -B 3 -A 3

Repository: glowingjade/obsidian-smart-composer

Length of output: 106


🏁 Script executed:

rg 'smtcmp-diff-empty' ./src -B 3 -A 3

Repository: glowingjade/obsidian-smart-composer

Length of output: 646


🏁 Script executed:

rg 'smtcmp-diff-empty' ./src/components/apply-view/ApplyViewRoot.tsx -B 10 -A 10

Repository: glowingjade/obsidian-smart-composer

Length of output: 678


Empty diff placeholders inherit added/removed tint due to CSS specificity.

When an empty diff block is rendered, it receives both .smtcmp-diff-block.added (or .removed) and .smtcmp-diff-empty classes. The compound selector .smtcmp-diff-block.added has specificity (0, 2, 0), while .smtcmp-diff-empty has only (0, 1, 0). This causes the colored background to override the transparent background.

🐛 Suggested CSS fix
-.smtcmp-diff-empty {
-  background: transparent;
-  min-height: var(--size-4-8);
-}
+.smtcmp-diff-block.smtcmp-diff-empty {
+  background-color: transparent;
+  min-height: var(--size-4-8);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.smtcmp-diff-empty {
background: transparent;
min-height: var(--size-4-8);
}
.smtcmp-diff-block.smtcmp-diff-empty {
background-color: transparent;
min-height: var(--size-4-8);
}
🤖 Prompt for AI Agents
In `@styles.css` around lines 688 - 691, Empty diff placeholders are being
coloured because .smtcmp-diff-block.added/.removed override .smtcmp-diff-empty;
change the rule to a more specific selector so it wins when an element has both
classes — e.g. add a rule targeting .smtcmp-diff-block.added.smtcmp-diff-empty
and .smtcmp-diff-block.removed.smtcmp-diff-empty and set background: transparent
(avoid using !important).

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