 updateKeys prefs.keys()
 
 CodeMirror.keyMap.dyalogDefault = fallthrough: 'default', F1: 'HLP', End: 'goLineEndSmart'
-CodeMirror.keyMap.dyalogDefault["'#{prefs.prefixKey()}'"] = (cm) ->
+CodeMirror.keyMap.dyalogDefault["'#{prefs.prefixKey()}'"] = 'BQC'
+
+CodeMirror.commands.BQC = (cm) ->
   if cm.dyalogBQ
     c = cm.getCursor(); cm.replaceSelection prefs.prefixKey(), 'end'
   else

    cm.setOption 'autoCloseBrackets0', cm.getOption 'autoCloseBrackets'
    cm.setOption 'autoCloseBrackets', false
    cm.on 'change', bqChangeHandler; cm.dyalogBQ = 1
    c = cm.getCursor(); cm.replaceSelection prefs.prefixKey(), 'end'
    ctid = delay 500, -> cm.showHint
      completeOnSingleClick: true
      extraKeys:
        Backspace: (cm, m) -> m.close(); cm.execCommand 'delCharBefore'; return
        Left:      (cm, m) -> m.close(); cm.execCommand 'goCharLeft'; return
        Right:     (cm, m) -> m.pick(); return
      hint: ->
        pk = prefs.prefixKey()
        data = from: c, to: cm.getCursor(), list: KS.map (k) ->
          if k == pk
            text: '', hint: bqbqHint, render: (e) -> e.innerHTML = "  #{pk}#{pk} <i>completion by name</i>"; return
          else
            v = bq[k]; text: v, render: (e) -> $(e).text "#{v} #{pk}#{k} #{squiggleDescriptions[v] || ''}  "; return
        CodeMirror.on data, 'close', -> bqCleanUp cm; return
        data
  return

# `x completions

@setBQMap = (bq1) -> $.extend bq, bq1; prefs.prefixMap join(for k, v of bq when v != (BQ[k] || ' ') then k + v); return

bqChangeHandler = (cm, o) -> # o: changeObj
  l = o.from.line; c = o.from.ch
  if o.origin == '+input' && o.text.length == 1 && o.text[0].length == 1
    x = o.text[0]; pk = prefs.prefixKey()
    if x == pk
      if c && cm.getLine(l)[c - 1] == pk then bqCleanUp cm; bqbqHint cm
    else
      bq[x] && cm.replaceRange bq[x], {line: l, ch: c - 1}, {line: l, ch: c + 1}, 'D'
      bqCleanUp cm
  else
    bqCleanUp cm
