Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@codemirror/merge

codemirror525.5kMIT6.10.2TypeScript support: included

A diff/merge view for CodeMirror

editor, code, diff, merge

readme

@codemirror/merge NPM version

[ WEBSITE | ISSUES | FORUM | CHANGELOG ]

This package implements a merge interface for the CodeMirror code editor.

The project page has more information, a number of examples and the documentation.

This code is released under an MIT license.

We aim to be an inclusive, welcoming community. To make that explicit, we have a code of conduct that applies to communication around the project.

Usage

A split merge view can be created like this:

import {MergeView} from "@codemirror/merge"
import {EditorView, basicSetup} from "codemirror"
import {EditorState} from "@codemirror/state"

let doc = `one
two
three
four
five`

const view = new MergeView({
  a: {
    doc,
    extensions: basicSetup
  },
  b: {
    doc: doc.replace(/t/g, "T") + "\nSix",
    extensions: [
      basicSetup,
      EditorView.editable.of(false),
      EditorState.readOnly.of(true)
    ]
  },
  parent: document.body
})

Or a unified view like this:

import {EditorView, basicSetup} from "codemirror"
import {unifiedMergeView} from "@codemirror/merge"

const view = new EditorView({
  parent: document.body,
  doc: "one\ntwo\nthree\nfour",
  extensions: [
    basicSetup,
    unifiedMergeView({
      original: "one\n...\nfour"
    })
  ]
})

API Reference

Side-by-side Merge View

interface MergeConfig

Configuration options to MergeView that can be provided both initially and to reconfigure.

orientation⁠?: "a-b" | "b-a"

Controls whether editor A or editor B is shown first. Defaults to "a-b".

revertControls⁠?: "a-to-b" | "b-to-a"

Controls whether revert controls are shown between changed chunks.

renderRevertControl⁠?: fn() → HTMLElement

When given, this function is called to render the button to revert a chunk.

highlightChanges⁠?: boolean

By default, the merge view will mark inserted and deleted text in changed chunks. Set this to false to turn that off.

gutter⁠?: boolean

Controls whether a gutter marker is shown next to changed lines.

collapseUnchanged⁠?: {margin⁠?: number, minSize⁠?: number}

When given, long stretches of unchanged text are collapsed. margin gives the number of lines to leave visible after/before a change (default is 3), and minSize gives the minimum amount of collapsible lines that need to be present (defaults to 4).

diffConfig⁠?: DiffConfig

Pass options to the diff algorithm. By default, the merge view sets scanLimit to 500.

interface DirectMergeConfig extends MergeConfig

Configuration options given to the MergeView constructor.

a: EditorStateConfig

Configuration for the first editor (the left one in a left-to-right context).

b: EditorStateConfig

Configuration for the second editor.

parent⁠?: Element | DocumentFragment

Parent element to append the view to.

root⁠?: Document | ShadowRoot

An optional root. Only necessary if the view is mounted in a shadow root or a document other than the global document object.

class MergeView

A merge view manages two editors side-by-side, highlighting the difference between them and vertically aligning unchanged lines. If you want one of the editors to be read-only, you have to configure that in its extensions.

By default, views are not scrollable. Style them (.cm-mergeView) with a height and overflow: auto to make them scrollable.

new MergeView(config: DirectMergeConfig)

Create a new merge view.

a: EditorView

The first editor.

b: EditorView

The second editor.

dom: HTMLElement

The outer DOM element holding the view.

chunks: readonly Chunk[]

The current set of changed chunks.

reconfigure(config: MergeConfig)

Reconfigure an existing merge view.

destroy()

Destroy this merge view.

uncollapseUnchanged: StateEffectType<number>

A state effect that expands the section of collapsed unchanged code starting at the given position.

Unified Merge View

unifiedMergeView(config: Object) → Extension[]

Create an extension that causes the editor to display changes between its content and the given original document. Changed chunks will be highlighted, with uneditable widgets displaying the original text displayed above the new text.

config
original: Text | string

The other document to compare the editor content with.

highlightChanges⁠?: boolean

By default, the merge view will mark inserted and deleted text in changed chunks. Set this to false to turn that off.

gutter⁠?: boolean

Controls whether a gutter marker is shown next to changed lines.

syntaxHighlightDeletions⁠?: boolean

By default, deleted chunks are highlighted using the main editor's language. Since these are just fragments, not full documents, this doesn't always work well. Set this option to false to disable syntax highlighting for deleted lines.

syntaxHighlightDeletionsMaxLength⁠?: number

Deleted blocks larger than this size do not get syntax-highlighted. Defaults to 3000.

mergeControls⁠?: boolean

Controls whether accept/reject buttons are displayed for each changed chunk. Defaults to true.

diffConfig⁠?: DiffConfig

Pass options to the diff algorithm. By default, the merge view sets scanLimit to 500.

collapseUnchanged⁠?: {margin⁠?: number, minSize⁠?: number}

When given, long stretches of unchanged text are collapsed. margin gives the number of lines to leave visible after/before a change (default is 3), and minSize gives the minimum amount of collapsible lines that need to be present (defaults to 4).

acceptChunk(view: EditorView, pos⁠?: number) → boolean

In a unified merge view, accept the chunk under the given position or the cursor. This chunk will no longer be highlighted unless it is edited again.

rejectChunk(view: EditorView, pos⁠?: number) → boolean

In a unified merge view, reject the chunk under the given position or the cursor. Reverts that range to the content it has in the original document.

getOriginalDoc(state: EditorState) → Text

Get the original document from a unified merge editor's state.

originalDocChangeEffect(state: EditorState, changes: ChangeSet) → StateEffect<{doc: Text, changes: ChangeSet}>

Create an effect that, when added to a transaction on a unified merge view, will update the original document that's being compared against.

updateOriginalDoc: StateEffectType<{doc: Text, changes: ChangeSet}>

The state effect used to signal changes in the original doc in a unified merge view.

Chunks

class Chunk

A chunk describes a range of lines which have changed content in them. Either side (a/b) may either be empty (when its to is equal to its from), or points at a range starting at the start of the first changed line, to 1 past the end of the last changed line. Note that to positions may point past the end of the document. Use endA/endB if you need an end position that is certain to be a valid document position.

new Chunk(changes: readonly Change[], fromA: number, toA: number, fromB: number, toB: number, precise⁠?: boolean = true)
changes: readonly Change[]

The individual changes inside this chunk. These are stored relative to the start of the chunk, so you have to add chunk.fromA/fromB to get document positions.

fromA: number

The start of the chunk in document A.

toA: number

The end of the chunk in document A. This is equal to fromA when the chunk covers no lines in document A, or is one unit past the end of the last line in the chunk if it does.

fromB: number

The start of the chunk in document B.

toB: number

The end of the chunk in document A.

precise: boolean

This is set to false when the diff used to compute this chunk fell back to fast, imprecise diffing.

endA: number

Returns fromA if the chunk is empty in A, or the end of the last line in the chunk otherwise.

endB: number

Returns fromB if the chunk is empty in B, or the end of the last line in the chunk otherwise.

static build(a: Text, b: Text, conf⁠?: DiffConfig) → readonly Chunk[]

Build a set of changed chunks for the given documents.

static updateA(chunks: readonly Chunk[], a: Text, b: Text, changes: ChangeDesc, conf⁠?: DiffConfig) → readonly Chunk[]

Update a set of chunks for changes in document A. a should hold the updated document A.

static updateB(chunks: readonly Chunk[], a: Text, b: Text, changes: ChangeDesc, conf⁠?: DiffConfig) → readonly Chunk[]

Update a set of chunks for changes in document B.

getChunks(state: EditorState) → {chunks: readonly Chunk[], side: "a" | "b" | null} | null

Get the changed chunks for the merge view that this editor is part of, plus the side it is on if it is part of a MergeView. Returns null if the editor doesn't have a merge extension active or the merge view hasn't finished initializing yet.

goToNextChunk: StateCommand

Move the selection to the next changed chunk.

goToPreviousChunk: StateCommand

Move the selection to the previous changed chunk.

Diffing Utilities

class Change

A changed range.

new Change(fromA: number, toA: number, fromB: number, toB: number)
fromA: number

The start of the change in document A.

toA: number

The end of the change in document A. This is equal to fromA in case of insertions.

fromB: number

The start of the change in document B.

toB: number

The end of the change in document B. This is equal to fromB for deletions.

diff(a: string, b: string, config⁠?: DiffConfig) → readonly Change[]

Compute the difference between two strings.

presentableDiff(a: string, b: string, config⁠?: DiffConfig) → readonly Change[]

Compute the difference between the given strings, and clean up the resulting diff for presentation to users by dropping short unchanged ranges, and aligning changes to word boundaries when appropriate.

interface DiffConfig

Options passed to diffing functions.

scanLimit⁠?: number

When given, this limits the depth of full (expensive) diff computations, causing them to give up and fall back to a faster but less precise approach when there is more than this many changed characters in a scanned range. This should help avoid quadratic running time on large, very different inputs.

timeout⁠?: number

When set, this makes the algorithm periodically check how long it has been running, and if it has taken more than the given number of milliseconds, it aborts detailed diffing in falls back to the imprecise algorithm.

changelog

6.10.2 (2025-06-09)

Bug fixes

Fix an issue where chunks in the unified diff weren't updated properly when a single transaction changed for the original and the edited document.

6.10.1 (2025-05-14)

Bug fixes

Fix an issue in presentableDiff where it sometimes doesn't expand changes over words with multiple individual changes in them.

6.10.0 (2025-03-06)

New features

The new allowInlineDiffs option to unifiedMergeView will display chunks with only limited inline changes inline in the code.

6.9.0 (2025-03-03)

New features

The new diff option timeout can be used to make the algorithm bail out after a given amount of milliseconds.

Chunks now have a precise property that is false when the diff that the chunk is based on fell back to imprecise diffing (because of a scan depth limit or timeout).

6.8.0 (2024-12-30)

Bug fixes

Limit the size of highlighted chunks in the unified view, to prevent freezing the interface highlighting huge amounts of code.

Fix a regression that caused deleted chunks in the unified view to be rendered with strike-through style by default.

New features

Export the uncollapseUnchanged effect that is used to uncollapse sections of code.

6.7.5 (2024-12-17)

Bug fixes

Fix a bug that hid the accept/reject buttons for insertions in the unified merge view.

The lines shown around collapsed unchanged lines are now css :before/:after elements, so that they can be customized more easily.

Render deleted lines in the unified merge view as block elements, for easier styling.

6.7.4 (2024-11-13)

Bug fixes

In the unified diff view, fix an issue where empty deleted lines were rendered for chunks that deleted nothing.

Fix a bug that made the diff algorithm miss some obvious opportunities to align changes on line boundaries.

6.7.3 (2024-11-05)

Bug fixes

Fix an issue where the last line of a deleted chunk, if there is no text on it, was collapsed by the browser and not visible.

6.7.2 (2024-10-10)

Bug fixes

Fix a bug in presentableDiff that could cause it to produce corrupted diffs.

6.7.1 (2024-09-17)

Bug fixes

Improve the way presentableDiff aligns changes to line boundaries when possible.

6.7.0 (2024-08-18)

New features

unifiedMergeView now supports the collapseUnchanged option the way the split view does.

6.6.7 (2024-07-31)

Bug fixes

Fix a bug in the way spacers were inserted at the top of the viewport.

6.6.6 (2024-07-30)

Bug fixes

Improve vertical alignment of huge unchanged chunks in the side-by-side view.

6.6.5 (2024-07-18)

Bug fixes

Fix an issue that would corrupt the text displayed for some deleted lines in the unified merge view.

6.6.4 (2024-07-18)

Bug fixes

Fix syntax and change highlighting in deleted lines in the unified merge view.

6.6.3 (2024-06-07)

Bug fixes

Fix originalDocChangeEffect to apply the changes to the appropriate document.

6.6.2 (2024-05-17)

Bug fixes

Restore the default scan limit when diffing for chunks, which looks like it was accidentally dropped when it was made configurable in 6.3.0.

6.6.1 (2024-03-08)

Bug fixes

Fix a bug that could cause the set of changed chunks to be updated incorrectly on some types of changes.

6.6.0 (2024-01-25)

Bug fixes

Fix a bug where big deletions could corrupt the merge state.

New features

The state effect used to change the original document in a unified merge view is now available to client code as updateOriginalDoc.

6.5.0 (2024-01-04)

New features

The new changeOriginalDocEffect function can be used to update the reference document in a unified merge editor.

6.4.0 (2023-12-14)

New features

The getOriginalDoc function extracts the original document from a unified merge editor.

6.3.1 (2023-12-03)

Bug fixes

Add a userEvent annotation to transactions that accept a change in the unified merge view.

Fix CSS selectors in the merge view base theme to avoid affecting the style of non-merge view editors.

6.3.0 (2023-11-16)

New features

Merge views (and Chunk building methods) now take an optional diff config object to allow precision to be configured.

6.2.0 (2023-10-06)

New features

The package now exports goToNextChunk and goToPreviousChunk commands that allow by-changed-chunk document navigation.

6.1.3 (2023-09-28)

Bug fixes

Create alignment spacers for the whole document, not just the viewport, to avoid scroll position popping and misalignment.

6.1.2 (2023-08-18)

Bug fixes

Fall back to treating entire documents as changed when they are too large to compute a diff in a reasonable timeframe.

6.1.1 (2023-06-05)

Bug fixes

Fix a crash when unifiedMergeView is added to an existing state by reconfiguration.

6.1.0 (2023-05-06)

Bug fixes

Add <ins>/<del> tags around inserted and deleted lines to give screen readers a chance to communicate their role.

New features

The new unifiedMergeView extension can be used to display a diff inside a single editor, by inserting deleted content as widgets in the document.

6.0.2 (2023-04-18)

Bug fixes

Fix a bug that could cause diff to loop endlessly when the input contains astral characters in specific positions.

6.0.1 (2023-03-28)

Bug fixes

Fix a bug that would cause diffing to loop infinitely with some inputs.

6.0.0 (2023-03-22)

Bug fixes

Improve performance of the merge view when the inputs are almost entirely different.

New features

diff and presentableDiff now take an optional scanLimit option that can be used to trade speed for accuracy on very different inputs.

0.1.6 (2023-02-28)

Bug fixes

Fix a bug where changed chunks could be found in equal documents.

0.1.5 (2023-02-26)

New features

Chunk now exposes static methods for building an updating sets of chunks directly.

0.1.4 (2023-02-17)

Bug fixes

Fix a bug that caused an extra stray newline to be inserted when pressing the merge button for a change at the end of the document.

Avoid generating incorrect chunks for insertions or deletions at the end of the document.

0.1.3 (2022-12-09)

New features

It is now possible to change the configuration of a merge view with its reconfigure method.

0.1.2 (2022-12-05)

New features

The Chunk data structure, and the set of chunks kept by the merge view, are now part of the public interface.

The new orientation option makes it possible to show editor B first.

0.1.1 (2022-11-14)

Bug fixes

Color changed chunks in editor A red by default.

0.1.0 (2022-11-10)

Breaking changes

First numbered release.