diff --git a/src/edit/commands.js b/src/edit/commands.js index fe39ed727f63b123e3b0386f10f933c13459a5f8..0b0125d1e9e658d40933b95c57fc1c5e4c8f35e1 100644 --- a/src/edit/commands.js +++ b/src/edit/commands.js @@ -106,9 +106,17 @@ export let commands = { if (cm.somethingSelected()) cm.indentSelection("add") else cm.execCommand("insertTab") }, + // Swap the two chars left and right of each selection's head. + // Move cursor behind the two swapped characters afterwards. + // + // Doesn't consider line feeds a character. + // Doesn't scan more than one line above to find a character. + // Doesn't do anything on an empty line. + // Doesn't do anything with non-empty selections. transposeChars: cm => runInOp(cm, () => { let ranges = cm.listSelections(), newSel = [] for (let i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) continue let cur = ranges[i].head, line = getLine(cm.doc, cur.line).text if (line) { if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1) @@ -118,10 +126,12 @@ export let commands = { Pos(cur.line, cur.ch - 2), cur, "+transpose") } else if (cur.line > cm.doc.first) { let prev = getLine(cm.doc, cur.line - 1).text - if (prev) + if (prev) { + cur = new Pos(cur.line, 1) cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose") + Pos(cur.line - 1, prev.length - 1), cur, "+transpose") + } } } newSel.push(new Range(cur, cur)) diff --git a/test/emacs_test.js b/test/emacs_test.js index 124575c72421e447e80d02c5ee16d9651a499b01..628651c786b2d97ee774d28b95dc74a429bfe883 100644 --- a/test/emacs_test.js +++ b/test/emacs_test.js @@ -111,7 +111,7 @@ sim("transposeChar", "abcd\ne", "Ctrl-F", "Ctrl-T", "Ctrl-T", txt("bcad\ne"), at(0, 3), "Ctrl-F", "Ctrl-T", "Ctrl-T", "Ctrl-T", txt("bcda\ne"), at(0, 4), - "Ctrl-F", "Ctrl-T", txt("bcde\na"), at(1, 0)); + "Ctrl-F", "Ctrl-T", txt("bcde\na"), at(1, 1)); sim("manipWordCase", "foo BAR bAZ", "Alt-C", "Alt-L", "Alt-U", txt("Foo bar BAZ"),