-"TODO get working on visual mode
-
-"- if inside a header
-" goes to the nearest head before current position
-" returns its initial hashes (#)
-"- else
-" goes to beginning of document
-" returns ''
+"TODO print messages when on visual mode. I only see VISUAL, not the messages.
+
+"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^#'
+
+"0 if not found
+fu! b:Markdown_GetLineNumCurHeader()
+ retu search( s:headerExpr, 'bcnW' )
+endf
+
+"- if inside a header goes to it
+" returns its hashes
+"- if on top level outside any headers,
+" print a warning
+" return ''
+fu! b:Markdown_GoCurHeaderGetHashes()
+ let l:lineNum = b:Markdown_GetLineNumCurHeader()
+ if l:lineNum != 0
+ cal cursor( l:lineNum, 1 )
+ retu matchstr( getline( lineNum ), '\v^#+' )
+ el
+ retu ''
+ en
+endf
+
+"- if inside a header goes to it
+" returns its line number
+"- if on top level outside any headers,
+" print a warning
+" return 0
fu! b:Markdown_GoCurHeader()
- if search( '^#', 'bcW' ) != 0
- return matchstr( getline('.'), '\v^#+' )
+ let l:lineNum = b:Markdown_GetLineNumCurHeader()
+ if l:lineNum != 0
+ cal cursor( l:lineNum, 1 )
el
- norm! gg
ec 'outside any header'
- return ''
+ "norm! gg
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^#+' )
+ retu l:lineNum
endf
"goes to next header of any level
-"returns its hashes
+"
+"if no there are no more headers print a warning
fu! b:Markdown_GoNextHeader()
- if search( '\v^#', 'W' ) != 0
- return matchstr( getline('.'), '\v^#+' )
- el
+ if search( s:headerExpr, 'W' ) == 0
"norm! G
- ec 'no more headers'
- return ''
+ ec 'no next header'
en
endf
"goes to previous header of any level
"
-"if there is no previous header, only print a warning
-"
-"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.
+"if it does not exist, print a warning
fu! b:Markdown_GoPreviousHeader()
- if search( '^#', 'bW' ) != 0
- return matchstr( getline('.'), '\v^#+' )
- el
+ let l:oldPos = getpos('.')
+ let l:curHeaderLineNumber = b:Markdown_GoCurHeader()
+ if l:curHeaderLineNumber == 0
+ cal setpos('.',l:oldPos)
+ en
+ if search( s:headerExpr, 'bW' ) == 0
"norm! gg
- ec 'no more headers'
- return ''
+ cal setpos('.',l:oldPos)
+ ec 'no previous header'
en
endf
-"if already at top level, go to beginning of buffer
+"goes to previous header of any level
+"
+"if it exists, return its lines number
+"
+"otherwise, print a warning and return 0
fu! b:Markdown_GoHeaderUp()
- let l:hashes = b:Markdown_GoCurHeader()
+ let l:oldPos = getpos('.')
+ let l:hashes = b:Markdown_GoCurHeaderGetHashes()
if len( l:hashes ) > 1
cal search( '^' . l:hashes[1:] . '[^#]', 'b' )
el
- norm! gg
+ cal setpos('.',l:oldPos)
+ ec 'already at top level'
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()
+ 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
+ let l:noSibling = 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: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
+ \ )
\ )
- \ )
- cal cursor( l:nextSameLevelLine, 0 )
- el
- ec 'no more siblings'
+ cal cursor( l:nextSameLevelLine, 1 )
+ el
+ let l:noSibling = 1
+ en
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' )
-
+ if l:noSibling
+ cal setpos('.',l:oldPos)
+ ec 'no next sibling'
+ en
endf
"if no more next siblings, print error message and do nothing.
fu! b:Markdown_GoPreviousSiblingHeader()
-
- let l:hashes = b:Markdown_GoCurHeader()
+ 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
+ let l:noSibling = 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
+ 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'
+ cal cursor( l:prevSameLevelLine, 1 )
+ el
+ let l:noSibling = 1
+ en
+ en
+
+ if l:noSibling
+ cal setpos('.',l:oldPos)
+ ec 'no previous sibling'
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>
+"wrapper to do move commands in visual mode
+fu! s:VisMove(f)
+ norm! gv
+ cal function(a:f)()
+endf
-nn <buffer><silent> [[ :cal b:Markdown_GoPreviousHeader()<cr>
-"vnoremap <buffer><silent> [[ ?^#<cr><esc>:nohl<cr>gv
+"map in both normal and visual modes
+fu! s:MapNormVis(rhs,lhs)
+ exe 'nn <buffer><silent> ' . a:rhs . ' :cal ' . a:lhs . '()<cr>'
+ exe 'vn <buffer><silent> ' . a:rhs . ' <esc>:cal <sid>VisMove(''' . a:lhs . ''')<cr>'
+endf
-"go up one level. Menmonic: Up.
-nn <buffer><silent> ]u :cal b:Markdown_GoHeaderUp()<cr>
+cal <sid>MapNormVis( ']]', 'b:Markdown_GoNextHeader' )
+cal <sid>MapNormVis( '[[', 'b:Markdown_GoPreviousHeader' )
+cal <sid>MapNormVis( '][', 'b:Markdown_GoNextSiblingHeader' )
+cal <sid>MapNormVis( '[]', 'b:Markdown_GoPreviousSiblingHeader' )
+"menmonic: Up
+cal <sid>MapNormVis( ']u', 'b:Markdown_GoHeaderUp' )
+"menmonic: Current
+cal <sid>MapNormVis( ']c', 'b:Markdown_GoCurHeader' )