Open Bug 433972 Opened 16 years ago Updated 2 years ago

[Mac] Emacs shortcuts parity: Ctrl-t should switch adjacent characters


(Core :: Widget: Cocoa, defect, P3)





(Reporter: nfagerlund, Unassigned)



User-Agent:       Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9pre) Gecko/2008051504 Minefield/3.0pre
Build Identifier: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9pre) Gecko/2008051504 Minefield/3.0pre

In a native Cocoa text view, ctrl-t swaps the positions of the characters on either side of the cursor. 

Exact reference behavior: 
- If the cursor is in the middle of a paragraph, the characters on either side of the cursor trade positions. The cursor moves forward one character so that it is after both of the characters it just switched.
- If the cursor is at the end of a paragraph, the last two characters trade positions. The cursor stays where it is.
- If the cursor is at the beginning of the *first* paragraph in the text view, nothing happens.
- If the cursor is at the beginning of any paragraph except the first one in the text view, the character after the cursor trades positions with the invisible newline character before the cursor. The cursor moves such that it is after both the newline and the former first character of the paragraph. Visually, this looks as though the cursor stays in the same place and the first character of the paragraph gets "kicked" back up to the previous paragraph. 

In all honestly, I find this feature to be useless and kind of offensive, and it'd probably be a pain to implement. But I'm doing emacs shortcut parity bugs this afternoon, so I'm including it for completeness' sake. 

Reproducible: Always
Depends on: 229473
Version: unspecified → Trunk
Not an XBL bug.  That said, this is by far the most useful of the emacs shortcuts that are missing on Mac.  I use it all the time in emacs itself (to fix typos when I've transposed two letters).

Oh, and Nicholas, thank you for the very clear description of the expected behavior!
Assignee: nobody → joshmoz
Component: XBL → Widget: Cocoa
Ever confirmed: true
QA Contact: xbl → cocoa
Ahaha, good -- I was hoping someone cared about this for reasons other than picture-straightening compulsiveness. 
Component: Widget: Cocoa → XBL
Component: XBL → Widget: Cocoa
Assignee: joshmoz → nobody
This ticket is very old, but this issue remains in Firefox to this day. Any chance of this getting fixed?
Also, I think this is a duplicate of
(In reply to echosa from comment #3)
> This ticket is very old, but this issue remains in Firefox to this day. Any
> chance of this getting fixed?

If someone who cares takes the time to write a patch and attach it, there's no reason to not fix this. It's a low priority bug, and there's always a lot of more important/urgent work to do.
For convenience, since was closed as a duplicate, here's my info comment from that ticket:

I also have this issue. I came here to report it, but see now that it was already reported. I submitted this issue to, to little avail, but there's additional info about reproducing the issue there. Specifically, there are some places where ctrl+t works, and many where it does not.

Here's a copy/paste of the important information: 

- The Firefox address/search bar: does not work. Not sure how to check or diagnose. 

- The Firefox page search: does not work. Also don't know how to diagnose. 

- The Facebook search bar: does not work. This is an HTML input tag. 

- The Facebook post text area: does work. This is a nested div, I assume that some JavaScript make it act as a text area. 

- The post area: does work. This is also a nested div, similar to the Facebook post text area. 

- The Tweetdeck post area: does not work. This is an HTML textarea tag. 

- The Twitter post area: does not work. This is nested divs, like Facebook and, however whereas those sites work, this one does not. 

- The DuckDuckGo search area: does not work. This is an HTML input tag. 

- The Fastmail email compose area: does not work. This is nested divs as well. Doesn't work, like Twitter. 

- This Mozilla Support forum: does not work. This text box I'm typing in right now is an HTML text area.
Priority: -- → P3
Rules 1-3 are correct.

Rule 4 is not wrong, but it's not really a special case.  It's just rule 1 again.  That is, it changes this (where |=cursor and nl=newline char):

    X nl | Y

into this:

    X Y nl |

which swaps the two characters around the cursor, and advances it by one, as per rule 1.

(Interestingly, both Emacs and standard Mac text areas do this, but Safari does a no-op in this particular case.)

The algorithm, then, is pretty simple:

 - If the cursor is at start-of-document, then do nothing.
 - Else if you're at the end of a line (character after cursor is newline or end-of-document), then swap the two previous characters.
 - Else, swap the two characters on either side of the cursor, and then advance the cursor by one position.

I'd add: if the user chooses "Undo" after pressing control-T, the characters are returned to their previous state, and both of the transposed characters (whether visible or newline) are selected.

Hi, I'm a new contributor and I'm interested in working on this bug. In, @emilio messaged me saying that the shortcut might be best added alongside undo and redo here:

It doesn't seem useful to support document.execCommand with this, so it would be added as a "no exec" command here: I think TransposeCharactersOperation could be a good name.

For input and textarea, that could be all that is necessary. In addition, it would be good to support:

  • html contenteditable, and
  • native Firefox UI elements such as the address bar and the bookmarks menu.

I'm a newbie to this project; any tips on how to approach this bug would be greatly appreciated!

Flags: needinfo?(masayuki)

I guess:

  1. Define new command for it as you said in widget/CommandList.h.
  2. Map native cocoa command to our internal command in widget/cocoa/, although I don't know which command is what the command reported to this bug.
  3. Then, the command will be set to WidgetKeyboardEvent's command list automatically.
  4. Then, it'll be call XUL command automatically by keypress event handler for editor.
  5. Declare command class and register it.
  6. Then, make it calls new public method of EditorBase from the command class.
  7. The new public method should be similar to EditorBase::InsertTextAsAction(), and perhaps, calls DeleteSelectionAsSubAction() and InsertTextAsSubAction() after creating AutoPlaceholderBatch to make it undo-able once.

However, I'm not sure how to compute the range for the "character". In HTMLEditor, you need to ignore invisible whitespaces with WSRunScanner. And you need to take care of surrogate-pair, IVS, etc for avoiding splitting them. So, it may be not easy work...

Flags: needinfo?(masayuki)

For plaintext editor it should be sorta straight forward shouldnt it?

(In reply to Emilio Cobos Álvarez (:emilio) from comment #12)

For plaintext editor it should be sorta straight forward shouldnt it?

Yes, it is. But there are a lot of contenteditable editor which looks simple text editor, for example, Google Spreadsheet's input box and Twitter's input box. I think that not supporting it in HTMLEditor makes users confused.

Severity: trivial → S4
You need to log in before you can comment on or make changes to this bug.