or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ace-editor.mddiff-editor.mdindex.mdsplit-editor.md

diff-editor.mddocs/

0

# Diff Editor

1

2

The Diff Editor component provides specialized functionality for comparing two pieces of text with visual highlighting of differences. It's built on top of the Split Editor and uses diff-match-patch for intelligent difference detection and highlighting.

3

4

## Capabilities

5

6

### DiffComponent

7

8

Diff editor component that compares two text sources and highlights their differences with visual indicators.

9

10

```typescript { .api }

11

/**

12

* Diff editor component for comparing and highlighting differences between two text sources

13

* Automatically detects changes and provides visual indicators for additions, deletions, and modifications

14

*/

15

declare class DiffComponent extends React.Component<IDiffEditorProps, IDiffEditorState> {}

16

17

interface IDiffEditorProps {

18

/** Starting cursor position */

19

cursorStart?: number;

20

/** Additional editor properties */

21

editorProps?: object;

22

/** Enable basic autocompletion */

23

enableBasicAutocompletion?: boolean | string[];

24

/** Enable live autocompletion */

25

enableLiveAutocompletion?: boolean | string[];

26

/** Auto-focus the diff editor on mount */

27

focus?: boolean;

28

/** Font size for both editor panes */

29

fontSize?: number;

30

/** Total height of the diff editor */

31

height?: string;

32

/** Highlight active line in both panes */

33

highlightActiveLine?: boolean;

34

/** Maximum lines for both editor panes */

35

maxLines?: number;

36

/** Minimum lines for both editor panes */

37

minLines?: number;

38

/** Syntax highlighting mode for both panes */

39

mode?: string;

40

/** Unique identifier for the diff editor instance */

41

name?: string;

42

/** CSS class name for the diff editor container */

43

className?: string;

44

/** Called when diff editor is fully loaded */

45

onLoad?: (editor: IEditorProps) => void;

46

/** Called when content changes in either pane */

47

onChange?: (value: string[], event?: any) => void;

48

/** Called when text is pasted into either pane */

49

onPaste?: (value: string) => void;

50

/** Called when either pane is scrolled */

51

onScroll?: (editor: IEditorProps) => void;

52

/** Split orientation ("beside" or "below") */

53

orientation?: string;

54

/** Make both editor panes read-only */

55

readOnly?: boolean;

56

/** Scroll margin for both editor panes */

57

scrollMargin?: number[];

58

/** Ace editor configuration options */

59

setOptions?: object;

60

/** Show line numbers in both panes */

61

showGutter?: boolean;

62

/** Show print margin in both panes */

63

showPrintMargin?: boolean;

64

/** Number of splits (typically 2 for diff view) */

65

splits?: number;

66

/** CSS styles for the diff editor container */

67

style?: object;

68

/** Tab size for both editor panes */

69

tabSize?: number;

70

/** Editor theme for both panes */

71

theme?: string;

72

/** Content for comparison [original, modified] */

73

value?: string[];

74

/** Total width of the diff editor */

75

width?: string;

76

/** Enable line wrapping in both panes */

77

wrapEnabled?: boolean;

78

}

79

80

interface IDiffEditorState {

81

/** Current content values [original, modified] */

82

value: string[];

83

}

84

```

85

86

### Usage Examples

87

88

**Basic Diff Comparison:**

89

90

```typescript

91

import React, { useState } from "react";

92

import { diff } from "react-ace";

93

94

import "ace-builds/src-noconflict/mode-javascript";

95

import "ace-builds/src-noconflict/theme-github";

96

97

const DiffEditor = diff;

98

99

function CodeComparison() {

100

const [values, setValues] = useState([

101

// Original code

102

`function calculateTotal(items) {

103

let total = 0;

104

for (let i = 0; i < items.length; i++) {

105

total += items[i].price;

106

}

107

return total;

108

}`,

109

// Modified code

110

`function calculateTotal(items) {

111

return items.reduce((total, item) => total + item.price, 0);

112

}`

113

]);

114

115

return (

116

<DiffEditor

117

mode="javascript"

118

theme="github"

119

value={values}

120

onChange={setValues}

121

name="code-diff"

122

width="100%"

123

height="400px"

124

fontSize={14}

125

showGutter={true}

126

highlightActiveLine={true}

127

/>

128

);

129

}

130

```

131

132

**Document Comparison with Headers:**

133

134

```typescript

135

import React, { useState } from "react";

136

import { diff } from "react-ace";

137

138

import "ace-builds/src-noconflict/mode-markdown";

139

import "ace-builds/src-noconflict/theme-github";

140

141

const DiffEditor = diff;

142

143

function DocumentDiff() {

144

const [originalDoc, setOriginalDoc] = useState(`# Project Documentation

145

146

## Overview

147

This project provides basic functionality.

148

149

## Features

150

- Feature A

151

- Feature B

152

153

## Installation

154

Run npm install to get started.`);

155

156

const [modifiedDoc, setModifiedDoc] = useState(`# Project Documentation

157

158

## Overview

159

This project provides comprehensive functionality with advanced features.

160

161

## Features

162

- Feature A (Enhanced)

163

- Feature B

164

- Feature C (New)

165

166

## Installation

167

Run npm install to get started.

168

169

## Configuration

170

Set environment variables before running.`);

171

172

const handleChange = (values) => {

173

setOriginalDoc(values[0]);

174

setModifiedDoc(values[1]);

175

};

176

177

return (

178

<div>

179

<div style={{ display: 'flex', marginBottom: '10px' }}>

180

<div style={{ flex: 1, textAlign: 'center', fontWeight: 'bold' }}>

181

Original

182

</div>

183

<div style={{ flex: 1, textAlign: 'center', fontWeight: 'bold' }}>

184

Modified

185

</div>

186

</div>

187

<DiffEditor

188

mode="markdown"

189

theme="github"

190

value={[originalDoc, modifiedDoc]}

191

onChange={handleChange}

192

name="document-diff"

193

width="100%"

194

height="500px"

195

fontSize={14}

196

showGutter={true}

197

orientation="beside"

198

/>

199

</div>

200

);

201

}

202

```

203

204

**Read-Only Diff Viewer:**

205

206

```typescript

207

import React from "react";

208

import { diff } from "react-ace";

209

210

import "ace-builds/src-noconflict/mode-json";

211

import "ace-builds/src-noconflict/theme-monokai";

212

213

const DiffEditor = diff;

214

215

interface DiffViewerProps {

216

beforeData: object;

217

afterData: object;

218

}

219

220

function DiffViewer({ beforeData, afterData }: DiffViewerProps) {

221

const values = [

222

JSON.stringify(beforeData, null, 2),

223

JSON.stringify(afterData, null, 2)

224

];

225

226

return (

227

<DiffEditor

228

mode="json"

229

theme="monokai"

230

value={values}

231

name="json-diff-viewer"

232

readOnly={true}

233

width="100%"

234

height="600px"

235

fontSize={14}

236

showGutter={true}

237

highlightActiveLine={false}

238

setOptions={{

239

showLineNumbers: true,

240

showFoldWidgets: true

241

}}

242

/>

243

);

244

}

245

```

246

247

**Diff with Custom Styling:**

248

249

```typescript

250

import React, { useState } from "react";

251

import { diff } from "react-ace";

252

253

const DiffEditor = diff;

254

255

function StyledDiffEditor() {

256

const [values, setValues] = useState([

257

"Original text content",

258

"Modified text content with changes"

259

]);

260

261

const customStyle = {

262

border: '2px solid #ccc',

263

borderRadius: '8px',

264

overflow: 'hidden'

265

};

266

267

return (

268

<div>

269

<style>{`

270

.diff-editor .ace_gutter {

271

background: #f5f5f5;

272

}

273

.diff-editor .ace_gutter-active-line {

274

background: #e8f4f8;

275

}

276

.diff-added {

277

background-color: #d4edda;

278

}

279

.diff-removed {

280

background-color: #f8d7da;

281

}

282

`}</style>

283

284

<DiffEditor

285

mode="text"

286

theme="github"

287

value={values}

288

onChange={setValues}

289

name="styled-diff"

290

className="diff-editor"

291

style={customStyle}

292

width="100%"

293

height="400px"

294

fontSize={14}

295

/>

296

</div>

297

);

298

}

299

```

300

301

**Vertical Diff Layout:**

302

303

```typescript

304

import React, { useState } from "react";

305

import { diff } from "react-ace";

306

307

import "ace-builds/src-noconflict/mode-html";

308

import "ace-builds/src-noconflict/theme-github";

309

310

const DiffEditor = diff;

311

312

function VerticalDiff() {

313

const [values, setValues] = useState([

314

'<div class="old-version">Old HTML</div>',

315

'<div class="new-version">New HTML with improvements</div>'

316

]);

317

318

return (

319

<DiffEditor

320

mode="html"

321

theme="github"

322

value={values}

323

onChange={setValues}

324

name="vertical-diff"

325

orientation="below"

326

width="100%"

327

height="600px"

328

fontSize={14}

329

showGutter={true}

330

splits={2}

331

/>

332

);

333

}

334

```

335

336

### Diff Features

337

338

**Automatic Difference Detection:**

339

340

The Diff Editor automatically detects and highlights:

341

- **Added lines**: New content in the modified version

342

- **Removed lines**: Content present in original but not modified

343

- **Changed lines**: Lines with modifications

344

- **Unchanged lines**: Content that remains the same

345

346

**Visual Indicators:**

347

348

- Different background colors for added/removed/changed content

349

- Line-by-line comparison with clear visual separation

350

- Gutter indicators showing change types

351

- Synchronized scrolling between panes

352

353

### Configuration Options

354

355

**Layout Configuration:**

356

357

```typescript { .api }

358

interface DiffLayoutConfig {

359

/** Split orientation */

360

orientation?: "beside" | "below";

361

/** Number of comparison panes */

362

splits?: number;

363

/** Synchronized scrolling */

364

syncScroll?: boolean;

365

}

366

```

367

368

**Diff-Specific Options:**

369

370

The Diff Editor inherits all standard Ace Editor options and adds diff-specific behavior:

371

372

- Automatic line-by-line comparison

373

- Visual difference highlighting

374

- Synchronized cursor movement (optional)

375

- Read-only mode for pure viewing

376

- Custom styling for different change types

377

378

### Event Handling

379

380

**Change Detection:**

381

382

```typescript { .api }

383

/** Called when content changes in either pane */

384

onChange?: (values: string[], event?: {

385

paneIndex: number;

386

changeType: 'addition' | 'deletion' | 'modification';

387

affectedLines: number[];

388

}) => void;

389

```

390

391

**Load Event:**

392

393

```typescript { .api }

394

/** Called when diff editor is fully loaded */

395

onLoad?: (editor: {

396

leftPane: Ace.Editor;

397

rightPane: Ace.Editor;

398

getDiffs: () => DiffResult[];

399

}) => void;

400

```

401

402

### Integration with diff-match-patch

403

404

The Diff Editor uses the diff-match-patch library internally for:

405

406

- Intelligent text comparison algorithms

407

- Efficient difference calculation

408

- Line-level and character-level diff detection

409

- Optimal highlighting placement

410

411

### Performance Considerations

412

413

- **Large Files**: Consider pagination or virtualization for very large files

414

- **Real-time Updates**: Use debouncing for frequently changing content

415

- **Memory Usage**: Diff calculations can be memory-intensive for large texts

416

- **Rendering**: Complex diffs may impact rendering performance

417

418

### Accessibility

419

420

The Diff Editor includes accessibility features:

421

422

- Keyboard navigation between panes

423

- Screen reader support for change descriptions

424

- High contrast mode compatibility

425

- Focus management for diff navigation