Perkecil vim lipatan ke satu baris, mirip dengan Atom atau Teks Sublime

13

Saya penggemar cara Atom dan Sublime Text menangani pelipatan garis, di mana baris pertama dari setiap lipatan terlihat (lengkap dengan penyorotan sintaks), dan marker ditambahkan ke ujung garis yang menunjukkan lipatan.

Lihat tangkapan layar di bawah ini yang membandingkan lipat indentasi Vim (atas) versus Atom (bawah):Vim vs. Lipat kode Atom

Vim mendedikasikan dua garis untuk setiap lipatan. Baris pertama berfungsi sebagai heading, dan baris kedua menjelaskan beberapa informasi tentang flip (jumlah baris dan teks di dalam flip).

Atom hanya menggunakan satu garis, dan menggunakan penanda kecil di ujung garis untuk menunjukkan lipatan, bersama dengan warna yang ditambahkan ke nomor garis di sebelah kiri. Gaya lipat Atom menggunakan real estate layar lebih sedikit tetapi masih mengkomunikasikan semua informasi yang saya butuhkan.

Saya sebagian dengan gaya lipat Atom. Tampaknya lebih bersih dan lebih konsisten, menurut pendapat saya, terutama ketika mendaftar beberapa metode atau atribut dalam satu baris (seperti pada screenshot di atas).

Apakah ada cara untuk memperkirakan perkiraan gaya lipat Atom di Vim?

Mike Hearn
sumber
1
Saya pikir itu karena lipatan Anda tidak benar-benar dimulai dengan garis yang berisi tanda kurung buka. Vim hanya menggunakan teks lipat pada baris tempat lipatan dimulai. Lihat, misalnya, bagaimana penempatan brace memengaruhinya di C: imgur.com/3h70dPf,wfCLPm7
muru
Tapi ini Python, tidak ada kawat gigi yang terlibat ( from __future__ import braces) ... Bagaimana Anda mengonfigurasi lipat? Dan dapatkah Anda menempelkan cuplikan kode ini (atau yang lain yang menunjukkan masalah)? Vim melipat ke satu baris, tetapi seperti yang disebutkan muru, lipatan Anda memulai garis terlambat.
Martin Tournoij
@Carpetsmoker kawat gigi hanya untuk ilustrasi dari mana lipatan dimulai. Efek yang sama dapat dilihat pada, katakanlah, Haskell.
muru
@ MikeHearn Jawaban saya sebelumnya benar-benar salah. Saya telah memperbaruinya untuk memasukkan solusi untuk masalah tersebut.
Kaya

Jawaban:

12

Dua baris vs satu baris

Dalam Vim, semua baris dalam lipatan akan diciutkan menjadi satu baris, dan 'foldtext'opsi kemudian menentukan sinopsis dari garis-garis tersebut (biasanya garis putus-putus, jumlah garis terlipat, dan konten dari garis pertama (atau semua)).

Dalam contoh Anda, di Vim hanya {...}blok parameter itu sendiri yang dilipat; baris di atas (yang menggunakan parameter) bukan bagian dari flip. Sebaliknya, di editor lain, baris yang menggunakan parameter milik flip, dan teks lipatnya (untuk menggunakan terminologi Vim) adalah isi dari baris itu ditambah penanda yang ditambahkan.

Beradaptasi

Dalam Vim, lipatan dapat dihasilkan melalui cara yang berbeda (lihat :help fold-methods), dan tergantung pada 'filetype'buffer. Kesulitan memasukkan garis di atas dalam lipatan tergantung pada hal itu; periksa dengan :setlocal foldmethod?. Dengan indent lipat, tidak ada yang bisa Anda pengaruhi; Anda harus beralih ke metode lain. Untuk lipat sintaks , itu berarti mengadaptasi definisi sintaks, dan bisa sangat rumit. Anda akan lebih beruntung jika ekspresi digunakan, tetapi itu masih berarti memahami dan mengubah logika. (Sepertinya pembuat plugin filetype tidak menyediakan konfigurasi untuk memengaruhi ini.)

Menyoroti sintaks dari garis terlipat

Sayangnya itu tidak mungkin sama sekali. Vim selalu menggunakan Foldedgrup sorotan untuk seluruh garis yang dilipat. Anda dapat men-tweak itu melalui :highlightperintah di Anda ~/.vimrc, tetapi diferensiasi sintaks individu akan hilang.

Ingo Karkat
sumber
5

Vim sudah menampilkan lipatan sebagai satu baris. Namun, dalam indentlipatan Vim , semua garis yang memiliki indentasi yang sama dimasukkan dalam lipatan. Jadi dalam tangkapan layar Anda, garis yang Anda sebut sebagai "header" (mis. Yang dimulai collection_base_url) tidak ada dalam lipatan.

Anda dapat mencapai sesuatu yang mirip dengan pelipat Atom dengan menggunakan 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

Ini mendefinisikan ekspresi lipatan (lihat :help fold-expr) sebagai berikut:

  • Untuk garis segera sebelum garis indentasi, ini mengembalikan lekukan blok yang mengikuti.
  • Untuk garis indentasi, ia mengembalikan indentasi. (Dibagi oleh lebar pita sehingga setiap tingkat indentasi menambah nilai yang dikembalikan sebesar 1)
  • Untuk garis di ujung blok garis indentasi, ia mengembalikan string "<N", di mana N diatur ke indentasi. Ini memberitahu Vim bahwa lipatan level N selesai pada baris itu.

Memperbarui

@alxndr bertanya di komentar apakah mungkin untuk memperpanjang ini untuk memasukkan Ruby yang sudah ketinggalan zaman enddalam lipatan. Anda bisa mulai dengan mengganti " Calculate indent levelbagian dengan yang berikut:

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

Seperti ini, ini bukan solusi yang paling kuat (mis. Itu akan gagal jika endpernyataan berada di baris yang sama, setelah titik koma). Anda dapat mengubah ekspresi reguler dan kode di sekitarnya untuk mengatasinya, tetapi karena Anda sekarang berada di ranah penguraian sintaks sebenarnya dari file tersebut, saya curiga hal-hal bisa menjadi jauh lebih rumit sebelum Anda memiliki solusi yang baik.

Kaya
sumber
Pendekatan yang bagus. Bisakah jawaban ini digeneralisasikan untuk juga menangani katakanlah Ruby, dengan yang sudah ketinggalan zaman enduntuk menyelesaikan blok?
alxndr
1
@alxndr Saya telah mengedit jawaban saya dengan beberapa diskusi.
Kaya
@ Rich: Saya juga menemukan lipatan teks Sublime yang hanya menunjukkan tanda ...di ujung baris sebagai simbol blok teks terlipat sangat berguna dan membuat lebih sedikit gangguan daripada harus menyorot seluruh baris pertama blok teks seperti di vim. Saya mencoba lipatan Anda di atas dengan perilaku lipatan default vim, sederhana tidak berhasil. Bagaimana cara membuat lipatan yang memberi tanda di akhir baris pertama blok teks dengan python? Haruskah saya membuka pertanyaan baru? Saya hanya menguji kembali lipatan Anda, itu memang bekerja sangat baik dengan garis indentasi. Super Terima kasih.
Tuyen Pham
Ini luar biasa! Saya telah mencari sesuatu yang melakukan org-mode seperti melipat dan ini sangat membantu!
priomsrb