merge upstream

This commit is contained in:
ckelsel 2017-07-21 20:25:36 +08:00
commit 2c89195afd
17 changed files with 1091 additions and 2745 deletions

View File

@ -16,6 +16,12 @@ function! s:selection.on_exit(jobid, data, event) abort
endif
endfunction
function! s:selection.on_stderr(jobid, data, event) abort
echohl WarningMsg
echomsg 'clipboard: error invoking '.get(self.argv, 0, '?').': '.join(a:data)
echohl None
endfunction
let s:selections = { '*': s:selection, '+': copy(s:selection)}
function! s:try_cmd(cmd, ...) abort
@ -135,24 +141,17 @@ function! s:clipboard.set(lines, regtype, reg) abort
end
let selection.data = [a:lines, a:regtype]
let argv = split(s:copy[a:reg], " ")
let selection.argv = argv
let selection.detach = s:cache_enabled
let selection.cwd = "/"
call extend(selection, {
\ 'on_stdout': function('s:set_errhandler'),
\ 'on_stderr': function('s:set_errhandler'),
\ })
let jobid = jobstart(argv, selection)
if jobid > 0
call jobsend(jobid, a:lines)
call jobclose(jobid, 'stdin')
let selection.owner = jobid
endif
endfunction
function! s:set_errhandler(job_id, data, event) abort
if a:job_id <= 0
else
echohl WarningMsg
echo 'clipboard: error when invoking provider: ' . join(a:data)
echomsg 'clipboard: failed to execute: '.(s:copy[a:reg])
echohl None
endif
endfunction

View File

@ -15,30 +15,17 @@ function! tutor#SetupVim()
endif
endfunction
" Mappings: {{{1
function! s:CheckMaps()
nmap
" Loads metadata file, if available
function! tutor#LoadMetadata()
let b:tutor_metadata = json_decode(join(readfile(expand('%').'.json'), "\n"))
endfunction
function! s:MapKeyWithRedirect(key, cmd)
if maparg(a:key) !=# ''
redir => l:keys
silent call s:CheckMaps()
redir END
let l:key_list = split(l:keys, '\n')
" Mappings: {{{1
let l:raw_map = filter(copy(l:key_list), "v:val =~# '\\* ".a:key."'")
if len(l:raw_map) == 0
exe "nnoremap <buffer> <expr> ".a:key." ".a:cmd
return
endif
let l:map_data = split(l:raw_map[0], '\s*')
exe "nnoremap <buffer> <expr> ".l:map_data[0]." ".a:cmd
else
exe "nnoremap <buffer> <expr> ".a:key." ".a:cmd
endif
function! tutor#SetNormalMappings()
nnoremap <silent> <buffer> <CR> :call tutor#FollowLink(0)<cr>
nnoremap <silent> <buffer> <2-LeftMouse> :call tutor#MouseDoubleClick()<cr>
nnoremap <buffer> >> :call tutor#InjectCommand()<cr>
endfunction
function! tutor#MouseDoubleClick()
@ -46,7 +33,7 @@ function! tutor#MouseDoubleClick()
normal! zo
else
if match(getline('.'), '^#\{1,} ') > -1
normal! zc
silent normal! zc
else
call tutor#FollowLink(0)
endif
@ -59,114 +46,6 @@ function! tutor#InjectCommand()
redraw | echohl WarningMsg | echon "tutor: ran" | echohl None | echon " " | echohl Statement | echon l:cmd
endfunction
function! tutor#SetNormalMappings()
call s:MapKeyWithRedirect('l', 'tutor#ForwardSkipConceal(v:count1)')
call s:MapKeyWithRedirect('h', 'tutor#BackwardSkipConceal(v:count1)')
call s:MapKeyWithRedirect('<right>', 'tutor#ForwardSkipConceal(v:count1)')
call s:MapKeyWithRedirect('<left>', 'tutor#BackwardSkipConceal(v:count1)')
nnoremap <silent> <buffer> <CR> :call tutor#FollowLink(0)<cr>
nnoremap <silent> <buffer> <2-LeftMouse> :call tutor#MouseDoubleClick()<cr>
nnoremap <buffer> >> :call tutor#InjectCommand()<cr>
endfunction
function! tutor#SetSampleTextMappings()
noremap <silent> <buffer> A :if match(getline('.'), '^--->') > -1 \| call search('\s{\@=', 'Wc') \| startinsert \| else \| startinsert! \| endif<cr>
noremap <silent> <buffer> $ :if match(getline('.'), '^--->') > -1 \| call search('.\s{\@=', 'Wc') \| else \| call search('$', 'Wc') \| endif<cr>
onoremap <silent> <buffer> $ :if match(getline('.'), '^--->') > -1 \| call search('.\s{\@=', 'Wc') \| else \| call search('$', 'Wc') \| endif<cr>
noremap <silent> <buffer> ^ :if match(getline('.'), '^--->') > -1 \| call search('\(--->\s\)\@<=.', 'bcW') \| else \| call search('^', 'bcW') \|endif<cr>
onoremap <silent> <buffer> ^ :if match(getline('.'), '^--->') > -1 \| call search('\(--->\s\)\@<=.', 'bcW') \| else \| call search('^', 'bcW') \|endif<cr>
nmap <silent> <buffer> 0 ^<esc>
nmap <silent> <buffer> <Home> ^<esc>
nmap <silent> <buffer> <End> $
imap <silent> <buffer> <Home> <esc>^<esc>:startinsert<cr>
imap <silent> <buffer> <End> <esc>$:startinsert<cr>
noremap <silent> <buffer> I :exe "normal! 0" \| startinsert<cr>
endfunction
" Navigation: {{{1
" taken from http://stackoverflow.com/a/24224578
function! tutor#ForwardSkipConceal(count)
let cnt=a:count
let mvcnt=0
let c=col('.')
let l=line('.')
let lc=col('$')
let line=getline('.')
while cnt
if c>=lc
let mvcnt+=cnt
break
endif
if stridx(&concealcursor, 'n')==-1
let isconcealed=0
else
let [isconcealed, cchar, group] = synconcealed(l, c)
endif
if isconcealed
let cnt-=strchars(cchar)
let oldc=c
let c+=1
while c < lc
let [isconcealed2, cchar2, group2] = synconcealed(l, c)
if !isconcealed2 || cchar2 != cchar
break
endif
let c+= 1
endwhile
let mvcnt+=strchars(line[oldc-1:c-2])
else
let cnt-=1
let mvcnt+=1
let c+=len(matchstr(line[c-1:], '.'))
endif
endwhile
return mvcnt.'l'
endfunction
function! tutor#BackwardSkipConceal(count)
let cnt=a:count
let mvcnt=0
let c=col('.')
let l=line('.')
let lc=0
let line=getline('.')
while cnt
if c<=1
let mvcnt+=cnt
break
endif
if stridx(&concealcursor, 'n')==-1 || c == 0
let isconcealed=0
else
let [isconcealed, cchar, group]=synconcealed(l, c-1)
endif
if isconcealed
let cnt-=strchars(cchar)
let oldc=c
let c-=1
while c>1
let [isconcealed2, cchar2, group2] = synconcealed(l, c-1)
if !isconcealed2 || cchar2 != cchar
break
endif
let c-=1
endwhile
let c = max([c, 1])
let mvcnt+=strchars(line[c-1:oldc-2])
else
let cnt-=1
let mvcnt+=1
let c-=len(matchstr(line[:c-2], '.$'))
endif
endwhile
return mvcnt.'h'
endfunction
" Hypertext: {{{1
function! tutor#FollowLink(force)
let l:stack_s = join(map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")'), '')
if l:stack_s =~# 'tutorLink'
@ -209,42 +88,40 @@ function! tutor#InfoText()
return join(l:info_parts, " ")
endfunction
" Marks {{{1
function! tutor#PlaceXMarks()
call cursor(1, 1)
let b:tutor_sign_id = 1
while search('^--->', 'W') > 0
call tutor#CheckText(getline('.'))
let b:tutor_sign_id+=1
endwhile
call cursor(1, 1)
" Marks: {{{1
function! tutor#ApplyMarks()
hi! link tutorExpect Special
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let b:tutor_sign_id = 1
for expct in keys(b:tutor_metadata['expect'])
let lnum = eval(expct)
call matchaddpos('tutorExpect', [lnum])
call tutor#CheckLine(lnum)
endfor
endif
endfunction
function! tutor#CheckText(text)
if match(a:text, '{expect:ANYTHING}\s*$') == -1
if match(getline('.'), '^--->\s*$') > -1
exe "sign place ".b:tutor_sign_id." line=".line('.')." name=tutorbad buffer=".bufnr('%')
else
if match(getline('.'), '|expect:.\+|') == -1
let l:cur_text = matchstr(a:text, '---> \zs.\{-}\ze {expect:')
let l:expected_text = matchstr(a:text, '{expect:\zs.*\ze}\s*$')
else
let l:cur_text = matchstr(a:text, '---> \zs.\{-}\ze |expect:')
let l:expected_text = matchstr(a:text, '|expect:\zs.*\ze|\s*$')
endif
if l:cur_text ==# l:expected_text
exe "sign place ".b:tutor_sign_id." line=".line('.')." name=tutorok buffer=".bufnr('%')
else
exe "sign place ".b:tutor_sign_id." line=".line('.')." name=tutorbad buffer=".bufnr('%')
endif
function! tutor#ApplyMarksOnChanged()
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let lnum = line('.')
if index(keys(b:tutor_metadata['expect']), string(lnum)) > -1
call tutor#CheckLine(lnum)
endif
endif
endfunction
function! tutor#OnTextChanged()
let l:text = getline('.')
if match(l:text, '^--->') > -1
call tutor#CheckText(l:text)
function! tutor#CheckLine(line)
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
let bufn = bufnr('%')
let ctext = getline(a:line)
if b:tutor_metadata['expect'][string(a:line)] == -1 || ctext ==# b:tutor_metadata['expect'][string(a:line)]
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorok buffer=".bufn
else
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorbad buffer=".bufn
endif
let b:tutor_sign_id+=1
endif
endfunction

View File

@ -4273,7 +4273,8 @@ getqflist([{what}]) *getqflist()*
If the optional {what} dictionary argument is supplied, then
returns only the items listed in {what} as a dictionary. The
following string items are supported in {what}:
nr get information for this quickfix list
nr get information for this quickfix list; zero
means the current quickfix list
title get the list title
winid get the |window-ID| (if opened)
all all of the above quickfix properties

View File

@ -19,27 +19,30 @@ setlocal noundofile
setlocal keywordprg=:help
setlocal iskeyword=@,-,_
setlocal foldmethod=expr
" The user will have to enable the folds himself, but we provide the foldexpr
" function.
setlocal foldmethod=manual
setlocal foldexpr=tutor#TutorFolds()
setlocal foldcolumn=1
setlocal foldlevel=4
setlocal nowrap
setlocal statusline=%{toupper(expand('%:t:r'))}\ tutorial%=
setlocal statusline+=%{tutor#InfoText()}
" Load metadata if it exists: {{{1
if filereadable(expand('%').'.json')
call tutor#LoadMetadata()
endif
" Mappings: {{{1
call tutor#SetNormalMappings()
call tutor#SetSampleTextMappings()
" Checks: {{{1
sign define tutorok text=texthl=tutorOK
sign define tutorbad text=texthl=tutorX
if !exists('g:tutor_debug') || g:tutor_debug == 0
call tutor#PlaceXMarks()
autocmd! TextChanged <buffer> call tutor#OnTextChanged()
autocmd! TextChangedI <buffer> call tutor#OnTextChanged()
if !exists('g:tutor_debug') || g:tutor_debug == 0
call tutor#ApplyMarks()
autocmd! TextChanged,TextChangedI <buffer> call tutor#ApplyMarksOnChanged()
endif

View File

@ -31,26 +31,20 @@ syn keyword tutorMarks TODO NOTE IMPORTANT TIP ATTENTION EXERCISE
syn keyword tutorMarks todo note tip attention exercise
syn keyword tutorMarks Todo Note Tip Excersise
syn match tutorTextMark /\\\@<!--->/ conceal cchar=
syn region tutorSampleText start=/^\(--->\)\@=/ end=/$/ keepend contains=@SPELL
syn match tutorSampleTextMark /^--->/ contained containedin=tutorSampleText conceal cchar=
syn match tutorSampleTextExpect /\}\@<! {expect:.\+}\s*$/ contained containedin=tutorSampleText conceal
syn match tutorSampleTextExpect /|\@<! |expect:.\+|\s*$/ contained containedin=tutorSampleText conceal
syn region tutorCodeblock matchgroup=Delimiter start=/^\~\{3}.*$/ end=/^\~\{3}/
syn region tutorShell matchgroup=Delimiter start=/^\~\{3} sh\s*$/ end=/^\~\{3}/ keepend contains=@TUTORSHELL concealends
syn region tutorShell matchgroup=Delimiter start=/^\~\{3} sh\s*$/ end=/^\~\{3}/ keepend contains=@TUTORSHELL
syn match tutorShellPrompt /\(^\s*\)\@<=[$#]/ contained containedin=tutorShell
syn region tutorInlineCode matchgroup=Delimiter start=/\\\@<!`/ end=/\\\@<!\(`{\@!\|`\s\)/ concealends
syn region tutorInlineCode matchgroup=Delimiter start=/\\\@<!`/ end=/\\\@<!\(`{\@!\|`\s\)/
syn region tutorCommand matchgroup=Delimiter start=/^\~\{3} cmd\( :\)\?\s*$/ end=/^\~\{3}/ keepend contains=@VIM concealends
syn region tutorInlineCommand matchgroup=Delimiter start=/\\\@<!`\(.*{vim}\)\@=/ end=/\\\@<!`\({vim}\)\@=/ nextgroup=tutorInlineType contains=@VIM concealends
syn region tutorCommand matchgroup=Delimiter start=/^\~\{3} cmd\( :\)\?\s*$/ end=/^\~\{3}/ keepend contains=@VIM
syn region tutorInlineCommand matchgroup=Delimiter start=/\\\@<!`\(.*{vim}\)\@=/ end=/\\\@<!`\({vim}\)\@=/ nextgroup=tutorInlineType contains=@VIM
syn region tutorNormal matchgroup=Delimiter start=/^\~\{3} norm\(al\?\)\?\s*$/ end=/^\~\{3}/ contains=@VIMNORMAL concealends
syn region tutorInlineNormal matchgroup=Delimiter start=/\\\@<!`\(\S*{normal}\)\@=/ end=/\\\@<!`\({normal}\)\@=/ nextgroup=tutorInlineType contains=@VIMNORMAL concealends
syn region tutorNormal matchgroup=Delimiter start=/^\~\{3} norm\(al\?\)\?\s*$/ end=/^\~\{3}/ contains=@VIMNORMAL
syn region tutorInlineNormal matchgroup=Delimiter start=/\\\@<!`\(\S*{normal}\)\@=/ end=/\\\@<!`\({normal}\)\@=/ nextgroup=tutorInlineType contains=@VIMNORMAL
syn match tutorInlineType /{\(normal\|vim\)}/ contained conceal
syn match tutorInlineType /{\(normal\|vim\)}/ contained
syn match tutorInlineOK /✓/
syn match tutorInlineX /✗/
@ -72,7 +66,7 @@ hi! tutorMarks cterm=bold gui=bold
hi! tutorEmphasis gui=italic cterm=italic
hi! tutorBold gui=bold cterm=bold
hi! link tutorSampleText Special
hi! link tutorExpect Special
hi! tutorOK ctermfg=green guifg=#00ff88 cterm=bold gui=bold
hi! tutorX ctermfg=red guifg=#ff2000 cterm=bold gui=bold
hi! link tutorInlineOK tutorOK

View File

@ -18,10 +18,10 @@ be saved. Don't worry about messing things up; just remember that pressing
[<Esc>](<Esc>) and then [u](u) will undo the latest change.
This tutorial is interactive, and there are a few things you should know.
Pressing [<Enter>](<Enter>) over text highlighted [like this](holy-grail) will take you to some relevant
help (hopefully), and pressing K over any word will try to do so too. Sometimes
you will be required to modify text like
---> this here {expect:this here}
Pressing [<Enter>](<Enter>) over text highlighted [like this](holy-grail) will take you to some
relevant help (hopefully), and pressing K over any word will try to do so too.
Sometimes you will be required to modify text like
this here
Once you have done the changes correctly, the ✗ sign at the left will change
to ✓. I imagine you can already see how neat Vim can be ;)
Other times, you'll be prompted to run a command (I'll explain this later):
@ -99,7 +99,7 @@ NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
4. Repeat steps 2 through 4 until the sentence is correct.
---> The ccow jumpedd ovverr thhe mooon. {expect:The cow jumped over the moon.}
The ccow jumpedd ovverr thhe mooon.
5. Now that the line is correct, go on to Lesson 1.4.
@ -119,8 +119,8 @@ NOTE: As you go through this tutor, do not try to memorize, learn by usage.
4. As each error is fixed press <Esc> to return to Normal mode.
Repeat steps 2 through 4 to correct the sentence.
---> There is text misng this . {expect:There is some text missing from this line.}
---> There is some text missing from this line. {expect:There is some text missing from this line.}
There is text misng this .
There is some text missing from this line.
5. When you are comfortable inserting text move to lesson 1.5.
@ -138,10 +138,10 @@ NOTE: As you go through this tutor, do not try to memorize, learn by usage.
4. Move the cursor to the second line marked ---> and repeat
steps 2 and 3 to correct this sentence.
---> There is some text missing from th {expect:There is some text missing from this line.}
---> There is some text missing from this line. {expect:There is some text missing from this line.}
---> There is also some text miss {expect:There is also some text missing here.}
---> There is also some text missing here. {expect:There is also some text missing here.}
There is some text missing from th
There is some text missing from this line.
There is also some text miss
There is also some text missing here.
5. When you are comfortable appending text move to lesson 1.6.
@ -212,7 +212,7 @@ Now continue with Lesson 2.
4. Type [d](d)[w](w) to make the word disappear.
---> There are a some words fun that don't belong paper in this sentence. {expect:There are some words that don't belong in this sentence.}
There are a some words fun that don't belong paper in this sentence.
5. Repeat steps 3 and 4 until the sentence is correct and go to Lesson 2.2.
@ -228,7 +228,7 @@ Now continue with Lesson 2.
4. Type `d$`{normal} to delete to the end of the line.
---> Somebody typed the end of this line twice. end of this line twice. {expect:ANYTHING}
Somebody typed the end of this line twice. end of this line twice.
5. Move on to Lesson 2.3 to understand what is happening.
@ -268,7 +268,7 @@ NOTE: Pressing just the motion while in Normal mode without an operator will
5. Repeat steps 2 and 3 with different numbers.
---> This is just a line with words you can move around in. {expect:ANYTHING}
This is just a line with words you can move around in.
6. Move on to Lesson 2.5.
@ -287,7 +287,7 @@ insert a count before the motion to delete more:
3. Repeat steps 1 and 2 with a different count to delete the consecutive
UPPER CASE words with one command
---> this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up. {expect:this line of words is cleaned up.}
this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
# Lesson 2.6: OPERATING ON LINES
@ -301,13 +301,13 @@ insert a count before the motion to delete more:
3. Now move to the fourth line.
4. Type `2dd`{normal} to delete two lines.
---> 1) Roses are red, {expect:ANYTHING}
---> 2) Mud is fun, {expect:ANYTHING}
---> 3) Violets are blue, {expect:ANYTHING}
---> 4) I have a car, {expect:ANYTHING}
---> 5) Clocks tell time, {expect:ANYTHING}
---> 6) Sugar is sweet {expect:ANYTHING}
---> 7) And so are you. {expect:ANYTHING}
1) Roses are red,
2) Mud is fun,
3) Violets are blue,
4) I have a car,
5) Clocks tell time,
6) Sugar is sweet
7) And so are you.
# Lesson 2.7: THE UNDO COMMAND
@ -322,7 +322,7 @@ insert a count before the motion to delete more:
6. Now type `u`{normal} a few times to undo the U and preceding commands.
7. Now type `<Ctrl-r>`{normal} a few times to redo the commands (undo the undo's).
---> Fiix the errors oon thhis line and reeplace them witth undo. {expect:Fix the errors on this line and replace them with undo.}
Fiix the errors oon thhis line and reeplace them witth undo.
8. These are very useful commands. Now move on to the Lesson 2 Summary.
@ -362,10 +362,10 @@ insert a count before the motion to delete more:
5. Repeat steps 2 through 4 to put all the lines in correct order.
---> d) Can you learn too? {expect:ANYTHING}
---> b) Violets are blue, {expect:ANYTHING}
---> c) Intelligence is learned, {expect:ANYTHING}
---> a) Roses are red, {expect:ANYTHING}
d) Can you learn too?
b) Violets are blue,
c) Intelligence is learned,
a) Roses are red,
# Lesson 3.2: THE REPLACE COMMAND
@ -379,8 +379,8 @@ insert a count before the motion to delete more:
4. Repeat steps 2 and 3 until the first line is equal to the second one.
---> Whan this lime was tuoed in, someone presswd some wrojg keys! {expect:When this line was typed in, someone pressed some wrong keys!}
---> When this line was typed in, someone pressed some wrong keys! {expect:When this line was typed in, someone pressed some wrong keys!}
Whan this lime was tuoed in, someone presswd some wrojg keys!
When this line was typed in, someone pressed some wrong keys!
5. Now move on to Lesson 3.3.
@ -400,8 +400,8 @@ NOTE: Remember that you should be learning by doing, not memorization.
5. Repeat steps 3 and 4 until the first sentence is the same as the second.
---> This lubw has a few wptfd that mrrf changing usf the change operator. {expect:This line has a few words that need changing using the change operator.}
---> This line has a few words that need changing using the change operator. {expect:This line has a few words that need changing using the change operator.}
This lubw has a few wptfd that mrrf changing usf the change operator.
This line has a few words that need changing using the change operator.
Notice that [c](c)e deletes the word and places you in Insert mode.
@ -421,8 +421,8 @@ Notice that [c](c)e deletes the word and places you in Insert mode.
5. Type `c$`{normal} and type the rest of the line like the second and press `<Esc>`{normal}.
---> The end of this line needs some help to make it like the second. {expect:The end of this line needs to be corrected using the c$ command.}
---> The end of this line needs to be corrected using the c$ command. {expect:The end of this line needs to be corrected using the c$ command.}
The end of this line needs some help to make it like the second.
The end of this line needs to be corrected using the c$ command.
NOTE: You can use the Backspace key to correct mistakes while typing.
@ -484,7 +484,7 @@ NOTE: You may see the cursor position in the lower right corner of the screen
5. To go back to where you came from press `<Ctrl-o>`{normal} (Keep Ctrl down while
pressing the letter o). Repeat to go back further. `<Ctrl-i>`{normal} goes forward.
---> "errroor" is not the way to spell error; errroor is an error. {expect:ANYTHING}
"errroor" is not the way to spell error; errroor is an error.
NOTE: When the search reaches the end of the file it will continue at the
start, unless the ['wrapscan']('wrapscan') option has been reset.
@ -503,7 +503,7 @@ NOTE: When the search reaches the end of the file it will continue at the
5. Move the cursor to another (,),[,],{ or } and see what `%`{normal} does.
---> This ( is a test line with ('s, ['s ] and {'s } in it. )) {expect:ANYTHING}
This ( is a test line with ('s, ['s ] and {'s } in it. ))
NOTE: This is very useful in debugging a program with unmatched parentheses!
@ -528,7 +528,7 @@ NOTE: This is very useful in debugging a program with unmatched parentheses!
Adding the g [flag](:s_flags) means to substitute globally in the line, change
all occurrences of "thee" in the line.
---> thee best time to see thee flowers is in thee spring. {expect:the best time to see the flowers is in the spring.}
thee best time to see thee flowers is in thee spring.
4. To change every occurrence of a character string between two lines, type
~~~ cmd
@ -719,12 +719,12 @@ NOTE: You can also read the output of an external command. For example,
3. Now type some text and press `<Esc>`{normal} to exit Insert mode.
---> After typing o the cursor is placed on the open line in Insert mode. {expect:ANYTHING}
After typing o the cursor is placed on the open line in Insert mode.
4. To open up a line ABOVE the cursor, simply type a [capital O](O), rather
than a lowercase `o`{normal}. Try this on the line below.
---> Open up a line above this by typing O while the cursor is on this line. {expect:ANYTHING}
Open up a line above this by typing O while the cursor is on this line.
# Lesson 6.2: THE APPEND COMMAND
@ -741,8 +741,8 @@ NOTE: You can also read the output of an external command. For example,
5. Use `e`{normal} to move to the next incomplete word and repeat steps 3 and 4.
---> This li will allow you to pract appendi text to a line. {expect:This line will allow you to practice appending text to a line.}
---> This line will allow you to practice appending text to a line. {expect:This line will allow you to practice appending text to a line.}
This li will allow you to pract appendi text to a line.
This line will allow you to practice appending text to a line.
NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only difference is where
the characters are inserted.
@ -762,8 +762,8 @@ NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only differ
4. Repeat the steps to replace the remaining "xxx".
---> Adding 123 to xxx gives you xxx. {expect:Adding 123 to 456 gives you 579.}
---> Adding 123 to 456 gives you 579. {expect:Adding 123 to 456 gives you 579.}
Adding 123 to xxx gives you xxx.
Adding 123 to 456 gives you 579.
NOTE: Replace mode is like Insert mode, but every typed character deletes an
existing character.
@ -785,8 +785,8 @@ NOTE: Replace mode is like Insert mode, but every typed character deletes an
6. Use Visual mode to select " item.", yank it with `y`{normal}, move to the end of
the next line with `j$`{normal} and put the text there with `p`{normal}.
---> a) this is the first item.
---> b) {expect: b) this is the second item}
a) this is the first item.
b)
NOTE: you can also use `y`{normal} as an operator; `yw`{normal} yanks one word.
@ -947,8 +947,10 @@ There are many resources online to learn more about vim. Here's a bunch of them:
- Vim Video-Tutorials by Derek Wyatt: http://derekwyatt.org/vim/tutorials/
- *Learn Vimscript the Hard Way*: http://learnvimscriptthehardway.stevelosh.com/
- *7 Habits of Effective Text Editing*: http://www.moolenaar.net/habits.html
- *vim-galore*: https://github.com/mhinz/vim-galore
If you prefer a book, *Practival Vim* by Drew Neil is recommended often.
If you prefer a book, *Practical Vim* by Drew Neil is recommended often (the sequel, *Modern
Vim*, includes material specific to nvim!).
This tutorial was written by Michael C. Pierce and Robert K. Ware, Colorado
School of Mines using ideas supplied by Charles Smith, Colorado State

View File

@ -0,0 +1,45 @@
{
"expect": {
"24": -1,
"102": "The cow jumped over the moon.",
"122": "There is some text missing from this line.",
"123": "There is some text missing from this line.",
"141": "There is some text missing from this line.",
"142": "There is some text missing from this line.",
"143": "There is also some text missing here.",
"144": "There is also some text missing here.",
"215": "There are some words that don't belong in this sentence.",
"231": "Somebody typed the end of this line twice.",
"271": -1,
"290": "this line of words is cleaned up.",
"304": -1,
"305": -1,
"306": -1,
"307": -1,
"308": -1,
"309": -1,
"310": -1,
"325": "Fix the errors on this line and replace them with undo.",
"365": -1,
"366": -1,
"367": -1,
"368": -1,
"382": "When this line was typed in, someone pressed some wrong keys!",
"383": "When this line was typed in, someone pressed some wrong keys!",
"403": "This line has a few words that need changing using the change operator.",
"404": "This line has a few words that need changing using the change operator.",
"424": "The end of this line needs to be corrected using the c$ command.",
"425": "The end of this line needs to be corrected using the c$ command.",
"487": -1,
"506": -1,
"531": "the best time to see the flowers is in the spring.",
"722": -1,
"727": -1,
"744": "This line will allow you to practice appending text to a line.",
"745": "This line will allow you to practice appending text to a line.",
"765": "Adding 123 to 456 gives you 579.",
"766": "Adding 123 to 456 gives you 579.",
"788": "a) this is the first item.",
"789": " b) this is the second item."
}
}

View File

@ -60,27 +60,27 @@ is displayed like
1. Format the line below so it becomes a lesson description:
---> This is text with important information {expect:This is text with **important information**}
---> This is text with **important information** {expect:This is text with **important information**}
This is text with important information
This is text with **important information**
Note: Some words (e.g., NOTE, IMPORTANT, tip, ATTENTION, etc.) will also be
highlighted. You don't need to mark them specially.
2. Turn the line below into a TODO item:
---> Document '&variable' {expect:TODO: Document '&variable'}
---> TODO: Document '&variable' {expect:TODO: Document '&variable'}
Document '&variable'
TODO: Document '&variable'
### Headers *headers*
3. Practice fixing the lines below:
---> This is a level 1 header {expect:# This is a level 1 header}
---> # This is a level 1 header {expect:# This is a level 1 header}
---> This is a level 3 header {expect:### This is a level 3 header}
---> ### This is a level 3 header {expect:### This is a level 3 header}
---> This is a header with a label {expect:# This is a header with a label {*label*}}
---> # This is a header with a label {*label*} {expect:# This is a header with a label {*label*}}
This is a level 1 header
# This is a level 1 header
This is a level 3 header
### This is a level 3 header
This is a header with a label
# This is a header with a label {*label*}
4. Now, create a 4th level section here, and add a label like in the previous
exercise:
@ -105,8 +105,8 @@ If the target of a link matches a help topic, opening it will open it.
5. Fix the following line:
---> A link to help for the 'breakindent' option {expect:A link to help for the ['breakindent']('breakindent') option}
---> A link to help for the ['breakindent']('breakindent') option {expect:A link to help for the ['breakindent']('breakindent') option}
A link to help for the 'breakindent' option
A link to help for the ['breakindent']('breakindent') option
#### Anchor links
@ -120,8 +120,8 @@ and are hidden by default. Links to them look like
6. Add the appropiate link:
---> A link to the Links section {expect:A link to the [Links](*links*) section}
---> A link to the [Links](*links*) section {expect:A link to the [Links](*links*) section}
A link to the Links section
A link to the [Links](*links*) section
7. Now, create a link to the section you created on exercise 4
above.
@ -136,8 +136,8 @@ You can also have links to other tutorials. For this, you'll write the anchor in
7. Create a link to this tutorial:
---> A link to the vim-tutor-mode tutorial {expect:A link to [the vim-tutor-mode tutorial](@tutor:tutor)}
---> A link to [the vim-tutor-mode tutorial](@tutor:tutor) {expect:A link to [the vim-tutor-mode tutorial](@tutor:tutor)}
A link to the vim-tutor-mode tutorial
A link to [the vim-tutor-mode tutorial](@tutor:tutor)
### Codeblocks *codeblocks*
@ -154,13 +154,13 @@ echom "hello"
8. Copy the viml section below
---> {expect:~~~ viml}
---> {expect:echom "the value of &number is".string(&number)}
---> {expect:~~~}
---> ~~~ viml {expect:~~~ viml}
---> echom "the value of &number is".string(&number) {expect:echom "the value of &number is".string(&number)}
---> ~~~ {expect:~~~}
~~~ viml
echom 'the value of &number is'.string(&number)
~~~
You can inline viml code using "\`" and "\`{vim}":
@ -185,13 +185,13 @@ Note: you can also write `norm` or `normal`.
9. Copy the normal section below
---> {expect:~~~ normal}
---> {expect:d2w}
---> {expect:~~~}
---> ~~~ normal {expect:~~~ normal}
---> d2w {expect:d2w}
---> ~~~ {expect:~~~}
~~~ normal
d2w
~~~
You can also inline normal commands by using "\`" and "\`{normal}":
@ -203,10 +203,11 @@ is displayed:
10. Complete the line as shown
---> d {expect:«d2w»}
---> «d2w» {expect:«d2w»}
d
`d2w`{normal}
Commands to run in the system shell can be highlighted by indenting a line starting with "$".
Commands to run in the system shell can be highlighted by indenting a line
starting with "$".
~~~ sh
$ vim --version
@ -215,45 +216,32 @@ Commands to run in the system shell can be highlighted by indenting a line start
## INTERACTIVE ELEMENTS *interactive*
As visible in this very document, vim-tutor-mode includes some interactive
elements, to provide feedback to the user about his progress. These elements
all have the syntax
\---> TEXT {CLAUSE}
where \---> must start at the beginning of the line. If TEXT satisfies CLAUSE,
a ✓ sign will appear to the left. A ✗ sign is displayed otherwise. The CLAUSE
itself is hidden unless debug mode is set or ['conceallevel']('conceallevel')
is 2.
elements to provide feedback to the user about his progress. If the text in
these elements satisfies some set condition, a ✓ sign will appear in the gutter
to the left. Otherwise, a ✗ sign is displayed.
### expect *expect*
The basic clause is "expect", which is satisfied if TEXT is the same as the
content of the clause. For example
"expect" lines check that the contents of the line are identical to some preset text
(like in the exercises above).
\---> TEXT {expect:TEXT}
These elements are specified in separate JSON files like this
is satisfied, but
~~~ json
{
"expect": {
"1": "This is how this line should look.",
"2": "This is how this line should look.",
"3": -1
}
}
~~~
\---> OTHER TEXT {expect:TEXT}
These files contain an "expect" dictionary, for which the keys are line numbers and
the values are the expected text. A value of -1 means that the condition for the line
will always be satisfied, no matter what (this is useful for letting the user play a bit).
is not.
This is an "expect" line that is always satisfied. Try changing it.
13. Make both lines the same:
---> this is not right {expect:---> this is right} |expect:---> this is right {expect:---> this is right}|
---> ---> this is right {expect:---> this is right} |expect:---> this is right {expect:---> this is right}|
If the content of a expect clause is ANYTHING, no checks will be performed. This is
useful to create a line that is highlighted you want the user to play with.
\---> TEXT {expect:ANYTHING}
is displayed
---> this is free text {expect:ANYTHING}
14. Turn the line below into free text:
---> this is some text |expect:---> this is some text {expect:ANYTHING}|
---> ---> this is some text {expect:ANYTHING} |expect:---> this is some text {expect:ANYTHING}|
These files conventionally have the same name as the tutorial document with the `.json`
extension appended (for a full example, see the file that corresponds to this tutorial).

View File

@ -0,0 +1,35 @@
{
"expect": {
"63": "This is text with **important information**",
"64": "This is text with **important information**",
"71": "Document '&variable'",
"72": "Document '&variable'",
"78": "# This is a level 1 header",
"79": "# This is a level 1 header",
"80": "### This is a level 3 header",
"81": "### This is a level 3 header",
"82": "# This is a header with a label {*label*}",
"83": "# This is a header with a label {*label*}",
"108": "A link to help for the ['breakindent']('breakindent') option",
"109": "A link to help for the ['breakindent']('breakindent') option",
"123": "A link to the [Links](*links*) section",
"124": "A link to the [Links](*links*) section",
"139": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
"140": "A link to [the vim-tutor-mode tutorial](@tutor:tutor)",
"157": "~~~ viml",
"158": "echom 'the value of &number is'.string(&number)",
"159": "~~~",
"161": "~~~ viml",
"162": "echom 'the value of &number is'.string(&number)",
"163": "~~~",
"188": "~~~ normal",
"189": "d2w",
"190": "~~~",
"192": "~~~ normal",
"193": "d2w",
"194": "~~~",
"206": "`d2w`{normal}",
"207": "`d2w`{normal}",
"244": -1
}
}

View File

@ -4239,11 +4239,17 @@ static int eval7(
// use its contents.
s = deref_func_name((const char *)s, &len, &partial, !evaluate);
// Need to make a copy, in case evaluating the arguments makes
// the name invalid.
s = xmemdupz(s, len);
// Invoke the function.
ret = get_func_tv(s, len, rettv, arg,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, partial, NULL);
xfree(s);
// If evaluate is false rettv->v_type was not set in
// get_func_tv, but it's needed in handle_subscript() to parse
// what follows. So set it here.

View File

@ -7039,8 +7039,11 @@ dict_T *get_winbuf_options(const int bufopt)
if (opt->flags & P_STRING) {
tv_dict_add_str(d, opt->fullname, strlen(opt->fullname),
*(const char **)varp);
} else if (opt->flags & P_NUM) {
tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname),
*(long *)varp);
} else {
tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *varp);
tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *(int *)varp);
}
}
}

View File

@ -383,6 +383,8 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr,
return 0;
}
static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls
static void free_efm_list(efm_T **efm_first)
{
for (efm_T *efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first) {
@ -390,6 +392,8 @@ static void free_efm_list(efm_T **efm_first)
vim_regfree(efm_ptr->prog);
xfree(efm_ptr);
}
fmt_start = NULL;
}
// Parse 'errorformat' option
@ -671,7 +675,6 @@ static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen,
efm_T *fmt_first, qffields_T *fields)
{
efm_T *fmt_ptr;
static efm_T *fmt_start = NULL; // cached across calls
size_t len;
int i;
int idx = 0;
@ -875,36 +878,38 @@ restofline:
qi->qf_multiignore = false; // reset continuation
} else if (vim_strchr((char_u *)"CZ", idx)
!= NULL) { // continuation of multi-line msg
qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last;
if (qfprev == NULL) {
return QF_FAIL;
}
if (*fields->errmsg && !qi->qf_multiignore) {
size_t len = STRLEN(qfprev->qf_text);
qfprev->qf_text = xrealloc(qfprev->qf_text,
len + STRLEN(fields->errmsg) + 2);
qfprev->qf_text[len] = '\n';
STRCPY(qfprev->qf_text + len + 1, fields->errmsg);
}
if (qfprev->qf_nr == -1) {
qfprev->qf_nr = fields->enr;
}
if (vim_isprintc(fields->type) && !qfprev->qf_type) {
qfprev->qf_type = fields->type; // only printable chars allowed
}
if (!qfprev->qf_lnum) {
qfprev->qf_lnum = fields->lnum;
}
if (!qfprev->qf_col) {
qfprev->qf_col = fields->col;
}
qfprev->qf_viscol = fields->use_viscol;
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory,
*fields->namebuf || qi->qf_directory
? fields->namebuf
: qi->qf_currfile && fields->valid
? qi->qf_currfile : 0);
if (!qi->qf_multiignore) {
qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last;
if (qfprev == NULL) {
return QF_FAIL;
}
if (*fields->errmsg && !qi->qf_multiignore) {
size_t len = STRLEN(qfprev->qf_text);
qfprev->qf_text = xrealloc(qfprev->qf_text,
len + STRLEN(fields->errmsg) + 2);
qfprev->qf_text[len] = '\n';
STRCPY(qfprev->qf_text + len + 1, fields->errmsg);
}
if (qfprev->qf_nr == -1) {
qfprev->qf_nr = fields->enr;
}
if (vim_isprintc(fields->type) && !qfprev->qf_type) {
qfprev->qf_type = fields->type; // only printable chars allowed
}
if (!qfprev->qf_lnum) {
qfprev->qf_lnum = fields->lnum;
}
if (!qfprev->qf_col) {
qfprev->qf_col = fields->col;
}
qfprev->qf_viscol = fields->use_viscol;
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory,
*fields->namebuf || qi->qf_directory
? fields->namebuf
: qi->qf_currfile && fields->valid
? qi->qf_currfile : 0);
}
}
if (idx == 'Z') {
qi->qf_multiline = qi->qf_multiignore = false;
@ -967,6 +972,7 @@ qf_init_ext(
NULL, 0, 0 };
qffields_T fields = { NULL, NULL, 0, 0L, 0, false, NULL, 0, 0, 0 };
qfline_T *old_last = NULL;
bool adding = false;
static efm_T *fmt_first = NULL;
char_u *efm;
static char_u *last_efm = NULL;
@ -992,6 +998,7 @@ qf_init_ext(
qf_new_list(qi, qf_title);
} else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
// Adding to existing list, use last entry.
adding = true;
old_last = qi->qf_lists[qi->qf_curlist].qf_last;
}
@ -1108,10 +1115,12 @@ qf_init_ext(
}
EMSG(_(e_readerrf));
error2:
qf_free(qi, qi->qf_curlist);
qi->qf_listcount--;
if (qi->qf_curlist > 0) {
qi->qf_curlist--;
if (!adding) {
qf_free(qi, qi->qf_curlist);
qi->qf_listcount--;
if (qi->qf_curlist > 0) {
qi->qf_curlist--;
}
}
qf_init_end:
if (state.fd != NULL) {
@ -1408,7 +1417,7 @@ void copy_loclist(win_T *from, win_T *to)
to->w_llist->qf_curlist = qi->qf_curlist; /* current list */
}
// Get buffer number for file "directory.fname".
// Get buffer number for file "directory/fname".
// Also sets the b_has_qf_entry flag.
static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
{
@ -2362,7 +2371,9 @@ static void qf_free(qf_info_T *qi, int idx)
qi->qf_lists[idx].qf_index = 0;
qf_clean_dir_stack(&qi->qf_dir_stack);
qi->qf_directory = NULL;
qf_clean_dir_stack(&qi->qf_file_stack);
qi->qf_currfile = NULL;
}
/*
@ -4025,9 +4036,12 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
// Use the specified quickfix/location list
if (di->di_tv.v_type == VAR_NUMBER) {
qf_idx = (int)di->di_tv.vval.v_number - 1;
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
// for zero use the current list
if (di->di_tv.vval.v_number != 0) {
qf_idx = (int)di->di_tv.vval.v_number - 1;
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
}
}
flags |= QF_GETLIST_NR;
} else {

View File

@ -87,9 +87,17 @@ function Test_get_buf_options()
endfunc
function Test_get_win_options()
if has('folding')
set foldlevel=999
endif
set list
let opts = getwinvar(1, '&')
call assert_equal(v:t_dict, type(opts))
call assert_equal(0, opts.linebreak)
call assert_equal(1, opts.list)
if has('folding')
call assert_equal(999, opts.foldlevel)
endif
if has('signs')
call assert_equal('auto', opts.signcolumn)
endif
@ -97,7 +105,12 @@ function Test_get_win_options()
let opts = gettabwinvar(1, 1, '&')
call assert_equal(v:t_dict, type(opts))
call assert_equal(0, opts.linebreak)
call assert_equal(1, opts.list)
if has('signs')
call assert_equal('auto', opts.signcolumn)
endif
set list&
if has('folding')
set foldlevel=0
endif
endfunc

View File

@ -418,6 +418,9 @@ func Test_function_with_funcref()
let s:fref = function(s:f)
call assert_equal(v:t_string, s:fref('x'))
call assert_fails("call function('s:f')", 'E700:')
call assert_fails("call function('foo()')", 'E475:')
call assert_fails("call function('foo()')", 'foo()')
endfunc
func Test_funcref()

View File

@ -1,32 +1,42 @@
"Tests for nested functions
"
function! NestedFunc()
fu! Func1()
func NestedFunc()
func! Func1()
let g:text .= 'Func1 '
endfunction
endfunc
call Func1()
fu! s:func2()
func! s:func2()
let g:text .= 's:func2 '
endfunction
endfunc
call s:func2()
fu! s:_func3()
func! s:_func3()
let g:text .= 's:_func3 '
endfunction
endfunc
call s:_func3()
let fn = 'Func4'
fu! {fn}()
func! {fn}()
let g:text .= 'Func4 '
endfunction
endfunc
call {fn}()
let fn = 'func5'
fu! s:{fn}()
func! s:{fn}()
let g:text .= 's:func5'
endfunction
endfunc
call s:{fn}()
endfunction
endfunc
function! Test_nested_functions()
func Test_nested_functions()
let g:text = ''
call NestedFunc()
call assert_equal('Func1 s:func2 s:_func3 Func4 s:func5', g:text)
endfunction
func Test_nested_argument()
func g:X()
let g:Y = function('sort')
endfunc
let g:Y = function('sort')
echo g:Y([], g:X())
delfunc g:X
unlet g:Y
endfunc

View File

@ -6,7 +6,7 @@ endif
set encoding=utf-8
function! s:setup_commands(cchar)
func s:setup_commands(cchar)
if a:cchar == 'c'
command! -nargs=* -bang Xlist <mods>clist<bang> <args>
command! -nargs=* Xgetexpr <mods>cgetexpr <args>
@ -68,10 +68,10 @@ function! s:setup_commands(cchar)
let g:Xgetlist = function('getloclist', [0])
let g:Xsetlist = function('setloclist', [0])
endif
endfunction
endfunc
" Tests for the :clist and :llist commands
function XlistTests(cchar)
func XlistTests(cchar)
call s:setup_commands(a:cchar)
" With an empty list, command should return error
@ -128,17 +128,17 @@ function XlistTests(cchar)
let l = split(result, "\n")
call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
endfunction
endfunc
function Test_clist()
func Test_clist()
call XlistTests('c')
call XlistTests('l')
endfunction
endfunc
" Tests for the :colder, :cnewer, :lolder and :lnewer commands
" Note that this test assumes that a quickfix/location list is
" already set by the caller.
function XageTests(cchar)
func XageTests(cchar)
call s:setup_commands(a:cchar)
" Jumping to a non existent list should return error
@ -171,20 +171,20 @@ function XageTests(cchar)
Xnewer 2
let l = g:Xgetlist()
call assert_equal('Line3', l[0].text)
endfunction
endfunc
function Test_cage()
func Test_cage()
let list = [{'bufnr': 1, 'lnum': 1}]
call setqflist(list)
call XageTests('c')
call setloclist(0, list)
call XageTests('l')
endfunction
endfunc
" Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen
" commands
function XwindowTests(cchar)
func XwindowTests(cchar)
call s:setup_commands(a:cchar)
" Create a list with no valid entries
@ -227,16 +227,16 @@ function XwindowTests(cchar)
" Calling cwindow should close the quickfix window with no valid errors
Xwindow
call assert_true(winnr('$') == 1)
endfunction
endfunc
function Test_cwindow()
func Test_cwindow()
call XwindowTests('c')
call XwindowTests('l')
endfunction
endfunc
" Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile
" commands.
function XfileTests(cchar)
func XfileTests(cchar)
call s:setup_commands(a:cchar)
call writefile(['Xtestfile1:700:10:Line 700',
@ -275,16 +275,16 @@ function XfileTests(cchar)
\ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333')
call delete('Xqftestfile1')
endfunction
endfunc
function Test_cfile()
func Test_cfile()
call XfileTests('c')
call XfileTests('l')
endfunction
endfunc
" Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and
" :lgetbuffer commands.
function XbufferTests(cchar)
func XbufferTests(cchar)
call s:setup_commands(a:cchar)
enew!
@ -316,26 +316,26 @@ function XbufferTests(cchar)
\ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750')
enew!
endfunction
endfunc
function Test_cbuffer()
func Test_cbuffer()
call XbufferTests('c')
call XbufferTests('l')
endfunction
endfunc
function XexprTests(cchar)
func XexprTests(cchar)
call s:setup_commands(a:cchar)
call assert_fails('Xexpr 10', 'E777:')
endfunction
endfunc
function Test_cexpr()
func Test_cexpr()
call XexprTests('c')
call XexprTests('l')
endfunction
endfunc
" Tests for :cnext, :cprev, :cfirst, :clast commands
function Xtest_browse(cchar)
func Xtest_browse(cchar)
call s:setup_commands(a:cchar)
call s:create_test_file('Xqftestfile1')
@ -366,14 +366,14 @@ function Xtest_browse(cchar)
call delete('Xqftestfile1')
call delete('Xqftestfile2')
endfunction
endfunc
function Test_browse()
func Test_browse()
call Xtest_browse('c')
call Xtest_browse('l')
endfunction
endfunc
function! s:test_xhelpgrep(cchar)
func s:test_xhelpgrep(cchar)
call s:setup_commands(a:cchar)
Xhelpgrep quickfix
Xopen
@ -385,9 +385,9 @@ function! s:test_xhelpgrep(cchar)
call assert_true(w:quickfix_title =~ title_text, w:quickfix_title)
" This wipes out the buffer, make sure that doesn't cause trouble.
Xclose
endfunction
endfunc
function Test_helpgrep()
func Test_helpgrep()
call s:test_xhelpgrep('c')
helpclose
call s:test_xhelpgrep('l')
@ -425,7 +425,7 @@ func Test_vimgreptitle()
augroup! QfBufWinEnter
endfunc
function XqfTitleTests(cchar)
func XqfTitleTests(cchar)
call s:setup_commands(a:cchar)
Xgetexpr ['file:1:1:message']
@ -444,16 +444,16 @@ function XqfTitleTests(cchar)
endif
call assert_equal(title, w:quickfix_title)
Xclose
endfunction
endfunc
" Tests for quickfix window's title
function Test_qf_title()
func Test_qf_title()
call XqfTitleTests('c')
call XqfTitleTests('l')
endfunction
endfunc
" Tests for 'errorformat'
function Test_efm()
func Test_efm()
let save_efm = &efm
set efm=%EEEE%m,%WWWW%m,%+CCCC%.%#,%-GGGG%.%#
cgetexpr ['WWWW', 'EEEE', 'CCCC']
@ -466,7 +466,7 @@ function Test_efm()
let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
call assert_equal("[['W', 1], ['ZZZZ', 0], ['E^@CCCC', 1], ['YYYY', 0]]", l)
let &efm = save_efm
endfunction
endfunc
" This will test for problems in quickfix:
" A. incorrectly copying location lists which caused the location list to show
@ -477,7 +477,7 @@ endfunction
" window it belongs to.
"
" Set up the test environment:
function! ReadTestProtocol(name)
func ReadTestProtocol(name)
let base = substitute(a:name, '\v^test://(.*)%(\.[^.]+)?', '\1', '')
let word = substitute(base, '\v(.*)\..*', '\1', '')
@ -496,9 +496,9 @@ function! ReadTestProtocol(name)
setl nomodifiable
setl readonly
exe 'doautocmd BufRead ' . substitute(a:name, '\v^test://(.*)', '\1', '')
endfunction
endfunc
function Test_locationlist()
func Test_locationlist()
enew
augroup testgroup
@ -578,15 +578,15 @@ function Test_locationlist()
wincmd n | only
augroup! testgroup
endfunction
endfunc
function Test_locationlist_curwin_was_closed()
func Test_locationlist_curwin_was_closed()
augroup testgroup
au!
autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
augroup END
function! R(n)
func! R(n)
quit
endfunc
@ -597,9 +597,9 @@ function Test_locationlist_curwin_was_closed()
call assert_fails('lrewind', 'E924:')
augroup! testgroup
endfunction
endfunc
function Test_locationlist_cross_tab_jump()
func Test_locationlist_cross_tab_jump()
call writefile(['loclistfoo'], 'loclistfoo')
call writefile(['loclistbar'], 'loclistbar')
set switchbuf=usetab
@ -613,10 +613,10 @@ function Test_locationlist_cross_tab_jump()
set switchbuf&vim
call delete('loclistfoo')
call delete('loclistbar')
endfunction
endfunc
" More tests for 'errorformat'
function! Test_efm1()
func Test_efm1()
if !has('unix')
" The 'errorformat' setting is different on non-Unix systems.
" This test works only on Unix-like systems.
@ -734,10 +734,10 @@ function! Test_efm1()
call delete('Xerrorfile1')
call delete('Xerrorfile2')
call delete('Xtestfile')
endfunction
endfunc
" Test for quickfix directory stack support
function! s:dir_stack_tests(cchar)
func s:dir_stack_tests(cchar)
call s:setup_commands(a:cchar)
let save_efm=&efm
@ -779,10 +779,10 @@ function! s:dir_stack_tests(cchar)
call assert_equal(5, qf[11].lnum)
let &efm=save_efm
endfunction
endfunc
" Tests for %D and %X errorformat options
function! Test_efm_dirstack()
func Test_efm_dirstack()
" Create the directory stack and files
call mkdir('dir1')
call mkdir('dir1/a')
@ -814,10 +814,33 @@ function! Test_efm_dirstack()
call delete('dir1', 'rf')
call delete('dir2', 'rf')
call delete('habits1.txt')
endfunction
endfunc
" Test for resync after continuing an ignored message
func Xefm_ignore_continuations(cchar)
call s:setup_commands(a:cchar)
let save_efm = &efm
let &efm =
\ '%Eerror %m %l,' .
\ '%-Wignored %m %l,' .
\ '%+Cmore ignored %m %l,' .
\ '%Zignored end'
Xgetexpr ['ignored warning 1', 'more ignored continuation 2', 'ignored end', 'error resync 4']
let l = map(g:Xgetlist(), '[v:val.text, v:val.valid, v:val.lnum, v:val.type]')
call assert_equal([['resync', 1, 4, 'E']], l)
let &efm = save_efm
endfunc
func Test_efm_ignore_continuations()
call Xefm_ignore_continuations('c')
call Xefm_ignore_continuations('l')
endfunc
" Tests for invalid error format specifies
function Xinvalid_efm_Tests(cchar)
func Xinvalid_efm_Tests(cchar)
call s:setup_commands(a:cchar)
let save_efm = &efm
@ -850,17 +873,17 @@ function Xinvalid_efm_Tests(cchar)
call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E379:')
let &efm = save_efm
endfunction
endfunc
function Test_invalid_efm()
func Test_invalid_efm()
call Xinvalid_efm_Tests('c')
call Xinvalid_efm_Tests('l')
endfunction
endfunc
" TODO:
" Add tests for the following formats in 'errorformat'
" %r %O
function! Test_efm2()
func Test_efm2()
let save_efm = &efm
" Test for %s format in efm
@ -946,19 +969,19 @@ function! Test_efm2()
call assert_equal('unittests/dbfacadeTest.py', bufname(l[4].bufnr))
let &efm = save_efm
endfunction
endfunc
function XquickfixChangedByAutocmd(cchar)
func XquickfixChangedByAutocmd(cchar)
call s:setup_commands(a:cchar)
if a:cchar == 'c'
let ErrorNr = 'E925'
function! ReadFunc()
func! ReadFunc()
colder
cgetexpr []
endfunc
else
let ErrorNr = 'E926'
function! ReadFunc()
func! ReadFunc()
lolder
lgetexpr []
endfunc
@ -981,10 +1004,10 @@ function XquickfixChangedByAutocmd(cchar)
augroup! testgroup
endfunc
function Test_quickfix_was_changed_by_autocmd()
func Test_quickfix_was_changed_by_autocmd()
call XquickfixChangedByAutocmd('c')
call XquickfixChangedByAutocmd('l')
endfunction
endfunc
func Test_caddbuffer_to_empty()
helpgr quickfix
@ -1006,7 +1029,7 @@ func Test_cgetexpr_works()
endfunc
" Tests for the setqflist() and setloclist() functions
function SetXlistTests(cchar, bnum)
func SetXlistTests(cchar, bnum)
call s:setup_commands(a:cchar)
call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 1},
@ -1041,9 +1064,9 @@ function SetXlistTests(cchar, bnum)
call g:Xsetlist([])
let l = g:Xgetlist()
call assert_equal(0, len(l))
endfunction
endfunc
function Test_setqflist()
func Test_setqflist()
new Xtestfile | only
let bnum = bufnr('%')
call setline(1, range(1,5))
@ -1053,9 +1076,9 @@ function Test_setqflist()
enew!
call delete('Xtestfile')
endfunction
endfunc
function Xlist_empty_middle(cchar)
func Xlist_empty_middle(cchar)
call s:setup_commands(a:cchar)
" create three quickfix lists
@ -1078,12 +1101,12 @@ function Xlist_empty_middle(cchar)
call assert_equal(matchlen, len(g:Xgetlist()))
endfunc
function Test_setqflist_empty_middle()
func Test_setqflist_empty_middle()
call Xlist_empty_middle('c')
call Xlist_empty_middle('l')
endfunction
endfunc
function Xlist_empty_older(cchar)
func Xlist_empty_older(cchar)
call s:setup_commands(a:cchar)
" create three quickfix lists
@ -1104,14 +1127,14 @@ function Xlist_empty_older(cchar)
call assert_equal(twolen, len(g:Xgetlist()))
Xnewer
call assert_equal(threelen, len(g:Xgetlist()))
endfunction
endfunc
function Test_setqflist_empty_older()
func Test_setqflist_empty_older()
call Xlist_empty_older('c')
call Xlist_empty_older('l')
endfunction
endfunc
function! XquickfixSetListWithAct(cchar)
func XquickfixSetListWithAct(cchar)
call s:setup_commands(a:cchar)
let list1 = [{'filename': 'fnameA', 'text': 'A'},
@ -1185,12 +1208,12 @@ function! XquickfixSetListWithAct(cchar)
call assert_fails("call g:Xsetlist(list1, 0)", 'E928:')
endfunc
function Test_quickfix_set_list_with_act()
func Test_quickfix_set_list_with_act()
call XquickfixSetListWithAct('c')
call XquickfixSetListWithAct('l')
endfunction
endfunc
function XLongLinesTests(cchar)
func XLongLinesTests(cchar)
let l = g:Xgetlist()
call assert_equal(4, len(l))
@ -1208,9 +1231,9 @@ function XLongLinesTests(cchar)
call assert_equal(10, len(l[3].text))
call g:Xsetlist([], 'r')
endfunction
endfunc
function s:long_lines_tests(cchar)
func s:long_lines_tests(cchar)
call s:setup_commands(a:cchar)
let testfile = 'samples/quickfix.txt'
@ -1231,22 +1254,22 @@ function s:long_lines_tests(cchar)
exe 'edit' testfile
exe 'Xbuffer' bufnr('%')
call XLongLinesTests(a:cchar)
endfunction
endfunc
function Test_long_lines()
func Test_long_lines()
call s:long_lines_tests('c')
call s:long_lines_tests('l')
endfunction
endfunc
function! s:create_test_file(filename)
func s:create_test_file(filename)
let l = []
for i in range(1, 20)
call add(l, 'Line' . i)
endfor
call writefile(l, a:filename)
endfunction
endfunc
function! Test_switchbuf()
func Test_switchbuf()
call s:create_test_file('Xqftestfile1')
call s:create_test_file('Xqftestfile2')
call s:create_test_file('Xqftestfile3')
@ -1333,9 +1356,9 @@ function! Test_switchbuf()
call delete('Xqftestfile1')
call delete('Xqftestfile2')
call delete('Xqftestfile3')
endfunction
endfunc
function! Xadjust_qflnum(cchar)
func Xadjust_qflnum(cchar)
call s:setup_commands(a:cchar)
enew | only
@ -1360,17 +1383,17 @@ function! Xadjust_qflnum(cchar)
enew!
call delete(fname)
endfunction
endfunc
function! Test_adjust_lnum()
func Test_adjust_lnum()
call setloclist(0, [])
call Xadjust_qflnum('c')
call setqflist([])
call Xadjust_qflnum('l')
endfunction
endfunc
" Tests for the :grep/:lgrep and :grepadd/:lgrepadd commands
function! s:test_xgrep(cchar)
func s:test_xgrep(cchar)
call s:setup_commands(a:cchar)
" The following lines are used for the grep test. Don't remove.
@ -1389,9 +1412,9 @@ function! s:test_xgrep(cchar)
set makeef=Temp_File_##
silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim
call assert_true(len(g:Xgetlist()) == 6)
endfunction
endfunc
function! Test_grep()
func Test_grep()
if !has('unix')
" The grepprg may not be set on non-Unix systems
return
@ -1399,9 +1422,9 @@ function! Test_grep()
call s:test_xgrep('c')
call s:test_xgrep('l')
endfunction
endfunc
function! Test_two_windows()
func Test_two_windows()
" Use one 'errorformat' for two windows. Add an expression to each of them,
" make sure they each keep their own state.
set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
@ -1427,12 +1450,10 @@ function! Test_two_windows()
laddexpr 'one.txt:3:one one one'
let loc_one = getloclist(one_id)
echo string(loc_one)
call assert_equal('Xone/a/one.txt', bufname(loc_one[1].bufnr))
call assert_equal(3, loc_one[1].lnum)
let loc_two = getloclist(two_id)
echo string(loc_two)
call assert_equal('Xtwo/a/two.txt', bufname(loc_two[1].bufnr))
call assert_equal(5, loc_two[1].lnum)
@ -1444,7 +1465,7 @@ echo string(loc_two)
call delete('Xtwo', 'rf')
endfunc
function XbottomTests(cchar)
func XbottomTests(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([{'filename': 'foo', 'lnum': 42}])
@ -1460,12 +1481,12 @@ function XbottomTests(cchar)
endfunc
" Tests for the :cbottom and :lbottom commands
function Test_cbottom()
func Test_cbottom()
call XbottomTests('c')
call XbottomTests('l')
endfunction
endfunc
function HistoryTest(cchar)
func HistoryTest(cchar)
call s:setup_commands(a:cchar)
call assert_fails(a:cchar . 'older 99', 'E380:')
@ -1505,7 +1526,7 @@ func Test_duplicate_buf()
endfunc
" Quickfix/Location list set/get properties tests
function Xproperty_tests(cchar)
func Xproperty_tests(cchar)
call s:setup_commands(a:cchar)
" Error cases
@ -1532,6 +1553,11 @@ function Xproperty_tests(cchar)
call assert_equal('N1', g:Xgetlist({'all':1}).title)
call g:Xsetlist([], ' ', {'title' : 'N2'})
call assert_equal(qfnr + 1, g:Xgetlist({'all':1}).nr)
let res = g:Xgetlist({'nr': 0})
call assert_equal(qfnr + 1, res.nr)
call assert_equal(['nr'], keys(res))
call g:Xsetlist([], ' ', {'title' : 'N3'})
call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title)
@ -1544,21 +1570,21 @@ function Xproperty_tests(cchar)
call assert_equal({}, g:Xgetlist({'abc':1}))
if a:cchar == 'l'
call assert_equal({}, getloclist(99, ['title']))
call assert_equal({}, getloclist(99, {'title': 1}))
endif
endfunction
endfunc
function Test_qf_property()
func Test_qf_property()
call Xproperty_tests('c')
call Xproperty_tests('l')
endfunction
endfunc
" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
function QfAutoCmdHandler(loc, cmd)
func QfAutoCmdHandler(loc, cmd)
call add(g:acmds, a:loc . a:cmd)
endfunction
endfunc
function Test_Autocmd()
func Test_Autocmd()
autocmd QuickFixCmdPre * call QfAutoCmdHandler('pre', expand('<amatch>'))
autocmd QuickFixCmdPost * call QfAutoCmdHandler('post', expand('<amatch>'))
@ -1586,9 +1612,9 @@ function Test_Autocmd()
\ 'precaddbuffer',
\ 'postcaddbuffer']
call assert_equal(l, g:acmds)
endfunction
endfunc
function! Test_Autocmd_Exception()
func Test_Autocmd_Exception()
set efm=%m
lgetexpr '?'
@ -1603,4 +1629,47 @@ function! Test_Autocmd_Exception()
call assert_equal('1', getloclist(0)[0].text)
set efm&vim
endfunction
endfunc
func Test_caddbuffer_wrong()
" This used to cause a memory access in freed memory.
let save_efm = &efm
set efm=%EEEE%m,%WWWW,%+CCCC%>%#,%GGGG%.#
cgetexpr ['WWWW', 'EEEE', 'CCCC']
let &efm = save_efm
caddbuffer
bwipe!
endfunc
func Test_caddexpr_wrong()
" This used to cause a memory access in freed memory.
cbuffer
cbuffer
copen
let save_efm = &efm
set efm=%
call assert_fails('caddexpr ""', 'E376:')
let &efm = save_efm
endfunc
func Test_dirstack_cleanup()
" This used to cause a memory access in freed memory.
let save_efm = &efm
lexpr '0'
lopen
fun X(c)
let save_efm=&efm
set efm=%D%f
if a:c == 'c'
caddexpr '::'
else
laddexpr ':0:0'
endif
let &efm=save_efm
endfun
call X('c')
call X('l')
call setqflist([], 'r')
caddbuffer
let &efm = save_efm
endfunc

File diff suppressed because it is too large Load Diff