I read the docs, but got even more confused.
I have the following error generated by the compiler:
rot;
^
"cpp\c1.cpp", line 13: error(114): identifier
"rot" is undefined
1 error detected in the compilation of "c1.cpp".
I know how to detect the line where the error line is given, but I get loads of extra useless info in my errorlist, and the error message is split in two lines, whcih i would prefer to merge.
My starting errorformat is:
:set efm=\"%f\"\\,\ line\ %l:\ error(%n):\ %m
Since we are at it, is there a quick way of testing the efm without resorting to run make all the time?
First of all, I talk about debugging. Unfortunately, there's no particularly easy way of doing it, but one useful possibility is to run make and spit the output into a file and then:
:let &makeprg="cat ~/outputfile.log"
:make
Regarding making the errorformat, this does require a bit of trial and error. You can use %A, %C and %Z for multiline messages and you can use %-G to ignore stuff. The order is very important and note that sometimes the %C or even %Z come before the %A! In your case, you may be able to get somewhere with the efm below. I tend to use let &efm = and let &efm .= rather than set as you don't have to escape every space or quotation mark and you can build it up gradually. It's also much more readable.
" Start of the multi-line error message (%A),
" %p^ means a string of spaces and then a ^ to
" get the column number
let &efm = '%A%p^' . ','
" Next is the main bit: continuation of the error line (%C)
" followed by the filename in quotes, a comma (\,)
" then the rest of the details
let &efm .= '%C"%f"\, line %l: error(%n): %m' . ','
" Next is the last line of the error message, any number
" of spaces (' %#': equivalent to ' *') followed by a bit
" more error message
let &efm .= '%Z %#%m' . ','
" This just ignores any other lines (must be last!)
let &efm .= '%-G%.%#'
Related
vim: insert original line number in g/pattern/move $
I'm debugging some event order in a log and like to check two set of events sequence by the line number of the showing log. Usually, I used g/pattern/move $ for some interesting info. But I cannot find a way to insert the original line number of them. Please help.
I tried :
g/pattern/move $; printf("%d",line("."))
but it does not work.
Can't help thinking of something very straightforward, for example:
g/pattern/call append(line('$'), line('.') . ' ' . getline('.'))
A slightly different way but I have following mapping in my _vimrc
nnoremap <F3> :redir! #f<cr>:silent g//<cr>:redir! END<cr>:enew!<cr>:put! f<cr>:let #f=#/<cr>:g/^$/d<cr>:let #/=#f<cr>gg
It opens a new buffer with all your search matches, including the linenumbers where the match occured.
I have figured out a way to insert at first the line number on the lines that have the pattern and after that moving the same lines to the end of the file:
:%s,\v^\ze.*pattern,\=line('.') . ' ' ,g | g/pattern/m$
We have two commands:
:%s,\v^\ze.*pattern,\=line('.') . ' ' ,g
, ....................... we are using comma as delimiter
\v ...................... very magic substitution
^ ....................... Regular expression for beginning of line
\ze ..................... indicates that all after it will not be substituted
\=line('.') ............. gets the line number
. ' ' .................. concatenates one space after the number
The second command is separated with |
g/pattern/m$
m$ ....................... moves the pattern to the end of file
I need to find all pairs of strings that have the same pattern.
For example:
another string, that is not interesting
la-di-da-di __pattern__ -di-la-di-la
la-di-da-da-di-la __pattern__ -la-da-li-la
and yet another usual string
So I want to delete strings with __pattern__ inside.
I don't know how to do it just with builtin commands and now I have the function, that doesn't work properly:
function! DelDup(pattern)
echom a:pattern
redir => l:count
execute "normal! :%s/a:pattern//n\<cr>"
redir END
echo l:count
endfunction
Here I try to run ":%s/a:pattern//n" to find the count of occurrences of pattern in the text.
And at the same time I try to put it into the variable "l:count".
Then I tried to echo the count I got, but nothing happens when I try to do it.
So the last my problem in function writing is that I can't write the command execution result to variable.
If you have another solution -- please describe it to me.
Update:
Excuse me for bad description. I want to delete only strings, that has pattern-twins in text.
I'm not sure if I understand your question correctly, but I'm assuming you want to remove all lines where there are at least 2 matches. If that's the case you can use the following command:
:g/\(__pattern__.*\)\{2,}/d
How this works is that it deletes all the lines where there is a match (:g/../d).
The pattern is made up of a group (\(..\)) which needs to be matched at least 2 times (\{2,}). And the pattern has a .* at the end so it matches everything between the matches of the pattern.
There are many ways to count occurrences of a pattern, and I'm quite sure there exist a Q/A on the subject. Let's do it yet another way and chain with the next step. (Yes this is completely obfuscated, but it permits to obtain programmatically the information without the need to parse the localized result of :substitute after redirection.)
" declare a list that contain all matches
let matches = []
" replace each occurrence of the "pattern" with:
" the result of the expression "\=" that can be
" interpreted as the last ([-1]) element of the
" list "matches" returned by the function (add)
" that adds the current match (submatch(0)) to the
" list
:%s/thepattern/\=add(matches, submatch(0))[-1]/gn
" The big caveat of this command is that it modifies
" the current buffer.
" We need something like the following to leave it unmodified:
:g/thepattern/call substitute(getline('.'), 'thepattern', '\=add(counter, submatch(0))[-1]', 'g')
" Note however that this flavour won't work with multi-lines patterns
" Now you can test the number of matches or do anything fancy with it
if len(matches) > 1
" replaces matches with nothing
:%s/thepattern//g
endif
Only if you want to define this as a function you'll need to play with:
exe 'normal :%s/'.escape(a:pattern, '/\').'/replacement..../flags....'
I've seen a couple of questions about passing line numbers from Vim to an external command, but I want to do the opposite. I want to run a file through jshint and then apply corrections to each line number based on the jshint output.
For example, I'm trying to append a semicolon on each line that is missing one. Right now I'm shelling out to jshint and parsing the output but I'm not sure how I can use that to run a macro on multiple lines.
My current thought right now is to:
call jshint and parse out the line numbers for "Missing semicolon" errors
iterate through line numbers
for each line number, run G<LINE_NUMBER>A;
Here is what I have so far for parsing the jshint output:
:r ! jshint % | grep 'Missing semicolon' | awk '{ print $3 }' | sed 's/,//'
Is there a convenient way for me to do something like xargs in Vim or to parse the output of the external command into an array that I can loop over?
Well, let's see. You might try using errorformat:
let lines = split(system('jshint --verbose ' . shellescape(expand('%', 1))), "\n", 1)
let &errorformat = '%f: line %l\, col %v\, %m'
cgetexpr lines
for line in uniq(sort(map(filter(getqflist(), 'v:val["valid"] && v:val["text"] =~# "\\m^Missing semicolon"'), 'v:val["lnum"]')))
execute line . 's/$/;/'
endfor
Not what I'd call "convenient", but what do I know.
Then it might occur to you that the missing semicolons might not always be at end of lines. So you'd modify the code like this:
function! Cmp(a, b)
return a:a[0] == a:b[0] ? a:b[1] - a:a[1] : a:b[0] - a:a[0]
endfunction
let lines = split(system('jshint --verbose ' . shellescape(expand('%', 1))), "\n", 1)
let &errorformat = '%f: line %l\, col %v\, %m'
cgetexpr lines
for p in uniq(sort(map(filter(getqflist(), 'v:val["valid"] && v:val["text"] =~# "\\m^Missing semicolon"'),
\ '[str2nr(v:val["lnum"]), str2nr(v:val["col"])]'), 'Cmp'))
let line = getline(p[0])
call setline(p[0], line[ : p[1]-2] . ';' . line[p[1]-1 :])
endfor
Then it may occur to you that this doesn't handle the case of tabs. That's a problem because by default JSHint's idea of a tab is tab stop = 4, while Vim's is tab stop = 8. Then you... might fix that as an exercise, or you might come to your senses and use a real JavaScript parser to fix this instead of Vim. :)
I have the jslint installed with npm on my system.
It produces error messages in the following format:
1 1,9: Missing name in function statement.
function() {
2 2,11: Use '===' to compare with '0'.
if (x == 0) {
3 4,2: Unnecessary semicolon.
};
I wrote a compiler plugin for Vim to parse the error messages, but I could not figure out the problem with the errorformat. I have the following now in my compiler file:
CompilerSet makeprg=jslint
\\ $*
\\ %
CompilerSet errorformat=
\%*[\ ]%n\ %l\,%c:\ %m,
\%-G%.%#
Which AFAIK should do the following:
%*[\ ] -- skip the whitespaces in the beginning of the line
%n -- match the error number
\ -- skip a space
%l -- match for the line number
\, -- skip the comma
%c -- match the column number
: -- skip the colon
\ -- skip the space again
%m -- match the error message
, -- new line
%-G%.%# -- skip all the others
It runs the jslint which shows the messages but the :clist command does not show any errors.
What am I missing?
The problem was with the \,, the skip comma, the correct format is:
CompilerSet errorformat=
\%*[\ ]%n\ %l%.%c:\ %m,
\%-G%.%#
The comma must be escaped with \\, since , is a special char in errorformat, and \ is a special char in vim config file, which must itself be escaped.
To vim, your error format is then %*[ ]%n %l\,%c: %m,%-G%.%#, since the \ at the beginning of the line or before spaces are escapes for vim, not for the error format.
I'm trying to create a script that helps creating shebangs (Ok, it may not be that useful but has advantages when you don't know where the program is, for example), here's what I have so far:
function! CreateShebang()
call inputsave()
let program = input('Enter the program name: ')
call inputrestore()
let path = system('which ' . program)
call append(0, '#!' . path)
endfunction
By the way, I'm just starting with vim scrips, so if you notice any wrong function and concepts or know a better way to achieve the result, please tell me. Any help is really appreciated.
The big problem is that after running, the scripts prompts for the program name correctly and then add something like this to the file:
#!/usr/bin/perl^#
What's that ^# doing there?
Also, If I may ask another question here, how can I clear the command line after input()? The text entered by the user keeps showing until another command is entered.
^# at the end of command is a newline translated to NULL by append() function, see :h NL-used-for-Nul (it the reason why your substitute(...\%d000...) worked while you don't have NULL in your string). As which command always outputs newline at the end of string, I suggest you to slightly modify your code by adding [:-2] to the end of the system() call. This construction will strip just the last byte of function output:
let path = system('which ' . program)[:-2]
If you use substitute, use
let path=substitute(path, '\n', '', 'g')
, don't confuse yourself with \%d000 which is semantically wrong.
Probably the which command output contains the NULL character.
The system() function replaces line breaks with <NL>s. (from :help system()). Therefore you could do:
let path = substitute(system('which ' . program), '\%x00', '', 'g')
Otherwise you could do the following:
function! CreateShebang()
call inputsave()
0 put = '#!/usr/bin/env ' . input('Enter the program name: ')
call inputrestore()
endfunction