Sublime Text 3 - End key toggles end of line and start of comment - sublimetext3

If I remember correctly, in Eclipse IDE you can press the End key and go to the end of a line, then again to go to the end of your code line, before the beginning of a comment. Here's an example with | as the cursor:
var str = 'press end to move the cursor here:'| // then here:|
It's very similar to how when you press Home it goes to the very start of the line, then another press moves the cursor to the beginning of your code, like this:
| |var str = 'press home to toggle cursor position';
Anyone know how to acheive this functionality in Sublime Text 3?

Sublime Text's native move and move_to commands don't support scopes or comments as an argument, therefore it is necessary to create a plugin in Python to achieve this behavior, and bind the End key to it.
From the Tools menu in Sublime Text, click New Plugin.
Replace the contents with the following:
import sublime, sublime_plugin
class MoveToEndOfLineOrStartOfCommentCommand(sublime_plugin.TextCommand):
def run(self, edit):
new_cursors = []
for cursor in self.view.sel():
cursor_end_pos = cursor.end()
line_end_pos = self.view.line(cursor_end_pos).end()
if line_end_pos == cursor_end_pos and self.view.match_selector(line_end_pos, 'comment'): # if the cursor is already at the end of the line and there is a comment at the end of the line
# move the cursor to the start of the comment
new_cursors.append(sublime.Region(self.view.extract_scope(line_end_pos).begin()))
else:
new_cursors.append(sublime.Region(line_end_pos)) # use default end of line behavior
self.view.sel().clear()
self.view.sel().add_all(new_cursors)
self.view.show(new_cursors[0]) # scroll to show the first cursor, if it is not already visible
Save it in the folder ST suggests, the name is unimportant as long as the extension is .py. (The command name for reference by the keybinding is based on the Python code/class name, not the file name.)
Goto Preferences menu -> Key Bindings - User and insert the following:
{ "keys": ["end"], "command": "move_to_end_of_line_or_start_of_comment" }
When pressing the End key, it will move to the end of the line as usual, unless it is already at the end of the line, and there is a comment, in which case it will move to the start of the comment.
Note that this is a tiny bit different to your example of:
var str = 'press end to move the cursor here:'| // then here:|
because it will move the cursor to after the whitespace at the end of the code like this:
var str = 'press end to move the cursor here:' |// then here:|
but it should give you a framework to work from. You can use the substr method of the view to get the characters in a certain region, so you can check for spaces using this quite easily.
EDIT: Note that since this answer was written, I have created a package for this functionality with some extra considerations, customization and use case support, as mentioned in another answer to this question.

Years later, I’ve stumbled onto this package: https://github.com/SublimeText/GoToEndOfLineOrScope
Sublime's scope documentation isn’t super easy to understand so it took a bit of digging and trial and error, but here’s a key binding that makes it work pretty well:
{
"keys": ["end"],
"command": "move_to_end_of_line_or_before_specified_scope",
"args": {
"scope": "comment.line",
"before_whitespace": true,
"eol_first": false
}
},
This makes the End key toggle between the end of the line and to the left of the comment delimiter, before any white space that trails code. It will also move to end of code first, then end of the line, saving a key press where that’s the intended behavior. It’s very easy to tweak though obviously.
The comment scope (as used above in Keith Hall’s answer) works too, but I don’t like the toggling behavior in block/multiline comments, so comment.line was a nice find.

Related

Vim copy line and comment out old line

I'm trying to achieve the same thing asked here, but in Vim.
Duplicate line and comment out old one
Basically I want to yank line, comment out the old one, paste new one, and keep cursor at the beginning of new line and end in insert mode.
For example:
def func (param)
will change to:
//def func (param)
def func (param)
I recorded a macro for it, put it into .vimrc and I'm using it via #y
" copy-and-comment-line macro
" yank line, comment out original line, move cursor at the begining
" of copied line and end in insert mode
let #y='yypkui//kdklkl'
(I'm not sure it will work for you as it contains unprintable ~# characters which code block won't display)
Macro works, but is there a built-in command in vim that I can achieve same thing with?
This mapping should do it for you:
nnoremap YOURKEY YI//<esc>p
The cursor will be on the pasted line.
replace YOURKEY by a key (or keys) you like
Note that this answer works only for your example, //style comment. If you want it to be generic solution, you have to build a function, in this function check the filetype, and decide which comment style should be used. There is no good built-in solution so far, but you can check the NERDCommenter or vim-commentary plugins to see how they achieve this, or you can install one of them (or a similar plugin) and call it's function in your mapping.

Substitute for vim replace in Sublime

I'm looking for a replacement for vim's "replace with character" command--specifically, I want to be able to select some text and replace each character with some character that I type (difficulty: No "vintage" mode)
Example:
Starting with
I am some text with an arbitrary number: 12358998281
I want an easy way to select 12358998281 and turn it into 99999999999, to make the result
I am some text with an arbitrary number: 99999999999
(in vim, this would be done by moving the cursor to the beginning of 12358998281, selecting with ve, then pressing r9)
I can do this by selecting the text, bringing up the "find" dialog, making sure "in selection" and "by regex" are enabled, searching for ., then typing my character into the resulting multiselect. This is incredibly laborious, however, and it prevents me from doing this process on a multiselect (for example, if 12358998281 exists in multiple parts of the file, I might want to quickly replace all instances of it with 99999999999, rather than performing the process above, getting the substitution, copying it to the clipboard, and then replacing with that).
Does Sublime have a command that acts like vim's "replace" that I can bind to something, or do I have to write a macro to get what I need? Or, am I approaching this from entirely the wrong direction?
A more generalized way of thinking of this is "how can I break a select into a multiselect on all characters", if that helps.
By using this package https://sublime.wbond.net/packages/RegReplace you can create regex patterns and bind them to shortcuts.
Also if there are multiple occurrences of one word, you can put cursor on whatever part of the word and press CTRL+D multiple times. One CTRL+D press will select the word under the cursor, every other press will select next occurrence of the word.
You could also use https://sublime.wbond.net/packages/Expand%20Selection%20to%20Whitespace to expand the selection to whitespace if your word contain some random characters, and then press CTDL+D to select next occurrences of the word.
Edit: With the package regex shortcuts indeed you have to create regexes before binding them. But the CTRL+D does work without it.
I don't see a problem with using "Expand selection to whitespace" and than doing the CTRL+D as I wrote in the answer.
I've checked the usage of visual as you wrote in the question and this solution seems much faster to do. You don't have to place cursor in the beggining of the word as It can be whereever in the word and no find/replace is needed, since you'll multiselect all occurrences by holding CTRL+D for a sec and You'll be free to edit it.
You can also use https://sublime.wbond.net/packages/Expand%20Selection%20to%20Quotes to select text inside quote and combine it with CTRL+D if standard CTRL+D doesn't work with some text, or if select to whitespace selects too much text.
I ended up solving this with a simple (if inelegant) plugin:
import sublime_plugin
import sublime
class MultiSelectWithinSelectedCommand(sublime_plugin.TextCommand):
def run(self, edit):
selection = self.view.sel()
new_regions = []
for selected_region in selection:
if selected_region.empty():
selection.add(self.view.word(selected_region))
for selected_region in selection:
if selected_region.a > selected_region.b:
region_begin = selected_region.b
else:
region_begin = selected_region.a
for pos in range(selected_region.size()):
subregion_begin = region_begin + pos
subregion_end = subregion_begin + 1
new_regions.append(sublime.Region(subregion_begin, subregion_end))
selection.clear()
selection.add_all(new_regions)
Once I've stuck this in my plugins directory, I would bind a command in the keymap file like usual:
{ "keys": ["alt+f"], "command": "multi_select_within_selected" }
(with alt+f chosen arbitrarily), and lo, multi-select on all selected characters with a keypress (after which, I can press my replacement character).

What key will skip to end of autocomplete?

I just started using Komodo by way of VS and Aptana. When I'm doing anything with parentheses, it helpfully autocompletes the closing parenthesis like in Aptana. My instinct is to then press TAB to skip to the end of the line, but that doesn't seem to work in Komodo. I've looked through the key bindings several times but I don't know what the action I'm looking for is actually called, so it doesn't do any good. How do I skip to the end of the autocomplete? The image below shows what the editor looks like when I want to skip to the end of the outlined parenthesis.
From http://docs.activestate.com/komodo/4.4/editor.html — "Cursor movement (e.g. moving over the soft character with the right-arrow) "hardens" soft characters."
Depending on what OS you're on, I expect the "go to end of line" character movement would have the same effect for multiple characters at once (i.e. the full autocomplete). Apple-right-arrow on OS X.
I know this is old, but press the "end" button to skip to the end of a line. This should do what you're asking.

Vim: replacing text within function body

I have some very useful plugins to find and replace text through files (see EasyGrep vim script - it's very helpful for programmers). I can even replace text only in the current buffer - by using plugins or :%s .... But what if I just want replace text within the current function body?
Consider the following example:
void f0()
{
int foo = 0;
// ...
}
// 99 other functions that uses foo as local variable.
void f100()
{
int foo = 0; // I want to replace foo with bar only in this function
// 1000 lines of code that uses foo goes below
// ...
}
Of course, I can use :%s ... with c flag for confirmation, but I believe there is a faster way to do this.
Thanks.
You can apply a substitution to the whole file using % or on a selection.
To create a selection :
Go in Visual mode Linewise for example, with Shift+v, select a few line and then type :.
Your prompt will look like :
:'<,'> it means : current selection
Type then s/foo/bar/g and it will replace foo by bar in the current selected line.
The better way to select a function content is to go inside a function with your cursor and type :
vi} it will select everything between { and }.
See :help text-objects for more tips on selection.
You could mark the function with V. Then when you type a command in :, it'll automatically be prefixed by and only be executed in the marked area.
There's probably a command for jumping to beginning of function and end of function, so you could do begin-function, V, end-function, substitute very quickly. Don't know those commands though.
I've always used [[ to jump to the beginning of the function, then use % to jump to the end of the function. I used mt and mb to mark the top and bottom of the function, respectively. Then to search and replace within the marked top and bottom, :'t,'bs/pattern/newpattern/g. This has always worked for me. I'm sure you can create a macro for this.
The visual select (vi}) is much easier and faster. It is aware of the cursor position. So, if the cursor is inside a fucntion sub block, then vi} selects all lines in that block. If you want to select the entire function, one needs to place the cursor outside of the sub blocks then do vi}. This is great for function blocks that fits in the current window. For functions that spans beyond the current window, the selection is lost once scroll up.
I really like the visual select of the vi} because it's so much easier and faster, but I have to resort the old school method on occasion.

Commenting out a function with NerdCommenter

Is there a way to do this? I know you can do all the obvious ones like ,c and ,cs
But I don't think there's a binding for commenting out an entire function...
From anywhere inside the function, do:
va{,c<space>
off course, you can map this to something:
:map ,o va{,c<space>
so pressing ,o inside a function will comment it (or uncomment it if it is already commented).
It depends..
It depends on how the function is, and where you are.
public function test()
{
$name = "whatever";
$data = array(
'name' => $name
);
return $data;
}
Scenario 1: Cursor Line 1 at public function test()
Sequence: Vj%
V Start linewise visual mode
j Go down one line
% Go to matching closing bracket
Scenario 2: Cursor Line 3 at $name = "whatever"
Sequence: va{ok
v Start visual mode
a{ Arround bracket
o Exchange cursor from top to bottom of selection
k Go up one line
Then, comment as usual ,,c depending on your Nerd Commenter mapping.
There are no binding for commenting out the whole function (as far as i know). I think there are couple of ways you can achieve this - for example you can place cursor on the closing bracket, go to the visual line mode, press % key (and select additional line if you place opening bracket in new line) and then use \cc for example.
When I want to achieve this i use textobj-user and textobj-rubyblock (I am currently programming mostly in Ruby) plugins, which allow me to easily select block of code with var and expand it with ar. That's quite nice, because I don't need to go to the end keyword (in C that would be closing bracket), but I select whole function without moving cursor from the function's body. I have not tried this, but for you this plugin should work. That's not a solution with one binding, but it's quite quick too. I hope this will be usefull for you. :)

Resources