What I Want To Do
My goal was to add a semi-colon at the end of my current line while maintaining my cursor position in the middle of the line.
e.g.
func([{''}])
// /\
// ||
// ||
// current cursor position
//
// Now I want to add a semi-colon to the end-of-the-line
// but then continue typing my string contents at the same
// cursor location. i.e. I now want this, with as few
// keystrokes as possible:
//
// Add this semi-colon...
// |
// |
// V
func([{''}]);
// /\
// ||
// ||
// ...while maintaining this cursor position
Why I Want To Do It
WebStorm nicely "completes" the punctuation as I type, i.e. after I type the ({[', it auto-completes to ({[' <<cursor here>> ']}). I want to make sure that I include the semicolon at the line's end now before I do more typing, 'cause I might forget later. After adding the semi-colon, however, I want to continue typing at the current cursor location. I know I can use auto-completion to add a semi-colon at the line's end, but this leaves the cursor at the end of the line forcing me to hit the back-arrow multiple times. Moreover, sometimes my half-completed line won't yet be correct JavaScript syntax, so auto-completion might not even work.
Why It Was Hard
The solution seemed easy: write a simple macro to jump to the end of the line, type a semi-colon, and return to my original location. The problem is, it's hard to figure out how to coax WebStorm to return to my original location! I tried setting a bookmark, going to line's end, typing a semi-colon, and returning to my bookmark, but that doesn't work because, as far as I can tell, bookmarks only remember the line, not the column. I tried first typing garbage marker text at my current location (e.g. xcursorx), going to line's end, typing a semi-colon, and doing a simple find of my garbage marker text, but that doesn't work either because WebStorm's macros don't seem to play nicely with entering text into the find routine. I tried first typing garbage marker text, going to line's end, typing a semi-colon, and using Navigate/Last Edit Location and deleting the garbage, but that also doesn't work.
What Eventually Worked
I made a macro as follows (keyboard shortcuts shown in individual steps are those from the "Mac OS X 10.5+" keymap...use whichever shortcuts or menu options are appropriate for your setup):
- starting with the cursor/caret at the desired location, start recording a macro (i.e.
Edit > Macros > Start Macro Recording)
- type a single non-space/non-word character, e.g. a period
- immediatly after that, type a single "word" of garbage marker text that you won't use anywhere else, e.g. "xcursorx"
- immediately after that, type another single non-space/non-word character, e.g. another period (i.e. you've now typed ".xcursorx.")
- jump to the end of the line (e.g. command-right arrow)
- type a semi-colon
- immediately after the semi-colon (i.e. no space), type the same single "word" of garbage marker text again but without the flanking non-space/non-word characters, e.g. type ";xcursorx"
- move the cursor back one "word" (e.g. option-left arrow)
- find the word at the cursor (i.e.
Edit > Find > Find Word at Caret) (do not use the normal find while manually typing in "xcursorx")
- delete the selected text (i.e. hit the delete or backspace key to delete the second "xcursorx" at the end of the line)
- find the previous occurrence of the last selected text (i.e.
Edit > Find > Find Previous/Move to Previous Occurrence or shift-command-G); this will select the "xcursorx" within the ".xcursorx."
- delete the selected text (i.e. hit the delete or backspace key)
- go forward one character (i.e. right arrow, to after the second period)
- delete two characters (i.e. hit delete or backspace twice, to delete the two periods)
- stop the macro recording (i.e.
Edit > Macros > Stop Macro Recording)
- give your macro a name (e.g. 'place-semicolon-at-end-of-line')
- give your macro a keyboard shortcut (e.g.
Preferences > (scroll down to) Macros > place-semicolon-at-end-of-line > (right click) > Add Keyboard Shortcut ... and enter the shortcut you want, e.g. option-semicolon)
Explanation of Some Obscure Steps
Not all of the above steps are required for some use-cases. e.g. Adding the extra periods is not needed for this to function in the example at the top using func([{''}]). However, the extra steps are required for some edge cases, e.g. if your cursor is already at the very end of the line.
How To Use It
To use the macro, begin with your normal typing (in the example at the top, type func([{' causing func([{''}]) to appear), type your shortcut (e.g. option-semicolon), and the semi-colon will appear at the end of the line, but your cursor will remain where it was.
Caveat
This solution is a bit of a hack, as the display does jump a little as the garbage text is inserted and then deleted. However, at least it works. If anyone can figure out how to accomplish the same end goal without requiring garbage marker text, that would be great.