Mismerge is a modern two-way and one-way merge editor for the web, built with Svelte. You can visit the demo and start merging now, or use it as a component for your project. It is also available in React and Vue.
▶️ One way merge editor- 🔀 Two way merge editor
- 📑 Support lines wrapping
- 🌈 Support syntax highlighting
- ➖ Can ignore whitespace
- 📜 Custom input history
- 🔠 Can ignore case
- 🔢 Blocks, words and chars counter
- ✅ Works in SvelteKit & TypeScript
- 🌎 Available in React & Vue
npm i @mismerge/core <script> import { MisMerge3 } from '@mismerge/core'; // Core styles, required for the editor to work properly import '@mismerge/core/styles.css'; import '@mismerge/core/light.css'; // Or '@mismerge/core/dark.css'; let lhs = 'foo'; let ctr = 'bar'; let rhs = 'baz'; </script> <!-- Left-hand side and right-hand side constant text --> <MisMerge3 {lhs} {rhs} bind:ctr /> <!-- All sides editable --> <MisMerge3 bind:lhs bind:ctr bind:rhs lhsEditable rhsEditable > <style> :global(.mismerge) { font-family: monospace; min-height: 600px; } </style>Install the additional adapter package:
npm i @mismerge/react import { DefaultDarkColors, MisMerge3 } from '@mismerge/react'; import { useEffect, useState } from 'react'; import '@mismerge/core/styles.css'; import '@mismerge/core/dark.css'; function App() { const [ctr, setCtr] = useState('Hello world!'); useEffect(() => { console.log(ctr); }, [ctr]); return ( <> <MisMerge3 lhs="Hello world!" ctr={ctr} rhs="Hello world!" onCtrChange={setCtr} colors={DefaultDarkColors} wrapLines={true} /> </> ); }Install the additional adapter package:
npm i @mismerge/vue Note
Due to some differences in how Vue treats boolean attributes, some default properties may not correspond to the ones described in the API section.
<script setup lang="ts"> import { MisMerge3, DefaultDarkColors } from '@mismerge/vue'; import '@mismerge/core/styles.css'; import '@mismerge/core/dark.css'; </script> <template> <MisMerge3 lhs="Hello" ctr="World" rhs="!" ctr-editable :colors="DefaultDarkColors" :on-ctr-change="console.log" /> </template>You need to provide your own syntax highlighter. Example and demo using Shiki-JS. The highlighter can be either sync or async.
<script> import { codeToHtml } from 'shiki'; // ... const highlight = async (text: string) => await codeToHtml(text, { lang: 'js', theme: 'min-dark' }); </script> <MisMerge3 ... {highlight} /><script> import { DefaultDarkColors } from '@mismerge/core'; // ... </script> <MisMerge3 ... colors={DefaultDarkColors} />If you want to customize the editor styles, you can copy the default light or dark theme and adapt it to your need.
Here is a basic explanation of how the the rendered html looks like:
<div class="mismerge"> <div> <!-- Main --> <div class="msm__main"> <!-- View --> <div class="msm__view"> <!-- Content --> <div class="msm__view-content"> <!-- Blocks wrapper --> <div class="msm__wrapper"> <!-- Blocks --> <div data-component-id="abcdefgh" class="msm__block block-type"> <!-- Lines --> <div class="msm__line"> <!-- ... --> </div> <!-- ... --> </div> <!-- ... --> </div> <!-- Highlight overlay --> <div class="msm__highlight-overlay"> <!-- ... --> </div> <!-- Input --> <textarea /> </div> <!-- Side panel --> <div class="msm__side-panel"> <!-- ... --> </div> </div> </div> </div> <!-- Footer --> <div class="msm__footer"> <!-- ... --> </div> </div>A list of properties for <MisMerge2>(2), <MisMerge3>(3), or both.
| Property | Type | Default | Description | Component |
|---|---|---|---|---|
lhs | string | "" | Left-hand side text | Both |
ctr | string | "" | Center text | 3 |
rhs | string | "" | Right-hand side text | Both |
colors | EditorColors | DefaultLightColors | Connections colors | Both |
highlight | (text: string) => string | Promise<string> | undefined | Syntax highlighter | Both |
lhsEditable | boolean | true(2), false(3) | Can edit left panel | Both |
ctrEditable | boolean | true | Can edit center panel | 3 |
rhsEditable | boolean | true(2), false(3) | Can edit right panel | Both |
lineDiffAlgorithm | 'characters' | 'words' | 'words_with_space' | words_with_space | Diff algorithm for same line side by side diff | Both |
disableMerging | boolean | false | Disables merging | Both |
wrapLines | boolean | false | Enables lines wrapping | Both |
disableWordsCounter | boolean | false | Disables words counter | Both |
disableCharsCounter | boolean | false | Disables chars counter | Both |
disableBlocksCounters | boolean | false | Disables blocks counter | Both |
disableFooter | boolean | false | Disables footer | Both |
ignoreWhitespace | boolean | false | Ignore whitespace in diff | Both |
ignoreCase | boolean | false | Ignore case in diff | Both |
conflictsResolved | boolean | - | Binding for when all conflicts have been resolved | 3 |
Events (available for Svelte):
| Name | Description |
|---|---|
on:merge | Fired when a block is merged from one side to an adjacent one |
on:resolve | Fired when a conflict has its resolved status toggled |
on:delete | Fired when a block is deleted in the center side |
on:input | Default textarea event |
on:keydown | Default textarea event |
on:keypress | Default textarea event |
on:keyup | Default textarea event |
Clone the repo:
git clone https://github.com/BearToCode/mismerge.git cd mismerge Download dependencies for all packages in the monorepo:
npm install The core package is inside packages/core. You can run the associated sveltekit app using npm run core or cd packages/core & npm run dev.
The demo is inside the demo root folder. You can run it from root using npm run demo or cd demo & npm run dev. It is automatically deployed to Github Pages with every push to master.
This repository uses commitizen to enforce similar commit messages. Commit using:
npm run commit # or git cz 
