]> git.madduck.net Git - etc/vim.git/blob - 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
1 "TODO print messages when on visual mode. I only see VISUAL, not the messages.
2
3 " This is how you should view things:
4 "
5 "   |BUFFER
6 "   |
7 "   |Outside any header
8 "   |
9 " a-+# a
10 "   |
11 "   |Inside a
12 "   |
13 " a-+
14 " b-+## b
15 "   |
16 "   |inside b
17 "   |
18 " b-+
19 " c-+### c
20 "   |
21 "   |Inside c
22 "   |
23 " c-+
24 " d-|# d
25 "   |
26 "   |Inside d
27 "   |
28 " d-+
29
30 let s:headerExpr = '\v^(\s*#|.+\n(\=+|-+)$)'
31
32 " Return 0 if not found, else the actual line number.
33 "
34 function! b:Markdown_GetLineNumCurHeader()
35     echo s:headerExpr
36     return search(s:headerExpr, 'bcnW')
37 endfunction
38
39 " - if inside a header goes to it.
40 "    Return its line number.
41 "
42 " - if on top level outside any headers,
43 "    print a warning
44 "    Return `0`.
45 "
46 function! b:Markdown_GoCurHeader()
47     let l:lineNum = b:Markdown_GetLineNumCurHeader()
48     if l:lineNum != 0
49         call cursor(l:lineNum, 1)
50     else
51         echo 'error: outside any header'
52         "normal! gg
53     end
54     return l:lineNum
55 endfunction
56
57 " Put cursor on next header of any level.
58 "
59 " If there are no more headers, print a warning.
60 "
61 function! b:Markdown_GoNextHeader()
62     if search(s:headerExpr, 'W') == 0
63         "normal! G
64         echo 'error: no next header'
65     end
66 endfunction
67
68 " Put cursor on previous header (before current) of any level.
69 "
70 " If it does not exist, print a warning.
71 "
72 function! b:Markdown_GoPreviousHeader()
73     let l:oldPos = getpos('.')
74     let l:curHeaderLineNumber = b:Markdown_GoCurHeader()
75     if l:curHeaderLineNumber == 0
76         call setpos('.', l:oldPos)
77     end
78     if search(s:headerExpr, 'bW') == 0
79         "normal! gg
80         call setpos('.', l:oldPos)
81         echo 'error: no previous header'
82     end
83 endfunction
84
85 "- if inside a header, cursor goes to it.
86 "   Return its hashes.
87 "
88 "- if on top level outside any headers,
89 "   print a warning
90 "   return ''
91 "
92 function! b:Markdown_GoCurHeaderGetHashes()
93     let l:linenum = b:Markdown_GetLineNumCurHeader()
94     if l:linenum != 0
95         call cursor(l:linenum, 1)
96         return matchlist(getline(linenum), '\v^\s*(#+)')[1]
97     else
98         return ''
99     end
100 endfunction
101
102 " Put cursor on previous header of any level.
103 "
104 " If it exists, return its lines number.
105 "
106 " Otherwise, print a warning and return `0`.
107 "
108 function! b:Markdown_GoHeaderUp()
109     let l:oldPos = getpos('.')
110     let l:hashes = b:Markdown_GoCurHeaderGetHashes()
111     if len(l:hashes) > 1
112         call search('^\s*' . l:hashes[1:] . '[^#]', 'b')
113     else
114         call setpos('.', l:oldPos)
115         echo 'error: already at top level'
116     end
117 endfunction
118
119 " If no more next siblings, print error message and do nothing.
120 "
121 function! b:Markdown_GoNextSiblingHeader()
122     let l:oldPos = getpos('.')
123     let l:hashes = b:Markdown_GoCurHeaderGetHashes()
124     let l:noSibling = 0
125     if l:hashes ==# ''
126         let l:noSibling = 1
127     else
128         let l:nhashes = len(l:hashes)
129         if l:nhashes == 1
130             "special case, just add the largest possible value
131             let l:nextLowerLevelLine = line('$') + 1
132         else
133             let l:nextLowerLevelLine = search('\v^\s*#{1,' . (l:nhashes - 1) . '}[^#]' , 'nW')
134         end
135         let l:nextSameLevelLine = search('\v^\s*' . l:hashes . '[^#]', 'nW')
136         if (
137                 \ l:nextSameLevelLine > 0
138                 \ &&
139                 \ (
140                 \   l:nextLowerLevelLine == 0
141                 \   ||
142                 \   l:nextLowerLevelLine > l:nextSameLevelLine
143                 \ )
144             \ )
145             call cursor(l:nextSameLevelLine, 1)
146         else
147             let l:noSibling = 1
148         end
149     end
150     if l:noSibling
151         call setpos('.', l:oldPos)
152         echo 'error: no next sibling'
153     end
154 endfunction
155
156 "if no more next siblings, print error message and do nothing.
157 function! b:Markdown_GoPreviousSiblingHeader()
158     let l:oldPos = getpos('.')
159     let l:hashes = b:Markdown_GoCurHeaderGetHashes()
160     let l:noSibling = 0
161     if l:hashes ==# ''
162         let l:noSibling = 1
163     else
164         let l:nhashes = len(l:hashes)
165         if l:nhashes == 1
166             "special case, just add the largest possible value
167             let l:prevLowerLevelLine = -1
168         else
169             let l:prevLowerLevelLine = search('\v^\s*#{1,' . (l:nhashes - 1) . '}[^#]' , 'bnW')
170         end
171         let l:prevSameLevelLine = search('\v^\s*' . l:hashes . '[^#]', 'bnW')
172         if (
173                 \ l:prevSameLevelLine > 0
174                 \ &&
175                 \ (
176                 \   l:prevLowerLevelLine == 0
177                 \   ||
178                 \   l:prevLowerLevelLine < l:prevSameLevelLine
179                 \ )
180             \)
181             call cursor(l:prevSameLevelLine, 1)
182         else
183             let l:noSibling = 1
184         end
185     end
186     if l:noSibling
187         call setpos('.', l:oldPos)
188         echo 'error: no previous sibling'
189     end
190 endfunction
191
192 "wrapper to do move commands in visual mode
193 function! s:VisMove(f)
194     norm! gv
195     call function(a:f)()
196 endfunction
197
198 "map in both normal and visual modes
199 function! s:MapNormVis(rhs,lhs)
200     execute 'nn <buffer><silent> ' . a:rhs . ' :call ' . a:lhs . '()<cr>'
201     execute 'vn <buffer><silent> ' . a:rhs . ' <esc>:call <sid>VisMove(''' . a:lhs . ''')<cr>'
202 endfunction
203
204 call <sid>MapNormVis(']]', 'b:Markdown_GoNextHeader')
205 call <sid>MapNormVis('[[', 'b:Markdown_GoPreviousHeader')
206 call <sid>MapNormVis('][', 'b:Markdown_GoNextSiblingHeader')
207 call <sid>MapNormVis('[]', 'b:Markdown_GoPreviousSiblingHeader')
208 "menmonic: Up
209 call <sid>MapNormVis(']u', 'b:Markdown_GoHeaderUp')
210 "menmonic: Current
211 call <sid>MapNormVis(']c', 'b:Markdown_GoCurHeader')