]> git.madduck.net Git - etc/vim.git/blobdiff - ftplugin/mkd.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

next, previous and current work for setext headers
[etc/vim.git] / ftplugin / mkd.vim
index 0f5d82d1e2c5832b38968ff5510043bb3c199805..d390c3bcde007aedb1261be6c364c8d76fcb8c4d 100644 (file)
-"TODO get working on visual mode
+"TODO print messages when on visual mode. I only see VISUAL, not the messages.
 
-"- if inside a header
-"    goes to the nearest head before current position
-"    returns its initial hashes (#)
-"- else
-"    goes to beginning of document
-"    returns ''
-fu! b:Markdown_GoCurHeader()
-    if search( '^#', 'bcW' ) != 0
-        return matchstr( getline('.'), '\v^#+' )
-    el
-        norm! gg
-        ec 'outside any header'
-        return ''
-    en
-endf
-
-"same as `b:Markdown_GoCurHeader`:function: but does not change cursor position
-fu! b:Markdown_GetHashesCurHeader()
-    let line = search( '\v^#', 'nW' ) != 0
-    retu matchstr( getline(line) '\v^#+' )
-endf
-
-"goes to next header of any level
-"returns its hashes
-fu! b:Markdown_GoNextHeader()
-    if search( '\v^#', 'W' ) != 0
-        return matchstr( getline('.'), '\v^#+' )
-    el
-        "norm! G
-        ec 'no more headers'
-        return ''
-    en
-endf
+" This is how you should view things:
+"
+"   |BUFFER
+"   |
+"   |Outside any header
+"   |
+" a-+# a
+"   |
+"   |Inside a
+"   |
+" a-+
+" b-+## b
+"   |
+"   |inside b
+"   |
+" b-+
+" c-+### c
+"   |
+"   |Inside c
+"   |
+" c-+
+" d-|# d
+"   |
+"   |Inside d
+"   |
+" d-+
+
+let s:headerExpr = '\v^(\s*#|.+\n(\=+|-+)$)'
+
+" Return 0 if not found, else the actual line number.
+"
+function! b:Markdown_GetLineNumCurHeader()
+    echo s:headerExpr
+    return search(s:headerExpr, 'bcnW')
+endfunction
 
-"goes to previous header of any level
+" - if inside a header goes to it.
+"    Return its line number.
+"
+" - if on top level outside any headers,
+"    print a warning
+"    Return `0`.
+"
+function! b:Markdown_GoCurHeader()
+    let l:lineNum = b:Markdown_GetLineNumCurHeader()
+    if l:lineNum != 0
+        call cursor(l:lineNum, 1)
+    else
+        echo 'error: outside any header'
+        "normal! gg
+    end
+    return l:lineNum
+endfunction
+
+" Put cursor on next header of any level.
+"
+" If there are no more headers, print a warning.
+"
+function! b:Markdown_GoNextHeader()
+    if search(s:headerExpr, 'W') == 0
+        "normal! G
+        echo 'error: no next header'
+    end
+endfunction
+
+" Put cursor on previous header (before current) of any level.
+"
+" If it does not exist, print a warning.
 "
-"if there is no previous header, only print a warning
+function! b:Markdown_GoPreviousHeader()
+    let l:oldPos = getpos('.')
+    let l:curHeaderLineNumber = b:Markdown_GoCurHeader()
+    if l:curHeaderLineNumber == 0
+        call setpos('.', l:oldPos)
+    end
+    if search(s:headerExpr, 'bW') == 0
+        "normal! gg
+        call setpos('.', l:oldPos)
+        echo 'error: no previous header'
+    end
+endfunction
+
+"- if inside a header, cursor goes to it.
+"   Return its hashes.
 "
-"if the cursor is not exactly at the header,
-"it goes to exactly the header. So this could be used
-"if you want to go to the current header line.
-fu! b:Markdown_GoPreviousHeader()
-    if search( '^#', 'bW' ) != 0
-        return matchstr( getline('.'), '\v^#+' )
-    el
-        "norm! gg
-        ec 'no more headers'
+"- if on top level outside any headers,
+"   print a warning
+"   return ''
+"
+function! b:Markdown_GoCurHeaderGetHashes()
+    let l:linenum = b:Markdown_GetLineNumCurHeader()
+    if l:linenum != 0
+        call cursor(l:linenum, 1)
+        return matchlist(getline(linenum), '\v^\s*(#+)')[1]
+    else
         return ''
-    en
-endf
-
-"if already at top level, go to beginning of buffer
-fu! b:Markdown_GoHeaderUp()
-    let l:hashes = b:Markdown_GoCurHeader()
-    if len( l:hashes ) > 1
-        cal search( '^' . l:hashes[1:] . '[^#]', 'b' )
-    el
-        norm! gg
-    en
-endf
-
-fu! b:Markdown_GoNextHeaderSameLevel()
-
-    let l:hashes = b:Markdown_GoCurHeader()
-    
-    "go to next occurrence of that number of hashes
-    cal search( '^' . l:hashes . '[^#]', 'W' )
-
-endf
-
-"if no more next siblings, print error message and do nothing.
-fu! b:Markdown_GoNextSiblingHeader()
-
-    let l:hashes = b:Markdown_GoCurHeader()
+    end
+endfunction
 
+" Put cursor on previous header of any level.
+"
+" If it exists, return its lines number.
+"
+" Otherwise, print a warning and return `0`.
+"
+function! b:Markdown_GoHeaderUp()
+    let l:oldPos = getpos('.')
+    let l:hashes = b:Markdown_GoCurHeaderGetHashes()
+    if len(l:hashes) > 1
+        call search('^\s*' . l:hashes[1:] . '[^#]', 'b')
+    else
+        call setpos('.', l:oldPos)
+        echo 'error: already at top level'
+    end
+endfunction
+
+" If no more next siblings, print error message and do nothing.
+"
+function! b:Markdown_GoNextSiblingHeader()
+    let l:oldPos = getpos('.')
+    let l:hashes = b:Markdown_GoCurHeaderGetHashes()
+    let l:noSibling = 0
     if l:hashes ==# ''
-        retu
-    en
-
-    let l:nhashes = len(l:hashes)
-    if l:nhashes == 1
-        "special case, just add the largest possible value
-        let l:nextLowerLevelLine  = line('$') + 1
-    el
-        let l:nextLowerLevelLine  = search( '\v^#{1,' . ( l:nhashes - 1 ) . '}[^#]' , 'nW' )
-    en
-
-    let l:nextSameLevelLine   = search( '\v^' . l:hashes . '[^#]', 'nW' )
-
-    if (
-            \ l:nextSameLevelLine > 0
-            \ &&
-            \ (
-            \   l:nextLowerLevelLine == 0
-            \   ||
-            \   l:nextLowerLevelLine > l:nextSameLevelLine
+        let l:noSibling = 1
+    else
+        let l:nhashes = len(l:hashes)
+        if l:nhashes == 1
+            "special case, just add the largest possible value
+            let l:nextLowerLevelLine = line('$') + 1
+        else
+            let l:nextLowerLevelLine = search('\v^\s*#{1,' . (l:nhashes - 1) . '}[^#]' , 'nW')
+        end
+        let l:nextSameLevelLine = search('\v^\s*' . l:hashes . '[^#]', 'nW')
+        if (
+                \ l:nextSameLevelLine > 0
+                \ &&
+                \ (
+                \   l:nextLowerLevelLine == 0
+                \   ||
+                \   l:nextLowerLevelLine > l:nextSameLevelLine
+                \ )
             \ )
-        \ )
-        cal cursor( l:nextSameLevelLine, 0 )
-    el
-        ec 'no more siblings'
-    en
-
-endf
-
-fu! b:Markdown_GoPreviousHeaderSameLevel()
-
-    let l:hashes = b:Markdown_GoCurHeader()
-
-    "go to next occurrence of that number of hashes
-    cal search( '^' . l:hashes . '[^#]', 'bW' )
-
-endf
+            call cursor(l:nextSameLevelLine, 1)
+        else
+            let l:noSibling = 1
+        end
+    end
+    if l:noSibling
+        call setpos('.', l:oldPos)
+        echo 'error: no next sibling'
+    end
+endfunction
 
 "if no more next siblings, print error message and do nothing.
-fu! b:Markdown_GoPreviousSiblingHeader()
-
-    let l:hashes = b:Markdown_GoCurHeader()
-
+function! b:Markdown_GoPreviousSiblingHeader()
+    let l:oldPos = getpos('.')
+    let l:hashes = b:Markdown_GoCurHeaderGetHashes()
+    let l:noSibling = 0
     if l:hashes ==# ''
-        retu
-    en
-
-    let l:nhashes = len(l:hashes)
-    if l:nhashes == 1
-        "special case, just add the largest possible value
-        let l:prevLowerLevelLine  = -1
-    el
-        let l:prevLowerLevelLine  = search( '\v^#{1,' . ( l:nhashes - 1 ) . '}[^#]' , 'bnW' )
-    en
-
-    let l:prevSameLevelLine   = search( '\v^' . l:hashes . '[^#]', 'bnW' )
-
-    if (
-            \ l:prevSameLevelLine > 0
-            \ &&
-            \ (
-            \   l:prevLowerLevelLine == 0
-            \   ||
-            \   l:prevLowerLevelLine < l:prevSameLevelLine
-            \ )
-        \ )
-        cal cursor( l:prevSameLevelLine, 0 )
-    el
-        ec 'no more siblings'
-    en
-
-endf
-
-"mnemonics: ']' next (like a right arrow)
-nn <buffer><silent> ]] :cal b:Markdown_GoNextHeader()<cr>
-"vnoremap <buffer><silent> ]] /^#<cr><esc>:nohl<cr>gv
-
-"mnemonics: '[' next (like a left arrow)
-nn <buffer><silent> ][ :cal b:Markdown_GoNextSiblingHeader()<cr>
-"vnoremap <buffer><silent> ][ <esc>:cal b:Markdown_GoNextHeaderSameLevel()<cr>
-
-nn <buffer><silent> [] :cal b:Markdown_GoPreviousSiblingHeader()<cr>
-
-nn <buffer><silent> [[ :cal b:Markdown_GoPreviousHeader()<cr>
-"vnoremap <buffer><silent> [[ ?^#<cr><esc>:nohl<cr>gv
-
-"go up one level. Menmonic: Up.
-nn <buffer><silent> ]u :cal b:Markdown_GoHeaderUp()<cr>
+        let l:noSibling = 1
+    else
+        let l:nhashes = len(l:hashes)
+        if l:nhashes == 1
+            "special case, just add the largest possible value
+            let l:prevLowerLevelLine = -1
+        else
+            let l:prevLowerLevelLine = search('\v^\s*#{1,' . (l:nhashes - 1) . '}[^#]' , 'bnW')
+        end
+        let l:prevSameLevelLine = search('\v^\s*' . l:hashes . '[^#]', 'bnW')
+        if (
+                \ l:prevSameLevelLine > 0
+                \ &&
+                \ (
+                \   l:prevLowerLevelLine == 0
+                \   ||
+                \   l:prevLowerLevelLine < l:prevSameLevelLine
+                \ )
+            \)
+            call cursor(l:prevSameLevelLine, 1)
+        else
+            let l:noSibling = 1
+        end
+    end
+    if l:noSibling
+        call setpos('.', l:oldPos)
+        echo 'error: no previous sibling'
+    end
+endfunction
+
+"wrapper to do move commands in visual mode
+function! s:VisMove(f)
+    norm! gv
+    call function(a:f)()
+endfunction
+
+"map in both normal and visual modes
+function! s:MapNormVis(rhs,lhs)
+    execute 'nn <buffer><silent> ' . a:rhs . ' :call ' . a:lhs . '()<cr>'
+    execute 'vn <buffer><silent> ' . a:rhs . ' <esc>:call <sid>VisMove(''' . a:lhs . ''')<cr>'
+endfunction
+
+call <sid>MapNormVis(']]', 'b:Markdown_GoNextHeader')
+call <sid>MapNormVis('[[', 'b:Markdown_GoPreviousHeader')
+call <sid>MapNormVis('][', 'b:Markdown_GoNextSiblingHeader')
+call <sid>MapNormVis('[]', 'b:Markdown_GoPreviousSiblingHeader')
+"menmonic: Up
+call <sid>MapNormVis(']u', 'b:Markdown_GoHeaderUp')
+"menmonic: Current
+call <sid>MapNormVis(']c', 'b:Markdown_GoCurHeader')