Два раза методы одновременно - PullRequest
10 голосов
/ 12 мая 2011

Я бы хотел установить два метода свертывания

  1. :set foldmethod=indent и сохранить все его функции
  2. , скрывая комментарии с

    :set foldmethod=marker

    :set foldmarker=/*,*/

Я обнаружил, что это невозможно.Можно ли добиться желаемого свертывания и установить его в .vimrc или использовать для этого какой-нибудь скрипт или плагин?

Ответы [ 3 ]

8 голосов
/ 12 мая 2011

Невозможно иметь разные типы фолдметодов в одном буфере. Как Vim должен знать, что есть некоторые комментарии на том же уровне отступа, что и другой текст, который вы хотите рассматривать как имеющий другой (более высокий номер) уровень?

Я уверен, что вы можете достичь того, чего хотите, установив метод сгибания в 'expr'. Это наиболее гибкий способ делать сгибы в Vim, но он может быть сложным (и / или медленным) в зависимости от того, что вы хотите. Я думаю, что это будет работать довольно легко для вашего случая использования.

Во-первых, где-то в вашем vimrc или vimscripts вам нужно убедиться, что foldexpr определен для рассматриваемого типа файла.

set foldexpr=MyFoldLevel(v:lnum)
set foldmethod=expr
" and for last code example
let b:previous_level = 0

и затем вам нужно конкретизировать свою функцию foldexpr, чтобы она назначала уровни таким образом, чтобы получить желаемое поведение. Нечто подобное приведенному ниже коду может быть близко к работе в тех случаях, когда каждая строка комментария имеет префиксный символ (т. Е. Не в вашем случае), но я ожидаю, что для этого потребуются некоторые изменения. h: fold-expr было бы хорошим местом для поиска помощи:

function! MyFoldLevel(linenum)
   " assign levels based on spaces indented and tabstop of 4
   let level = indent(a:linenum) / 4
   if getline(a:linenum) =~ [put line-based comment prefix pattern here]
       let level = 20
   endif
endfunction

Необходимо изменить, чтобы назначить более высокий уровень для строк между маркерами начала и конца комментария так, как вы хотите:

function! MyFoldLevel(linenum)
   let linetext = getline(a:linenum)
   if linetext =~ [put line-based comment prefix pattern here]
       let level = 20
   elseif linetext =~ '^\s*/\*'
       let level = 20
   elseif linetext =~ '^\s*\*/'
       let level = 21
   else
       if b:previous_level == 20
           let level = 20
       else
           "assuming code is space-indented with tabstop of 4
           let level = indent(a:linenum) / 4
       endif
   endif

   let b:previous_level = level
   return level

endfunction

Я не ожидаю, что написанные мной функции метода сгиба будут работать точно так же, как написанные. Но они указывают на то, что будет работать.

Обратите внимание, что использование уровня '20' для комментариев - это просто произвольный уровень, который позволяет их сворачивать, в то время как весь код с отступами (предположительно с более низким уровнем) может быть видимым. «21» для последней строки комментария просто отличает его от предыдущих строк комментариев, имеющих уровень 20, чтобы знать, что следующую строку следует рассматривать как обычную строку кода.

Кроме того, ключевые операции, такие как 'zc' и 'zo', не будут работать правильно в комментариях, когда они настроены на уровень намного выше, чем окружающий код. Хотелось бы использовать прямую команду, например :set foldlevel=21, чтобы показать все строки комментариев.

Не красиво, и я ожидаю, что это может быть немного упрощено, но что-то вроде этого, я думаю, требуется для того, что вы хотите.

На самом деле, подумав немного об этом, я думаю, вы бы хотели, чтобы первая строка любых блоков комментариев была на одном уровне, как если бы это была строка без комментариев, только последующие строки комментариев в том же блоке должны быть более высокого уровня, чтобы они «свернули» в начальную строку комментария. В приведенном мною коде, если он работает или приближается к работе вообще, я думаю, что vim свернет все строк комментариев за предыдущей строкой без комментариев, что не то, что вы хотите, но я к сожалению, нет больше времени, чтобы посвятить этой маленькой загадке. , , Я проделывал этот вид пользовательского фолдинга довольно много раз и, как правило, всегда получаю немного проб и ошибок, чтобы получить именно то, что я хочу.

1 голос
/ 09 июня 2016

У меня те же запросы, что и у вас, вот мое не идеальное решение

моя пара создателей # <=== и # ===> (или #region и #endregion как в pycharm)

let b:inBlock=0
let b:lastLineNum=0
let b:lastLevel=0
let b:lastGoodLine=0
let b:lastGoodBlock=0
let b:startFoldingMark='^\s*.\?#<==*\|^\s*.\?#region'
let b:endFoldingMark='^\s*.\?#=*=>\|^\s*.\?#endregion'
function! MyFold(linenum)
    let linetext = getline(a:linenum)
    let level     = indent(a:linenum)   / &shiftwidth
    "the first line have 0 fold level
    if (a:linenum == 1)
        if linetext =~ b:startFoldingMark
            let b:inBlock = 1
            let b:lastLineNum=a:linenum
            let b:lastGoodLine=0
            let b:lastGoodBlock=0
            let b:lastLevel=level
            return level
        endif
        let b:inBlock=0
        let b:lastInBlock=0
        let b:lastLineNum=a:linenum
        let b:lastGoodLine=0
        let b:lastGoodBlock=b:inBlock
        let b:lastLevel=level + b:inBlock
        return level + b:inBlock
    endif

    " not calculate from the mid of text
    if ((b:lastLineNum+1) != a:linenum)
        let level     = indent(a:linenum)   / &shiftwidth
        let lastGoodNum = a:linenum-1
        while (lastGoodNum>1 && getline(lastGoodNum) =~? '\v^\s*$' )
            let lastGoodNum -= 1
        endwhile
        if  (foldlevel(lastGoodNum)==-1)
            let b:inBlock=b:lastGoodBlock
        else
            let lastlevel = indent(lastGoodNum)   / &shiftwidth
            let lastlinetext = getline(lastGoodNum)
            let lastlinelevel = foldlevel(lastGoodNum)
            if lastlinetext =~ b:startFoldingMark
                let b:inBlock = lastlinelevel - lastlevel + 1
            elseif lastlinetext =~ b:endFoldingMark
                let b:inBlock = lastlinelevel - lastlevel - 1
            else
                let b:inBlock = lastlinelevel - lastlevel
            endif
        endif
    endif

    "blank lines have undefined fold level
    if getline(a:linenum) =~? '\v^\s*$'
        let b:lastLineNum=a:linenum
        let b:lastLevel=-1
        return -1
    endif

    "if next line is a start of new marker block, inBlock ++
    if linetext =~ b:startFoldingMark
        let b:lastLineNum=a:linenum
        if (b:lastLevel != -1)
            let b:lastGoodLine=a:linenum
            let b:lastGoodBlock=b:inBlock
        endif
        let b:lastLevel=level + b:inBlock - 1
        return level + b:inBlock - 1
    "if next line is an end of new marker block, inBlock -
    elseif linetext =~ b:endFoldingMark
        let b:inBlock = b:inBlock - 1
        let b:lastLineNum=a:linenum
        let b:lastGoodLine=a:linenum
        let b:lastGoodBlock=b:inBlock
        let b:lastLevel=level + b:inBlock + 1
        return level + b:inBlock + 1
    endif

    let b:lastLineNum=a:linenum
    if (b:lastLevel != -1)
        let b:lastGoodLine=a:linenum
        let b:lastGoodBlock=b:inBlock
    endif
    let b:lastLevel=level + b:inBlock
    return level+b:inBlock
endfunction

Теперь я могу сохранить все функции при использовании метода Indent Fold, и я могу сложить каждый блок маркера # <=, # =>, также, отношения сворачивания отступа строк все еще сохраняются в каждомblock.

В этой функции я избегаю использования уровней "a1", "s1" и "=", что вызовет итерацию для этой функции и может быть медленным для больших файлов.Однако, когда вы обновляете строки, вычисление уровня сгиба может быть неправильным (поскольку vim может не обновлять весь уровень сгиба с начала, и, следовательно, иметь неверное значение inBlock)

вы можете использовать zx обновить уровни сгиба вручную.

подробнее на https://github.com/Fmajor/configs

1 голос
/ 12 мая 2011

Сворачивание на основе синтаксиса может быть лучшим способом получить то, что вы хотите, чем метод на основе expr, который я предложил в другом ответе на ваш вопрос.Проверьте :h fold-syn для получения дополнительной информации.Я думаю, что может быть несколько хороших решений для фолдинга на основе c.Не знаю, насколько это хорошо, но вот файл c-синтаксиса с поддержкой свертывания на основе синтаксиса: http://www.vim.org/scripts/script.php?script_id=234 и другой: http://www.vim.org/scripts/script.php?script_id=925

Решения, приведенные выше, полностью синтаксическиена основе не использовать отступы для определения уровней сгиба.Но вы можете изменить синтаксическое свертывание, чтобы сделать основное свертывание по областям с отступом, если хотите.Если вы делаете отступ на основе синтаксических элементов, результат может быть таким же.

Вот совет, который показывает, как просто сложить комментарии в стиле c (не фактический код) http://vim.wikia.com/wiki/Fold_C-style_comments

...