Vim Markdown折叠?

时间:2010-09-30 07:23:15

标签: vim markdown

我刚刚意识到VIM 7.3内置支持突出显示Markdown文件。优秀。但是,它不会在标题上折叠。

可以提供有关如何使其正常工作的建议吗?


或者,我只使用Markdown作为获取简单结构化文本的方法。如果有更好的替代格式,请同时建议。但我不确定是否会挖掘TVO或VimOutliner。

13 个答案:

答案 0 :(得分:28)

当我使用markdown时,我只使用带有空格分隔哈希和文本的哈希样式标题。 这使得折叠任务变得更加简单。

我对Vim很新,所以请自行承担以下风险。 我将以下代码添加到我的vimrc中,它根据哈希数量折叠标题,并保留语法着色。

function! MarkdownLevel()
    if getline(v:lnum) =~ '^# .*$'
        return ">1"
    endif
    if getline(v:lnum) =~ '^## .*$'
        return ">2"
    endif
    if getline(v:lnum) =~ '^### .*$'
        return ">3"
    endif
    if getline(v:lnum) =~ '^#### .*$'
        return ">4"
    endif
    if getline(v:lnum) =~ '^##### .*$'
        return ">5"
    endif
    if getline(v:lnum) =~ '^###### .*$'
        return ">6"
    endif
    return "=" 
endfunction
au BufEnter *.md setlocal foldexpr=MarkdownLevel()  
au BufEnter *.md setlocal foldmethod=expr     

答案 1 :(得分:7)

我有同样的问题,并且玩弄了Jander的好解决方案。唯一的问题是,通过使用语法定义折叠,您将丢失任何Markdown语法突出显示。

鉴于您可能对备用标记感兴趣,我建议使用reStructuredText和神奇 Vst vim extension。它折叠得非常好。 Rst比Markdown强大得多。

答案 2 :(得分:6)

https://github.com/plasticboy/vim-markdown有一个vim-markdown插件。

与折叠相关的代码似乎是:

" fold region for headings
syn region mkdHeaderFold
    \ start="^\s*\z(#\+\)"
    \ skip="^\s*\z1#\+"
    \ end="^\(\s*#\)\@="
    \ fold contains=TOP

" fold region for lists
syn region mkdListFold
    \ start="^\z(\s*\)\*\z(\s*\)"
    \ skip="^\z1 \z2\s*[^#]"
    \ end="^\(.\)\@="
    \ fold contains=TOP

syn sync fromstart
setlocal foldmethod=syntax

答案 3 :(得分:5)

这是对递归标题折叠规则的尝试。它不包括Markdown标题的下划线样式,但我猜这些对你的目的来说都很尴尬。

将以下代码放入.vimrc:

au FileType markdown syn region myMkdHeaderFold
        \ start="\v^\s*\z(\#{1,6})"
        \ skip="\v(\n\s*\z1\#)\@="
        \ end="\v\n(\s*\#)\@="ms=s-1,me=s-1
        \ fold contains=myMkdHeaderFold

au FileType markdown syn sync fromstart
au FileType markdown set foldmethod=syntax

答案 4 :(得分:4)

在GitHub上有一个app 插件。

vim-markdown-folding

使用Vim编辑Markdown文件时,您可能还想安装Tim Pope的Markdown插件。

vim-markdown

答案 5 :(得分:3)

折叠在markdown中工作的唯一方法是非常优雅,:set fdm=marker并使用html评论标记

 <!-- My folding {{{1 -->

更多帮助:help folding

答案 6 :(得分:3)

let g:markdown_folding = 1

如果您使用的是最新版本的Vim,可以在.vimrc中添加此功能来启用降价折叠功能 - 不需要是最新版本,但我不知道具体版本。

由于某些原因,自述文件中没有记录,you can find the related code in the repository

仅供参考,如果您不想在打开文件时关闭这些部分,refer to this SO thread。我认为添加这个是最好的方法,但你可能有不同的偏好。

set nofoldenable

答案 7 :(得分:2)

我猜你不看VimCasts。制造这个的人只是为此做了一个pugin。这是:https://github.com/nelstrom/vim-markdown-folding

答案 8 :(得分:2)

基于Jeromy&amp; Omar的建议,我想出了这个(对于我的vimrc)来自动和明确地折叠我的DokuWiki文件(其中顶级标题在开头的行标记为======,标记为==的第四级标题=):

function! DWTitleLevel()
    let j = len(matchstr(getline(v:lnum), '^=\+'))
    if     j =~ 6 | return ">1"
    elseif j =~ 5 | return ">2"
    elseif j =~ 4 | return ">3"
    elseif j =~ 3 | return ">4"
    endif
endfunction

'^ = +'表示从行的开头匹配任意数量的连续'='s

然后在vim模式行中,它可以很好地用于DokuWiki文件:

foldmethod=expr foldexpr=DWTitleLevel() foldcolumn=5

对于Markdown,我需要像这样编写Omar的代码:

if empty(j) | return "=" | else | return ">".len(j) | endif

答案 9 :(得分:1)

VOoM : Vim two-pane outliner 值得一试。

它不仅提供基本折叠,还通过第二个大纲视图窗格提供轮廓导航(类似于MS Word中的文档地图)。它支持大量标记语言,包括其他答案中提到的其他语言--Markdown,viki,reStructuredText,vimwiki,org等等。

有关详细信息,请参阅screenshotshelp page

答案 10 :(得分:1)

从Vim 8开始,它默认包含在内(通过Tim Pope的降价插件)。只需将其添加到.vimrc:

let g:markdown_folding=1

要确保已加载此插件,您可以运行

:showscripts

并寻找

vim80/syntax/markdown.vim

答案 11 :(得分:0)

@Omar注释到this answer,我将fold方法编码为使用//注释的语言,例如JS。将以下内容添加到〜/。 vimrc

autocmd FileType javascript setlocal foldmethod=expr foldcolumn=6 
autocmd FileType javascript setlocal foldexpr=JSFolds()

" Level of a folding:
    "// #: level 1
    "// ##: level 2
    "// ###: level 3
function! JSFolds()
    " Option 1: // and no space and hashes:
        "if getline(v:lnum) =~ '^//#'
    " Option 2: // and 1 space and hashes:
        "if getline(v:lnum) =~ '^//\+ #'
    " Option 3: spaces/tabs/nothing  and // and 1 space and hashes:
    if getline(v:lnum) =~ '^\s*//\+ #'
    " Option 4: anything and // and 1 space and hashes:
    " DANEGROUS! Potential conflict with code. E.g. print("// # Title");
    " if getline(v:lnum) =~ '//\+ #'

        " Number of hashs # in line that success previous condition (if)
        " determine the fold level
       let repeatHash = len(matchstr(getline(v:lnum), '#\+'))
       return ">" . repeatHash
    endif
    return "=" 
endfunction

示例。注意左侧的折叠级别(“ |”和“-”):

-     // # ** Fold style recommended **
-     // #       1  easy case
|-    // ##      2  easy case
||-   // ###     3  easy case
|||   //            Comment inside level 3
|||-  // ####    4  easy case
||||  //            Comment inside level 4
|-        // ##  2  easy case (indents are OK with Option 3)
||    /####     error (JS comment needs 2 slashes)
||  
-     // # ** Fold of just 1 line **
|--   // ###    3  easy case
||-   // ###    =  same fold level as previous line, thus previous line folds just itself ?!? (not concerns this fold function) 
|||   
-     // # ** Space needed before, BUT not needed after hash/-es **
|-    // ##Fold Level   changed Because no space after hashes is OK:    '// # ' vs '// #NoSpace'. NoSpace could even be a return carriage (enter). 
||    //## Fold Level Unchanged Because no space after pair of slashes: '// #' vs '//#'
||    //     ##txt    Unchanged Because too much space after slashes
||    //     ## txt   Unchanged Because too much space after slashes
||    
-     // # ** Odds vs Even slashes **
-     /// #     1  overrides typo 3 slash instead of just 2 (/// vs //)
-     ///// #   1  overrides typo 5 slash instead of just 4 (///// vs ////). Read Recommenting Comments notes.
|-    // ## ** As long as the pattern is at least '// # ', further previous slashes are ok  **
-     // #            1  easy case
|--   // ###          3  ok (and recommended fold style)
||-   ///// ###       3  ok (recommented + typo)
||-   ////// ###      3  ok (re-recommented)
||-   /// ###         3  ok (typo)
||-   //// ###        3  ok (recommented)
||-   ///////// ###   3  ok (who cares? it works!)
|||   
-     // # ** Recommenting Comments **
-     // #      1  easy case
|     //           Comment inside level 1
-     //// #    1  recommented a comment
|     ////         Comment inside level 1
-     ///// #   1  re-re-recomment
|     /////        Comment inside level 1
|     
-     // # ** Recommenting Comments adding text **
|--   // ### //// #    3  changing fold level on purpose of a recommented a comment
|||   //               Comment inside level 3
|||   // text  // ##         2  (recommented a comment adding text)
|||   // text#text  // ##    2  right   {recommented a comment adding initial text, as long as this text has no hash just after '// ' (2*slash + space) would be ok }
-     // #text#text  // ##   2  wrongly {recommented a comment adding initial text, as long as this text has no hash just after '// ' (2*slash + space) would be ok }
-     // # changeFoldIntentionally // ##     1  clear intention to change fold level of comments
-     // #changeFoldIntentionally // ##      1  clear intention to change fold level of comments (previousi example, with space after hash would be clearer)
|--   // ### changeFoldIntentionally // ##   3  clear intention to change fold level of comments
|||   

PD:完全向批评家开放和改进代码。其实我是vimscript的初学者。

答案 12 :(得分:0)

这是我在这里结合许多其他答案得出的结论。我发现它们中的大多数,包括内置的 g:markdown_folding,不能正确处理包含 # 字符作为注释一部分的代码块。我基于匹配语法 ID,它也可以正确处理 <h1-6> 标签。

" ~/.vim/ftplugin/markdown.vim

function MarkdownLevel(lnum)
  for synID in synstack(a:lnum, 1)
    let name = synIDattr(synID, "name")
    if     name == 'htmlH1' | return ">1"
    elseif name == 'htmlH2' | return ">2"
    elseif name == 'htmlH3' | return ">3"
    elseif name == 'htmlH4' | return ">4"
    elseif name == 'htmlH5' | return ">5"
    elseif name == 'htmlH6' | return ">6"
    endif
  endfor
  return "="
endfunction

setlocal foldexpr=MarkdownLevel(v:lnum)
setlocal foldmethod=expr
setlocal foldlevel=1