PhpStorm: any solution for 4 annoying problems? - regex

I'm a rather happy PhpStorm user, but there are a few things that really annoy me, but I'm not a settings expert and wish there is a solution for them (editing PHP files) :
Navigation
Often in the editor, one want to go back to where the cursor was 100 lines above etc... And in PhpStorm Back Alt-Shift-Left and Forward Alt-Shift-Right do this - but they follow an algorithm that is beyond me: it definitely misses "steps" (e.g. from line 500 go to line 300 using keys like arrows or -even worse- page-up/down, then Alt-Shift-Left doesn't bring you back to line 500)
=> Is there a way to refine the conditions that drive the behavior of Back and Forward?
Indentation
Is there a way to refine the indentor behavior? For instance
$a = array('X' => 'Something',
'Y' => 'Something else',[RETURN]
^ ^
now there
like in Emacs the cursor would go there right under the first quote after the spaces (and not at now where PS goes)?
=> Is a regexp (or something else) able to refine the behavior of the indentor, Not only for this very specific case but for the behavior in general?
(Not mentioning another problem when Shift-Inserting where the indent is often unreliable)
Quotes (automatic)
I don't want to disable the automatic quoting feature as it is sometimes convenient, but it seems the algorithm doesn't parse correctly the environment where the " or ' is inserted (don't have an example right now but at times it was annoying, like inserting 2 " unexpectedly while only one is required, deleting one will actually delete the 2 (normal because they were inserted automatically... but I needed 1 only!) so have in this case to trick PhpStorm to force a 1 ").
=> Is there a regexp or similar to control the quoting behavior?
Select via Shift-Arrow (for instance, to delete...)
Almost forgot: PhpStorm remembers at which column the cursor is when navigating Up and Down. Fine. But when one want to select (using Shift and Up/Down Arrows) from beginning of line it is usually to select lines. Not a line-to-where-cursor-was-earlier. An example will explain better: * is where the cursor is [beginning of line 3], % is where the cursor was [middle of line 2]
1. $x = 'string';
2. $y = %'string';
3.*
doing Shift-Up will select (all s)
1. $x = 'string';
2. $y = *sssssssss
3.
while in the specific case of a selection, it should select that:
1. $x = 'string';
2.*sssssssssssssssss
3.
not sure there is a way to configure that though - just in case there is?
Thanks

Oh well...
1) Is there a way to refine the conditions that drive the behavior of Back and Forward?
No. Maybe (just maybe) it takes into consideration what you were doing at that location (even if you done nothing, then maybe how long the pause was). But mainly it looks at editing activity, navigation events (jump to declaration/implementation etc).
2) Is a regexp (or something else) able to refine the behavior of the indentor, Not only for this very specific case but for the behavior in general?
RegEx -- definitely no. This question is not clear for me anyway -- are you talking about formatting or navigation? If first -- then all currently existing settings are in "Settings | Code Style". If second -- then check "Settings | Editor | Smart keys" -- maybe they will help.
Otherwise -- please record some screencast/bunch of screenshots for current and desired behaviour and submit it as a new ticket to the Issue Tracker: http://youtrack.jetbrains.com/issues/WI
3) Is there a regexp or similar to control the quoting behavior?
No. You explanation is not clear enough. I suggest the same as for #2 -- get a code example and submit it as a new ticket to the Issue Tracker: http://youtrack.jetbrains.com/issues/WI . This way it may gets implemented/fixed for next version
4) not sure there is a way to configure that though - just in case there is?
Don't know. I'm also facing this usability issue and would like to know workaround. The way I'm using it -- pressing "Home" before (or during/after) making the selection (not ideal "solution" as it is still annoying to do so, but works). Alternatively you can use mouse to select the lines (use it over editor gutter area -- where the line numbers are).
If selection is to just delete/duplicate the line -- then there are shortcuts just for that.

Regarding quotes, in cases when you just want the one quote, hit del instead of backspace after typing ".
I've some qualms about the indentation (and code (re)formatting in general) too, but it's that it changes from release to release, there's not much you can do about it though...
Re: selection - in your case you can just hit Home while still holding shift. It never even registered to me as unexpected behavior.

Related

Find and replace in Visual Studio code in a selection

I have the following line in a file I'm editing in VSCode:
...............111.........111.............111..
I want to replace all .s with 0s. However, when I highlight the line and do a find/replace for .s, all the .s in the document are replaced, not just the ones in the line I've select, even when I toggle the "Find in selection" button. Is this a bug? In other editors, if I select a chunk of text and then do a find/replace, it will only find/replace matches within the selected block.
Below is a snippet that you should be able to reproduce the issue with. The ...............111.........111.............111.. line is inside the test_unicode function.
def test_simple2(self):
"""Simple CSV transduction test with empty fields, more complex idx, different pack_size.
100011000001000 ->
..........111....................111..........11111..........111..
"""
field_width_stream = pablo.BitStream(int('1000110001000001000', 2))
idx_marker_stream = pablo.BitStream(int('11101', 2))
pack_size = 4
target_format = TransductionTarget.JSON
csv_column_names = ["col1", "col2", "col3", "col4", "col5"]
pdep_marker_stream = pablo.BitStream(generate_pdep_stream(field_width_stream,
idx_marker_stream,
pack_size, target_format,
csv_column_names))
self.assertEqual(pdep_marker_stream.value, 63050402300395548)
def test_unicode(self):
"""Non-ascii column names.
Using UTF8. Hard coded SON boilerplate byte size should remain the same, column name
boilerplate bytes should expand.
100010010000000 ->
2 + 4 + 9 2 + 4 + 6 2 + 4 + 7
...............111.........111.............111..
"""
field_width_stream = pablo.BitStream(int('100010001000', 2))
idx_marker_stream = pablo.BitStream(1)
pack_size = 64
target_format = TransductionTarget.JSON
csv_column_names = ["한국어", "中文", "English"]
pdep_marker_stream = pablo.BitStream(generate_pdep_stream(field_width_stream,
idx_marker_stream,
pack_size, target_format,
csv_column_names))
self.assertEqual(pdep_marker_stream.value, 1879277596)
I'm using VSCode 1.12.2 in Ubuntu 16.04.
I was able to get it to work but the workflow is poor:
control + H to open Find/Replace
Select your line of text
Click the "Find in selection" icon to the right Alt L or ⎇ ⌘ L on macOS)
Enter your find and replace characters in their inputs
Click the Replace all icon
It works but you have to go through the workflow all over again for each new selection (except for CTR + H of course). BTW I have the exact same behavior in Sublime Text.
Could you go with a regExp to find your lines? Do they contain only .'s and 1's?
This is a more general answer for other users who come here just wanting to use basic find and replace functionality.
On Mac you can press Command + Option + F to open Find and Replace:
Alternatively, you can press Command + F to open Find and then click the little triangle on the left to show the Replace field:
From the VSCode devs:
We used to enable find in selection automatically when opening the
find widget with a selection, but it was too easy to trigger
accidentally and produced a lot of complaints. You probably want to
set "editor.find.autoFindInSelection": true which will make it work
the way you expect.
The VSCode GitHub issue has more details if anyone is interested.
EDIT: The autoFindInSelection option is available starting from VSCode 1.13. That version is currently in development (as of 6/7/2017), so this fix won't work until the new version is released.
I found the following workflow to be fairly painless:
Select text region with mouse or keyboard.
Ctrl+H to toggle find and replace
Alt+L to toggle find in selection
Ctrl+Alt+Enter to replace all (or enter to replace individually)
Since sometimes we might have similarly named things so you don't want to select everything, one of my favorites shortcut sequences is to select the next occurrence:
Use shift and arrows to highlight the term you want to match.
Use Ctrl + d to highlight the next occurrence of the term.
The Basic Editing in VS Code documentation page has some extremely useful variations on find and replace. One extremely useful shortcut is the Column (Box) Selection.
Just ran into this, my solution was to do
command + N to create a new file
paste my selection in there
do my find and replace operations on that while file
copy result back on top of my original selection
On Mac:
Select the text
Press command + shift + L
For mac
Press command + option + f to bring up this menu:
Press the little icon that has the arrow pointing at it above (3 horizontal bars)
Select the text you want to do a find and replace in, and enter the 'find' and 'replace' fields
Press this icon:
That's all!
In 2022, there's a bug to be wary of 🐛
There is a silent bug (I'll add more about this as I learn more about it). But sometimes find and replace within selection doesn't find the values, even if you can see them with your own eyes. This is dangerous because you could think you've replaced them all but it really hasn't.
So do these two things:
a visual check after doing a find and replace (to make sure it worked)
if vscode completely ignores you (and doesn't do the find and replace within selection after you've followed the above instructions), close the find and replace box by pressing the "x" in the corner, and retry the sequence of steps (it worked for me after closing and retrying).
Okay, this is really dumb, at first I felt really stupid when I finally found this, then I realized its just VS Code which has a bad interface.
The key is, there are TWO TOOLS here,
Search/Replace (the pane on the left at the top of the Explorer) and Find/Replace (which is a dialogue which opens when you press CTRL-F)
THESE ARE NOT THE SAME TOOL!!
SEARCH-REPLACE is a tool written for project-wide searches and
changes
FIND-REPLACE is a small dialogue best suited for more
surgical editing.
i.e. you should use FIND-REPLACE!
find replace window image with find-in-selection highlighted
Also, its SUPER IMPORTANT to follow these steps in the right order, or it doesn't give the expected results.
Press CTRL-F to open the find dialogue (usually opens in the top right)
press the little arrow to the right of the find field which opens the replace input field
ensure "find in selection" is turned off (i.e. not highlighted)
type in the fields the strings you want to search/replace
select the text you want to do a search/replace within.
Now press "find in selection" (or type ALT-L)
You should see only highlighting in the area you previously selected.
Now you can click either "replace all" (CTRL-ALT-ENTER) or line-by-line "replace" (ENTER)
I hope this helps.
My suggestion to VSC developers, there should be a refresh button so that after you have selected the area of interest, and you already have your find and replace strings defined, you can select a new region and click "refresh find" instead of needing to repeat steps 3 to 8.
For those where it still does not work, there is one step omitted in all of the above answers: Uncheck "Find in selection" if it is checked (which it probably is when you are struggling with it and in despair googled the problem, and then found this SO entry). Only then select the lines and then re-check "Find in selection".
For Ubuntu, highlight the lines where you want to make changes, press alt-L and then ctrl-H. Then type the name you want to replace and replacement name in the top right dropdown.
Or some combination of these actions depending on whether the dropdown is already open or you're already in alt-L mode. I'm still learning but thought I'd share what's working.

How to set up word wrap for an stc.StyledTextCtrl() in wxPython

I was wondering about this, so I did quite a bit of google searches, and came up with the SetWrapMode(self, mode) function. However, it was never really detailed, and there was nothing that really said how to use it. I ended up figuring it out, so I thought I'd post a thread here and answer my own question for anyone else who is wondering how to make an stc.StyledTextCtrl() have word wrap.
Ok, so first you need to have your Styled Text Control already defined, of course. If you don't know how to do this, then go watch some tutorials on wxPython. I recommend a youtuber called sentdex http://youtube.com/sentdex, who has a complete series on wxPython, as well as Zach King, who has a 4 episode series on making a text editor. Anyways, my definition of my text control looks like this: self.control = stc.StyledTextCtrl(self, style=wx.TE_MULTILINE). Yours could look a little different, but the overall idea is the same.
self.control = stc.StyledTextCtrl(self, style=wx.TE_MULTILINE)
Many places will tell you that it will need to be SetWrapMode(self, mode), but if you have self.CONTROLNAME at the beginning like I do, you will get an error if you also put self as an argument because self. at the beginning counts as the argument. However, if your control is defined with self.CONTROLNAME and you don't put the self.CONTROLNAME at the beginning of your SetWordWrap()function, you'll also get an error, so be careful with that. Mode just has to be 0 or 1-3. So for example, mine looks like this: self.control.SetWrapMode(mode=1). Word wrap mode options:
0: None |
1: Word Wrap |
2: Character Wrap |
3: White Space Wrap
My final definition and word wrap setup looks like this:
self.control = stc.StyledTextCtrl(self, style=wx.TE_MULTILINE)
self.control.SetWrapMode(mode=1)
And that's it! Hope this helped.
Thanks to #Chris Beaulieu for correcting me on an issue with the mode options.
I see you answered your own question, and you are right in every way except for one small detail. There are actually several different wrap modes. The types and values corresponding to them are as follows:
0: None
1: Word Wrap
2: Character Wrap
3: White Space Wrap
So you cannot enter any value above 0 to get word wrap. In fact if you enter a value outside of the 0-3 you should just end up getting no wrap as the value shouldn't be recognized by Scintilla, which is what the stc library is.
It would be more maintainable to use the constants stc.WRAP_NONE, stc.WRAP_WORD, stc.WRAP_CHAR and stc.WRAP_WHITESPACE instead of their numerical values.

How to get the list of all installed color schemes in Vim?

Is there a way to get a list of all installed color schemes in Vim? That would make very easy to select one without looking at the .vim directory.
Type
:colorscheme then Space followed by TAB.
or as Peter said,
:colorscheme then Space followed by CTRLd
The short version of the command is :colo so you can use it in the two previous commands, instead of using the "long form".
Just for convenient reference as I see that there are a lot of people searching for this topic and are too laz... sorry, busy, to check for themselves (including me). Here is a list of the default set of colour schemes for Vim 7.4:
blue.vim
darkblue.vim,
delek.vim
desert.vim
elflord.vim
evening.vim
industry.vim
koehler.vim
morning.vim
murphy.vim
pablo.vim
peachpuff.vim
ron.vim
shine.vim
slate.vim
torte.vim
zellner.vim
You can see the list of color schemes under /usr/share/vim/vimNN/colors (with NN being the version, e.g. vim74 for vim 7.4).
This is explained here.
On the linux servers I use via ssh, TAB prints ^I and CTRLd prints ^D.
If you are willing to install a plugin, I recommend https://github.com/vim-scripts/CycleColor.
to cycle through all installed colorschemes. Nice way to easily choose a colorscheme.
Looking at my system's menu.vim (look for 'Color Scheme submenu') and #chappar's answer, I came up with the following function:
" Returns the list of available color schemes
function! GetColorSchemes()
return uniq(sort(map(
\ globpath(&runtimepath, "colors/*.vim", 0, 1),
\ 'fnamemodify(v:val, ":t:r")'
\)))
endfunction
It does the following:
Gets the list of available color scheme scripts under all runtime
paths (globpath, runtimepath)
Maps the script paths to their base names (strips parent dirs and
extension) (map, fnamemodify)
Sorts and removes duplicates (uniq, sort)
Then to use the function I do something like this:
let s:schemes = GetColorSchemes()
if index(s:schemes, 'solarized') >= 0
colorscheme solarized
elseif index(s:schemes, 'darkblue') >= 0
colorscheme darkblue
endif
Which means I prefer the 'solarized' and then the 'darkblue' schemes; if none of them is available, do nothing.
Here is a small function I wrote to try all the colorschemes in $VIMRUNTIME/colors directory.
Add the below function to your vimrc, then open your source file and call the function from command.
function! DisplayColorSchemes()
let currDir = getcwd()
exec "cd $VIMRUNTIME/colors"
for myCol in split(glob("*"), '\n')
if myCol =~ '\.vim'
let mycol = substitute(myCol, '\.vim', '', '')
exec "colorscheme " . mycol
exec "redraw!"
echo "colorscheme = ". myCol
sleep 2
endif
endfor
exec "cd " . currDir
endfunction
If you have your vim compiled with +menu, you can follow menus with the :help of console-menu. From there, you can navigate to Edit.Color\ Scheme to get the same list as with in gvim.
Other method is to use a cool script ScrollColors that previews the colorschemes while you scroll the schemes with j/k.
i know i am late for this answer but the correct answer seems to be
See :help getcompletion():
:echo getcompletion('', 'color')
which you can assign to a variable:
:let foo = getcompletion('', 'color')
or use in an expression register:
:put=getcompletion('', 'color')
This is not my answer, this solution is provided by u/romainl in this post on reddit.
A great solution, and my thanks to your contributors. For years I've been struggling with a totally crappy color scheme -- using SSH under Windows Vista to a Redhat system, terminal type xterm.
The editor would come up with a black background and weird colors for various keywords.
Worse -- that weird color scheme sticks in the xterm terminal after leaving Vim.
Really confusing.
Also, Backspace failed during an insert mode, which was nasty to remember -- though Delete did the same thing.
The cure --
In the SSH monitor, select Edit/Settings.
a. Choose Profile Settings/Colors
b. check 'enable ANSI colors'
c. The standard Text colors are probably OK
Add these lines to $HOME/.vimrc:
colorscheme default
if &term == "xterm"
set t_kb=^H
fixdel
endif
NOTE: the ^H MUST be typed as ctrl-V ctrl-H. Seems peculiar, but this seems to work.
Try
set wildmenu
set wildmode=list:full
set wildcharm=<C-z>
let mapleader=','
nnoremap <leader>c :colorscheme <C-z><S-Tab>
in your ~/.vimrc.
The first two lines make possible matches appear as lists. You can use either or both.
The fourth line makes leader , instead of the default \.
The last line allows you to simply type ,c to get a list and a prompt to change your colorscheme.
The third line effectively allows for Tabs to appear in key maps.
(Of course, all of these strategies I've learned from the internet, and mostly SO, very recently.)
Another simpler way is while you are editing a file - tabe ~/.vim/colors/ ENTER
Will open all the themes in a new tab within vim window.
You may come back to the file you were editing using - CTRL + W + W ENTER
Note: Above will work ONLY IF YOU HAVE a .vim/colors directory within your home directory for current $USER
(I have 70+ themes)
[user#host ~]$ ls -l ~/.vim/colors | wc -l
72

Making Dreamweaver more like Notepad++

I'm moving to Dreamweaver from Notepad++, and while Dw does have many better features than Notepad++, there are a few that I'm really missing.
Is there a way to make the "Home" key on the keyboard take you to the front of where the code starts, instead of the very front of the line? In Notepad++ this is how it works by default, and I don't know why anyone would want to go to the very front of the line instead of the front of the code. I use tabbing to keep it more organized, so this feature is really important to me.
How do I duplicate a line in Dw? In Notepad++ I can select the line and press ctrl + d and it automatically duplicated the code. This is awesome for something like a gallery or a table where I don't want to have to type out every line because it's so similar.
Less important, as I don't use this that often, but can you vertically select in Dw? In Notepad++ you can hold down alt and select lines vertically. Ex:
http://dl.dropbox.com/u/12147973/vert-select.jpg
Thanks in advance.
For #2, check out the Code Extras extension for Dreamweaver
No Longer works in DW5.5; Try here - http://yoropan.com/en/archives/544
I was also wanting some of this features... I discovered that, at least in CS6, #2 is already in Dreamweaver, but the shortcut is Ctrl+Alt+Down ou Up, depending on the direction that you wanna duplicate the code.
Note that I had to disable the shortcut that turns your screen view for that to work. (It's an intel default, press Ctrl+Alt+f12 to open the options)
And tãa dãaa... IT WORKS! :D
I want to say one thing different. My Dreamweaver theme (Users who use Dreamweaver after use Notepad++). Download Dreamweaver.xml
"Dreamweaver.xml" file is in here for windows: C:\Program Files\Notepad++\themes\Dreamweaver.xml
The answer to #1 = Ctrl+Home in anything in windows will take you to the absolute start of the documents, same as Ctrl+End, Home and End to start and finish of lines, Ctrl+Left or Right arrow to jump entire words...
I too am on the quest for duplicating lines in DW. #3 your image no longer shows.
If I want to duplicated a line I click on the line number, then CTRL+C to copy and CTRL+V to paste. Is that what you're looking for or am I being simple?

Vim: Invert string (by words)

This is my string:
"this is my sentence"
I would like to have this output:
"sentence my is this"
I would like to select a few words on a line (in a buffer) and reverse it word by word.
Can anyone help me?
It's not totally clear what the context is here: you could be talking about text in a line in a buffer or about a string stored in a VimScript variable.
note: Different interpretations of the question led to various approaches and solutions.
There are some "old updates" that start about halfway through that have been rendered more or less obsolete by a plugin mentioned just above that section. I've left them in because they may provide useful info for some people.
full line replacement
So to store the text from the current line in the current buffer in a vimscript variable, you do
let words = getline('.')
And then to reverse their order, you just do
let words = join(reverse(split(words)))
If you want to replace the current line with the reversed words, you do
call setline('.', words)
You can do it in one somewhat inscrutable line with
call setline('.', join(reverse(split(getline('.')))))
or even define a command that does that with
command! ReverseLine call setline('.', join(reverse(split(getline('.')))))
partial-line (character-wise) selections
As explained down in the "old updates" section, running general commands on a character- or block-wise visual selection — the former being what the OP wants to do here — can be pretty complicated. Ex commands like :substitute will be run on entire lines even if only part of the line is selected using a character-wise visual select (as initiated with an unshifted v).
I realized after the OP commented below that reversing the words in a partial-line character-wise selection can be accomplished fairly easily with
:s/\%V.*\%V./\=join(reverse(split(submatch(0))))/
wherein
\%V within the RE matches some part of the visual selection. Apparently this does not extend after the last character in the selection: leaving out the final . will exclude the last selected character.
\= at the beginning of the replacement indicates that it is to be evaluated as a vimscript expression, with some differences.
submatch(0) returns the entire match. This works a bit like perl's $&, $1, etc., except that it is only available when evaluating the replacement. I think this means that it can only be used in a :substitute command or in a call to substitute()
So if you want to do a substitution on a single-line selection, this will work quite well. You can even pipe the selection through a system command using ...\=system(submatch(0)).
multiple-line character-wise selections
This seems to also work on a multiple-line character-wise selection, but you have to be careful to delete the range (the '<,'> that vim puts at the beginning of a command when coming from visual mode). You want to run the command on just the line where your visual selection starts. You'll also have to use \_.* instead of .* in order to match across newlines.
block-wise selections
For block-wise selections, I don't think there's a reasonably convenient way to manipulate them. I have written a plugin that can be used to make these sorts of edits less painful, by providing a way to run arbitrary Ex commands on any visual selection as though it were the entire buffer contents.
It is available at https://github.com/intuited/visdo. Currently there's no packaging, and it is not yet available on vim.org, but you can just git clone it and copy the contents (minus the README file) into your vimdir.
If you use vim-addon-manager, just clone visdo in your vim-addons directory and you'll subsequently be able to ActivateAddons visdo. I've put in a request to have it added to the VAM addons repository, so at some point you will be able to dispense with the cloning and just do ActivateAddons visdo.
The plugin adds a :VisDo command that is meant to be prefixed to another command (similarly to the way that :tab or :silent work). Running a command with VisDo prepended will cause that command to run on a buffer containing only the current contents of the visual selection. After the command completes, the buffer's contents are pasted into the original buffer's visual selection, and the temp buffer is deleted.
So to complete the OP's goal with VisDo, you would do (with the words to be reversed selected, and with the above-defined ReverseLine command available):
:'<,'>VisDo ReverseLine
old updates
...previous updates follow ... warning: verbose, somewhat obselete, and mostly unnecessary...
The OP's edit makes it more clear that the goal here is to be able to reverse the words contained in a visual selection, and specifically a character-wise visual selection.
This is decidedly not a simple task. The fact that vim does not make this sort of thing easy really confused me when I first started using it. I guess this is because its roots are still very much in the line-oriented editing functionality of ed and its predecessors and descendants. For example, the substitute command :'<,'>s/.../.../ will always work on entire lines even if you are in character-wise or block-wise (ctrlv) visual selection mode.
Vimscript does make it possible to find the column number of any 'mark', including the beginning of the visual selection ('<) and the end of the visual selection ('>). That is, as far as I can tell, the limit of its support. There is no direct way to get the contents of the visual selection, and there is no way to replace the visual selection with something else. Of course, you can do both of those things using normal-mode commands (y and p), but this clobbers registers and is kind of messy. But then you can save the initial registers and then restore them after the paste...
So basically you have to go to sort of extreme lengths to do with parts of lines what can easily done with entire lines. I suspect that the best way to do this is to write a command that copies the visual selection into a new buffer, runs some other command on it, and then replaces the original buffer's visual selection with the results, deleting the temp buffer. This approach should theoretically work for both character-wise and block-wise selections, as well as for the already-supported linewise selections. However, I haven't done that yet.
This 40-line code chunk declares a command ReverseCharwiseVisualWords which can be called from visual mode. It will only work if the character-wise visual selection is entirely on a single line. It works by getting the entire line containing the visual selection (using getline()) running a parameterized transformation function (ReverseWords) on the selected part of it, and pasting the whole partly-transformed line back. In retrospect, I think it's probably worth going the y/p route for anything more featureful.
" Return 1-based column numbers for the start and end of the visual selection.
function! GetVisualCols()
return [getpos("'<")[2], getpos("'>")[2]]
endfunction
" Convert a 0-based string index to an RE atom using 1-based column index
" :help /\%c
function! ColAtom(index)
return '\%' . string(a:index + 1) . 'c'
endfunction
" Replace the substring of a:str from a:start to a:end (inclusive)
" with a:repl
function! StrReplace(str, start, end, repl)
let regexp = ColAtom(a:start) . '.*' . ColAtom(a:end + 1)
return substitute(a:str, regexp, a:repl, '')
endfunction
" Replace the character-wise visual selection
" with the result of running a:Transform on it.
" Only works if the visual selection is on a single line.
function! TransformCharwiseVisual(Transform)
let [startCol, endCol] = GetVisualCols()
" Column numbers are 1-based; string indexes are 0-based
let [startIndex, endIndex] = [startCol - 1, endCol - 1]
let line = getline("'<")
let visualSelection = line[startIndex : endIndex]
let transformed = a:Transform(visualSelection)
let transformed_line = StrReplace(line, startIndex, endIndex, transformed)
call setline("'<", transformed_line)
endfunction
function! ReverseWords(words)
return join(reverse(split(a:words)))
endfunction
" Use -range to allow range to be passed
" as by default for commands initiated from visual mode,
" then ignore it.
command! -range ReverseCharwiseVisualWords
\ call TransformCharwiseVisual(function('ReverseWords'))
update 2
It turns out that doing things with y and p is a lot simpler, so I thought I'd post that too. Caveat: I didn't test this all too thoroughly, so there may be edge cases.
This function replaces TransformCharwiseVisual (and some of its dependencies) in the previous code block. It should theoretically work for block-wise selections too — it's up to the passed Transform function to do appropriate things with line delimiters.
function! TransformYankPasteVisual(Transform)
let original_unnamed = [getreg('"'), getregtype('"')]
try
" Reactivate and yank the current visual selection.
normal gvy
let #" = a:Transform(#")
normal gvp
finally
call call(function('setreg'), ['"'] + original_unnamed)
endtry
endfunction
So then you can just add a second command declaration
command! -range ReverseVisualWords
\ call TransformYankPasteVisual(function('ReverseWords'))
tangentially related gory detail
Note that the utility of a higher-level function like the ones used here is somewhat limited by the fact that there is no (easy or established) way to declare an inline function or block of code in vimscript. This wouldn't be such a limitation if the language weren't meant to be used interactively. You could write a function which substitutes its string argument into a dictionary function declaration and returns the function. However, dictionary functions cannot be called using the normal invocation syntax and have to be passed to call call(dictfunct, args, {}).
note: A more recent update, given above, obsoletes the above code. See the various sections preceding old updates for a cleaner way to do this.
Maybe:
:s/\v(.*) (.*) (.*) (.*)/\4 \3 \2 \1/
Of course you probably need to be more specific in the first part to find that particular sentence. Generally you can refer to match groups as \number with \0 being the whole match.
Here's a way to do by calling out to Ruby. After selecting the line you want to reverse, you can do this in command mode to replace it:
!ruby -e 'puts ARGF.read.strip.split(/\b/).reverse.join'
I found the solution myself thank to your answers and a lot of trying :)
This works:
function! Test()
exe 'normal ' . 'gv"ay'
let r = join(reverse(split(getreg('a'))))
let #a = r
exe 'normal ' . 'gv"ap'
endfunction
Didn't thought that I was enable to write such a function :)