Свернуть Vim сворачивает в одну строку, как Atom или Sublime Text

13

Я фанат способа, которым Atom и Sublime Text обрабатывают сгибание строк, когда первая строка каждого сгиба видима (завершена подсветкой синтаксиса), и к концу строки, указывающей сгиб, добавляется маркер.

См. Скриншот ниже, сравнивающий отступ в Vim (вверху) и Atom (внизу):Vim vs. Atom сворачивание кода

Vim посвящает две строки для каждого сгиба. Первая строка служит заголовком, а вторая строка описывает некоторую информацию о сгибе (количество строк и текст внутри сгиба).

Atom использует только одну строку и использует маленький маркер в конце строки для обозначения сгиба вместе с цветом, добавленным к номерам строк слева. Складной стиль Atom использует меньше экранного пространства, но все же передает всю информацию, которая мне действительно нужна.

Я неравнодушен к складному стилю Atom. На мой взгляд, он выглядит чище и последовательнее, особенно при перечислении нескольких методов или атрибутов подряд (как на скриншоте выше).

Есть ли способ примерно приблизить стиль складывания Atom в Vim?

Майк Хирн
источник
1
Я думаю, это потому, что ваши сгибы на самом деле не начинаются со строки, содержащей открывающие скобки. Vim использует только текст сгиба в строке, где начинается сгиб. Посмотрите, например, как размещение фигурных скобок влияет на это в C: imgur.com/3h70dPf,wfCLPm7
muru
Но это Python, без фигурных скобок ( from __future__ import braces) ... Как вы настроили складывание? И вы можете вставить этот фрагмент кода (или другой, который демонстрирует проблему)? Vim сбрасывает на одну строчку, но, как уже упоминалось, ваши сгибы начинают линию поздно.
Мартин Турной
@Carpetsmoker фигурные скобки только для иллюстрации того, где начинается сгиб. Тот же эффект можно увидеть, скажем, на Haskell.
Муру
@MikeHearn Мой предыдущий ответ был совершенно неверным. Я обновил его, чтобы включить решение проблемы.
Богатый

Ответы:

12

Две линии против одной линии

В Vim все строки в сгибе будут свернуты в одну строку, и 'foldtext'затем параметр определяет синопсис этих строк (обычно штрихи, количество сложенных строк и содержимое из первых (или всех) строк).

В вашем примере, в Vim {...}свернут только сам блок параметров; строка выше (которая использует параметры) не является частью сгиба. Напротив, в другом редакторе эта строка, использующая параметры, принадлежит к сгибу, а ее сгибный текст (если использовать терминологию Vim) - это содержимое этой строки плюс добавленный маркер.

адаптация

В Vim складки могут генерироваться различными способами (см. :help fold-methods) И зависят 'filetype'от буфера. Сложность включения вышеупомянутой линии в сгиб зависит от этого; проверить с :setlocal foldmethod?. При складывании отступа вы не можете повлиять; Вы должны переключиться на другой метод. Для свертывания синтаксиса это означало бы адаптацию определений синтаксиса и может быть очень сложным. Вам повезет больше, если использовать выражение , но это все равно будет означать понимание и изменение логики. (Маловероятно, что автор плагина filetype предоставил конфигурацию, чтобы повлиять на это.)

Подсветка синтаксиса согнутой строки

К сожалению, это невозможно вообще. Vim всегда использует группу Foldedвыделения для всей сложенной строки. Вы можете настроить это с помощью своих :highlightкоманд ~/.vimrc, но индивидуальная дифференциация синтаксиса будет потеряна.

Инго Каркат
источник
5

Vim уже отображает сгибы одной строкой. Однако при indentсворачивании Vim все линии с одинаковым отступом включаются в сгиб. Таким образом, на скриншоте строки, которые вы называете «заголовками» (например, начинающими collection_base_url), не находятся в пределах сгиба.

Вы можете добиться чего-то похожего на свертывание Atom, используя Vim foldexpr foldmethod:

" Finds the indent of a line. The indent of a blank line is the indent of the
" first non-blank line above it.
function! FindIndent(line_number, indent_width)
    " Regular expression for a "blank" line
    let regexp_blank = "^\s*$"

    let non_blank_line = a:line_number
    while non_blank_line > 0 && getline(non_blank_line) =~ regexp_blank
        let non_blank_line = non_blank_line - 1
    endwhile
    return indent(non_blank_line) / a:indent_width
endfunction

" 'foldexpr' for Atom-style indent folding
function! AtomStyleFolding(line_number)
    let indent_width = &shiftwidth

    " Find current indent
    let indent = FindIndent(a:line_number, indent_width)

    " Now find the indent of the next line
    let indent_below = FindIndent(a:line_number + 1, indent_width)

    " Calculate indent level
    if indent_below > indent
        return indent_below
    elseif indent_below < indent
        return "<" . indent
    else
        return indent
    endif
endfunction

set foldexpr=AtomStyleFolding(v:lnum)
set foldmethod=expr

Это определяет выражение сгиба (см. :help fold-expr) Следующим образом:

  • Для строк, непосредственно предшествующих отступам, он возвращает отступ следующего блока.
  • Для строк с отступом возвращает отступ. (Делится на ширину смещения, поэтому каждый уровень отступа увеличивает возвращаемое значение на 1)
  • Для строк в конце блока с отступом возвращает строку "<N", в которой для N задан отступ. Это говорит Vim, что сгиб уровня N заканчивается на этой линии.

Обновить

@alxndr спрашивает в комментариях, возможно ли расширить это, чтобы включить устаревшие ends Руби в сгибы. Вы можете начать с замены " Calculate indent levelраздела следующим:

if indent_below > indent
    return indent_below
elseif getline(a:line_number) =~ '^\s*end\s*$'
    return "<" . (indent + 1)
else
    return indent
endif

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

Богатый
источник
Отличный подход. Можно ли обобщить этот ответ, чтобы он также обрабатывал, скажем, Ruby, с его расширением endдля завершения блока?
alxndr
1
@alxndr Я отредактировал свой ответ, обсудив его.
Рич
@Rich: Я также нахожу Sublime text fold, который показывает только отметку ...в конце строки как символ свернутого текстового блока, очень полезен и отвлекает меньше, чем нужно выделять всю первую строку текстового блока, как в vim. Я пробовал ваш фолд выше с поведением фолда vim по умолчанию, просто не работает. Как сделать сгиб, который дает отметку в конце первой строки текстового блока с помощью python? Должен ли я открыть новый вопрос? Я просто проверяю ваш фолд, это действительно хорошо работает с отступом. супер спасибо.
Туйен Фам
Это потрясающе! Я искал что-то, что делает режим орг, как складывание, и это очень помогает!
priomsrb