I have ths line in my .vimrc:
map gu :%s/\s\+$//<enter> :w<enter>
to remove trailing spaces and saving the file in the same time.
When there are trailing spaces in the file, it works OK (it removes the spaces and saves the file), but when there are not trailing spaces it doesn't save the file, it just says Pattern not found: \s+$.
NOTE: I found this, but I'm curious about the way I'm asking.
Add an e to the search flags to suppress error messages:
map gu :%s/\s\+$//e<enter> :w<enter>
From :help substitute:
[e] When the search pattern fails, do not issue an error message and, in
particular, continue in maps as if no error occurred. This is most
useful to prevent the "No match" error from breaking a mapping. Vim
does not suppress the following error messages, however:
Regular expressions can't be delimited by letters
\ should be followed by /, ? or &
No previous substitute regular expression
Trailing characters
Interrupted
Related
Background
I want to convert an if statement from Fortran to C++. I like to have braces on a new line.
So I want to make
! this may be nested so indentation is unknown
if ( condition ) then
block
end if
to
if ( condition )
{
block
}
Changing end if to } is easy since the indentation is already how I want it. I just used :%s/end if/}/gc.
However, changing then is more challenging. I need to create a new line and set its the leading whitespace to the same as the previous line.
The closest I have to a solution is :%s/then/\=printf("\n%s{",indent(line('.')))/gc
However I want to use the value returned from indent(line('.') to set the number of indents.
Problem
Can I use a number I receive from a function to set the number of tabs at the beginning of line in a search and replace?
You want to substitute then with:
a newline,
followed by n spaces, as many as used for indenting the current line,
followed by an opening brace.
As is, your command does the following:
a newline,
followed by the number of spaces used for the indentation of the current line,
followed by an opening brace.
:help repeat() to the rescue:
:%s/then/\=printf("\n%s{",repeat(' ',indent(line('.'))))/gc
But there is still room for improvement…
you only want to substitute trailing thens so the g flag is useless:
:%s/then/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
the search pattern may match other thens so it should be restricted a little:
:%s/then\s*$/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
also, the pattern should include any whitespace before the then to avoid leaving annoying trailing whitespace behind:
:%s/\s*then\s*$/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
line('.') is unnecessary:
:%s/\s*then\s*$/\=printf("\n%s{",repeat(' ',indent('.')))/c
and we could use the new-ish "method" syntax to limit parenthesis nesting:
:%s/\s*then\s*$/\=repeat(' ',indent('.'))->printf("\n%s{")/c
I want to create a command or function to combine multiple finds and replaces. I have tried following command:
command MyFR %s/first/1st/g | %s/second/2nd/g | %s/third/3rd/g
It works but stops midway if no 'first' or 'second' is found. The error is:
E486: Pattern not found: <pattern>
How can I make this command work for 'second' and 'third' to be replaced, even if there is no 'first' in text? Thanks for your help.
You could add the e flag to each of your substitution command, which is described in :h :s_flags:
[e] When the search pattern fails, do not issue an error message and, in
particular, continue in maps as if no error occurred. This is most
useful to prevent the "No match" error from breaking a mapping. Vim
does not suppress the following error messages, however:
Regular expressions can't be delimited by letters
\ should be followed by /, ? or &
No previous substitute regular expression
Trailing characters
Interrupted
It would give:
com! MyFR %s/first/1st/ge | %s/second/2nd/ge | %s/third/3rd/ge
Another solution would be to merge all substitutions into a single one:
com! MyFR %s/\vfirst|second|third/\={'first': '1st', 'second': '2nd', 'third': '3rd'}[tolower(submatch(0))]/g
This time, in the replacement part, instead of using a literal string, you would use an expression (see :h s/\=). Here, the expression is a given value of a dictionary.
The keys of the dictionary are all your possible matched texts, and the values are their replacements.
The value you retrieve from the dictionary is tolower(submatch(0)) which evaluates into the matched text (see :h submatch()), normalized in its lowercase version (all uppercase characters are turned into their lowercase counterpart through tolower()).
I am a new user of vim (gvim in windows), and have found abbreviations a nice time saver - however they would be even better if i could stop the trailing whitespace at times.
I have some directories that i use a lot, and so i added some abbreviation/path pairs to my _vimrc:
:ab diR1 C:/dirA/dira/dir1/
:ab diR2 C:/dirA/dirb/dir2/
etc ...
Now when i type diR1 <space> i get C:/dirA/dira/dir1/[]| where the whitespace is represented by [] and the cursor is the | character. I would like to get rid of the [] == whitespace.
This is a minor complaint: however you seem to be able to customise everthing else in Vim so i figured i'd ask -- is it possible to avoid the trailing whitespace when one uses abbreviations in vim?
An alternate tool used within Vim is a good answer - my objective is to save re-typing frequently used directory structures, but to have the cursor handy as i would almost always add something to the end, such as myFile.txt.
The trailing white space (doubtless due to the fact that the space triggered the abbreviation) which i backspace over before adding myFile.txt to the end is less annoying than typing the whole thing over and over, but it would be ideal if i could avoid doing so ...
pb2q answer is exactly what you want in your current scenario, but does not fully answer the question presented in the title. This exact problem is addressed in the vim help file. See :helpgrep Eatchar. The example it gives is this:
You can even do more complicated things. For example, to consume the space
typed after an abbreviation: >
func Eatchar(pat)
let c = nr2char(getchar(0))
return (c =~ a:pat) ? '' : c
endfunc
iabbr <silent> if if ()<Left><C-R>=Eatchar('\s')<CR>
You would put the Eatchar function in your ~/.vimrc file and then use like so in your abbreviations:
iabbr <silent> diR1 C:/dirA/dira/dir1/<c-r>=Eatchar('\m\s\<bar>/')<cr>
This would "eat" any trailing white space character or a slash. Note that I used iabbr instead of just abbr, because it is rare to actually want abbreviations to expand in command line mode. You must be careful with abbreviations in command line mode as they will expand in unexpected places such as searches and input() commands.
For more information see:
:h abbreviations
:helpgrep Eatchar
:h :helpgrep
This is possible, without more customization than just abbrev.
The abbreviation is being triggered by the space character, as you know. The space is a non-keyword character, and remains after the abbreviation is expanded.
But there are other ways to trigger the expansion, such as other non-keyword characters, including /. So if you instead define your abbreviations like this:
:ab diR1 C:/dirA/dira/dir1
That is, without the trailing path separator, then you can type diR1/, have the abbreviation expand for you because of the slash /, and continue typing, appending to your path with a file name.
Alternately, you can force abbreviation expansion using Ctrl-]. That is, type the abbreviation: diR1, with no following space or other non-keyword character, and then type Ctrl-]. The abbreviation will be expanded and you'll remain in insert mode, and can append your file name to the expanded path.
Check out :help abbreviations, there may be something else useful for you there, including more complicated constructions for always consuming e.g. the space character that triggered the abbreviation.
Instead of abbreviations, you could use mappings. They're expanded as soon as you have typed the last character of the mapping, so there won't be a trailing space:
:inoremap diR1 c:/dirA/dira/dir1
The downside for this approach is that the letters you type while a mapping could be expanded are not displayed until the mapping is finished. This takes some using used to.
If I do something like:
:%s/aaa/bbb/ | %s/111/222/
and the first search and replace doesn't find any matches, the second search and replace won't be executed. Is there any way to tell vim to carry on even when a command "failed"?
Try
:%s/aaa/bbb/e | %s/111/222/e
and read
:help :s_flags
especially the entry under [e]:
When the search pattern fails, do not issue an error message and, in
particular, continue in maps as if no error occurred. This is most
useful to prevent the "No match" error from breaking a mapping. Vim
does not suppress the following error messages, however:
Regular expressions can't be delimited by letters
\ should be followed by /, ? or &
No previous substitute regular expression
Trailing characters
Interrupted
I'd like to write a function in vimscript that finds the last open parenthese or bracket in a line. This isn't necessarily an easy problem, because it needs to be able to handle all of the following:
function(abc
function(abc, [def
function(abc, [def], "string("
function(abc, [def], "string(", ghi(
As you can see, nested parenthesis, differing symbols, and string tokens all need to be handled intelligently. Is this even possible? Are there tools with vimscript regexes to do context-aware searches that know the difference between unclosed parentheses and parenthesis in strings?
Given that you can syntax highlight unbalanced brackets, it should be possible to find the last unclosed parenthese/bracket on a line. How can this be done?
So, basicly, you have to find the last parenthese which is not in comment and not in string.
I am not sure what this syntax is so I placed those lines in a buffer and did
:set ft=javascript
to get strings highlighting
function(abc
function(abc, [def
function(abc, [def], "string("
function(abc, [def], "string(", ghi(
Now put your cursor to the 3rd line open parenthese and issue the following command:
:echo synIDattr(synID(line('.'), col('.'), 0), 'name') =~? '\(Comment\|String\)'
It'll echo you '1' and it means that character under the cursor is in comment or in a string.
If you place the cursor to the last col of the last line and do the same command you'll get '0'.
Now you can iterate backwards over parenthesis and test them against 'comment' and 'string' and get the last open parenthese.
You can check this archive of "LISP: Balance unmatched parentheses in Vim" to see how to close unmatched parenthesis using vimscript.
Use [( and ]):
[( go to [count] previous unmatched '('.
]) go to [count] next unmatched ')'.
For curly braces: [{ and [}.
I don't have any direct answer for you, but you may want to check out the code in the matchparen.vim plugin, which is a standard plugin included in Vim installs (in the plugin directory). That plugin is the one used for highlighting of matching parens, if you have that function enabled. The code is more general than what you need, since it matches across lines, but you may be able to work with it and test whether it finds a match on same line, or at least get some ideas from its code.