/mismerge

A modern merge editor for the Web

Primary LanguageTypeScriptMIT LicenseMIT

npm bundle license demo

banner

banner

A web-based merge editor

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.

Features

  • ▶️ 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

Installation

npm i @mismerge/core

Usage

Svelte

<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>

React

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}
			/>
		</>
	);
}

Vue

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>

Customization

Adding syntax highlighting

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} />

Changing connections colors

<script>
	import { DefaultDarkColors } from '@mismerge/core';
	// ...
</script>

<MisMerge3 ... colors={DefaultDarkColors} />

Styles

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>

API

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

Contributing

Project setup

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

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

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.

Committing

This repository uses commitizen to enforce similar commit messages. Commit using:

npm run commit
# or
git cz