changeset 36459:8917088e2df9 draft v9.1.0836

patch 9.1.0836: The vimtutor can be improved Commit: https://github.com/vim/vim/commit/a54816b884157f6b7973a188f85c708d15cbf72f Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sun Nov 3 10:49:23 2024 +0100 patch 9.1.0836: The vimtutor can be improved Problem: the vimtutor can be improved Solution: port and include the interactive vimtutor plugin from Neovim (by Felipe Morales) (Yegappan Lakshmanan) closes: #6414 Signed-off-by: Christian Brabandt <cb@256bit.org> Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author Christian Brabandt <cb@256bit.org>
date Sun, 03 Nov 2024 11:15:03 +0100
parents 6d746d9952c2
children 3957ecd3ae3f
files Filelist runtime/autoload/tutor.vim runtime/defaults.vim runtime/doc/Make_all.mak runtime/doc/pi_tutor.txt runtime/doc/tags runtime/doc/usr_01.txt runtime/doc/version9.txt runtime/filetype.vim runtime/ftplugin/tutor.vim runtime/plugin/tutor.vim runtime/syntax/tutor.vim runtime/syntax/vimnormal.vim runtime/tutor/en/vim-01-beginner.tutor runtime/tutor/en/vim-01-beginner.tutor.json runtime/tutor/tutor.tutor runtime/tutor/tutor.tutor.json src/Makefile src/version.c
diffstat 19 files changed, 1752 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -762,6 +762,10 @@ RT_ALL =	\
 		runtime/tools/[a-z]*[a-z0-9] \
 		runtime/tutor/README.txt \
 		runtime/tutor/tutor \
+		runtime/tutor/en/vim-01-beginner.tutor \
+		runtime/tutor/en/vim-01-beginner.tutor.json \
+		runtime/tutor/tutor.tutor \
+		runtime/tutor/tutor.tutor.json \
 		runtime/tutor/tutor.vim \
 		runtime/vimrc_example.vim \
 		runtime/pack/dist/opt/cfilter/plugin/cfilter.vim \
new file mode 100644
--- /dev/null
+++ b/runtime/autoload/tutor.vim
@@ -0,0 +1,219 @@
+" vim: fdm=marker et ts=4 sw=4
+
+" Setup: {{{1
+function! tutor#SetupVim()
+    if !exists('g:did_load_ftplugin') || g:did_load_ftplugin != 1
+        filetype plugin on
+    endif
+    if has('syntax')
+        if !exists('g:syntax_on') || g:syntax_on == 0
+            syntax on
+        endif
+    endif
+endfunction
+
+" Loads metadata file, if available
+function! tutor#LoadMetadata()
+    let b:tutor_metadata = json_decode(join(readfile(expand('%').'.json'), "\n"))
+endfunction
+
+" Mappings: {{{1
+
+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()
+    if foldclosed(line('.')) > -1
+        normal! zo
+    else
+        if match(getline('.'), '^#\{1,} ') > -1
+            silent normal! zc
+        else
+            call tutor#FollowLink(0)
+        endif
+    endif
+endfunction
+
+function! tutor#InjectCommand()
+    let l:cmd = substitute(getline('.'),  '^\s*', '', '')
+    exe l:cmd
+    redraw | echohl WarningMsg | echon  "tutor: ran" | echohl None | echon " " | echohl Statement | echon l:cmd
+endfunction
+
+function! tutor#FollowLink(force)
+    let l:stack_s = join(map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")'), '')
+    if l:stack_s =~# 'tutorLink'
+        let l:link_start = searchpairpos('\[', '', ')', 'nbcW')
+        let l:link_end = searchpairpos('\[', '', ')', 'ncW')
+        if l:link_start[0] == l:link_end[0]
+            let l:linkData = getline(l:link_start[0])[l:link_start[1]-1:l:link_end[1]-1]
+        else
+            return
+        endif
+        let l:target = matchstr(l:linkData, '(\@<=.*)\@=')
+        if a:force != 1 && match(l:target, '\*.\+\*') > -1
+            call cursor(l:link_start[0], l:link_end[1])
+            call search(l:target, '')
+            normal! ^
+        elseif a:force != 1 && match(l:target, '^@tutor:') > -1
+            let l:tutor = matchstr(l:target, '@tutor:\zs.*')
+            exe "Tutor ".l:tutor
+        else
+            exe "help ".l:target
+        endif
+    endif
+endfunction
+
+" Folding And Info: {{{1
+
+function! tutor#TutorFolds()
+    if getline(v:lnum) =~# '^#\{1,6}'
+        return ">". len(matchstr(getline(v:lnum), '^#\{1,6}'))
+    else
+        return "="
+    endif
+endfunction
+
+" 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#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#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
+
+" Tutor Cmd: {{{1
+
+function! s:Locale()
+    if exists('v:lang') && v:lang =~ '\a\a'
+        let l:lang = v:lang
+    elseif $LC_ALL =~ '\a\a'
+        let l:lang = $LC_ALL
+    elseif $LANG =~ '\a\a'
+        let l:lang = $LANG
+    else
+        let l:lang = 'en_US'
+    endif
+    return split(l:lang, '_')
+endfunction
+
+function! s:GlobPath(lp, pat)
+    if version >= 704 && has('patch279')
+        return globpath(a:lp, a:pat, 1, 1)
+    else
+        return split(globpath(a:lp, a:pat, 1), '\n')
+    endif
+endfunction
+
+function! s:Sort(a, b)
+    let mod_a = fnamemodify(a:a, ':t')
+    let mod_b = fnamemodify(a:b, ':t')
+    if mod_a == mod_b
+        let retval =  0
+    elseif mod_a > mod_b
+        if match(mod_a, '^vim-') > -1 && match(mod_b, '^vim-') == -1
+            let retval = -1
+        else
+            let retval = 1
+        endif
+    else
+        if match(mod_b, '^vim-') > -1 && match(mod_a, '^vim-') == -1
+            let retval = 1
+        else
+            let retval = -1
+        endif
+    endif
+    return retval
+endfunction
+
+function! s:GlobTutorials(name)
+    " search for tutorials:
+    " 1. non-localized
+    let l:tutors = s:GlobPath(&rtp, 'tutor/'.a:name.'.tutor')
+    " 2. localized for current locale
+    let l:locale_tutors = s:GlobPath(&rtp, 'tutor/'.s:Locale()[0].'/'.a:name.'.tutor')
+    " 3. fallback to 'en'
+    if len(l:locale_tutors) == 0
+        let l:locale_tutors = s:GlobPath(&rtp, 'tutor/en/'.a:name.'.tutor')
+    endif
+    call extend(l:tutors, l:locale_tutors)
+    return uniq(sort(l:tutors, 's:Sort'), 's:Sort')
+endfunction
+
+function! tutor#TutorCmd(tutor_name)
+    if match(a:tutor_name, '[[:space:]]') > 0
+        echom "Only one argument accepted (check spaces)"
+        return
+    endif
+
+    if a:tutor_name == ''
+        let l:tutor_name = 'vim-01-beginner.tutor'
+    else
+        let l:tutor_name = a:tutor_name
+    endif
+
+    if match(l:tutor_name, '\.tutor$') > 0
+        let l:tutor_name = fnamemodify(l:tutor_name, ':r')
+    endif
+
+    let l:tutors = s:GlobTutorials(l:tutor_name)
+
+    if len(l:tutors) == 0
+        echom "No tutorial with that name found"
+        return
+    endif
+
+    if len(l:tutors) == 1
+        let l:to_open = l:tutors[0]
+    else
+        let l:idx = 0
+        let l:candidates = ['Several tutorials with that name found. Select one:']
+        for candidate in map(copy(l:tutors),
+                    \'fnamemodify(v:val, ":h:h:t")."/".s:Locale()[0]."/".fnamemodify(v:val, ":t")')
+            let l:idx += 1
+            call add(l:candidates, l:idx.'. '.candidate)
+        endfor
+        let l:tutor_to_open = inputlist(l:candidates)
+        let l:to_open = l:tutors[l:tutor_to_open-1]
+    endif
+
+    call tutor#SetupVim()
+    exe "edit ".l:to_open
+endfunction
+
+function! tutor#TutorCmdComplete(lead,line,pos)
+    let l:tutors = s:GlobTutorials('*')
+    let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort'))
+    return join(l:names, "\n")
+endfunction
--- a/runtime/defaults.vim
+++ b/runtime/defaults.vim
@@ -1,7 +1,7 @@
 " The default vimrc file.
 "
 " Maintainer:	The Vim Project <https://github.com/vim/vim>
-" Last change:	2023 Aug 10
+" Last Change:	2024 Nov 03
 " Former Maintainer:	Bram Moolenaar <Bram@vim.org>
 "
 " This is loaded if no vimrc file was found.
@@ -107,11 +107,11 @@ if 1
     " (happens when dropping a file on gvim), for a commit or rebase message
     " (likely a different one than last time), and when using xxd(1) to filter
     " and edit binary files (it transforms input files back and forth, causing
-    " them to have dual nature, so to speak)
+    " them to have dual nature, so to speak) or when running the new tutor
     autocmd BufReadPost *
       \ let line = line("'\"")
       \ | if line >= 1 && line <= line("$") && &filetype !~# 'commit'
-      \      && index(['xxd', 'gitrebase'], &filetype) == -1
+      \      && index(['xxd', 'gitrebase', 'tutor'], &filetype) == -1
       \ |   execute "normal! g`\""
       \ | endif
 
--- a/runtime/doc/Make_all.mak
+++ b/runtime/doc/Make_all.mak
@@ -75,6 +75,7 @@ DOCS = \
 	pi_paren.txt \
 	pi_spec.txt \
 	pi_tar.txt \
+	pi_tutor.txt \
 	pi_vimball.txt \
 	pi_zip.txt \
 	popup.txt \
@@ -228,6 +229,7 @@ HTMLS = \
 	pi_paren.html \
 	pi_spec.html \
 	pi_tar.html \
+	pi_tutor.html \
 	pi_vimball.html \
 	pi_zip.html \
 	popup.html \
new file mode 100644
--- /dev/null
+++ b/runtime/doc/pi_tutor.txt
@@ -0,0 +1,51 @@
+*pi_tutor.txt*    For Vim version 9.1.  Last change: 2024 Nov 02
+
+INTERACTIVE TUTORIALS FOR VIM			 *vim-tutor-mode*
+
+vim-tutor-mode provides a system to follow and create interactive tutorials
+for vim and third party plugins. It replaces the venerable `vimtutor` system.
+
+==============================================================================
+1. Usage                                                      *vim-tutor-usage*
+
+vim-tutor-mode tutorials are hypertext documents, they have rich text and
+contain links. To stand out from the rest of the text, links are underlined.
+You can follow them by placing the cursor over them and pressing <Enter>, or
+by double-clicking them.
+
+1.1 Commands
+------------
+								      *:Tutor*
+:Tutor {tutorial}	Opens a tutorial. Command-line completion for
+			{tutorial} is provided, the candidates are a list of
+			'.tutor' files found in the 'tutor/'  folder in
+			the 'runtimepath'. Tutorials prefixed with 'vim-' will
+			always be shown first.
+
+			If no {tutorial} is provided, the command starts the
+			'vim-01-beginner' tutorial, which is equivalent to
+			Vim's `vimtutor`.
+
+=============================================================================
+2. Creating tutorials                                        *vim-tutor-create*
+
+Writing vim-tutor-mode tutorials is easy. For an overview of the format used,
+please consult the 'tutor.tutor' file: >
+
+    :Tutor tutor
+<
+New tutorials must be placed in the 'tutor/' folder in the 'runtimepath'
+to be detected by the :Tutor command.
+
+It is recommended to use a less formal style when writing tutorials than in
+regular documentation (unless the content requires it).
+
+============================================================================
+3. Contributing
+
+Development of the plugin is done over at github [1].  Feel free to report
+issues and make suggestions.
+
+[1]: https://github.com/fmoralesc/vim-tutor-mode
+
+" vim: set ft=help :
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -2177,6 +2177,7 @@ 90.5	usr_90.txt	/*90.5*
 :Termdebug	terminal.txt	/*:Termdebug*
 :TermdebugCommand	terminal.txt	/*:TermdebugCommand*
 :Texplore	pi_netrw.txt	/*:Texplore*
+:Tutor	pi_tutor.txt	/*:Tutor*
 :Until	terminal.txt	/*:Until*
 :Up	terminal.txt	/*:Up*
 :UseVimball	pi_vimball.txt	/*:UseVimball*
@@ -9438,6 +9439,7 @@ pi_netrw.txt	pi_netrw.txt	/*pi_netrw.txt
 pi_paren.txt	pi_paren.txt	/*pi_paren.txt*
 pi_spec.txt	pi_spec.txt	/*pi_spec.txt*
 pi_tar.txt	pi_tar.txt	/*pi_tar.txt*
+pi_tutor.txt	pi_tutor.txt	/*pi_tutor.txt*
 pi_vimball.txt	pi_vimball.txt	/*pi_vimball.txt*
 pi_zip.txt	pi_zip.txt	/*pi_zip.txt*
 pkzip	options.txt	/*pkzip*
@@ -11244,6 +11246,9 @@ vim-script-intro	usr_41.txt	/*vim-script
 vim-script-library	eval.txt	/*vim-script-library*
 vim-security	intro.txt	/*vim-security*
 vim-shebang	various.txt	/*vim-shebang*
+vim-tutor-create	pi_tutor.txt	/*vim-tutor-create*
+vim-tutor-mode	pi_tutor.txt	/*vim-tutor-mode*
+vim-tutor-usage	pi_tutor.txt	/*vim-tutor-usage*
 vim-use	intro.txt	/*vim-use*
 vim-variable	eval.txt	/*vim-variable*
 vim.b	if_lua.txt	/*vim.b*
--- a/runtime/doc/usr_01.txt
+++ b/runtime/doc/usr_01.txt
@@ -1,4 +1,4 @@
-*usr_01.txt*	For Vim version 9.1.  Last change: 2024 May 11
+*usr_01.txt*	For Vim version 9.1.  Last change: 2024 Nov 03
 
 		     VIM USER MANUAL - by Bram Moolenaar
 
@@ -107,6 +107,8 @@ For more info see |vimrc| and |compatibl
 ==============================================================================
 *01.3*	Using the Vim tutor				*tutor* *vimtutor*
 
+For the interactive tutor, see |vim-tutor-mode|
+
 Instead of reading the text (boring!) you can use the vimtutor to learn your
 first Vim commands.  This is a 30-minute tutorial that teaches the most basic
 Vim functionality hands-on.
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt*  For Vim version 9.1.  Last change: 2024 Nov 02
+*version9.txt*  For Vim version 9.1.  Last change: 2024 Nov 03
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -41603,6 +41603,8 @@ Changed~
 - the putty terminal is detected using an |TermResponse| autocommand in
   |defaults.vim| and Vim switches to a dark background
 - the |help-TOC| package is included to ease navigating the documentation.
+- an interactive tutor plugin has been included |vim-tutor-mode|, can be
+  started via |:Tutor|
 
 							*added-9.2*
 Added ~
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -2589,6 +2589,9 @@ au BufNewFile,BufReadPost *.tsscl		setf 
 " TSV Files
 au BufNewFile,BufRead *.tsv			setf tsv
 
+" Tutor mode
+au BufNewFile,BufReadPost *.tutor		setf tutor
+
 " TWIG files
 au BufNewFile,BufReadPost *.twig		setf twig
 
new file mode 100644
--- /dev/null
+++ b/runtime/ftplugin/tutor.vim
@@ -0,0 +1,45 @@
+" vim: fdm=marker
+
+" Base: {{{1
+call tutor#SetupVim()
+
+" Buffer Settings: {{{1
+setlocal noreadonly
+if !exists('g:tutor_debug') || g:tutor_debug == 0
+    setlocal buftype=nofile
+    setlocal concealcursor+=inv
+    setlocal conceallevel=2
+else
+    setlocal buftype=
+    setlocal concealcursor&
+    setlocal conceallevel=0
+endif
+setlocal noundofile
+
+setlocal keywordprg=:help
+setlocal iskeyword=@,-,_
+
+" The user will have to enable the folds himself, but we provide the foldexpr
+" function.
+setlocal foldmethod=manual
+setlocal foldexpr=tutor#TutorFolds()
+setlocal foldlevel=4
+
+" Load metadata if it exists: {{{1
+if filereadable(expand('%').'.json')
+    call tutor#LoadMetadata()
+endif
+
+" Mappings: {{{1
+
+call tutor#SetNormalMappings()
+
+" 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#ApplyMarks()
+    autocmd! TextChanged,TextChangedI <buffer> call tutor#ApplyMarksOnChanged()
+endif
new file mode 100644
--- /dev/null
+++ b/runtime/plugin/tutor.vim
@@ -0,0 +1,6 @@
+if exists('g:loaded_tutor_mode_plugin') || &compatible
+    finish
+endif
+let g:loaded_tutor_mode_plugin = 1
+
+command! -nargs=? -complete=custom,tutor#TutorCmdComplete Tutor call tutor#TutorCmd(<q-args>)
new file mode 100644
--- /dev/null
+++ b/runtime/syntax/tutor.vim
@@ -0,0 +1,77 @@
+if exists("b:current_syntax")
+    finish
+endif
+
+syn include @VIM syntax/vim.vim
+unlet b:current_syntax
+syn include @TUTORSHELL syntax/sh.vim
+unlet b:current_syntax
+syn include @VIMNORMAL syntax/vimnormal.vim
+
+syn match tutorLink /\[.\{-}\](.\{-})/ contains=tutorInlineNormal
+syn match tutorLinkBands /\[\|\]\|(\|)/ contained containedin=tutorLink,tutorLinkAnchor conceal
+syn match tutorLinkAnchor /(.\{-})/ contained containedin=tutorLink conceal
+syn match tutorURL /\(https\?\|file\):\/\/[[:graph:]]\+\>\/\?/
+syn match tutorEmail /\<[[:graph:]]\+@[[:graph:]]\+\>/
+syn match tutorInternalAnchor /\*[[:alnum:]-]\+\*/ contained conceal containedin=tutorSection
+
+syn match tutorSection /^#\{1,6}\s.\+$/ fold contains=tutorInlineNormal
+syn match tutorSectionBullet /#/ contained containedin=tutorSection
+
+syn match tutorTOC /\ctable of contents:/
+
+syn match tutorConcealedEscapes /\\[`*!\[\]():$-]\@=/ conceal
+
+syn region tutorEmphasis matchgroup=Delimiter start=/[\*]\@<!\*\*\@!/ end=/[\*]\@<!\*\*\@!/
+	    \ concealends contains=tutorInlineCommand,tutorInlineNormal
+syn region tutorBold matchgroup=Delimiter start=/\*\{2}/ end=/\*\{2}/
+	    \ concealends contains=tutorInlineCommand,tutorInlineNormal
+
+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 region tutorCodeblock matchgroup=Delimiter start=/^\~\{3}.*$/ end=/^\~\{3}/
+
+syn region tutorShell matchgroup=Delimiter start=/^\~\{3} sh\s*$/ end=/^\~\{3}/ keepend contains=@TUTORSHELL concealends
+syn match tutorShellPrompt /\(^\s*\)\@<=[$#]/ contained containedin=tutorShell
+
+syn region tutorInlineCode matchgroup=Delimiter start=/\\\@<!`/ end=/\\\@<!\(`{\@!\|`\s\)/ concealends
+
+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 keepend
+
+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 keepend
+
+syn match tutorInlineType /{\(normal\|vim\)}/ contained conceal
+
+syn match tutorInlineOK /✓/
+syn match tutorInlineX /✗/
+
+hi def tutorLink cterm=underline gui=underline ctermfg=lightblue guifg=#0088ff
+hi def link tutorLinkBands Delimiter
+hi def link tutorLinkAnchor Underlined
+hi def link tutorInternalAnchor Underlined
+hi def link tutorURL tutorLink
+hi def link tutorEmail tutorLink
+
+hi def link tutorSection Title
+hi def link tutorSectionBullet Delimiter
+
+hi def link tutorTOC Directory
+
+hi def tutorMarks cterm=bold gui=bold
+
+hi def tutorEmphasis gui=italic cterm=italic
+hi def tutorBold gui=bold cterm=bold
+
+hi def link tutorExpect Special
+hi def tutorOK ctermfg=green guifg=#00ff88 cterm=bold gui=bold
+hi def tutorX ctermfg=red guifg=#ff2000  cterm=bold gui=bold
+hi def link tutorInlineOK tutorOK
+hi def link tutorInlineX tutorX
+
+hi def link tutorShellPrompt Delimiter
+
+let b:current_syntax = "tutor"
new file mode 100644
--- /dev/null
+++ b/runtime/syntax/vimnormal.vim
@@ -0,0 +1,16 @@
+syn match normalOp /[dcrypoaxv!"#%&.-\/:<>=?@ABCDGHIJKLMNOPQRSUVWXYZgmqstz~iu]/ nextgroup=normalMod
+syn match normalMod /m\@<![ia]/
+syn match normalObject /["'()<>BW\[\]`bstweE{}ftFT;,$]/
+syn match normalCount /[0-9]/
+syn region normalSearch start=/[/?]\@<=./ end=/.<CR>\@=/ contains=normalKey keepend
+syn region normalChange start=/\([cr][wWbBeE()\[\]{}pst]\)\@<=./ end=/.\@=/ contains=normalKey keepend
+syn match normalCharSearch /\c[ftr]\@<=\w/
+syn match normalMark /\(f\@<!m\)\@<=[a-zA-Z0-9]/
+syn match normalKey /<'\@!.\{-}>'\@!/
+
+hi! link normalOp Operator
+hi! link normalMod PreProc
+hi! link normalObject Structure
+hi! link normalCount Number
+hi! link normalMark Identifier
+hi! link normalKey Special
new file mode 100644
--- /dev/null
+++ b/runtime/tutor/en/vim-01-beginner.tutor
@@ -0,0 +1,980 @@
+#             Welcome   to   the   VIM   Tutor
+
+Vim is a very powerful editor that has many commands, too many to explain in
+a tutor such as this. This tutor is designed to describe enough of the
+commands that you will be able to easily use Vim as an all-purpose editor.
+It is IMPORTANT to remember that this tutor is set up to teach by use. That
+means that you need to do the exercises to learn them properly. If you only
+read the text, you will soon forget what is most important!
+
+For now, make sure that your Shift-Lock key is NOT depressed and press the
+`j`{normal} key enough times to move the cursor so that Lesson 0 completely
+fills the screen.
+
+# Lesson 0
+
+NOTE: The commands in the lessons will modify the text, but those changes
+won't 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.
+- Type [<Enter>](<Enter>) on links [like this](holy-grail    ) to open the linked help section.
+- Or simply type [K](K) on any word to find its documentation!
+- 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):
+~~~ cmd
+    :help <Enter>
+~~~
+or press a sequence of keys
+~~~ normal
+    <Esc>0f<Space>d3wP$P
+~~~
+
+Text within <'s and >'s (like `<Enter>`{normal}) describes a key to press
+instead of text to type.
+
+Now, move to the next lesson (use the `j`{normal} key to scroll down).
+
+## Lesson 1.1: MOVING THE CURSOR
+
+** To move the cursor, press the `h`, `j`, `k`, `l` keys as indicated. **
+
+         ↑
+         k          Hint: The `h`{normal} key is at the left and moves left.
+     ← h   l →            The `l`{normal} key is at the right and moves right.
+         j                The `j`{normal} key looks like a down arrow.
+         ↓
+
+  1. Move the cursor around the screen until you are comfortable.
+
+  2. Hold down the down key (`j`{normal}) until it repeats.
+     Now you know how to move to the next lesson.
+
+  3. Using the down key, move to Lesson 1.2.
+
+NOTE: If you are ever unsure about something you typed, press <Esc> to place
+      you in Normal mode. Then retype the command you wanted.
+
+NOTE: The cursor keys should also work. But using hjkl you will be able to
+      move around much faster, once you get used to it. Really!
+
+# Lesson 1.2: EXITING VIM
+
+!! NOTE: Before executing any of the steps below,
+read this entire lesson !!
+
+ 1. Press the <Esc> key (to make sure you are in Normal mode).
+
+ 2. Type:
+
+    `:q!`{vim} `<Enter>`{normal}.
+
+     This exits the editor, DISCARDING any changes you have made.
+
+ 3. Open vim and get back here by executing the command that got you into
+     this tutor. That might be:
+
+     :Tutor <Enter>
+
+ 4. If you have these steps memorized and are confident, execute steps
+     1 through 3 to exit and re-enter the editor.
+
+NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
+       will learn how to save the changes to a file.
+
+ 5. Move the cursor down to Lesson 1.3.
+
+## Lesson 1.3: TEXT EDITING - DELETION
+
+** Press `x`{normal} to delete the character under the cursor. **
+
+ 1. Move the cursor to the line below marked ✗.
+
+ 2. To fix the errors, move the cursor until it is on top of the
+     character to be deleted.
+
+ 3. Press [the x key](x) to delete the unwanted character.
+
+ 4. Repeat steps 2 through 4 until the sentence is correct.
+
+The ccow jumpedd ovverr thhe mooon.
+
+ 5. Now that the line is correct, go on to Lesson 1.4.
+
+NOTE: As you go through this tutor, do not try to memorize, learn by
+      usage.
+
+# Lesson 1.4: TEXT EDITING: INSERTION
+
+** Press `i`{normal} to insert text. **
+
+ 1. Move the cursor to the first line below marked ✗.
+
+ 2. To make the first line the same as the second, move the cursor on top
+     of the first character AFTER where the text is to be inserted.
+
+ 3. Press `i`{normal} and type in the necessary additions.
+
+ 4. As each error is fixed press `<Esc>`{normal} to return to Normal mode.
+     Repeat steps 2 through 4 to correct the sentence.
+
+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.
+
+# Lesson 1.5: TEXT EDITING: APPENDING
+
+** Press `A`{normal} to append text. **
+
+ 1. Move the cursor to the first line below marked ✗.
+    It does not matter on what character the cursor is in that line.
+
+ 2. Press [A](A) and type in the necessary additions.
+
+ 3. As the text has been appended press `<Esc>`{normal} to return to Normal
+     mode.
+
+ 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
+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.
+
+# Lesson 1.6: EDITING A FILE
+
+** Use `:wq`{vim} to save a file and exit. **
+
+!! NOTE: Before executing any of the steps below, read this entire lesson !!
+
+ 1. Exit this tutor as you did in Lesson 1.2: `:q!`{vim}
+    Or, if you have access to another terminal, do the following there.
+
+ 2. At the shell prompt type this command:
+~~~ sh
+     $ vim tutor
+~~~
+    'vim' is the command to start the Vim editor, 'tutor' is the name of
+    the file you wish to edit. Use a file that may be changed.
+
+ 3. Insert and delete text as you learned in the previous lessons.
+
+ 4. Save the file with changes and exit Vim with:
+~~~ cmd
+     :wq
+~~~
+
+    Note you'll need to press `<Enter>` to execute the command.
+
+ 5. If you have quit vimtutor in step 1 restart the vimtutor and move down
+     to the following summary.
+
+ 6. After reading the above steps and understanding them: do it.
+
+# Lesson 1 SUMMARY
+
+ 1. The cursor is moved using either the arrow keys or the hjkl keys.
+     h (left)   j (down)       k (up)       l (right)
+
+ 2. To start Vim from the shell prompt type:
+
+~~~ sh
+    $ vim FILENAME
+~~~
+
+ 3. To exit Vim type: `<Esc>`{normal} `:q!`{vim} `<Enter>`{normal} to trash
+    all changes.
+              OR type: `<Esc>`{normal} `:wq`{vim} `<Enter>`{normal} to save
+    the changes.
+
+ 4. To delete the character at the cursor type: `x`{normal}
+
+ 5. To insert or append text type:
+    `i`{normal} insert text `<Esc>`{normal}     insert before the cursor.
+    `A`{normal} append text `<Esc>`{normal}     append after the line.
+
+NOTE: Pressing `<Esc>`{normal} will place you in Normal mode or will cancel
+      an unwanted and partially completed command.
+
+Now continue with Lesson 2.
+
+# Lesson 2.1: DELETION COMMANDS
+
+** Type `dw`{normal} to delete a word. **
+
+ 1. Press `<Esc>`{normal} to make sure you are in Normal mode.
+
+ 2. Move the cursor to the line below marked ✗.
+
+ 3. Move the cursor to the beginning of a word that needs to be deleted.
+
+ 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.
+
+ 5. Repeat steps 3 and 4 until the sentence is correct and go to Lesson 2.2.
+
+# Lesson 2.2: MORE DELETION COMMANDS
+
+** Type `d$`{normal} to delete to the end of the line. **
+
+ 1. Press `<Esc>`{normal} to make sure you are in Normal mode.
+
+ 2. Move the cursor to the line below marked ✗.
+
+ 3. Move the cursor to the end of the correct line (AFTER the first . ).
+
+ 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.
+
+ 5. Move on to Lesson 2.3 to understand what is happening.
+
+# Lesson 2.3: ON OPERATORS AND MOTIONS
+
+Many commands that change text are made from an [operator](operator) and
+a [motion](navigation).
+The format for a delete command with the [d](d) delete operator is as follows:
+
+    d   motion
+
+  Where:
+    d      - is the delete operator.
+    motion - is what the operator will operate on (listed below).
+
+  A short list of motions:
+    [w](w) - until the start of the next word, EXCLUDING its first character.
+    [e](e) - to the end of the current word, INCLUDING the last character.
+    [$]($) - to the end of the line, INCLUDING the last character.
+
+  Thus typing `de`{normal} will delete from the cursor to the end of the word.
+
+NOTE:  Pressing just the motion while in Normal mode without an operator
+       will move the cursor as specified.
+
+# Lesson 2.4: USING A COUNT FOR A MOTION
+
+** Typing a number before a motion repeats it that many times. **
+
+ 1. Move the cursor to the start of the line marked ✓ below.
+
+ 2. Type `2w`{normal} to move the cursor two words forward.
+
+ 3. Type `3e`{normal} to move the cursor to the end of the third word forward.
+
+ 4. Type `0`{normal} ([zero](0)) to move to the start of the line.
+
+ 5. Repeat steps 2 and 3 with different numbers.
+
+This is just a line with words you can move around in.
+
+ 6. Move on to Lesson 2.5.
+
+# Lesson 2.5: USING A COUNT TO DELETE MORE
+
+** Typing a number with an operator repeats it that many times. **
+
+In the combination of the delete operator and a motion mentioned above you
+insert a count before the motion to delete more:
+     d   number   motion
+
+ 1. Move the cursor to the first UPPER CASE word in the line marked ✗.
+
+ 2. Type `d2w`{normal} to delete the two UPPER CASE words
+
+ 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.
+
+# Lesson 2.6: OPERATING ON LINES
+
+** Type `dd`{normal} to delete a whole line. **
+
+Due to the frequency of whole line deletion, the designers of Vi decided
+it would be easier to simply type two d's to delete a line.
+
+ 1. Move the cursor to the second line in the phrase below.
+ 2. Type [dd](dd) to delete the line.
+ 3. Now move to the fourth line.
+ 4. Type `2dd`{normal} to delete two lines.
+
+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
+
+** Press `u`{normal} to undo the last commands, `U`{normal} to fix a whole line. **
+
+ 1. Move the cursor to the line below marked ✗ and place it on the
+    first error.
+ 2. Type `x`{normal} to delete the first unwanted character.
+ 3. Now type `u`{normal} to undo the last command executed.
+ 4. This time fix all the errors on the line using the `x`{normal} command.
+ 5. Now type a capital `U`{normal} to return the line to its original state.
+ 6. Now type `u`{normal} a few times to undo the `U`{normal} and preceding
+    commands.
+ 7. Now type `<C-r>`{normal} (Control + R) a few times to redo the commands
+     (undo the undos).
+
+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.
+
+# Lesson 2 SUMMARY
+
+ 1. To delete from the cursor up to the next word type:    `dw`{normal}
+ 2. To delete from the cursor to the end of a line type:   `d$`{normal}
+ 3. To delete a whole line type:                           `dd`{normal}
+ 4. To repeat a motion prepend it with a number:           `2w`{normal}
+
+ 5. The format for a change command is:
+               operator   [number]   motion
+    where:
+       operator -   is what to do, such as [d](d) for delete
+       [number] -   is an optional count to repeat the motion
+       motion   -   moves over the text to operate on, such as:
+                        [w](w) (word),
+                        [$]($) (to the end of line), etc.
+
+ 6. To move to the start of the line use a zero: [0](0)
+
+ 7. To undo previous actions, type:            `u`{normal}  (lowercase u)
+    To undo all the changes on a line, type:   `U`{normal}  (capital U)
+    To undo the undo's, type:                  `<C-r>`{normal}
+
+# Lesson 3.1: THE PUT COMMAND
+
+** Type `p`{normal} to put previously deleted text after the cursor. **
+
+ 1. Move the cursor to the first ✓ line below.
+
+ 2. Type `dd`{normal} to delete the line and store it in a Vim register.
+
+ 3. Move the cursor to the c) line, ABOVE where the deleted line should go.
+
+ 4. Type `p`{normal} to put the line below the cursor.
+
+ 5. Repeat steps 2 through 4 to put all the lines in correct order.
+
+d) Can you learn too?
+b) Violets are blue,
+c) Intelligence is learned,
+a) Roses are red,
+
+# Lesson 3.2: THE REPLACE COMMAND
+
+** Type `rx`{normal} to replace the character at the cursor with x. **
+
+ 1. Move the cursor to the first line below marked ✗.
+
+ 2. Move the cursor so that it is on top of the first error.
+
+ 3. Type `r`{normal} and then the character which should be there.
+
+ 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!
+When this line was typed in, someone pressed some wrong keys!
+
+ 5. Now move on to Lesson 3.3.
+
+NOTE: Remember that you should be learning by doing, not memorization.
+
+# Lesson 3.3: THE CHANGE OPERATOR
+
+** To change until the end of a word, type `ce`{normal}. **
+
+ 1. Move the cursor to the first line below marked ✗.
+
+ 2. Place the cursor on the "u" in "lubw".
+
+ 3. Type `ce`{normal} and the correct word (in this case, type "ine" ).
+
+ 4. Press `<Esc>`{normal} and move to the next character that needs to be
+     changed.
+
+ 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.
+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.
+
+# Lesson 3.4: MORE CHANGES USING `c`{normal}
+
+** The change operator is used with the same motions as delete. **
+
+ 1. The change operator works in the same way as delete. The format is:
+
+         c    [number]   motion
+
+ 2. The motions are the same, such as `w`{normal} (word) and `$`{normal} (end of line).
+
+ 3. Move to the first line below marked ✗.
+
+ 4. Move the cursor to the first error.
+
+ 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.
+The end of this line needs to be corrected using the `c$`{normal} command.
+
+NOTE: You can use the Backspace key to correct mistakes while typing.
+
+# Lesson 3 SUMMARY
+
+ 1. To put back text that has just been deleted, type [p](p). This puts the
+    deleted text AFTER the cursor (if a line was deleted it will go on the
+    line below the cursor).
+
+ 2. To replace the character under the cursor, type [r](r) and then the
+    character you want to have there.
+
+ 3. The [change operator](c) allows you to change from the cursor to where
+    the motion takes you. Type `ce`{normal} to change from the cursor to the
+    end of the word, `c$`{normal} to change to the end of a line.
+
+ 4. The format for change is:
+
+     c   [number]   motion
+
+Now go on to the next lesson.
+
+# Lesson 4.1: CURSOR LOCATION AND FILE STATUS
+
+** Type `<C-g>`{normal} to show your location in a file and the file status.
+ Type `G`{normal} to move to a line in the file. **
+
+NOTE: Read this entire lesson before executing any of the steps!!
+
+ 1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this
+    `<C-g>`{normal}. A message will appear at the bottom of the page with the
+    filename and the position in the file. Remember the line number for
+    Step 3.
+
+NOTE: You may see the cursor position in the lower right corner of the
+      screen. This happens when the ['ruler']('ruler') option is set.
+ 2. Press [G](G) to move you to the bottom of the file.
+    Type [gg](gg) to move you to the start of the file.
+
+ 3. Type the number of the line you were on and then `G`{normal}. This will
+    return you to the line you were on when you first pressed `<C-g>`{normal}.
+
+ 4. If you feel confident to do this, execute steps 1 through 3.
+
+# Lesson 4.2: THE SEARCH COMMAND
+
+** Type `/`{normal} followed by a phrase to search for the phrase. **
+
+ 1. In Normal mode type the `/`{normal} character. Notice that it and the
+    cursor appear at the bottom of the screen as with the `:`{normal} command.
+
+ 2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search
+    for.
+
+ 3. To search for the same phrase again, simply type [n](n).
+    To search for the same phrase in the opposite direction, type [N](N).
+
+ 4. To search for a phrase in the backward direction, use [?](?) instead
+    of `/`{normal}.
+
+ 5. To go back to where you came from press `<C-o>`{normal} (keep `<Ctrl>`{normal}    pressed down while pressing the letter `o`{normal}). Repeat to go back
+    further. `<C-i>`{normal} goes forward.
+
+"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.
+
+# Lesson 4.3: MATCHING PARENTHESES SEARCH
+
+** Type `%`{normal} to find a matching ),], or }. **
+
+ 1. Place the cursor on any (, [, or { in the line below marked ✓.
+
+ 2. Now type the [%](%) character.
+
+ 3. The cursor will move to the matching parenthesis or bracket.
+
+ 4. Type `%`{normal} to move the cursor to the other matching bracket.
+
+ 5. Move the cursor to another (,),[,],{ or } and see what `%`{normal} does.
+
+This ( is a test line with ('s, ['s ] and {'s } in it. ))
+
+NOTE: This is very useful in debugging a program with unmatched parentheses!
+
+# Lesson 4.4: THE SUBSTITUTE COMMAND
+
+** Type `:s/old/new/g` to substitute "new" for "old". **
+
+ 1. Move the cursor to the line below marked ✗.
+
+ 2. Type
+~~~ cmd
+    :s/thee/the/
+~~~
+
+    NOTE that the [:s](:s) command only changed the first occurrence of "thee" in the line.
+
+ 3. Now type
+~~~ cmd
+     :s/thee/the/g
+~~~
+
+    Adding the g [flag](:s_flags) means to substitute globally in the line,
+    change all occurrences of "thee" in the line.
+
+Usually 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
+     :#,#s/old/new/g
+~~~
+    where #,# are the line numbers of the range of lines where the
+    substitution is to be done.
+
+    Type
+~~~ cmd
+    :%s/old/new/g
+~~~
+    to change every occurrence in the whole file.
+
+    Type
+~~~ cmd
+    :%s/old/new/gc
+~~~
+    to find every occurrence in the whole file, with a prompt whether to
+    substitute or not.
+
+# Lesson 4 SUMMARY
+
+ 1. `<C-g>`{normal}     displays your location and the file status.
+    `G`{normal}         moves to the end of the file.
+     number `G`{normal} moves to that line number.
+    `gg`{normal}        moves to the first line.
+
+ 2. Typing `/`{normal} followed by a phrase searches FORWARD for the phrase.
+    Typing `?`{normal} followed by a phrase searches BACKWARD for the phrase.
+    After a search type `n`{normal} to find the next occurrence in the same
+    direction or `N`{normal} to search in the opposite direction.
+    `<C-o>`{normal} takes you back to older positions, `<C-i>`{normal} to
+    newer positions.
+
+ 3. Typing `%`{normal} while the cursor is on a (,),[,],{, or } goes to its
+    match.
+
+ 4. To substitute new for the first old in a line type
+~~~ cmd
+        :s/old/new
+~~~
+    To substitute new for all 'old's on a line type
+~~~ cmd
+        :s/old/new/g
+~~~
+    To substitute phrases between two line #'s type
+~~~ cmd
+        :#,#s/old/new/g
+~~~
+    To substitute all occurrences in the file type
+~~~ cmd
+        :%s/old/new/g
+~~~
+    To ask for confirmation each time add 'c'
+~~~ cmd
+        :%s/old/new/gc
+~~~
+
+# Lesson 5.1: HOW TO EXECUTE AN EXTERNAL COMMAND
+
+** Type `:!`{vim} followed by an external command to execute that command. **
+
+ 1. Type the familiar command `:`{normal} to set the cursor at the bottom of
+    the screen. This allows you to enter a command-line command.
+
+ 2. Now type the [!](!cmd) (exclamation point) character. This allows you to
+    execute any external shell command.
+
+ 3. As an example type "ls" following the "!" and then hit `<Enter>`{normal}.
+    This will show you a listing of your directory, just as if you were
+    at the shell prompt.
+
+NOTE: It is possible to execute any external command this way, also with
+      arguments.
+
+NOTE: All `:`{vim} commands must be finished by hitting `<Enter>`{normal}.
+      From here on we will not always mention it.
+
+# Lesson 5.2: MORE ON WRITING FILES
+
+** To save the changes made to the text, type `:w`{vim} FILENAME. **
+
+ 1. Type `:!ls`{vim} to get a listing of your directory.
+    You already know you must hit `<Enter>`{normal} after this.
+
+ 2. Choose a filename that does not exist yet, such as TEST.
+
+ 3. Now type:
+~~~ cmd
+        :w TEST
+~~~
+   (where TEST is the filename you chose.)
+
+ 4. This saves the whole file (the Vim Tutor) under the name TEST.
+    To verify this, type `:!ls`{vim} again to see your directory.
+
+NOTE: If you were to exit Vim and start it again with `vim TEST`, the file
+      would be an exact copy of the tutor when you saved it.
+
+ 5. Now remove the file by typing:
+~~~ cmd
+        :!rm TEST
+~~~
+
+# Lesson 5.3: SELECTING TEXT TO WRITE
+
+** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim}. **
+
+ 1. Move the cursor to this line.
+
+ 2. Press [v](v) and move the cursor to the fifth item below. Notice that the
+    text is highlighted.
+
+ 3. Press the `:`{normal} character. At the bottom of the screen
+
+        :'<,'>
+
+    will appear.
+
+ 4. Type
+
+        `:w TEST`{vim}
+
+    where TEST is a filename that does not exist yet. Verify that you see
+
+        `:'<,'>w TEST`{vim}
+
+    before you press `<Enter>`{normal}.
+
+ 5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see    it. Do not remove it yet! We will use it in the next lesson.
+
+NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
+      the cursor around to make the selection bigger or smaller. Then you can
+      use an operator to do something with the text. For example, `d`{normal}
+      deletes the text.
+
+# Lesson 5.4: RETRIEVING AND MERGING FILES
+
+** To insert the contents of a file, type `:r FILENAME`{vim}. **
+
+ 1. Place the cursor just above this line.
+
+NOTE:  After executing Step 2 you will see text from Lesson 5.3. Then move
+       DOWN to see this lesson again.
+
+ 2. Now retrieve your TEST file using the command
+
+        `:r TEST`{vim}
+
+     where TEST is the name of the file you used.
+     The file you retrieve is placed below the cursor line.
+
+ 3. To verify that a file was retrieved, cursor back and notice that there
+    are now two copies of Lesson 5.3, the original and the file version.
+
+NOTE: You can also read the output of an external command. For example,
+
+        `:r !ls`{vim}
+
+      reads the output of the `ls` command and puts it below the cursor.
+
+# Lesson 5 SUMMARY
+
+ 1. [:!command](:!cmd) executes an external command.
+
+     Some useful examples are:
+     `:!ls`{vim}              -  shows a directory listing
+     `:!rm FILENAME`{vim}     -  removes file FILENAME
+
+ 2. [:w](:w) FILENAME             writes the current Vim file to disk with
+                            name FILENAME.
+
+ 3. [v](v)  motion  :w FILENAME   saves the Visually selected lines in file
+                             FILENAME.
+
+ 4. [:r](:r) FILENAME             retrieves disk file FILENAME and puts it
+                            below the cursor position.
+
+ 5. [:r !dir](:r!)                reads the output of the dir command and
+                           puts it below the cursor position.
+
+# Lesson 6.1: THE OPEN COMMAND
+
+** Type `o`{normal} to open a line below the cursor and place you in Insert mode. **
+
+ 1. Move the cursor to the line below marked ✓.
+
+ 2. Type the lowercase letter `o`{normal} to [open](o) up a line BELOW the
+    cursor and place you in Insert mode.
+
+ 3. Now type some text and press `<Esc>`{normal} to exit Insert mode.
+
+After typing `o`{normal} 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.
+
+# Lesson 6.2: THE APPEND COMMAND
+
+** Type `a`{normal} to insert text AFTER the cursor. **
+
+ 1. Move the cursor to the start of the line below marked ✗.
+
+ 2. Press `e`{normal} until the cursor is on the end of "li".
+
+ 3. Type the lowercase letter `a`{normal} to [append](a) text AFTER the
+     cursor.
+
+ 4. Complete the word like the line below it. Press `<Esc>`{normal} to exit
+     Insert mode.
+
+ 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.
+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.
+
+# Lesson 6.3: ANOTHER WAY TO REPLACE
+
+** Type a capital `R`{normal} to replace more than one character. **
+
+ 1. Move the cursor to the first line below marked ✗. Move the cursor to
+     the beginning of the first "xxx".
+
+ 2. Now press `R`{normal} ([capital R](R)) and type the number below it in the
+ second line, so that it replaces the "xxx".
+
+ 3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that
+     the rest of the line remains unmodified.
+
+ 4. Repeat the steps to replace the remaining "xxx".
+
+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.
+
+# Lesson 6.4: COPY AND PASTE TEXT
+
+** Use the `y`{normal} operator to copy text and `p`{normal} to paste it. **
+
+ 1. Go to the line marked with ✓ below and place the cursor after "a)".
+
+ 2. Start Visual mode with `v`{normal} and move the cursor to just before
+    "first".
+
+ 3. Type `y`{normal} to [yank](yank) (copy) the highlighted text.
+
+ 4. Move the cursor to the end of the next line: `j$`{normal}
+
+ 5. Type `p`{normal} to [put](put) (paste) the text.
+
+ 6. Press `a`{normal} and then type "second". Press `<Esc>`{normal} to leave
+    Insert mode.
+
+ 7. 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)
+
+NOTE: you can use `y`{normal} as an operator: `yw`{normal} yanks one word.
+
+# Lesson 6.5: SET OPTION
+
+** Set an option so a search or substitute ignores case. **
+
+ 1. Search for 'ignore' by entering: `/ignore`
+    Repeat several times by pressing `n`{normal}.
+
+ 2. Set the 'ic' (Ignore case) option by entering:
+~~~ cmd
+        :set ic
+~~~
+ 3. Now search for 'ignore' again by pressing `n`{normal}.
+    Notice that Ignore and IGNORE are now also found.
+
+ 4. Set the 'hlsearch' and 'incsearch' options:
+~~~ cmd
+        :set hls is
+~~~
+ 5. Now type the search command again and see what happens: /ignore <Enter>
+
+ 6. To disable ignoring case enter:
+~~~ cmd
+        :set noic
+~~~
+ 7. To toggle the value of a setting, prepend it with "inv":
+~~~ cmd
+        :set invic
+~~~
+NOTE: To remove the highlighting of matches enter:
+~~~ cmd
+        :nohlsearch
+~~~
+NOTE: If you want to ignore case for just one search command, use [\c](/\c)
+      in the phrase: /ignore\c <Enter>
+
+# Lesson 6 SUMMARY
+
+ 1. Type `o`{normal} to open a line BELOW the cursor and start Insert mode.
+    Type `O`{normal} to open a line ABOVE the cursor.
+
+ 2. Type `a`{normal} to insert text AFTER the cursor.
+    Type `A`{normal} to insert text after the end of the line.
+
+ 3. The `e`{normal} command moves to the end of a word.
+
+ 4. The `y`{normal} operator copies text, `p`{normal} pastes it.
+
+ 5. Typing a capital `R`{normal} enters Replace mode until `<Esc>`{normal} is
+     pressed.
+
+ 6. Typing "[:set](:set) xxx" sets the option "xxx". Some options are:
+
+        'ic' 'ignorecase'   ignore upper/lower case when searching
+        'is' 'incsearch'    show partial matches for a search phrase
+        'hls' 'hlsearch'    highlight all matching phrases
+
+     You can either use the long or the short option name.
+
+ 7. Prepend "no" to switch an option off:
+~~~ cmd
+        :set noic
+~~~
+ 8. Prepend "inv" to toggle an option:
+~~~ cmd
+        :set invic
+~~~
+
+# Lesson 7.1: GETTING HELP
+
+** Use the on-line help system. **
+
+Vim has a comprehensive on-line help system. To get started, try one of
+these three:
+    - press the `<HELP>`{normal} key (if you have one)
+    - press the `<F1>`{normal} key (if you have one)
+    - type
+        `:help`{vim}
+
+Read the text in the help window to find out how the help works.
+Type `<C-w><C-w>`{normal} to jump from one window to another.
+Type `:q`{vim} to close the help window.
+
+You can find help on just about any subject, by giving an argument to the
+":help" command. Try these (don't forget pressing <Enter>):
+~~~ cmd
+    :help w
+    :help c_CTRL-D
+    :help insert-index
+    :help user-manual
+~~~
+# Lesson 7.2: CREATE A STARTUP SCRIPT
+
+** Enable Vim features. **
+
+Vim has many more features than Vi, but most of them are disabled by
+default. To start using more features you have to create a "vimrc" file.
+
+ 1. Start editing the "vimrc" file.
+    `:call mkdir(stdpath('config'),'p')`{vim}
+    `:exe 'edit' stdpath('config').'/init.vim'`{vim}
+
+ 2. Write the file with:
+    `:w`{vim}
+
+  You can add all your preferred settings to this "vimrc" file.
+  For more information type `:help vimrc-intro`{vim}.
+
+# Lesson 7.3: COMPLETION
+
+** Command line completion with `<C-d>`{normal} and `<Tab>`{normal}. **
+
+ 1. Look what files exist in the directory: `:!ls`{vim}
+
+ 2. Type the start of a command: `:e`{vim}
+
+ 3. Press `<C-d>`{normal} and Vim will show a list of commands that start
+     with "e".
+
+ 4. Press `<Tab>`{normal} and Vim will complete the command name to ":edit".
+
+ 5. Now add a space and the start of an existing file name: `:edit FIL`{vim}
+
+ 6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
+
+NOTE: Completion works for many commands. It is especially useful for
+      `:help`{vim}.
+
+# Lesson 7 SUMMARY
+
+ 1. Type `:help`{vim}
+    or press `<F1>`{normal} or `<Help>`{normal} to open a help window.
+
+ 2. Type `:help TOPIC`{vim} to find help on TOPIC.
+
+ 3. Type `<C-w><C-w>`{normal} to jump to another window
+
+ 4. Type `:q`{vim} to close the help window
+
+ 5. Create a vimrc startup script to keep your preferred settings.
+
+ 6. While in command mode, press `<C-d>`{normal} to see possible completions.
+     Press `<Tab>`{normal} to use one completion.
+
+# CONCLUSION
+
+This was intended to give a brief overview of the Vim editor, just enough to
+allow you to use the editor fairly easily. It is far from complete as Vim has
+many many more commands. Consult the help often.
+
+There are many resources online to learn more about vim. Here's a bunch of
+them:
+
+- *Learn Vim Progressively*: http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
+- *Learning Vim in 2014*: http://benmccormick.org/learning-vim-in-2014/
+- *Vimcasts*: http://vimcasts.org/
+- *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, *Practical Vim* and the sequel *Modern Vim* by Drew Neil
+are recommended often.
+
+This tutorial was written by Michael C. Pierce and Robert K. Ware, Colorado
+School of Mines using ideas supplied by Charles Smith, Colorado State
+University. E-mail: bware@mines.colorado.edu.
+
+Modified for Vim by Bram Moolenaar.
+Modified for vim-tutor-mode by Felipe Morales.
new file mode 100644
--- /dev/null
+++ b/runtime/tutor/en/vim-01-beginner.tutor.json
@@ -0,0 +1,45 @@
+{
+  "expect": {
+    "24": -1,
+    "103": "The cow jumped over the moon.",
+    "124": "There is some text missing from this line.",
+    "125": "There is some text missing from this line.",
+    "144": "There is some text missing from this line.",
+    "145": "There is some text missing from this line.",
+    "146": "There is also some text missing here.",
+    "147": "There is also some text missing here.",
+    "220": "There are some words that don't belong in this sentence.",
+    "236": "Somebody typed the end of this line twice.",
+    "276": -1,
+    "295": "This line of words is cleaned up.",
+    "309": -1,
+    "310": -1,
+    "311": -1,
+    "312": -1,
+    "313": -1,
+    "314": -1,
+    "315": -1,
+    "332": "Fix the errors on this line and replace them with undo.",
+    "372": -1,
+    "373": -1,
+    "374": -1,
+    "375": -1,
+    "389": "When this line was typed in, someone pressed some wrong keys!",
+    "390": "When this line was typed in, someone pressed some wrong keys!",
+    "411": "This line has a few words that need changing using the change operator.",
+    "412": "This line has a few words that need changing using the change operator.",
+    "432": "The end of this line needs to be corrected using the `c$` command.",
+    "433": "The end of this line needs to be corrected using the `c$` command.",
+    "497": -1,
+    "516": -1,
+    "541": "Usually the best time to see the flowers is in the spring.",
+    "735": -1,
+    "740": -1,
+    "759": "This line will allow you to practice appending text to a line.",
+    "760": "This line will allow you to practice appending text to a line.",
+    "780": "Adding 123 to 456 gives you 579.",
+    "781": "Adding 123 to 456 gives you 579.",
+    "807": "a) This is the first item.",
+    "808": "b) This is the second item."
+  }
+}
new file mode 100644
--- /dev/null
+++ b/runtime/tutor/tutor.tutor
@@ -0,0 +1,247 @@
+# CREATING A VIM TUTORIAL WITH VIM-TUTOR-MODE
+
+This tutorial will guide you through the steps required to create a tutorial
+file for vim-tutor-mode. It is also meant as a demo of vim-tutor-mode
+capabilities.
+
+Table of contents:
+
+- [Setting up](*setting-up*)
+- [vim-tutor-mode's markup](*markup*)
+    - [emphasis](*emphasis*)
+    - [headers](*headers*)
+    - [links](*links*)
+    - [codeblocks](*codeblocks*)
+- [Interactive elements](*interactive*)
+    - [expect](*expect*)
+
+## SETTING UP *setting-up*
+
+First, you'll need to enable "debug" mode
+~~~ cmd
+    :let g:tutor_debug = 1
+~~~
+This will allow saving changes to the tutor files and will disable conceals, so
+you can more easily check your changes.
+
+After this, create a new .tutor file (we will be practicing on this very file, so you
+don't need to do this now):
+~~~ cmd
+    :e new-tutorial.tutor
+~~~
+
+## VIM-TUTOR-MODE's MARKDOWN *markup*
+
+vim-tutor-mode uses a subset of markdown's syntax to format the tutorials. The
+subset supported should be enough for most tutorials and the maintainers will
+try to keep it as small as possible (if regular markdown allows for several
+ways to do the same thing, tutor markdown will only provide the one the
+maintainers think is easier to handle).
+
+### Emphasis *emphasis*
+
+For emphasized text (italics), as in normal markdown, you use \*. E.g.:
+
+    \*text\*
+
+is displayed like
+
+    *text*
+
+Note: The underscores variant is not supported.
+
+For strong emphasis (bold), you use \*\*. E.g.:
+
+    \*\*this\*\*
+
+is displayed like
+
+    **this**
+
+1. Format the line below so it becomes a lesson description:
+
+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'
+TODO: Document '&variable'
+
+### Headers *headers*
+
+3. Practice fixing the lines below:
+
+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:
+
+
+
+   ATTENTION We will use this label later, so remember it.
+
+### Links *links*
+
+It is good practice to include links in your tutorials to reference materials,
+like vim's own help or external documents. You can also link to other parts of
+the document.
+
+Links have the syntax
+
+    \[label\]\(target\)
+
+#### Help links
+
+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
+A link to help for the ['breakindent']('breakindent') option
+
+#### Anchor links
+
+A link can also lead to a place in the file itself. Anchors are written
+
+    \*anchor\*
+
+and are hidden by default. Links to them look like
+
+    \[label\]\(\*anchor\*\)
+
+6. Add the appropriate link:
+
+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.
+
+
+
+# Tutorial links
+
+You can also have links to other tutorials. For this, you'll write the anchor in the format
+
+    @tutor:TUTORIAL
+
+7. Create a link to this tutorial:
+
+A link to the vim-tutor-mode tutorial
+A link to [the vim-tutor-mode tutorial](@tutor:tutor)
+
+### Codeblocks *codeblocks*
+
+vim-tutor-mode tutorials can include viml sections
+
+    ~~~ cmd
+    echom "hello"
+    ~~~
+
+is displayed as
+~~~ cmd
+echom "hello"
+~~~
+
+8. Copy the viml section below
+
+
+
+
+
+~~~ viml
+echom 'the value of &number is'.string(&number)
+~~~
+
+You can inline viml code using "\`" and "\`{vim}":
+
+    \`call myFunction()\`{vim}
+
+is displayed as
+
+    `call myFunction()`{vim}
+
+[normal](Normal-mode) commands can also be embedded in tutorials.
+
+    ~~~ normal
+    ftdaW
+    ~~~
+
+is displayed as
+~~~ normal
+ftdaW
+~~~
+
+Note: you can also write `norm` or `normal`.
+
+9. Copy the normal section below
+
+
+
+
+
+~~~ normal
+d2w
+~~~
+
+You can also inline normal commands by using "\`" and "\`{normal}":
+
+    \`gq\`{normal} is very useful.
+
+is displayed:
+
+    `gq`{normal} is very useful.
+
+10. Complete the line as shown
+
+d
+`d2w`{normal}
+
+Commands to run in the system shell can be highlighted by indenting a line
+starting with "$".
+
+~~~ sh
+    $ vim --version
+~~~
+
+## 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. 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*
+
+"expect" lines check that the contents of the line are identical to some preset text
+(like in the exercises above).
+
+These elements are specified in separate JSON files like this
+
+~~~ json
+{
+    "expect": {
+	"1": "This is how this line should look.",
+	"2": "This is how this line should look.",
+	"3": -1
+    }
+}
+~~~
+
+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).
+
+This is an "expect" line that is always satisfied. Try changing it.
+
+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).
new file mode 100644
--- /dev/null
+++ b/runtime/tutor/tutor.tutor.json
@@ -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
+    }
+}
--- a/src/Makefile
+++ b/src/Makefile
@@ -2346,7 +2346,7 @@ installrtbase: $(HELPSOURCE)/vim.1 $(DES
 		$(DEST_AUTO) $(DEST_AUTO)/dist $(DEST_AUTO)/xml \
 		$(DEST_AUTO)/rust $(DEST_AUTO)/cargo \
 		$(DEST_IMPORT) $(DEST_IMPORT)/dist \
-		$(DEST_PLUG) $(DEST_TUTOR) $(DEST_SPELL) $(DEST_COMP)
+		$(DEST_PLUG) $(DEST_TUTOR) $(DEST_TUTOR)/en $(DEST_SPELL) $(DEST_COMP)
 	-$(SHELL) ./installman.sh install $(DEST_MAN) "" $(INSTALLMANARGS)
 # Generate the help tags with ":helptags" to handle all languages.
 # Move the distributed tags file aside and restore it, to avoid it being
@@ -2473,8 +2473,10 @@ installgtutorbin: $(DEST_BIN)
 
 installtutor: $(DEST_RT) $(DEST_TUTOR)
 	-$(INSTALL_DATA) $(TUTORSOURCE)/README* $(TUTORSOURCE)/tutor* $(DEST_TUTOR)
+	-$(INSTALL_DATA) $(TUTORSOURCE)/en/* $(DEST_TUTOR)/en/
 	-rm -f $(DEST_TUTOR)/*.info
 	chmod $(HELPMOD) $(DEST_TUTOR)/*
+	chmod $(DIRMOD) $(DEST_TUTOR)/en
 
 # Install the spell files, if they exist.  This assumes at least the English
 # spell file is there.
@@ -2671,7 +2673,8 @@ install-icons:
 		$(DEST_SYN)/modula2 $(DEST_SYN)/modula2/opt \
 		$(DEST_IND) $(DEST_FTP) \
 		$(DEST_LANG) $(DEST_KMAP) $(DEST_COMP) $(DEST_MACRO) \
-		$(DEST_PACK) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_SPELL) \
+		$(DEST_PACK) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_TUTOR)/en \
+		$(DEST_SPELL) \
 		$(DEST_AUTO) $(DEST_AUTO)/dist $(DEST_AUTO)/xml \
 		$(DEST_AUTO)/cargo $(DEST_AUTO)/rust \
 		$(DEST_IMPORT) $(DEST_IMPORT)/dist $(DEST_PLUG):
@@ -2854,6 +2857,7 @@ uninstall_runtime:
 	-rm -f $(DEST_IND)/*.vim $(DEST_IND)/README.txt
 	-rm -rf $(DEST_MACRO)
 	-rm -rf $(DEST_PACK)
+	-rm -rf $(DEST_TUTOR)/en
 	-rm -rf $(DEST_TUTOR)
 	-rm -rf $(DEST_SPELL)
 	-rm -rf $(DEST_TOOLS)
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    836,
+/**/
     835,
 /**/
     834,