lists.vim 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. " vim: set fdm=marker et ts=4 sw=4 sts=4:
  2. " functions for list navigation
  3. "
  4. function! markdown#lists#ListItemStart(...) abort "{{{1
  5. if a:0 > 0
  6. let line = getline(a:1)
  7. else
  8. let line = getline('.')
  9. endif
  10. if
  11. \ line =~# '^>\=\s*[*+-]\s\+-\@!' ||
  12. \ line =~# '^\s*\(\((*\d\+[.)]\+\)\|\((*\l[.)]\+\)\)\s\+' ||
  13. \ line =~# '^\s*(*\u[.)]\+\s\{2,}' ||
  14. \ line =~# '^\s*(*[#][.)]\+\s\{1,}' ||
  15. \ line =~# '^\s*(*@.\{-}[.)]\+\s\{1,}' ||
  16. \ line =~# '^\s*(*x\=l\=\(i\{,3}[vx]\=\)\{,3}c\{,3}[.)]\+'
  17. return 1
  18. endif
  19. return 0
  20. endfunction
  21. function! markdown#lists#ListStart(...) abort "{{{1
  22. if a:0 > 0
  23. let l:l = a:1
  24. else
  25. let l:l = line('.')
  26. endif
  27. let orig_pos = getpos('.')[1:]
  28. call cursor(l:l, 0)
  29. normal! {
  30. if getpos('.')[1:] == orig_pos && markdown#lists#ListItemStart() != 1
  31. return -1
  32. endif
  33. normal! w
  34. let pos = markdown#lists#ListItemStart()
  35. if pos == 1
  36. let c_par_start = line('.')
  37. normal! 2{w
  38. let p_par_start = line('.')
  39. if c_par_start != p_par_start
  40. let check_prev = markdown#lists#ListItemStart()
  41. if check_prev == 1
  42. let l:l = markdown#lists#ListStart()
  43. else
  44. normal! }w
  45. let l:l = line('.')
  46. endif
  47. else
  48. let l:l = c_par_start
  49. endif
  50. else
  51. let l:l = -1
  52. endif
  53. call cursor(orig_pos)
  54. return l:l
  55. endfunction
  56. function! markdown#lists#ListEnd(...) abort "{{{1
  57. if markdown#lists#ListStart() == -1
  58. " not in a list
  59. return -1
  60. endif
  61. if a:0 > 0
  62. let l:l = a:1
  63. else
  64. let l:l = line('.')
  65. endif
  66. let orig_pos = getpos('.')[1:]
  67. call cursor(l:l,0)
  68. if getline(l:l) =~# '^\s*$' && markdown#lists#ListItemStart(l:l+1) == 0
  69. " the list just ended
  70. return l:l-1
  71. endif
  72. normal! }
  73. let c_lnum = line('.')
  74. let c_par_end = c_lnum-1
  75. let next_par_start = c_lnum+1
  76. let pos = markdown#lists#ListItemStart(next_par_start)
  77. if pos == 1
  78. let l:l = markdown#lists#ListEnd(next_par_start)
  79. elseif c_lnum == line('$')
  80. let l:l = c_lnum
  81. else
  82. let l:l = c_par_end
  83. endif
  84. call cursor(orig_pos)
  85. return l:l
  86. endfunction
  87. function! markdown#lists#ListKind(...) abort "{{{1
  88. if a:0 > 0
  89. let line = getline(a:1)
  90. else
  91. let line = getline('.')
  92. endif
  93. if line =~# '^>\=\s*[*+-]\s\+-\@!'
  94. return 'ul'
  95. else
  96. return 'ol'
  97. endif
  98. endfunction
  99. function! markdown#lists#NextListItem(...) abort "{{{1
  100. if a:0 > 0
  101. let search_from = a:1
  102. else
  103. let search_from = line('.')
  104. endif
  105. let lnum = search_from + 1
  106. if markdown#lists#ListStart(search_from) > -1
  107. while lnum <= line('$')
  108. if markdown#lists#ListStart(lnum+1) == -1
  109. return markdown#lists#CurrentListItem(lnum)
  110. endif
  111. if markdown#lists#ListItemStart(lnum) == 1
  112. return lnum
  113. else
  114. let lnum = lnum + 1
  115. continue
  116. endif
  117. endwhile
  118. endif
  119. return -1
  120. endfunction
  121. function! markdown#lists#PrevListItem(...) abort "{{{1
  122. if a:0 > 0
  123. let search_from = a:1
  124. else
  125. let search_from = line('.')
  126. endif
  127. let lnum = search_from - 1
  128. while lnum >= 1
  129. if markdown#lists#ListStart(lnum) == -1
  130. return -1
  131. endif
  132. if markdown#lists#ListItemStart(lnum) == 1
  133. return lnum
  134. else
  135. let lnum = lnum - 1
  136. continue
  137. endif
  138. endwhile
  139. return -1
  140. endfunction
  141. function! markdown#lists#CurrentListItem(...) abort "{{{1
  142. if a:0 > 0
  143. let search_from = a:1
  144. else
  145. let search_from = line('.')
  146. endif
  147. if markdown#lists#ListItemStart(search_from) == 1
  148. return search_from
  149. else
  150. return markdown#lists#PrevListItem(search_from)
  151. endif
  152. endfunction
  153. function! markdown#lists#ListItemLevel(line) abort "{{{1
  154. return len(matchstr(a:line, '^\s\+'))/4+1
  155. endfunction
  156. function! markdown#lists#CurrentListItemParent(...) abort "{{{1
  157. if a:0 > 0
  158. let search_from = a:1
  159. else
  160. let search_from = line('.')
  161. endif
  162. let c_listitem = markdown#lists#CurrentListItem(search_from)
  163. if c_listitem != -1
  164. let c_listitem_text = getline(c_listitem)
  165. let level = markdown#lists#ListItemLevel(c_listitem_text)
  166. let lnum = c_listitem
  167. while lnum >= 1
  168. let p_listitem = markdown#lists#PrevListItem(lnum)
  169. let p_level = markdown#lists#ListItemLevel(p_listitem)
  170. if p_level < level
  171. return p_listitem
  172. else
  173. let lnum = p_listitem
  174. continue
  175. endif
  176. endwhile
  177. endif
  178. return -1
  179. endfunction
  180. function! markdown#lists#ListItemSibling(direction, ...) abort "{{{1
  181. if a:0 > 0
  182. let search_from = a:1
  183. else
  184. let search_from = line('.')
  185. endif
  186. let c_listitem_lnum = markdown#lists#CurrentListItem(search_from)
  187. let c_listitem_level = markdown#lists#ListItemLevel(getline(c_listitem_lnum))
  188. let parent_lnum = markdown#lists#CurrentListItemParent(c_listitem_lnum)
  189. if a:direction ==# 'b'
  190. let while_cond = 'lnum >= 1'
  191. else
  192. let while_cond = 'lnum <= line("$")'
  193. endif
  194. let lnum = c_listitem_lnum
  195. while eval(while_cond)
  196. if a:direction ==# 'b'
  197. let listitem_lnum = markdown#lists#PrevListItem(lnum)
  198. else
  199. let listitem_lnum = markdown#lists#NextListItem(lnum)
  200. endif
  201. let listitem_level = markdown#lists#ListItemLevel(getline(listitem_lnum))
  202. if listitem_level == c_listitem_level
  203. return listitem_lnum
  204. else
  205. if listitem_level > c_listitem_level
  206. let lnum = listitem_lnum
  207. else
  208. return -1
  209. endif
  210. endif
  211. endwhile
  212. endfunction
  213. function! markdown#lists#NextListItemSibling(...) abort "{{{1
  214. if a:0 > 0
  215. let search_from = a:1
  216. else
  217. let search_from = line('.')
  218. endif
  219. return markdown#lists#ListItemSibling('', search_from)
  220. endfunction
  221. function! markdown#lists#PrevListItemSibling(...) abort "{{{1
  222. if a:0 > 0
  223. let search_from = a:1
  224. else
  225. let search_from = line('.')
  226. endif
  227. return markdown#lists#ListItemSibling('b', search_from)
  228. endfunction
  229. function! markdown#lists#FirstChild(...) abort "{{{1
  230. if a:0 > 0
  231. let search_from = a:1
  232. else
  233. let search_from = line('.')
  234. endif
  235. let c_listitem_level = markdown#lists#ListItemLevel(getline(markdown#lists#CurrentListItem()))
  236. let n_litem_lnum = markdown#lists#NextListItem()
  237. let n_litem_text = getline(n_litem_lnum)
  238. let n_litem_level = markdown#lists#ListItemLevel(n_litem_text)
  239. if n_litem_level > c_listitem_level
  240. return n_litem_lnum
  241. else
  242. return -1
  243. endif
  244. endfunction
  245. function! markdown#lists#LastChild(...) abort "{{{1
  246. if a:0 > 0
  247. let search_from = a:1
  248. else
  249. let search_from = line('.')
  250. endif
  251. let first_child = markdown#lists#FirstChild(search_from)
  252. if first_child != -1
  253. let n_litem_lnum = markdown#lists#NextListItemSibling(first_child)
  254. let n_litem_parent_lnum = markdown#lists#CurrentListItemParent(n_litem_lnum)
  255. while 1
  256. let n_n_litem_lnum = markdown#lists#NextListItemSibling(n_litem_lnum)
  257. if n_n_litem_lnum == -1
  258. return n_litem_lnum
  259. else
  260. let n_litem_lnum = n_n_litem_lnum
  261. endif
  262. endwhile
  263. else
  264. return -1
  265. endif
  266. return -1
  267. endfunction
  268. function! markdown#lists#NthChild(count, ...) abort "{{{1
  269. if a:0 > 0
  270. let search_from = a:1
  271. else
  272. let search_from = line('.')
  273. endif
  274. let item_lnum = markdown#lists#FirstChild(search_from)
  275. if item_lnum != -1
  276. if a:count == 1
  277. return item_lnum
  278. else
  279. for idx in range(a:count-1)
  280. let item_lnum = markdown#lists#NextListItemSibling(item_lnum)
  281. endfor
  282. endif
  283. return item_lnum
  284. endif
  285. endfunction