จะเขียน fold-expr ได้อย่างไร?


10

ฉันได้อ่านหน้าความช่วยเหลือเกี่ยวกับ fold-expr ( :h fold-expr) แล้ว แต่ไม่ได้อธิบายว่าไวยากรณ์ที่ใช้ในนิพจน์คืออะไร

มีสี่ตัวอย่าง:

  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

ฉันเข้าใจว่าv:lnumเป็นสายที่ต้องการระดับการเยื้องและการแสดงออกที่สองนั้นเป็นการเรียกใช้ฟังก์ชัน

สิ่งที่เกี่ยวกับการแสดงออก 1,3 และ 4 ใครช่วยอธิบายให้ฉันฟังหน่อยได้ไหม?


ความเข้าใจของฉันคือการแสดงออกควรกลับจำนวนและจำนวนที่จะใช้ในการกำหนดระดับที่บรรทัดที่กำหนดจะถูกพับ 0 ไม่ถูกพับ, 1 คือรอยพับด้านนอกสุด, 2 เป็นการซ้อนซ้อนกันในระดับ 1 เท่าและอื่น ๆ
tommcdo

คำตอบ:


12

จาก: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"
  1. getline(v:lnum) รับทั้งบรรทัด
  2. [0] รับตัวละครตัวแรกของเรื่องนั้น
  3. และ== "\t"ตรวจสอบว่าเป็นอักขระแท็บหรือไม่
  4. VimL ไม่มี "จริง" หรือ "เท็จ" เพียงใช้ "0" สำหรับเท็จและ "1" สำหรับจริง ดังนั้นหากบรรทัดนี้เริ่มต้นด้วยแท็บมันจะถูกพับที่ foldlevel 1 หากไม่เป็นเช่นนั้นก็จะไม่เป็นแบบพับ (0)

หากคุณจะขยายสิ่งนี้เพื่อนับจำนวนแท็บคุณจะมีการพับตามการเยื้อง (อย่างน้อยเมื่อexpandtabไม่ได้เปิดใช้งาน)


ที่สาม

อันที่สามนั้นไม่ซับซ้อนกว่าตัวแรกมากนัก เช่นเดียวกับตัวอย่างแรกเราต้องการทำให้อ่านง่ายขึ้น:

getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
  1. เรารับทั้งบรรทัดด้วย getline(v:lnum)
  2. เราจับคู่นั้นเป็น regexp ด้วย=~ถึง'^\s*$'; ^จุดยึดที่จุดเริ่มต้น\sหมายถึงอักขระช่องว่างใด ๆ*หมายถึงการทำซ้ำศูนย์ก่อนหน้านี้หรือมากกว่าครั้งและ$จุดยึดไปยังจุดสิ้นสุด ดังนั้น regexp นี้จับคู่ (คืนค่าจริง) สำหรับบรรทัดว่างหรือบรรทัดที่มีช่องว่างเท่านั้น
  3. getline(v:lnum + 1)รับบรรทัดถัดไป
  4. เราจับคู่สิ่งนี้กับ\Sซึ่งตรงกับอักขระที่ไม่ใช่ช่องว่างที่ใดก็ได้ในบรรทัดนี้
  5. หากทั้ง 2 เงื่อนไขที่เป็นจริงที่เราประเมินเพื่อมิฉะนั้น<1 1นี้จะกระทำกับ "ประกอบไปด้วย" ifที่รู้จักจากซีและบางส่วนภาษาอื่น ๆcondition ? return_if_true : return_if_false:
  6. <1หมายถึงการพับสิ้นสุดในบรรทัดนี้และ1หมายถึงการพับหนึ่งครั้ง

ดังนั้นถ้าเราจบพับถ้าสายไม่ว่างและบรรทัดต่อไปคือไม่ว่างเปล่า มิฉะนั้นเราจะอยู่ในสถานะ foldlevel 1. หรืออย่างที่:h foldexprบอกว่า:

สิ่งนี้จะทำให้ย่อหน้าย่อยแยกออกจากกันด้วยบรรทัดว่าง


ที่สี่

ตัวที่สี่ทำหน้าที่เหมือนกับตัวที่สาม แต่ทำในลักษณะที่แตกต่างออกไปเล็กน้อย ขยายตัวคือ:

getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1

หากบรรทัดก่อนหน้าเป็นบรรทัดว่างและบรรทัดปัจจุบันเป็นบรรทัดที่ไม่ว่างเปล่าเราจะเริ่มต้นครึ่งหน้าบนบรรทัดนี้ ( >1) หากไม่เป็นเช่นนั้นเรากำลังตั้งค่าระดับการพับเป็น 1


เล่ม

ตรรกะของตัวอย่างทั้ง 3 นั้นค่อนข้างง่ายมาก ปัญหาส่วนใหญ่เกิดจากการขาดช่องว่างและการใช้แบ็กสแลชบางส่วน

ฉันสงสัยว่าการเรียกใช้ฟังก์ชั่นมีค่าใช้จ่ายบางส่วนและเนื่องจากการประเมินนี้สำหรับทุกบรรทัดที่คุณต้องการให้มีประสิทธิภาพที่ดี ฉันไม่รู้ว่าความแตกต่างของเครื่องจักรสมัยใหม่นั้นดีแค่ไหนและอยากจะแนะนำให้คุณใช้ฟังก์ชั่น (ดังตัวอย่างที่ 2) เว้นแต่คุณจะมีปัญหาเรื่องประสิทธิภาพ จำ Knuth: "การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากของความชั่วร้ายทั้งหมด"

คำถามนี้อยู่ใน StackOverflowซึ่งมีคำตอบที่แตกต่างกันเล็กน้อย แต่แน่นอนว่าเป็นของฉันดีกว่า ;-)


3

คุณกำลังถามว่าองค์ประกอบอื่น ๆ ในนิพจน์เหล่านี้คืออะไรซึ่งสามารถพบได้โดยการเรียก:helpหาสิ่งเหล่านี้

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>

ฉันได้แบ่งการแสดงออกเหล่านี้ตามส่วนด้านล่างเพื่อช่วยอธิบายความหมายของพวกเขา:

1 จะส่งคืน 1 สำหรับทุกบรรทัดที่ขึ้นต้นด้วยแท็บและ 0 สำหรับบรรทัดอื่น ๆ :

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 สิ้นสุดการพับบรรทัดว่างหลังย่อหน้า:

 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 เริ่มพับในบรรทัดว่างเริ่มต้นย่อหน้า:

(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 

ความหมายของ<1, >1ฯลฯ อยู่ด้านล่างของสำนวนเหล่านี้ใน:help fold-expr


1

โพสต์คำตอบของฉันเป็นความคิดเห็นโดยบังเอิญและส่งไปก่อน แดนมือถือ

ความเข้าใจของฉันคือการแสดงออกควรกลับจำนวนและจำนวนที่จะใช้ในการกำหนดระดับที่บรรทัดที่กำหนดจะถูกพับ 0 ไม่ถูกพับ 1 คือรอยพับด้านนอกสุด 2 คือรอยพับซ้อนภายในระดับ 1 เท่าและอื่น ๆ

การแสดงออกในตัวอย่างดูเหมือนว่าพวกเขาจะประเมินเป็นจริงหรือเท็จ VimScript ไม่มีประเภทบูลีนที่เหมาะสมดังนั้นนี่จะเป็น 1 หรือ 0 ซึ่งเป็นระดับการพับที่ถูกต้อง

คุณสามารถเขียนนิพจน์ของคุณเองโดยใช้ VimScript ที่เรียบง่ายเท่ากับส่งคืน 1 หรือ 0 หรือซับซ้อนกว่าทำให้สามารถซ้อนได้หลายเท่า


การใช้ตัวเลขเพียงอย่างเดียวจะได้ผล แต่ก็น่าสังเกตว่า foldexpr สามารถประเมินค่าพิเศษอื่น ๆ เช่น =, a1, s1,> 1, <1, -1
Matt Boehm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.