Làm thế nào để viết một expr-expr?


10

Tôi đã đọc trang trợ giúp về Fold-expr ( :h fold-expr) nhưng nó không giải thích được cú pháp được sử dụng trong biểu thức là gì.

Có bốn ví dụ:

  1. :set foldexpr=getline(v:lnum)[0]==\"\\t\"
  2. :set foldexpr=MyFoldLevel(v:lnum)
  3. :set foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1
  4. :set foldexpr=getline(v:lnum-1)=~'^\\s*$'&&getline(v:lnum)=~'\\S'?'>1':1

Tôi hiểu rằng đó v:lnumlà dòng cần một mức độ chỉ định và biểu thức hai là một lời gọi đến một hàm.

Còn biểu thức 1,3 và 4 thì sao? Ai đó có thể vui lòng giải thích chúng cho tôi?


Hiểu biết của tôi là biểu thức sẽ trả về một số và số đó sẽ được sử dụng để xác định mức độ nào của dòng đã cho sẽ được gấp lại. 0 không bị gập, 1 là ngoài cùng gấp, 2 là một lần lồng vào bên trong một mức độ 1 lần, và vân vân
tommcdo

Câu trả lời:


12

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 :setlệnh này hoạt động trong một lệnh:

getline(v:lnum)[0] == "\t"
  1. getline(v:lnum) được toàn bộ dòng.
  2. [0] có được nhân vật đầu tiên
  3. == "\t"kiểm tra nếu đó là một ký tự tab.
  4. 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 expandtabkhô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
  1. Chúng tôi nhận được toàn bộ dòng với getline(v:lnum)
  2. Chúng tôi kết hợp đó như là một regexp với =~tới '^\s*$'; ^neo vào đầu, \scó 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.
  3. getline(v:lnum + 1)được dòng tiếp theo .
  4. 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.
  5. 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.
  6. <1có nghĩa là một nếp gấp kết thúc trên dòng này, và 1có 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 foldexprnó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 ;-)


3

Về cơ bản, bạn đang hỏi các yếu tố khác trong các biểu thức này là gì, có thể được tìm thấy bằng cách gọi :helplần lượt bất kỳ trong số chúng:

v:lnum: the line being evaluated
getline(): get the line of text for a line number
==: equals
=~: matches
<cond>?<if-true>:<if-false>: evaluates to <if-true> if <cond> is true, else to <if-false>

Tôi đã chia nhỏ các biểu thức này bằng các phần của chúng bên dưới để giúp minh họa ý nghĩa của chúng:

1 Sẽ trả về 1 cho tất cả các dòng bắt đầu bằng một tab và 0 cho các dòng khác:

v:lnum                      the current line number
getline(v:lnum)             the text of the current line
getline(v:lnum)[0]          the first character of the current line
getline(v:lnum)[0]==\"\\t\" the first char of the current line is 'tab'

3 Kết thúc nếp gấp trên các dòng trống sau đoạn văn:

 getline(v:lnum)=~'^\\s*$'                                       current line is only spaces
                              getline(v:lnum+1)=~'\\S'           next line has non-space
(getline(v:lnum)=~'^\\s*$' && getline(v:lnum+1)=~'\\S') ? '<1'   if both of these: <1
                                                              :1 otherwise: 1
(getline(v:lnum)=~'^\\s*$' && getline(v:lnum+1)=~'\\S') ? '<1':1

4 Bắt đầu gấp trên các dòng trống đoạn đầu:

(getline(v:lnum-1)=~'^\\s*$'                                     previous line only spaces
                                getline(v:lnum)=~'\\S'           this line has non-space
(getline(v:lnum-1)=~'^\\s*$' && getline(v:lnum)=~'\\S') ? '>1'   if both of these: >1
                                                              :1 otherwise: 1
(getline(v:lnum-1)=~'^\\s*$' && getline(v:lnum)=~'\\S') ? '>1':1 

Ý nghĩa của <1, >1v.v ... ngay bên dưới các biểu thức này trong:help fold-expr


1

Vô tình đăng câu trả lời của tôi như một bình luận và gửi nó sớm. Di động chết tiệt.

Sự hiểu biết của tôi là biểu thức sẽ trả về một số và số đó sẽ được sử dụng để xác định mức độ nào của dòng đã cho sẽ được gấp lại. 0 không được gấp, 1 là nếp gấp ngoài cùng, 2 là nếp gấp được lồng bên trong nếp gấp cấp 1, v.v.

Các biểu thức trong các ví dụ trông giống như chúng đánh giá là đúng hay sai. VimScript không có loại Boolean thích hợp, vì vậy đây thực sự sẽ là 1 hoặc 0, là các mức gấp hợp lệ.

Bạn có thể viết biểu thức của riêng mình bằng VimScript đơn giản như trả về 1 hoặc 0 hoặc phức tạp hơn, cho phép các nếp gấp lồng nhau.


Chỉ sử dụng các số sẽ hoạt động, nhưng đáng chú ý là Foldexpr có thể đánh giá các giá trị đặc biệt khác, như =, a1, s1,> 1, <1, -1
Matt Boehm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.