วิธีค้นหารูปแบบในขอบเขตไวยากรณ์ที่แน่นอน?


10

ฉันใช้เสียงเรียกเข้าเพื่อแก้ไขเอกสารลาเท็กซ์ บ่อยครั้งที่ฉันต้องการเปลี่ยนชื่อของตัวแปรเป็นอย่างอื่น อย่างไรก็ตามมันเป็นเรื่องน่ารำคาญเล็กน้อยที่ต้องลุยผ่านการจับคู่ที่ไม่เกี่ยวข้องเมื่อฉันค้นหาชื่อตัวแปร ฉันต้องการค้นหาเฉพาะใน "โซนคณิตศาสตร์" ตามที่กำหนดไว้ในไฟล์ไวยากรณ์ของ tex มีวิธีง่าย ๆ ในการ จำกัด การค้นหาไปยังขอบเขตไวยากรณ์เฉพาะหรือไม่?


1
ฉันคิดว่าคำตอบคือไม่: ไม่มีวิธีง่ายๆในการ จำกัด การค้นหาในขอบเขตไวยากรณ์ที่เฉพาะเจาะจง
Karl Yngve Lervåg

2
การแมปนี้ใช้synIDattr()เพื่อรับกลุ่มไวยากรณ์สำหรับอักขระภายใต้เคอร์เซอร์ คุณสามารถเขียนฟังก์ชั่นที่ทำการค้นหา (หรือทำnormal n) จากนั้นใช้synIDattr()เพื่อตัดสินใจว่าจะอยู่ที่ตำแหน่งนี้หรือทำการค้นหาต่อไป
joeytwiddle

@ Joetwiddle ฉันเห็นความคิดเห็นของคุณตอนนี้หลังจากโพสต์คำตอบด้วยฟังก์ชั่นดังกล่าว มันเหมือนสิ่งที่คุณมีในใจ?
jjaderberg

@jjaderberg ใช่มันเป็น เยี่ยมมาก!
joeytwiddle

เพื่อความสมบูรณ์แบบ (ฉันพบว่ามันเป็นคำตอบที่ดี): stackoverflow.com/a/2696143/5000478
VanLaser

คำตอบ:


4

นี่คือฟังก์ชั่นที่คุณสามารถลองได้ ฉันทดสอบเพียงเล็กน้อย แต่ดูเหมือนว่าจะใช้ได้

function! JJSyntaxSearch(pattern, syntaxitem)
  while search(a:pattern, 'W') > 0
    for id in synstack(line("."),col("."))
      if synIDattr(id,"name") =~? a:syntaxitem
        return line(".")
      endif
    endfor
  endwhile
  return 0
endfunc

command! -nargs=* JJSyntaxSearch call JJSyntaxSearch(<f-args>)

ฟังก์ชันเรียกฟังก์ชันการค้นหาของ Vim ในลูปจนกว่าจะพบการจับคู่ 'สามัญ' ที่ยังมีการจับคู่ 'ที่ผ่านการรับรอง' ไปยังรายการไวยากรณ์เฉพาะหรือจนกว่าจะถึงจุดสิ้นสุดของบัฟเฟอร์

มันต้องใช้สองข้อโต้แย้ง สิ่งแรกคือรูปแบบการค้นหาและมันถูกส่งผ่านไปยังsearch()ฟังก์ชั่นของ Vim ไม่เปลี่ยนแปลง ดู:help search()ว่าฟังก์ชั่นนั้นทำงานอย่างไร อาร์กิวเมนต์ที่สองคือชื่อของรายการไวยากรณ์ที่คุณต้องการกรองรายการที่ตรงกันเหล่านี้ นี่อาจเป็นรูปแบบและถูกเปรียบเทียบเป็นนิพจน์ทั่วไปที่ไม่ตรงตามตัวพิมพ์ใหญ่ - เล็ก

หากต้องการค้นหารูปแบบ 'อัลฟา' ในโซนคณิตศาสตร์ที่คุณสามารถทำได้

:JJSyntaxSearch alpha texMathZone.

ที่สิ้นสุดเป็นอะตอมรูปแบบสำหรับอักขระตัวเดียวดู. :help /.นี้เป็นเพราะมีรายการไวยากรณ์โซนคณิตศาสตร์หลายคนเรียกtexMathZoneA, texMathZoneBฯลฯ

search()ฟังก์ชั่นย้ายเคอร์เซอร์ไปถัดไป 'สามัญ' การแข่งขัน synstack()จากนั้นฟังก์ชั่นของเราได้รับทุกรหัสรายการไวยากรณ์สำหรับที่ตำแหน่งของเคอร์เซอร์ใหม่ที่มี วนลูปผ่านมันเรียกชื่อของแต่ละรายการในทางกลับกันและทดสอบกับsyntaxitemอาร์กิวเมนต์ ดูและ:help synstack() :help synIDattr()หากมีการจับคู่ 'ที่ผ่านการรับรอง' จะส่งคืนหมายเลขบรรทัด ถ้ามันถึงจุดสิ้นสุดของบัฟเฟอร์โดยไม่ต้องค้นหาใด ๆ ที่มีคุณภาพ 0'การแข่งขันก็จะส่งกลับ จุดของฟังก์ชั่นคือการเลื่อนเคอร์เซอร์ไปที่การแข่งขัน 'ที่ผ่านการรับรอง' ครั้งต่อไปเพื่อให้คุณสามารถดำเนินการบางอย่างได้ แต่จะมีประโยชน์ในการส่งกลับ "หมายเลขบรรทัดหรือ 0" เพื่อระบุว่ามีความหมายที่จะเรียกใช้ฟังก์ชันอีกครั้งหรือไม่ อินสแตนซ์ถ้าคุณต้องการเรียกใช้ฟังก์ชั่นซ้ำ ๆ จากฟังก์ชั่นอื่นหรือแมโคร

ฉันเลือกที่จะใช้การWตั้งค่าสถานะสำหรับการsearch()ป้องกันการ 'ล้อมรอบ' จุดสิ้นสุดของบัฟเฟอร์ มิฉะนั้นฟังก์ชั่นอาจจะติดอยู่เพราะมันค้นหาการแข่งขัน 'สามัญ' ที่เหมือนกัน แต่ไม่มีการจับคู่ 'ที่ผ่านการรับรอง'


ขอบคุณสำหรับความช่วยเหลือของคุณ! ฉันยังไม่ได้ลองใช้ฟังก์ชั่นนี้ แต่ดูเหมือนว่าฉันต้องการ
Rob F.

vimtips วิกิพีเดียในการค้นหาไวยากรณ์:
joeytwiddle

1

ในกรณีที่ "พื้นที่ทางคณิตศาสตร์" ของคุณผ่านการรับรองโดยรูปแบบการสร้างประโยคเช่นสตริง "คณิตศาสตร์" อย่างน้อยคุณก็สามารถใช้ลำดับของรูปแบบเพื่อค้นหาบรรทัดที่มีรูปแบบการจับคู่ได้เช่นใน:

:/math//your pattern/

(หมายเหตุ: ทั้งสองรูปแบบอาจแตกต่างกัน!)

สิ่งนี้อาจไม่ จำกัด การแข่งขันของคุณไปยังโซน - สำหรับสิ่งที่คุณต้องระบุจุดสิ้นสุดของโซน - แต่มันจะแสดงเฉพาะการแข่งขันเหล่านั้นหลังจากรูปแบบเริ่มต้น / คณิตศาสตร์ / คุณสามารถค้นหาการเกิดซ้ำครั้งถัดไปซ้ำได้โดยใช้ประวัติโหมดอดีต ( : up-arrow enter)


หมายเหตุ: ISTR ที่ในเวอร์ชัน vim / vi ก่อนหน้านี้ฉันยังสามารถใช้วิธีดังกล่าวโดยตรงเป็นคำสั่งการค้นหา (ซึ่งต่างจากคำสั่งโหมดอดีต) /math//your pattern/ด้วยข้อดีของการพิมพ์และการใช้คำสั่งnและน้อยลงNแต่ฉันไม่สามารถยืนยันได้ สำหรับเวอร์ชันเสียงเรียกเข้าปัจจุบันของฉัน


1

หากคุณกำลังค้นหาสตริงที่fooอยู่ภายใน$...$หรือ$$...$$ควรดำเนินการดังนี้

\$.*\zsfoo

นี่เป็นการจับคู่กับ$อักขระ แต่เลือกสตริงfooเท่านั้น

มันไม่ใช่วิธีง่าย ๆ แต่สามารถใช้:global+ :substituteเพื่อค้นหา "โซนคณิตศาสตร์" และค้นหาภายใน:

:global /\v\\begin\{%(align|alignat|displaymath)\}/ +1,/\\end/-1 s/foo/&/gc

แสร้งทำเป็นว่า:substituteเป็นคำสั่งค้นหาคุณสามารถไปที่เกิดขึ้นต่อไปด้วยและเลิกกับn qหากคุณยืนยันการเปลี่ยนตัวโดยไม่ตั้งใจจะไม่มีปัญหาใด ๆ

คุณจะต้องตั้งอยู่ภายในรายการ%(... )ชื่อของสภาพแวดล้อมทางคณิตศาสตร์ที่คุณใช้ (รายการเต็มรูปแบบเป็นบิตหนัก: align|alignat|displaymath|eqnarray|equation|flalign|gather|math|multline|subequations|xalignat|xxalignat) โปรดทราบว่าฉันใช้\vรูปแบบเวทย์มนตร์ ( ) ที่นี่มาก

คำอธิบาย:

:globalรันคำสั่ง Ex ( :s) ในแต่ละบรรทัดที่ตรงกับรูปแบบ ( :help :global)
/\vเริ่มต้นรูปแบบมายากลมาก ( :h /, :h pattern, :h magic)
\\begin\{ตรงกับตัวอักษร\begin{
%(align|alignat|displaymath)การแข่งขันใด ๆ ของคำเหล่านี้ ( :h /\%(, :h /bar)
\}/ตรงกับตัวอักษร}และจบรูปแบบ

+1,/\\end/-1ช่วงประกอบด้วยบรรทัดถัดไป (นับจากที่พบโดย:global) /\\endถึงเส้นก่อนที่หนึ่งที่พบได้โดยรูปแบบการค้นหา ภายในช่วงนั้น

s/foo/&/gcค้นหาและแทนที่ตัวอักษรทุกตัวที่เกิดขึ้นfooด้วยตัวเองหลังจากการยืนยัน ( :h :substitute)


นี่เป็นการเริ่มต้นอย่างแน่นอน แต่ฉันใช้สภาพแวดล้อมสมการจัดและ IEEEeqnarray บ่อยครั้งและฉันไม่ต้องการแยกสิ่งเหล่านั้นออกจากการค้นหาของฉัน
Rob F.

@RobF: มันค่อนข้างเป็นไปได้ที่จะจับคู่ในช่วงของสภาพแวดล้อมต่าง ๆ แต่มันจะไม่ง่ายถ้ามีสคริปต์เดียว อย่างไรก็ตามหากคุณใช้\mathitชื่อตัวแปรอย่างสม่ำเสมอการค้นหาพวกมันจะง่ายกว่ามาก
Peter Lewerin

0

หากคุณกำลังค้นหาไฟล์ 'Morning' ในไฟล์ /morningจากนั้นenterกดnเพื่อเลื่อนไปข้างหน้า


1
คำถามที่ว่าI would like to search only in "math zones"วิธีการของคุณค้นหาไฟล์ทั้งหมดมันไม่ได้กำหนดเขตการวิจัย
statox

0

ไม่มีตัวเลือกนอกจากเขียนฟังก์ชั่นเฉพาะสำหรับสิ่งนี้ ฉันเขียนฟังก์ชันที่ค้นหาสตริงที่คุณต้องการและจะหยุดก็ต่อเมื่อ:

  1. มันหมดการแข่งขัน
  2. มีการแข่งขันซึ่งอยู่ในสภาพแวดล้อมทางคณิตศาสตร์ (มันจะหยุดในการแข่งขัน)

คุณเพียงแค่เรียกมันด้วยสตริงที่คุณต้องการค้นหา

function! Finmath(nextstr)
    while 1
        if search(a:nextstr)==0
            break
        endif
        if searchpairpos('\(', '','\)','n')!=[0,0]
            break
        endif
        if searchpairpos('\[', '','\]','n')!=[0,0]
            break
        endif
        let a = getcurpos() 
        if count(strpart(getline('.'),0,a[2]),'$')%2==1
            break
        endif 
    endwhile 
endfunction

ฉันตั้งใจจะเขียนฟังก์ชั่นที่คล้ายกันสำหรับ GrammerousCheck ซึ่งจะหยุดเฉพาะกับข้อผิดพลาดทางไวยากรณ์นอกคณิตศาสตร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.