Skip to lesson
Exit
Applied Coding & Editor Primitives1 / 3

1 min lesson

Applying a single edit

Use "Model an edit as a range you cut and a string you splice in" to say what you would do next.

Step 1 of 3

Applying a single editoffset + length + replacement

Model an edit as a range you cut and a string you splice in. The minimal shape is { offset, length, text }: delete length characters at offset, then insert text. Everything harder is built on this.

Learn more

Full explanation

Full explanation

The atom every editor edit decomposes into.ts
interface Edit {
  offset: number;  // 0-based start in the current buffer
  length: number;  // chars to delete (0 = pure insert)
  text: string;    // chars to insert ('' = pure delete)
}

function applyEdit(buf: string, e: Edit): string {
  return buf.slice(0, e.offset) + e.text + buf.slice(e.offset + e.length);
}

Composing many edits without corrupting positionswhere off-by-one bugs are born

The trap: every edit you apply shifts the offsets of every later edit. Apply edit A at offset 10 and an edit that used to target offset 50 now targets a different character. Two disciplines avoid the corruption.

  1. 1Resolve against one snapshot. Compute all edit offsets relative to the original buffer, never against the partially-mutated one.
  2. 2Apply right-to-left. Sort edits by descending offset and apply from the end of the file backward, so each edit lands before any unprocessed edit's position can shift.
Right-to-left application keeps earlier offsets valid throughout.ts
function applyEdits(buf: string, edits: Edit[]): string {
  const sorted = [...edits].sort((a, b) => b.offset - a.offset);
  for (const e of sorted) {
    if (e.offset < 0 || e.offset + e.length > buf.length) {
      throw new Error(`edit out of range at ${e.offset}`);
    }
    buf = buf.slice(0, e.offset) + e.text + buf.slice(e.offset + e.length);
  }
  return buf;
}
Position mapping is the real test

If two edits overlap, you have a conflict, not just a sort order. Detect it: after sorting by offset, if any edit's range intersects the next one's, reject the batch or merge deliberately. Saying this out loud, even if you don't code the merge, shows you've met this bug before.

Sanity checks before you call it done

Empty buffer with one insert. Pure delete at end-of-file. Two adjacent non-overlapping edits. One edit whose range runs off the end - does it throw or silently corrupt? Walk these in the interview; they're the cases that separate correct from almost-correct.

Learn more

Optional practice

Practice: Applying a single edit

QYou must apply a batch of non-overlapping edits to a buffer. Why apply them sorted by descending offset?