จาก:help 'foldexpr'
:
มันถูกประเมินสำหรับแต่ละบรรทัดเพื่อให้ได้ระดับการพับ
การfoldexpr
ประเมินผลดังนั้นมันจะต้องเป็นรหัส VimL; ไม่มีการกล่าวถึง "ไวยากรณ์พิเศษ" หรือสิ่งที่คล้ายกัน ผลลัพธ์ของการประเมินนี้จะควบคุมสิ่งที่ Vim เห็นว่าเป็นการหมอบหรือไม่
ค่าที่เป็นไปได้คือ
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
นี่ไม่ใช่รายการทั้งหมด; ตัวอย่างที่ใช้ในคำถามของคุณ ดู:help foldexpr
รายการทั้งหมด
เป็นครั้งแรก
อันแรกนั้นค่อนข้างง่ายเมื่อเราเพิ่มช่องว่างและลบแบ็กสแลชที่เราต้องการเพื่อให้มันทำงานใน:set
คำสั่ง:
getline(v:lnum)[0] == "\t"
getline(v:lnum)
รับทั้งบรรทัด
[0]
รับตัวละครตัวแรกของเรื่องนั้น
- และ
== "\t"
ตรวจสอบว่าเป็นอักขระแท็บหรือไม่
- VimL ไม่มี "จริง" หรือ "เท็จ" เพียงใช้ "0" สำหรับเท็จและ "1" สำหรับจริง ดังนั้นหากบรรทัดนี้เริ่มต้นด้วยแท็บมันจะถูกพับที่ foldlevel 1 หากไม่เป็นเช่นนั้นก็จะไม่เป็นแบบพับ (0)
หากคุณจะขยายสิ่งนี้เพื่อนับจำนวนแท็บคุณจะมีการพับตามการเยื้อง (อย่างน้อยเมื่อexpandtab
ไม่ได้เปิดใช้งาน)
ที่สาม
อันที่สามนั้นไม่ซับซ้อนกว่าตัวแรกมากนัก เช่นเดียวกับตัวอย่างแรกเราต้องการทำให้อ่านง่ายขึ้น:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- เรารับทั้งบรรทัดด้วย
getline(v:lnum)
- เราจับคู่นั้นเป็น regexp ด้วย
=~
ถึง'^\s*$'
; ^
จุดยึดที่จุดเริ่มต้น\s
หมายถึงอักขระช่องว่างใด ๆ*
หมายถึงการทำซ้ำศูนย์ก่อนหน้านี้หรือมากกว่าครั้งและ$
จุดยึดไปยังจุดสิ้นสุด ดังนั้น regexp นี้จับคู่ (คืนค่าจริง) สำหรับบรรทัดว่างหรือบรรทัดที่มีช่องว่างเท่านั้น
getline(v:lnum + 1)
รับบรรทัดถัดไป
- เราจับคู่สิ่งนี้กับ
\S
ซึ่งตรงกับอักขระที่ไม่ใช่ช่องว่างที่ใดก็ได้ในบรรทัดนี้
- หากทั้ง 2 เงื่อนไขที่เป็นจริงที่เราประเมินเพื่อมิฉะนั้น
<1
1
นี้จะกระทำกับ "ประกอบไปด้วย" if
ที่รู้จักจากซีและบางส่วนภาษาอื่น ๆcondition ? return_if_true : return_if_false
:
<1
หมายถึงการพับสิ้นสุดในบรรทัดนี้และ1
หมายถึงการพับหนึ่งครั้ง
ดังนั้นถ้าเราจบพับถ้าสายไม่ว่างและบรรทัดต่อไปคือไม่ว่างเปล่า มิฉะนั้นเราจะอยู่ในสถานะ foldlevel 1. หรืออย่างที่:h foldexpr
บอกว่า:
สิ่งนี้จะทำให้ย่อหน้าย่อยแยกออกจากกันด้วยบรรทัดว่าง
ที่สี่
ตัวที่สี่ทำหน้าที่เหมือนกับตัวที่สาม แต่ทำในลักษณะที่แตกต่างออกไปเล็กน้อย ขยายตัวคือ:
getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1
หากบรรทัดก่อนหน้าเป็นบรรทัดว่างและบรรทัดปัจจุบันเป็นบรรทัดที่ไม่ว่างเปล่าเราจะเริ่มต้นครึ่งหน้าบนบรรทัดนี้ ( >1
) หากไม่เป็นเช่นนั้นเรากำลังตั้งค่าระดับการพับเป็น 1
เล่ม
ตรรกะของตัวอย่างทั้ง 3 นั้นค่อนข้างง่ายมาก ปัญหาส่วนใหญ่เกิดจากการขาดช่องว่างและการใช้แบ็กสแลชบางส่วน
ฉันสงสัยว่าการเรียกใช้ฟังก์ชั่นมีค่าใช้จ่ายบางส่วนและเนื่องจากการประเมินนี้สำหรับทุกบรรทัดที่คุณต้องการให้มีประสิทธิภาพที่ดี ฉันไม่รู้ว่าความแตกต่างของเครื่องจักรสมัยใหม่นั้นดีแค่ไหนและอยากจะแนะนำให้คุณใช้ฟังก์ชั่น (ดังตัวอย่างที่ 2) เว้นแต่คุณจะมีปัญหาเรื่องประสิทธิภาพ จำ Knuth: "การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากของความชั่วร้ายทั้งหมด"
คำถามนี้อยู่ใน StackOverflowซึ่งมีคำตอบที่แตกต่างกันเล็กน้อย แต่แน่นอนว่าเป็นของฉันดีกว่า ;-)