anuvyklack/pretty-fold.nvim

github github
editing-support
stars 420
issues 10
subscribers 3
forks 19
CREATED

2021-12-21

UPDATED

2 years ago


Pretty Fold

:warning: WARNING: Neovim v0.7 or higher is required

There is a 0.6 branch which is lack of some features.

Pretty Fold is a lua plugin for Neovim which provides framework for easy foldtext customization. Filetype specific and foldmethod specific configuration is supported.

https://user-images.githubusercontent.com/13056013/148261501-56677c8f-24a7-4c45-b008-8c1863bf06e8.mp4

Installation and quickstart

Installation and setup example with packer:

use{ 'anuvyklack/pretty-fold.nvim',
   config = function()
      require('pretty-fold').setup()
   end
}

Foldtext configuration

The plugin comes with the following defaults (the description of each option is below):

config = {
   sections = {
      left = {
         'content',
      },
      right = {
         ' ', 'number_of_folded_lines', ': ', 'percentage', ' ',
         function(config) return config.fill_char:rep(3) end
      }
   },
   fill_char = '•',

   remove_fold_markers = true,

   -- Keep the indentation of the content of the fold string.
   keep_indentation = true,

   -- Possible values:
   -- "delete" : Delete all comment signs from the fold string.
   -- "spaces" : Replace all comment signs with equal number of spaces.
   -- false    : Do nothing with comment signs.
   process_comment_signs = 'spaces',

   -- Comment signs additional to the value of `&commentstring` option.
   comment_signs = {},

   -- List of patterns that will be removed from content foldtext section.
   stop_words = {
      '@brief%s*', -- (for C++) Remove '@brief' and all spaces after.
   },

   add_close_pattern = true, -- true, 'last_line' or false

   matchup_patterns = {
      {  '{', '}' },
      { '%(', ')' }, -- % to escape lua pattern char
      { '%[', ']' }, -- % to escape lua pattern char
   },

   ft_ignore = { 'neorg' },
}

sections

The main part. Contains two tables: config.sections.left and config.sections.right which content will be left and right aligned respectively. Each of them can contain names of the components and functions that returns string.

Built-in components

The strings from the table below will be expanded according to the table.

Item Expansion
'content' The content of the first non-blank line of the folded region, somehow modified according to other options.
'number_of_folded_lines' The number of folded lines.
'percentage' The percentage of the folded lines out of the whole buffer.

Custom functions

All functions accept config table as an argument, so if you would like to pass any arguments into your custom function, place them into the config table which you pass to setup function and then you can access them inside your function, like this:

require('pretty-fold').setup {
   custom_function_arg = 'Hello from inside custom function!',
   sections = {
      left = {
         function(config)
            return config.custom_function_arg
         end
      },
   }
}

image

fill_char

default: '•'

Character used to fill the space between the left and right sections.

remove_fold_markers

default: true

Remove foldmarkers from the content component.

keep_indentation

default: true

Keep the indentation of the content of the fold string.

process_comment_signs

What to do with comment signs: default: spaces

Option Description
'delete' delete all comment signs from the foldstring
'spaces' replace all comment signs with equal number of spaces
false do nothing with comment signs

comment_signs

default: {}

Table with comment signs additional to the value of &commentstring option. Add additional comment signs only when you really need them. Otherwise, they give computational overhead without any benefits.

Example for Lua. Default &commentstring value for Lua is: '--'.

comment_signs = {
    { '--[[', '--]]' }, -- multiline comment
}

Example for C++. Default &commentstring value for C++ is: { '/*', '*/' }

comment_signs = { '//' }

stop_words

default: '@brief%s*' (for C++) Remove '@brief' and all spaces after.

Lua patterns that will be removed from the content section.

add_close_pattern

default: true

If this option is set to true for all opening patterns that will be found in the first non-blank line of the folded region, all corresponding closing elements will be added after ellipsis. (The synthetical string with matching closing elements will be constructed).

If it is set to last_line, the last line content (without comments) will be added after the ellipsis . This behavior was the first algorithm I implemented, but turns out it is not always relevant. For some languages (at least for all lisps) this does not work. Since it is already written and if someone like this behavior, I keep this option to choose.

matchup_patterns

The list with matching elements. Each item is a list itself with two items: opening lua pattern and close string which will be added if oppening pattern is found.

Examples for lua (Lua patterns are explained with railroad diagrams):

matchup_patterns = {
   -- ╟─ Start of line ──╭───────╮── "do" ── End of line ─╢
   --                    ╰─ WSP ─╯
   { '^%s*do$', 'end' }, -- `do ... end` blocks

   -- ╟─ Start of line ──╭───────╮── "if" ─╢
   --                    ╰─ WSP ─╯
   { '^%s*if', 'end' },

   -- ╟─ Start of line ──╭───────╮── "for" ─╢
   --                    ╰─ WSP ─╯
   { '^%s*for', 'end' },

   -- ╟─ "function" ──╭───────╮── "(" ─╢
   --                 ╰─ WSP ─╯
   { 'function%s*%(', 'end' }, -- 'function(' or 'function ('

   {  '{', '}' },
   { '%(', ')' }, -- % to escape lua pattern char
   { '%[', ']' }, -- % to escape lua pattern char
},

image

image

The comment substring in foldtext is correctly handled on close elements adding.

image

image

If process_comment_signs = 'spaces' is set, the output will be

image

Setup for particular filetype

This plugin provides two setup functions.

  1. The first one setup configuration which will be used for all filetypes for which you doesn't set their own configuration.

    require('pretty-fold').setup(config: table)
    
  2. The second one allows to setup filetype specific configuration:

    require('pretty-fold').ft_setup(filtype: string, config: table)
    

Example of ready to use foldtext configuration only for lua files

require('pretty-fold').ft_setup('lua', {
   matchup_patterns = {
      { '^%s*do$', 'end' }, -- do ... end blocks
      { '^%s*if', 'end' },  -- if ... end
      { '^%s*for', 'end' }, -- for
      { 'function%s*%(', 'end' }, -- 'function( or 'function (''
      {  '{', '}' },
      { '%(', ')' }, -- % to escape lua pattern char
      { '%[', ']' }, -- % to escape lua pattern char
   },
}

ft_ignore options

default: { 'neorg' }

Filetypes to be ignored.

ft_ignore is a unique option. It exists only in a single copy for all global and filetype specific configurations. You can pass it in any function (setup() or ft_setup()) and all this values will be collected in this one single value.

Foldmethod specific configuration

The pretty-fold.nvim plugin supports saparate configuration for different foldmethods. For this pass the configuration table for a particular foldmethod as a value to the key named after foldmethod.

You can also pass global configuration table for all foldmethods and tune only desired options in foldmethod specific config table. All options that don't have value in foldmethod config table will be taken from global config table.

Example:

require('pretty-fold').setup({
    global = {...}, -- global config table for all foldmethods
    marker = { process_comment_signs = 'spaces' },
    expr   = { process_comment_signs = false },
})

Examples

require('pretty-fold').setup{
   keep_indentation = false,
   fill_char = '•',
   sections = {
      left = {
         '+', function() return string.rep('-', vim.v.foldlevel) end,
         ' ', 'number_of_folded_lines', ':', 'content',
      }
   }
}

image

require('pretty-fold').setup{
   keep_indentation = false,
   fill_char = '━',
   sections = {
      left = {
         '━ ', function() return string.rep('*', vim.v.foldlevel) end, ' ━┫', 'content', '┣'
      },
      right = {
         '┫ ', 'number_of_folded_lines', ': ', 'percentage', ' ┣━━',
      }
   }
}

image

Configuration for C++ to get nice foldtext for Doxygen comments

require('pretty-fold').ft_setup('cpp', {
   process_comment_signs = false,
   comment_signs = {
      '/**', -- C++ Doxygen comments
   },
   stop_words = {
      -- ╟─ "*" ──╭───────╮── "@brief" ──╭───────╮──╢
      --          ╰─ WSP ─╯              ╰─ WSP ─╯
      '%*%s*@brief%s*',
   },
})

image

image

Preview

Preview module have been moved into separate plugin.

Additional information

Check 'fillchars' option. From lua it can be set the next way:

vim.opt.fillchars:append('fold:•')