In a recent question, I asked how to make vimdiff ignore the extra spaces when comparing. Following the answer and some further reading, I tried to do the following:
.1. Locate _vimrc and find the MyDiff() function definition. It contains the line:
if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif
.2. Duplicate the function as MyDiff2() in _vimrc, while changing that line to:
if &diffopt =~ 'iwhite' | let opt = opt . '--ignore-all-space ' | endif
.3. Open gVim with two files in Diff mode, then:
:set diffexpr=MyDiff2()
:set diffopt+=iwhite
:call MyDiff2()
and also:
:diffupdate
I expected this to make vimdiff ignore differences like:
r3=r2; vs r3 = r2;, but it does not. Why is that?
My settings are as following:
diffexpr=MyDiff2()
diffopt=filler,iwhite,icase
OK, it seems like I found a solution that works, following this question. Instead of using --ignore-all-space, I used -w and now it looks like gVim ignores the differences between r3=r2; and r3 = r2;.
Related
I know how to use CtrlP. I type ctrl+p, then I start to write file name, ... and so on. But, ... I am very lazy developer. I want to directly send to CtrlP current word. I know how to get current word:
let l:currentWord = expand('<cword>')
In Vim Language, ... I How can I send l:currentWord to CtrlP?
map <F6> :call ComposerKnowWhereCurrentFileIs()<CR>
function! ComposerKnowWhereCurrentFileIs()
let l:currentWord = expand('<cword>')
let l:command = "grep " . l:currentWord . " ../path/to/composer -R | awk '{print $6}' | awk -F\\' '{print $2}'"
let l:commandFileFound = l:command . ' | wc -l'
let l:numberOfResults = system(l:commandFileFound)
if l:numberOfResults == 1
let l:fileName = system(l:command)
let l:openFileCommand = 'tabe /path/to/project' . l:fileName
exec l:openFileCommand
else
echo "Too many files :-( - use CtrlP ;-) "
endif
endfunction
<C-P><C-\>w
See :h ctrlp-mappings. You may map this combination:
map <F6> <C-P><C-\>w
In a function:
exe "normal \<C-P>" . expand('<cword>')
The whole point of CtrlP and similar plugins is to provide an alternative command-line where you can refine your search as you type.
If you don't need fuzzy search and you already have the filename under the cursor… why not simply use the built-in gf?
-- edit --
In the gif below:
I jump to /path/not/knowable/BlaBlaClassName.php with gf,
I jump back to the previous buffer with <C-^> (unrelated to your question),
I jump to the declaration of BlaBlaClassName in /path/not/knowable/BlaBlaClassName.php again with <C-]> thanks to a tagsfile generated with ctags.
function! LazyP()
let g:ctrlp_default_input = expand('<cword>')
CtrlP
let g:ctrlp_default_input = ''
endfunction
command! LazyP call LazyP()
nnoremap <C-P> :LazyP<CR>
(this could probably be simplified but I suck at vim syntax)
For that, you wouldn't use the <C-P> mapping, but the :CtrlP command, as that one takes parameters.
To build a mapping that passes the current word to the command, there are two approaches. Either directly insert the current word into the command-line (via :help c_CTRL-R_CTRL-W):
:nnoremap <Leader>p :CtrlP <C-r><C-p><CR>
Or, in order to use expand(), build the Ex command via :execute:
:nnoremap <Leader>p :execute 'CtrlP' expand('<cword>')<CR>
I am a vim user and has nerdcommenter plugin, the problem is when I use <leader>c<space> to comment out code (also block of code), it prefix # right in front of the code, but pep8 style checker is complaining that I should have a space after the #
eg.
#string = 'abc'
but I want it to comment to:
# string = 'abc'
I found that adding the following to my .vimrc was helpful.
let NERDSpaceDelims=1
This adds the desired extra space for all languages
(see "NERDSpaceDelims" at https://github.com/scrooloose/nerdcommenter/blob/master/doc/NERD_commenter.txt)
It appears that the delimiters are hardcoded in the /plugin/NERD_commenter.vim file, starting on line 67. You should be able to change '#' to '# ' for the filetypes that you wish to modify.
UPDATE:
I found a more intended and more preferred way of accomplishing this. The plugin has code to handle what it calls CustomDelimiters. You can use something like this in your vimrc to accomplish the same thing as above in a more visible and transferable way:
let g:NERDCustomDelimiters = { 'py' : { 'left': '# ', 'leftAlt': '', 'rightAlt': '' }}
Not super tested but seems to work.
EDIT: I think they fixed the plugin so this works now without the code below: let g:NERDSpaceDelims = 1
augroup NERDCommenter_whitespace_defender
au!
" NOTE: g:NERDSpaceDelims can only be set to [0,1] according to :h NERDSpaceDelims
au BufEnter * if has_key(nerdcommenter#delimiterMap, &ft) |
\ let g:NERDSpaceDelims = (nerdcommenter#delimiterMap[&ft]['left'][-1:] =~ '\s') ? 0 : 1 |
\elseif &filetype ==? 'vim' |
\ let g:NERDSpaceDelims = 1 |
\endif
augroup END
I know my question title is not explanatory enough so let me try to explain.
I created a vim function that displays my current battery state. My function is as follows:
function! BatteryStatus()
let l:status = system("~/battery_status.sh")
echo join(split(l:status))
endfunction
I have mapped the above function as nnoremap <F3> :call BatteryStatus()<cr>. Now, when I press F3 it displays my battery status as Discharging, 56%, 05:01:42 remaining which is my required output but my question is how do I make the above output disappear.
Currently what happens is after function call it continuously displays the output and I have to manually use :echo to clear the command window(:).
So, what necessary changes are to be made in my function so that I can achieve toggle like behaviour.
battery_status.sh
acpi | awk -F ": " '{print $2}'
PS: This is part of a learning exercise. So, please don't suggest alternative vim scripts.
Simplistic straightforward way to toggling the output:
let s:battery_status_output_flag = "show"
function! BatteryStatus()
if s:battery_status_output_flag == "show"
let l:status = system("~/battery_status.sh")
echo join(split(l:status))
let s:battery_status_output_flag = "clear"
else
echo ""
let s:battery_status_output_flag = "show"
endif
endfunction
Note s: prefix, see :help script-variable
You can define a autocmd:
:au CursorHold * redraw!
Vim redraws itself 4 sec (set by updatetime option) after it's idle.
vim
function! pseudocl#render#clear()
echon "\r\r"
echon ''
endfunction
You can just Ctrl+ L to clear the message on the status
line.
I just realized that VIM 7.3 has built-in support for highlighting Markdown files. Excellent. However, it doesn't fold on the headings.
Can any offer suggestions on how to get this working?
Alternatively, I'm using Markdown only as a way to get simple structured text. If there is a better alternative format, please also suggest. But not sure I dig TVO or VimOutliner.
When I use markdown I only use the hash-style headings with space separating hashes and text.
This makes the folding task a lot simpler.
I'm pretty new to Vim, so use the following at your own risk.
I added the following code to my vimrc and it folds headings based on number of hashes, and it retains the syntax colouring.
function! MarkdownLevel()
if getline(v:lnum) =~ '^# .*$'
return ">1"
endif
if getline(v:lnum) =~ '^## .*$'
return ">2"
endif
if getline(v:lnum) =~ '^### .*$'
return ">3"
endif
if getline(v:lnum) =~ '^#### .*$'
return ">4"
endif
if getline(v:lnum) =~ '^##### .*$'
return ">5"
endif
if getline(v:lnum) =~ '^###### .*$'
return ">6"
endif
return "="
endfunction
au BufEnter *.md setlocal foldexpr=MarkdownLevel()
au BufEnter *.md setlocal foldmethod=expr
let g:markdown_folding = 1
You can enable markdown folding feature by adding this in your .vimrc if you are using the latest version of Vim - no need to be the latest, but I don't know the exact version.
For some reason it's not documented in the README but you can find the related code in the repository.
FYI, if you don't want the sections closed when you open a file, refer to this SO thread. I think adding this would be the best way but you may have a different preference.
set nofoldenable
Update
Unfortunately, I stopped using markdown_folding since it makes things slow (Github issue).
I had the same question, and played around with Jander's nice solution. The only problem is that by defining folding using syntax, you lose any Markdown syntax highlighting.
Given that you might be interested in alternate markups, I would suggest using reStructuredText, and the amazing Vst vim extension. It does folding very nicely. Rst is much more powerful than Markdown.
Here is a try at a recursive header folding rule. It doesn't include the underline style of Markdown header, but I'm guessing those would be awkward for your purposes anyway.
Put the following code into your .vimrc:
au FileType markdown syn region myMkdHeaderFold
\ start="\v^\s*\z(\#{1,6})"
\ skip="\v(\n\s*\z1\#)\#="
\ end="\v\n(\s*\#)\#="ms=s-1,me=s-1
\ fold contains=myMkdHeaderFold
au FileType markdown syn sync fromstart
au FileType markdown set foldmethod=syntax
There is a vim-markdown plugin at https://github.com/plasticboy/vim-markdown .
The code related to folding from there appears to be:
" fold region for headings
syn region mkdHeaderFold
\ start="^\s*\z(#\+\)"
\ skip="^\s*\z1#\+"
\ end="^\(\s*#\)\#="
\ fold contains=TOP
" fold region for lists
syn region mkdListFold
\ start="^\z(\s*\)\*\z(\s*\)"
\ skip="^\z1 \z2\s*[^#]"
\ end="^\(.\)\#="
\ fold contains=TOP
syn sync fromstart
setlocal foldmethod=syntax
There is an app a plugin for that on GitHub.
vim-markdown-folding
When you are editing Markdown files with Vim, you probably also want to install Tim Pope's Markdown plugin.
vim-markdown
The only way how I get folding to work in markdown, was't very elegant, :set fdm=marker and use html comment tag
<!-- My folding {{{1 -->
more help :help folding
I'm guessing you don't watch VimCasts. The guy who makes that made a pugin for just this. Here it is: https://github.com/nelstrom/vim-markdown-folding
Based on Jeromy & Omar's suggestions, I came up with this (for my vimrc) to automatically and unambiguously fold my DokuWiki files (in which top level header is marked by ====== at start of line, down to fourth level header marked by ===):
function! DWTitleLevel()
let j = len(matchstr(getline(v:lnum), '^=\+'))
if j =~ 6 | return ">1"
elseif j =~ 5 | return ">2"
elseif j =~ 4 | return ">3"
elseif j =~ 3 | return ">4"
endif
endfunction
'^=+' means match from the start of the line any number of contiguous '='s
Then this in a vim modeline makes it work nicely for a DokuWiki file:
foldmethod=expr foldexpr=DWTitleLevel() foldcolumn=5
And for Markdown, I needed to write Omar's code like this:
if empty(j) | return "=" | else | return ">".len(j) | endif
VOoM : Vim two-pane outliner is worth checking it out.
Not only does it provide basic folding, but it also provides outline navigation via a 2nd outline view pane (similar to document map in MS Word). And it supports a large number of markup languages including others mentioned in other answers - Markdown, viki, reStructuredText, vimwiki, org, and many others.
For more info see the screenshots and the help page.
As of Vim 8 it is included by default (via Tim Pope's markdown plugin). Just add this to .vimrc:
let g:markdown_folding=1
To make sure you have this plugin loaded you can run
:showscripts
and look for
vim80/syntax/markdown.vim
Working from #Omar comment to this answer, I coded a fold method to languages which comment with //, like JS. Add following to ~/.vimrc:
autocmd FileType javascript setlocal foldmethod=expr foldcolumn=6
autocmd FileType javascript setlocal foldexpr=JSFolds()
" Level of a folding:
"// #: level 1
"// ##: level 2
"// ###: level 3
function! JSFolds()
" Option 1: // and no space and hashes:
"if getline(v:lnum) =~ '^//#'
" Option 2: // and 1 space and hashes:
"if getline(v:lnum) =~ '^//\+ #'
" Option 3: spaces/tabs/nothing and // and 1 space and hashes:
if getline(v:lnum) =~ '^\s*//\+ #'
" Option 4: anything and // and 1 space and hashes:
" DANEGROUS! Potential conflict with code. E.g. print("// # Title");
" if getline(v:lnum) =~ '//\+ #'
" Number of hashs # in line that success previous condition (if)
" determine the fold level
let repeatHash = len(matchstr(getline(v:lnum), '#\+'))
return ">" . repeatHash
endif
return "="
endfunction
Examples. Note on the left the fold levels ("|" and "-"):
- // # ** Fold style recommended **
- // # 1 easy case
|- // ## 2 easy case
||- // ### 3 easy case
||| // Comment inside level 3
|||- // #### 4 easy case
|||| // Comment inside level 4
|- // ## 2 easy case (indents are OK with Option 3)
|| /#### error (JS comment needs 2 slashes)
||
- // # ** Fold of just 1 line **
|-- // ### 3 easy case
||- // ### = same fold level as previous line, thus previous line folds just itself ?!? (not concerns this fold function)
|||
- // # ** Space needed before, BUT not needed after hash/-es **
|- // ##Fold Level changed Because no space after hashes is OK: '// # ' vs '// #NoSpace'. NoSpace could even be a return carriage (enter).
|| //## Fold Level Unchanged Because no space after pair of slashes: '// #' vs '//#'
|| // ##txt Unchanged Because too much space after slashes
|| // ## txt Unchanged Because too much space after slashes
||
- // # ** Odds vs Even slashes **
- /// # 1 overrides typo 3 slash instead of just 2 (/// vs //)
- ///// # 1 overrides typo 5 slash instead of just 4 (///// vs ////). Read Recommenting Comments notes.
|- // ## ** As long as the pattern is at least '// # ', further previous slashes are ok **
- // # 1 easy case
|-- // ### 3 ok (and recommended fold style)
||- ///// ### 3 ok (recommented + typo)
||- ////// ### 3 ok (re-recommented)
||- /// ### 3 ok (typo)
||- //// ### 3 ok (recommented)
||- ///////// ### 3 ok (who cares? it works!)
|||
- // # ** Recommenting Comments **
- // # 1 easy case
| // Comment inside level 1
- //// # 1 recommented a comment
| //// Comment inside level 1
- ///// # 1 re-re-recomment
| ///// Comment inside level 1
|
- // # ** Recommenting Comments adding text **
|-- // ### //// # 3 changing fold level on purpose of a recommented a comment
||| // Comment inside level 3
||| // text // ## 2 (recommented a comment adding text)
||| // text#text // ## 2 right {recommented a comment adding initial text, as long as this text has no hash just after '// ' (2*slash + space) would be ok }
- // #text#text // ## 2 wrongly {recommented a comment adding initial text, as long as this text has no hash just after '// ' (2*slash + space) would be ok }
- // # changeFoldIntentionally // ## 1 clear intention to change fold level of comments
- // #changeFoldIntentionally // ## 1 clear intention to change fold level of comments (previousi example, with space after hash would be clearer)
|-- // ### changeFoldIntentionally // ## 3 clear intention to change fold level of comments
|||
PD: totally open to critics and improvements of the code. Actually I'm a beginner with vimscript.
Here's what I came up with as a combination of many of the other answers here. I found that most of them, including the builtin g:markdown_folding, do not properly handle code blocks that contain # characters as part of comments. I based this on matching the syntax IDs, which also handles <h1-6> tags properly.
" ~/.vim/ftplugin/markdown.vim
function MarkdownLevel(lnum)
for synID in synstack(a:lnum, 1)
let name = synIDattr(synID, "name")
if name == 'htmlH1' | return ">1"
elseif name == 'htmlH2' | return ">2"
elseif name == 'htmlH3' | return ">3"
elseif name == 'htmlH4' | return ">4"
elseif name == 'htmlH5' | return ">5"
elseif name == 'htmlH6' | return ">6"
endif
endfor
return "="
endfunction
setlocal foldexpr=MarkdownLevel(v:lnum)
setlocal foldmethod=expr
setlocal foldlevel=1
I want to be able to write \bit and have it expand to something in vim. How do I encode a backslash in the left-hand side of an abbreviation, though?
I tried all of these:
:iab \bit replacement_text
:iab <Bslash>bit replacement_text
:iab <bs>bit replacement_text
but got E474: Invalid argument for all of these.
The map_backslash help-topic suggests <Bslash>, but this doesn't seem to work.
You can define your abbreviation on "bit", and then test if it is preceded by "", if so, return the new text, or "bit" otherwise.
function! s:Expr(default, repl) expr
if getline('.')[col('.')-2]=='\'
return "\<bs>".a:repl
else
return a:default
endif
endfunction
:inoreab bit <c-r>=<sid>Expr('bit', 'foobar')<cr>
That's the kind of tricks I used in MapNoContext().
EDIT: see :h abbreviations for the reasons why what you asked can't be achieved directly.
EDIT2: It can be easily encapsulated this way:
function! s:DefIab(nore, ...) abort
let opt = ''
let i = 0
while i != len(a:000)
let arg = a:000[i]
if arg !~? '<buffer>\|<silent>'
break
endif
let opt .= ' '.arg
let i += 1
endwhile
if i+2 != len(a:000)
throw "Invalid number of arguments"
endif
let lhs = a:000[i]
let rhs = a:000[i+1]
exe 'i'.a:nore.'ab'.opt.' '.lhs.' <c-r>=<sid>Expr('.string(lhs).', '.string(rhs).')<cr>'
endfunction
command! -nargs=+ InoreabBSlash call s:DefIab('nore', <f-args>)
And used with a simple:
InoreabBSlash <buffer> locbit foobar
or
InoreabBSlash bit foobar
I suggest using backslash on both sides, vim is happy that way:
inoreabbr \bit\ replacement_text
Note that I am using the "nore" version of abbr, better to be clear if you don't intend a recursive expansion. I have been using the below abbreviations for a long time and they work great:
inoreabbr \time\ <C-R>=strftime("%d-%b-%Y # %H:%M")<CR>
inoreabbr \date\ <C-R>=strftime("%d-%b-%Y")<CR>
:set iskeyword+=\
in vimrc_tex (or just vimrc) works perfectly.
you could
inoremap \bit replacementtext
Also if you dont like the lag an alternative leader like backtick ` (above the tab for me)
:iab `f foobar
if you are not using them in your code often
You can only use a backslash as a prefix for an abbreviation if it's only got a single character following it, so :iab \b replacementtext will work.