Change:
import * as nls from 'vs/nls'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; <ins> import { isLowSurrogate, isHighSurrogate } from 'vs/base/common/strings'; </ins> import { Range } from 'vs/editor/common/core/range'; <ins> import { Position, IPosition } from 'vs/editor/common/core/position'; </ins> import { ICommand } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { registerEditorAction, EditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; <ins> import { ITextModel } from 'vs/editor/common/model'; </ins> class TransposeLettersAction extends EditorAction { <ins> private positionLeftOf(start: IPosition, model: ITextModel): Position { let column = start.column; let lineNumber = start.lineNumber; if (column > model.getLineMinColumn(lineNumber)) { if (isLowSurrogate(model.getLineContent(lineNumber).charCodeAt(column - 2))) { // character before column is a low surrogate column = column - 2; } else { column = column - 1; } } else if (lineNumber > 1) { lineNumber = lineNumber - 1; column = model.getLineMaxColumn(lineNumber); } return new Position(lineNumber, column); } private positionRightOf(start: IPosition, model: ITextModel): Position { let column = start.column; let lineNumber = start.lineNumber; if (column < model.getLineMaxColumn(lineNumber)) { if (isHighSurrogate(model.getLineContent(lineNumber).charCodeAt(column - 1))) { // character after column is a high surrogate column = column + 2; } else { column = column + 1; } } else if (lineNumber < model.getLineCount()) { lineNumber = lineNumber + 1; column = 0; } return new Position(lineNumber, column); } </ins> constructor() { super({ id: 'editor.action.transposeLetters',

Discussion:
VSCode Version: Version 1.3.0-insider (1.3.0-insider) 2016-06-30T05:01:53.185Z OS Version: OSX 10.11.5 (15F34) Steps to Reproduce: a new document, type 'ab'. the editor caret between the two characters. . In any standard OSX text area, this results in the text 'ba'. In VS Code, the result is 'bab', which I cannot imagine justifying as desirable. Note that there is a separate behavior when the caret is at end-of-line: in the EOL case, the previous two characters are transposed. VS Code handles this correctly; it is only the "in between" case that is broken (as far as I can tell). Any fix should make sure to test both cases.
I had a look in the source to see if I could fix this since it's driving me nuts. :) I think it may be an Electron issue since I don't see where this editor command is defined. I'm new to the source code so I may be missing it, but I don't see where a command is defined for ctrl-t.
This seems to have gotten worse recently; occasionally ctrl-t will cause multiple lines of text below the cursor to get duplicated into the text buffer.
do you have any idea if the likely source of this bug is in the vscode or electron code bases? I also went hunting around in vscode and could not find anything. I tried downloading an electron tutorial app but could not find a text field in which to test the problem. Any guidance here would be much appreciated.
For what it's worth the Atom app does not exhibit the broken vscode behavior. However, Atom's implementation has slightly different behavior than 'traditional' bash and native Cocoa controls. The traditional behavior is to transpose characters before and after the cursor AND move the cursor to after the transposed pair, or if there is no character after the cursor (end-of-line case) then transpose the preceding two characters. Atom transposes before and after characters around the cursor but does not move them; for the end-of-line case it does no transposition but instead moves the cursor back by one character.

I would assume that the solution would be to manually reimplement it, like VSCode already does for ^a ^e ^b ^f ^n ^p This extension does just that. It'd be nice if the functionality of this extension were bundled, since it's basic functionality that works on every other macOS textbox. The Sublime Text selection transpose is just bonus that's really nice.
Verified that when the cursor is in between 2 letters, they get transposed. But when cursor is at eol, previously last 2 letters were getting transposed. That doesn't happen anymore. ?
I tried ctrl+t in TextEdit and implemented the behaviour I observed there. Is the behaviour different than what TextEdit does?
I was basing my comment off of the OP's
ctrl+t in the editor now transposes characters like the default mac text editor. IMHO that is a good thing.
sadly it only matches half of the behavior; there are two cases. When I reported this bug I noted that the EOL case worked correctly but the in-between case did not. Now as of insiders build it appears that the situation has been reversed. Could we please reopen the issue? Thank you.
I just noticed that the start-of-line case is also incorrect: TextEdit transposes the newline before the caret with the character after the caret while VSCode simply advances the caret.
I cannot reproduce this issue. Using VS Code 1.12.1 and default key bindings. Move to have this issue closed?
This can probably be closed; I believe Transpose has been rewritten since then for Sublime compatibility?
VSCode does not match TextEdit behavior in the following cases: (where n is newline and ^ is the insertion caret). In all of these cases VSCode does nothing where TextEdit does a transpose operation.
This can be closed. I can't reproduce this issue too. (version: 1.13.1)
I can still reproduce the cases I describe above on OSX; VSCode Version 1.14.0-insider . I think that in order to close this issue somebody needs to explicitly decide that they want VSCode to ship with default behavior that does not match that of OSX and Cocoa.
I can reproduce, too. VS Code's and commands both do something different with each other and both different from the macOS/emacs standard.