【问题标题】:Vim Markdown Folding?Vim Markdown 折叠?
【发布时间】:2010-09-30 07:23:14
【问题描述】:

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

任何人都可以提供有关如何使其工作的建议吗?


另外,我使用 Markdown 只是作为获取简单结构化文本的一种方式。如果有更好的替代格式,也请提出建议。但不确定我喜欢 TVO 还是 VimOutliner。

【问题讨论】:

标签: vim markdown


【解决方案1】:

当我使用 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     

【讨论】:

  • 您可以将 MarkdownLevel 函数简化为 function MarkdownLevel() let h = matchstr(getline(v:lnum), '^#\+') if empty(h) return "=" else return ">" . len(h) endif endfunction,我将其贴在一行中,因为这是一条评论。
  • op 解决方案对我有用,但 cmets 中的短路解决方案对我不起作用。
【解决方案2】:
let g:markdown_folding = 1

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

由于某种原因,它没有记录在自述文件中,而是you can find the related code in the repository

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

set nofoldenable

更新

不幸的是,我停止使用 markdown_folding,因为它会使事情变慢 (Github issue)。

【讨论】:

  • 我不知道为什么它没有得到更多的支持 - 它对我来说非常有效。
【解决方案3】:

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

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

【讨论】:

  • 我最终改用 Viki。这不是 Markdown,但可以正确折叠。
  • 我认为 Rst 的好处在于它可以用于许多其他用途,例如 Jekyll wiki、HTML、LaTex..
  • 不再需要变通方法。请参阅下面关于内置 vimrc 标志的 Sanghyun 的回答。
【解决方案4】:

这是一个递归标题折叠规则的尝试。它不包括 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

【讨论】:

    【解决方案5】:

    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
    

    【讨论】:

    • 我发现这些正则表达式还捕获了我以 # 开头的缩进代码块(表示 shell 命令行)。取出 start 和 end 中的 \s* 进行修复。
    【解决方案6】:

    GitHub上有一个应用插件。

    vim-markdown-folding

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

    vim-markdown

    【讨论】:

      【解决方案7】:

      我在 Markdown 中折叠工作的唯一方法不是很优雅,:set fdm=marker 并使用 html 注释标签

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

      更多帮助:help folding

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          根据 Jeromy & 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
          

          【讨论】:

          • 我不知道代码语法是如何工作的,但是你能用return "&gt;" . 7 - j这样的东西吗?
          • @Brady Trainor,我尝试了类似let k = 7 - len(j),然后是return "&gt;".k,但由于某种原因我无法让它工作,现在我实际上更喜欢我的更长的解决方案,因为它只会触发j 的值在 3 到 6 之间,这就是我想要的。
          • 感谢let 的技巧,我只是用它来解决类似的问题。
          【解决方案10】:

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

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

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

          【讨论】:

          • 我无法使用该插件折叠降价文件本身,但大纲还是不错的 :)
          【解决方案11】:

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

          let g:markdown_folding=1
          

          为了确保你已经加载了这个插件,你可以运行

          :showscripts
          

          然后寻找

          vim80/syntax/markdown.vim
          

          【讨论】:

          • 我不确定:showscripts 是否适用于其他任何人,但我必须使用:scriptnames 来列出加载的插件。
          【解决方案12】:

          @Omar 注释到this answer,我为使用// 注释的语言编写了折叠方法,例如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 的初学者。

          【讨论】:

            【解决方案13】:

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

            " ~/.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
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-07-01
              • 2011-10-09
              • 2013-01-16
              • 1970-01-01
              • 2012-06-13
              • 2011-04-09
              • 1970-01-01
              • 2013-02-11
              相关资源
              最近更新 更多