xaizek / vim-preamble (License: Unspecified) (since 2018-12-07)
Preamble Vim plugin by Mel Davis with a couple of fixes.
<root> / autoload / Preamble.vim (7890ef4133d88971827719f020cfcaf24b5f0273) (6,826B) (mode 100644) [raw]
if &cp || exists("s:loaded_preamble")
    finish
endif
let s:loaded_preamble = 1


" ########################################################
" Public Methods
" ########################################################


" ========================================================
" Enable: enables automatic preamble for the specified
"   filetypes
"
" Parameters --
"   filetypes - -- string of comma delimited filetypes,
"               -- an empty string disables the plugin
"               -- "*" enables plugin for all filetyps
" Example --
"   In your .vimrc file, add a line like this:
"       call Preamble#Enable("c,cpp,java")
" ========================================================

fun! Preamble#Enable(filetypes)
    silent! au! AugroupPreamble
    if a:filetypes == "" | return | endif

    augroup AugroupPreamble
        execute 'au BufWinEnter,FileType' a:filetypes 'call Preamble#Fold()'
    augroup END
endfunction



" ========================================================
" Fold: folds the preamble according to the options that
"   that are set
" ========================================================

fun! Preamble#Fold()
    if exists('b:preamble_disable_thisbuffer') && b:preamble_disable_thisbuffer != 0
        return
    endif

    call s:LoadOptions()

    let pl = s:Length()
    if pl < s:preamble_min_lines | return | endif
    if pl > s:preamble_max_lines && !s:preamble_fold_partial | return | endif

    " if a fold aleady exists in line 1
    if foldlevel(1)
        " and it's open, close it
        if foldclosed(1) == -1
            execute ':1,'.pl.'foldclose'
        endif
        " or do nothing
        return
    endif

    if &foldmethod=='syntax' | return | endif

    execute 'set foldmethod=manual | :1,'.pl.'fold | :1,'.pl.'foldclose'
endfunction



" ########################################################
" Private Methods
" ########################################################

" ========================================================
" LoadOptions: Initializes user options
"
"   If defined, the buffer specific option is used.
"   Else, if defined, the global option is used.
"   Else, the default is used.
" ========================================================

fun! s:LoadOptions()

    " ------------------------------------------------------------------
    " Option: preamble_min_lines
    "
    " Minimum lines that preamble should have before it can be folded
    " If the preamble is less than this number, no fold is created
    "
    " Default: 25
    " ------------------------------------------------------------------

    if !exists('g:preamble_min_lines')
        let s:preamble_min_lines=25
    else
        let s:preamble_min_lines=g:preamble_min_lines
    endif
    if exists('b:preamble_min_lines')
        let s:preamble_min_lines=b:preamble_min_lines
    endif

    " ------------------------------------------------------------------
    " Option: preamble_max_lines
    "
    " Maximum lines to include in the preamble fold
    " If the preamble is greater than this number, behavior is
    " determined by the 'preamble_fold_partial' option
    "
    " Default: 150
    " ------------------------------------------------------------------

    if !exists('g:preamble_max_lines')
        let s:preamble_max_lines=150
    else
        let s:preamble_max_lines=g:preamble_max_lines
    endif
    if exists('b:preamble_max_lines')
        let s:preamble_max_lines=b:preamble_max_lines
    endif
    if line('$') < s:preamble_max_lines
        let s:preamble_max_lines = line('$')
    endif

    " ------------------------------------------------------------------
    " Option: preamble_fold_partial
    "
    " If the preamble is greater the 'max_lines'
    " fold or do not fold up to 'max_lines'
    "
    " Values:   0 = do not fold partial preambles  (default)
    "           1 = do fold max lines of the preamble
    " ------------------------------------------------------------------

    if !exists('g:preamble_fold_partial')
        let s:preamble_fold_partial=0
    else
        let s:preamble_fold_partial=g:preamble_fold_partial
    endif
    if exists('b:preamble_fold_partial')
        let s:preamble_fold_partial=b:preamble_fold_partial
    endif

    " ------------------------------------------------------------------
    " Option: b:preamble_disable_thisbuffer
    "
    " Disable folding for buffer
    " This option is only for buffer level folding
    "
    " Values:  exists and not 0 = do not create fold
    " ------------------------------------------------------------------
    " b:preamble_disable_thisbuffer


endfunction


" ========================================================
" Length: Calculates the preamble's length
"
"   The preamble
"       -- starts on line 1 of the file
"       -- includes initial blank lines
"       -- includes lines having a character in column one
"          with a 'Comment' syntax
"       -- stops when first non-Comment line is reached
"
"   Blank lines before the first comment are included.
"   Blank lines after the first comment line are not.
" ========================================================

fun! s:Length()

    let line_pos = 1

    while(line_pos <= s:preamble_max_lines)
        let synId = synID(line_pos, 1, 1)
        let realSynId = synIDtrans(synId)
        let attrName = synIDattr( realSynId, 'name' )
        " skip shebang in python
        if attrName == 'PreProc'
            let line_pos += 1
            continue
        endif

        " skip <?php line in PHP sources
        if attrName == 'Delimiter'
            let line_pos += 1
            break
        endif

        " skip blank lines at top of file
        if getline(line_pos) =~ '\S'
            break
        endif

        let line_pos += 1
    endwhile

    while(line_pos <= s:preamble_max_lines)
        " assume each line of a preamble has a character in col one
        let synStack = synstack(line_pos, 1)
        let synId = empty(synStack) ? 0 : synStack[-1]
        let realSynId = synIDtrans(synId)
        let attrName = synIDattr( realSynId, 'name' )
        if attrName != 'Comment' && !s:IsInString(line_pos)
            break
        endif

        let line_pos += 1
    endwhile

    return line_pos-1
endfunction


" ========================================================
" IsInString: Checks whether line is part of a string
"
"   This is important for example for python, which
"   doesn't have multiline comments and multiline string
"   literals are used instead.
" ========================================================

fun! s:IsInString(line)
    for id in synstack(a:line, 1)
        let attrName = synIDattr(synIDtrans(id), 'name')
        if attrName == 'String'
            return 1
        endif
    endfor
    return 0
endfunction
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vim-preamble

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vim-preamble

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master