     cm.setOption 'readOnly', false
     cm.setOption 'cursorHeight', 1
     l = cm.lineCount() - 1
-    if (why == 1 && !mod[l]) || why !in [1, 4]
+    if (why == 1 && !dirty[l]?) || why !in [1, 4]
       cm.replaceRange '      ', {line: l, ch: 0}, {line: l, ch: cm.getLine(l).length}, 'D'
     cm.setCursor l, cm.getLine(l).length
     return

autocompletion = require './autocompletion'
module.exports = (e, opts = {}) ->

  # keep track of which lines have been modified and preserve the original content
  mod = {} # line number -> original content

  hist = ['']
  histIndex = 0
  histAdd = (lines) -> hist[0] = ''; hist[1...1] = lines; histIndex = 0; return

    FD: -> histMove -1; return # Forward or Redo
    QT: QT = -> # Quit (and lose changes)
      c = cm.getCursor(); l = c.line
      if dirty[l] == 0
        if l == cm.lineCount() - 1
          cm.replaceRange '', {line: l - 1, ch: cm.getLine(l - 1).length}, {line: l, ch: cm.getLine(l).length}, 'D'
        else
          cm.replaceRange '', {line: l, ch: 0}, {line: l + 1, ch: 0}, 'D'
        delete dirty[l]; h = dirty; dirty = {}; for x, y of h then dirty[x - (x > l)] = y
      else if dirty[l]?
        cm.replaceRange dirty[l], {line: l, ch: 0}, {line: l, ch: cm.getLine(l).length}, 'D'
        delete dirty[l]; cm.removeLineClass l, 'background', 'modified'; cm.setCursor l + 1, c.ch
      return
    EP: QT # Exit (and save changes); in this case we are deliberately making QT and EP the same; Esc is an easier shortcut to discover than Shift-Esc
    ER: -> exec 0 # Enter
    TC: -> exec 1 # Trace

  exec = (trace) ->
    ls = for l of dirty then +l
    if ls.length
      ls.sort (x, y) -> x - y
      es = ls.map (l) -> cm.getLine l # strings to execute
      ls.reverse().forEach (l) ->
        cm.removeLineClass l, 'background', 'modified'
        if dirty[l] == 0
          cm.replaceRange '', {line: l, ch: 0}, {line: l + 1, ch: 0}, 'D'
        else
          cm.replaceRange dirty[l], {line: l, ch: 0}, {line: l, ch: cm.getLine(l).length}, 'D'
        return
    else
      es = [cm.getLine cm.getCursor().line]
    opts.exec es, trace; dirty = {}; histAdd es; return

  # CodeMirror supports 'dblclick' events but they are unreliable and seem to require rather a short time between the two clicks
  # So, let's track clicks manually:
