Từ :help 'foldexpr'
:
Nó được ước tính cho mỗi dòng để có được mức độ gấp của nó
Các foldexpr
được đánh giá, vì vậy nó cần phải được VimL mã; không có đề cập đến "cú pháp đặc biệt" hoặc tương tự. Kết quả của đánh giá này kiểm soát những gì Vim xem xét có gấp hay không.
Giá trị có thể là
0 the line is not in a fold
1, 2, .. the line is in a fold with this level
"<1", "<2", .. a fold with this level ends at this line
">1", ">2", .. a fold with this level starts at this line
Đây không phải là danh sách đầy đủ; chỉ những cái được sử dụng trong các ví dụ trong câu hỏi của bạn. Xem :help foldexpr
để biết danh sách đầy đủ.
Đầu tiên
Cái đầu tiên khá đơn giản một khi chúng ta thêm một số khoảng trắng và loại bỏ dấu gạch chéo ngược, chúng ta cần làm cho :set
lệnh này hoạt động trong một lệnh:
getline(v:lnum)[0] == "\t"
getline(v:lnum)
được toàn bộ dòng.
[0]
có được nhân vật đầu tiên
- và
== "\t"
kiểm tra nếu đó là một ký tự tab.
- VimL không có "true" hoặc "false", nó chỉ sử dụng "0" cho false và "1" cho true. Vì vậy, nếu dòng này bắt đầu bằng một tab, nó được gấp lại ở Foldlevel 1. Nếu không, nó không nằm trong một nếp gấp (0).
Nếu bạn sẽ mở rộng số này để đếm số lượng tab bạn sẽ có khả năng gập dựa trên thụt đầu dòng (ít nhất là khi expandtab
không được bật).
Ngày thứ ba
Cái thứ ba thực sự không phức tạp hơn cái thứ nhất; như với ví dụ đầu tiên, trước tiên chúng tôi muốn làm cho nó dễ đọc hơn:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- Chúng tôi nhận được toàn bộ dòng với
getline(v:lnum)
- Chúng tôi kết hợp đó như là một regexp với
=~
tới '^\s*$'
; ^
neo vào đầu, \s
có nghĩa là bất kỳ ký tự khoảng trắng nào, *
có nghĩa là lặp lại số 0 hoặc nhiều lần trước đó và $
neo vào cuối. Vì vậy, biểu thức chính quy này khớp (trả về giá trị true) cho các dòng trống hoặc các dòng chỉ có khoảng trắng.
getline(v:lnum + 1)
được dòng tiếp theo .
- Chúng tôi khớp với điều này
\S
, phù hợp với bất kỳ ký tự không phải khoảng trắng ở bất kỳ đâu trên dòng này.
- Nếu 2 điều kiện này là đúng, chúng tôi ước tính
<1
, nếu không , 1
. Điều này được thực hiện với "ternary" if
được biết đến từ C và một số ngôn ngữ khác : condition ? return_if_true : return_if_false
.
<1
có nghĩa là một nếp gấp kết thúc trên dòng này, và 1
có nghĩa là một nếp gấp .
Vì vậy, nếu chúng ta kết thúc một nếp gấp nếu dòng trống và dòng tiếp theo không trống. Mặt khác, chúng tôi đang ở Foldlevel 1. Hoặc, như đã :h foldexpr
nói:
Điều này sẽ tạo ra một đoạn trong các đoạn được phân tách bằng các dòng trống
Thứ tư
Cái thứ tư hành xử giống như cái thứ ba, nhưng thực hiện nó theo một cách hơi khác. Mở rộng, đó là:
getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1
Nếu dòng trước là một dòng trống và dòng hiện tại là một dòng không trống, chúng tôi bắt đầu một nếp gấp trên dòng này ( >1
), nếu không, chúng tôi sẽ đặt nếp gấp thành 1.
Lời bạt
Vì vậy, logic trên cả 3 ví dụ thực sự khá đơn giản. Hầu hết các khó khăn đến từ việc thiếu không gian và một số sử dụng dấu gạch chéo ngược.
Tôi nghi ngờ rằng việc gọi một hàm có một số chi phí, và vì điều này được đánh giá cho mỗi dòng bạn muốn có một hiệu suất tốt. Tôi không biết sự khác biệt lớn như thế nào trên các máy hiện đại và sẽ khuyên bạn nên sử dụng một chức năng (như trong ví dụ thứ 2) trừ khi bạn gặp vấn đề về hiệu năng. Hãy nhớ The Knuth: "tối ưu hóa sớm là gốc rễ của mọi tội lỗi" .
Câu hỏi này cũng có trên StackOverflow , có một câu trả lời hơi khác. Nhưng của tôi tất nhiên là tốt hơn ;-)