code: function setSelection(from, to, oldFrom, oldTo) {
        goalColumn = null;
        if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
        if (posEq(sel.from, from) && posEq(sel.to, to)) return;
        if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
  
        // Skip over hidden lines.
        if (from.line != oldFrom) {
          var from1 = skipHidden(from, oldFrom, sel.from.ch);
          // If there is no non-hidden line left, force visibility on current line
          if (!from1) setLineHidden(from.line, false);
          else from = from1;
        }
        if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
  
        if (posEq(from, to)) sel.inverted = false;
        else if (posEq(from, sel.to)) sel.inverted = false;
        else if (posEq(to, sel.from)) sel.inverted = true;
  
        if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
          var head = sel.inverted ? from : to;
          if (head.line != sel.from.line && sel.from.line < doc.size) {
            var oldLine = getLine(sel.from.line);
            if (/^\s+$/.test(oldLine.text))
              setTimeout(operation(function() {
                if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
                  var no = lineNo(oldLine);
                  replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
                }
              }, 10));
          }
        }
  
        sel.from = from; sel.to = to;
        selectionChanged = true;
      }
docs: Update the selection. Last two args are only used by updateLines, since they have to be expressed in the line numbers before the update.