วิธีแก้ไข elisp โดยไม่หลงทางในวงเล็บ


13

ฉันกำลังแก้ไขโค้ด elisp จาก linum.el:

(custom-set-variables '(linum-format 'dynamic))
(defadvice linum-update-window (around linum-dynamic activate)
   (let* ((w (length (number-to-string
      (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (concat " %" (number-to-string w) "d ")))
            ad-do-it))

ผมสามารถที่จะแก้ไขข้อผิดพลาดที่เยื้องถูกปิดโดยหนึ่งโดยการปรับเปลี่ยนไป(count-lines (point-min) (point-max)) (+ (count-lines (point-min) (point-max)) 1)นั่นเป็นเรื่องง่าย

แต่ตอนนี้ฉันต้องการแก้ไขเพื่อให้ความกว้างต่ำสุดคือ 2 โดยการเพิ่ม if-conditional โดยที่(concat " %" (number-to-string w) "2d ")ถ้าจำนวนบรรทัดเป็น <10

มันควรจะง่ายนะ! เพิ่มหนึ่งเงื่อนไขและคัดลอก / วาง concat เค้กชิ้นใช่มั้ย ฉันหมายถึงฉันรู้ว่าฉันควรจะทำอะไร แต่ฉันไม่ค่อยได้สัมผัสกับ elisp และฉันมักจะหวาดกลัวเมื่อฉันต้องแก้ไขสิ่งใด ๆ

สไตล์ "ถูกต้อง" จากสิ่งที่ฉันเข้าใจคือการจัดโครงสร้างโค้ดตามการเยื้องและล้อมรอบวงเล็บท้ายท้ายบรรทัดแทนที่จะเป็นของมันเอง มาจากภาษาสไตล์ 'C' อื่น ๆ ฉันต่อสู้กับทั้งการอ่านและการเขียนโค้ดด้วยวิธีนี้ ดังนั้นคำถามของฉันคือฉันกำลังทำอะไรผิด ฉันควรจะแก้ไข elisp และนำทางไปรอบ ๆ โค้ดอย่างไรโดยที่ฉันไม่ต้องนั่งที่นั่นและนับทุกวงเล็บ

เมื่อฉันทำงานกับบางสิ่งบางอย่างใน elisp ที่ลึกเกินไปฉันต้องปิดประตูดึงผ้าม่านและเริ่มวางตำแหน่งวงเล็บ K & R-style เพื่อที่ฉันจะได้ไม่เพียง แต่อ่าน แต่แก้ไขสิ่งที่สาปโดยไม่ต้องออกนอกลู่นอกทาง

เห็นได้ชัดว่าฉันทำผิดทั้งหมด ฉันจะสัมผัสเอลลิสแบบนี้ได้อย่างไรโดยไม่ต้องกลัว

โปรดทราบว่าคำถามของฉันคือวิธีการนำทางและแก้ไข elisp ไม่ใช่คำถามอย่างมีสไตล์ ฉันใช้คำแนะนำสไตล์ต่อไปนี้แล้ว: https://github.com/bbatsov/emacs-lisp-style-guide

ปรับปรุง:

วิธีการจัดรูปแบบ elisp อย่างถูกต้องก่อนที่จะทำการอายบน emacs.stackexchange:

ทำเครื่องหมาย Elisp M-x indent-regionคุณและดำเนินการ

ทางออกของปัญหา:

สำหรับผู้ที่ต้องการทราบวิธีดำเนินการปรับชิดขวาสำหรับ linum ที่มีความกว้างอย่างน้อยสองตัวนี่คือคำตอบ:

(defadvice linum-update-window (around linum-dynamic activate)
  (let* ((w (length (number-to-string
                     (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (if (> w 1)
                           (concat " %" (number-to-string w) "d ")
                         " %2d ")))
    ad-do-it))

1
ทุกคนต้องดิ้นรนกับการอ่านเสียงกระเพื่อมที่มาจาก C. มันต้องใช้เวลา แต่ในที่สุดมันก็กลายเป็นเรื่องธรรมดามาก นอกจากนี้คุณยังสามารถแก้ปัญหาของคุณได้โดยเปลี่ยนรูปแบบ linum เป็นสตริงรูปแบบเช่น "% 2d"
Jordon Biondo

ฉันไม่สามารถใช้เพียง%2dเพราะเมื่อความกว้างเลื่อนไปถึง 3 ตัวอักษรหรือมากกว่านั้นมันจะย้ายจากนำมาชิดขวาไปทางซ้ายชิดขอบ
Zhro

มีบางห้องสมุดที่เน้นวงเล็บที่ตรงกันซึ่งมีค่า (ในความคิดของฉัน), เช่น, highlight-parentheses; rainbow-delimiters; เป็นต้นนี่คือเวอร์ชั่นที่เรียบง่ายของฉันเองhighlight-parenthesesที่อนุญาตให้เลื่อนโดยไม่ต้องลบวงเล็บที่เป็นสีสุดท้าย: stackoverflow.com/a/23998965/2112489 ในอนาคตมีคำถามหนึ่งข้อต่อลูกค้า / เธรด
กฎหมาย

1
ฟังดูเหมือนปัญหาของคุณกำลังอ่านอยู่จริงๆไม่ใช่การแก้ไขรหัส Elisp คุณฟังดูเหมือนว่าคุณมีปัญหาในการเข้าใจโครงสร้างของ Lisp และนั่นทำให้การแก้ไขของคุณแย่ลง
PythonNut

1
ในการป้องกันของคุณนั่นเป็นรหัสที่เว้า ๆ แหว่ง ๆ ฉันอ่านผิดไปเอง 3 ครั้งแรกเพราะเรื่องนั้น นอกจากนี้paredit
Malabarba

คำตอบ:


12

มีแพ็กเกจเสริมจำนวนมากที่อาจช่วยได้เช่น paredit, smartparens และ lispy แพ็กเกจเหล่านี้ช่วยให้นำทางและจัดการกับ lisp code ได้ง่ายขึ้นเพื่อให้คุณสามารถคิดในรูปแบบ s-expressions และให้ผู้แก้ไขกังวลเกี่ยวกับการทำ parens parens

Emacs ยังมีคำสั่งในตัวมากมายสำหรับจัดการกับ sexps และรายการที่ควรค่าแก่การเรียนรู้และอาจช่วยให้คุณคุ้นเคยกับโครงสร้างของรหัส lisp มากขึ้น โดยทั่วไปจะมีC-M-คำนำหน้าผูกไว้เช่น:

  • C-M-f/ C-M-bเพื่อเลื่อนไปข้างหน้า / ย้อนหลังโดย sexp
  • C-M-n/ C-M-pเพื่อเลื่อนไปข้างหน้า / ถอยหลังตามรายการ
  • C-M-u/ C-M-dเพื่อเลื่อนขึ้น / ลงหนึ่งระดับ
  • C-M-t เพื่อสลับสอง sexps รอบ ๆ จุด
  • C-M-k เพื่อฆ่า sexp
  • C-M-SPC เพื่อทำเครื่องหมาย sexp
  • C-M-q เพื่อเยื้อง sexp อีกครั้ง

โค้ดตัวอย่างที่คุณระบุอาจชัดเจนขึ้นหากคุณแก้ไขการเยื้อง: ใส่จุดที่จุดเริ่มต้นของ(defadvice...และกดC-M-qเพื่อเยื้องการแสดงออกทั้งหมด เพื่อแทนที่(concat...ฉันจะเริ่มต้นด้วยการวางจุดเริ่มต้นของ sexp ที่และกดปุ่มC-M-oเพื่อแยกบรรทัดในขณะที่รักษาการเยื้อง จากนั้นเพิ่มของคุณ(if...และใช้คำสั่งด้านบนเพื่อข้ามไปยังจุดสิ้นสุดของรายการเพื่อเพิ่ม paren การปิดอื่นกลับไปที่จุดเริ่มต้นเพื่อเยื้องและอื่น ๆ

คุณอาจต้องการเปิดshow-paren-modeซึ่งจะเน้น paren ที่เกี่ยวข้องเมื่อจุดอยู่ที่จุดเริ่มต้นหรือจุดสิ้นสุดของรายการ show-paren-styleคุณอาจต้องการที่จะเน้นการแสดงออกทั้งหมดแทนที่จะวงเล็บที่ตรงกันจึงพยายามปรับแต่ง

ตามที่ @Tyler ได้กล่าวถึงในความคิดเห็นเกี่ยวกับคำตอบอื่นคุณควรดูคู่มือเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับคำสั่งเหล่านี้และคำสั่งที่เกี่ยวข้อง


โปรดทราบว่าC-M-qสามารถเรียกได้ด้วยอาร์กิวเมนต์นำหน้า ( C-u C-M-q) เพื่อพิมพ์พจน์ที่จุด การทำเช่นนี้จะทำให้ทุกสิ่งทุกอย่างแยกออกจากกันและเยื้องเพื่อให้การทำรังมีความชัดเจนมาก โดยทั่วไปคุณไม่ต้องการให้เสียงกระเพื่อมรหัสของคุณเป็นเช่นนั้น แต่มันอาจเป็นประโยชน์ในการทำความเข้าใจบิตของรหัสโดยไม่ต้องไปเต็ม K&R ด้วยตนเอง (และคุณสามารถC-x uยกเลิกได้เสมอ)
ลูกัส

6

วิธีที่ดีในการแก้ไข LISP คือการจัดการ AST แทนที่จะใช้อักขระหรือบรรทัดแต่ละบรรทัด ฉันได้ทำอย่างนั้นกับแพ็คเกจของฉัน lispyที่ฉันเริ่ม 2 ปีที่ผ่านมา ฉันคิดว่าจริง ๆ แล้วมันอาจใช้เวลาสักหน่อยในการฝึกฝนเพื่อเรียนรู้วิธีการทำสิ่งนี้ให้ดี แต่การใช้เพียงแค่พื้นฐานก็น่าจะช่วยคุณได้อยู่แล้ว

ฉันสามารถอธิบายได้ว่าฉันจะดำเนินการเปลี่ยนแปลงอย่างไร:

ขั้นตอนที่ 1

ตำแหน่งเริ่มต้นมักจะมีจุดก่อน sexp ระดับบนสุด นี่|คือประเด็น

|(defadvice linum-update-window (around linum-dynamic activate)
   (let* ((w (length (number-to-string
      (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (concat " %" (number-to-string w) "d ")))
            ad-do-it))

คุณจะต้องมีการเยื้องรหัสอย่างถูกต้องดังนั้นกดiหนึ่งครั้ง มันจะเยื้องมันอย่างใหม่

ขั้นตอนที่ 2

คุณจะต้องการทำเครื่องหมาย"d "ด้วยภูมิภาคเนื่องจากวัตถุที่สามารถจัดการlispyได้เป็นรายการซึ่งไม่จำเป็นต้องทำเครื่องหมายหรือลำดับของสัญลักษณ์หรือ / และรายการที่ต้องทำเครื่องหมายด้วยภูมิภาค

กดatเพื่อทำเช่นนั้น aคำสั่งช่วยให้การทำเครื่องหมายสัญลักษณ์ใด ๆ เดียวในรายการแม่และtเป็นดัชนีของสัญลักษณ์นี้โดยเฉพาะอย่างยิ่ง

ขั้นตอนที่ 3

  1. การห่อภูมิภาคในปัจจุบันมีการกด()(
  2. กดที่จะก้าวไปข้างหน้าหนึ่งถ่านและแทรกC-fif
  3. กดอีกครั้งเพื่อแทรก(()
  4. > w 10แทรก
  5. C-f C-m เพื่อย้ายสตริงไปยังบรรทัดใหม่

ขั้นตอนที่ 4

วิธีโคลนสตริง:

  1. M-mทำเครื่องหมายสัญลักษณ์หรือสตริงที่จุดที่มี
  2. cกด

หากคุณต้องการปิดการใช้งานภูมิภาคอย่างสวยงามและใส่จุดเริ่มต้นของสตริงคุณสามารถกดidm:

  1. i จะเลือกเนื้อหาภายในของสตริง
  2. d จะสลับจุดและทำเครื่องหมาย
  3. m จะปิดการใช้งานภูมิภาค

หรือคุณอาจจะทำในกรณีนี้หรือm C-b C-b C-b C-g C-b C-b C-bฉันคิดว่าidmดีกว่าเนื่องจากมันเหมือนกันโดยไม่คำนึงถึงความยาวของสตริง ฉันคิดว่าC-x C-x C-f C-g จะทำงานโดยไม่คำนึงถึงความยาวสตริง

สุดท้ายแทรก2เพื่อรับรหัสสิ้นสุด:

(defadvice linum-update-window (around linum-dynamic activate)
  (let* ((w (length (number-to-string
                     (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (concat " %" (number-to-string w) (if (> w 10)
                                                             "2|d "
                                                           "d "))))
    ad-do-it))

สรุป

ลำดับเต็ม: at( C-f, if, (, > w 10, ,C-f C-m M-m cidm2

โปรดทราบว่าถ้าคุณนับจากการแทรกโค้ดปุ่มเพียงไม่เกี่ยวข้องกับการจัดการ AST สองและเป็นหนึ่งในC-fC-m


3
Lispy ฟังดูน่าสนใจ! ไปที่ OP: คุณสามารถพัฒนาเวิร์กโฟลว์ที่คล้ายกันด้วย paredit: emacsrocks.com/e14.htmlและขยายขอบเขต: github.com/magnars/expand-region.elหรือเพียงแค่เล่นกับคำสั่งวงเล็บที่จับคู่ในตัว: gnu org / software / emacs / manual / html_node / emacs / Parentheses.html
Tyler

ฉันแน่ใจว่าคุณคาดเดาเมื่อคุณเชื่อมโยงกับการแก้ปัญหาสำหรับฉัน ขอบคุณสำหรับความพยายาม ฉันจัดการยุ่งเหยิงทางของฉันผ่านมันโดยใช้รหัสของคุณเป็นตัวอย่าง ดูการอัปเดตของฉันสำหรับวิธีแก้ไขปัญหาที่ถูกต้อง
Zhro

6

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

รอยหยัก

มีวิธีการบ้านี้ ในเสียงกระเพื่อมคุณสามารถทำสิ่งนี้:

(a-fun (another-fun (magic-macro 1)))

สมมติว่า1เป็นนิพจน์ที่มีขนาดใหญ่จริงๆและคุณต้องการเยื้องลงบนบรรทัดของมันเอง

(a-fun (another-fun (magic-macro 
  1)))

นี่เป็นสิ่งที่ทำให้เข้าใจผิด 1มีการเยื้องเพียงช่องเดียวเท่านั้นถึงแม้ว่ามันจะมีทั้งสามระดับของการซ้อนที่สูงขึ้น! ดีกว่าวางโดยผู้ปกครองของมัน

(a-fun (another-fun (magic-macro 
                      1)))

หากเราใช้รูปแบบนี้กับรหัสของคุณเราจะได้รับ:

(custom-set-variables '(linum-format 'dynamic))
(defadvice linum-update-window (around linum-dynamic activate)
  (let* ((w (length (number-to-string
                      (+ (count-lines (point-min) (point-max)) 1))))       
          (linum-format 
            (concat " %" (number-to-string w) "d ")))
     ad-do-it))

สังเกตความสัมพันธ์ที่ดีระหว่างการเยื้องกับระดับของการซ้อน เส้นที่มีการซ้อนในระดับที่สูงกว่าจะถูกเยื้องเสมอมากกว่าเส้นที่มีน้อย

เพียงอย่างเดียวนี้จะช่วยได้มาก คุณสามารถดู "รูปร่าง" ของรหัสได้อย่างง่ายดายและภาษาอื่น ๆ ส่วนใหญ่ได้ฝึกให้คุณเชื่อมโยงการเยื้องกับบล็อกและบล็อกด้วยรูปแบบการซ้อนบางอย่าง (ชัดเจนหรือโดยนัย)

ในการออกกำลังกายฉันได้ลบวงเล็บที่ไม่จำเป็นออกจากโค้ด คุณควรจะสามารถอ่านโค้ดและใส่วงเล็บที่หายไปให้ได้รับความรู้พื้นฐานของ Elisp (กล่าวคืออะไรคือฟังก์ชั่นและค่านิยมและโครงสร้างของlet*)

custom-set-variables '(linum-format 'dynamic)
defadvice linum-update-window (around linum-dynamic activate)
  let* w length number-to-string
                  + 
                    count-lines (point-min) (point-max) 
                    1       
         linum-format 
           concat " %" (number-to-string w) "d "
     ad-do-it

1
โปรดทราบว่าใน Emacs แท็บการกดปุ่มจะตั้งค่าการเยื้องอย่างถูกต้องตามที่อธิบายไว้ที่นี่ - คุณไม่ควรเพิ่มการเว้นวรรคด้วยมือ!
ไทเลอร์

ผูก "ซม." เป็นnewline-and-indentสำหรับ emacs-lisp-mode และ lisp-interaction-mode แก้ปัญหา PythonNut ตัวอย่างแรกของคุณ และ TAB จะทำงานตลอดเวลาที่เหลือ
Davor Cubranic

5

ฉันรวมนี่เป็นคำตอบที่แตกต่างกัน

บางครั้งการเยื้องอาจทำให้คุณล้มเหลว การขอความช่วยเหลือจากคุณคือการใช้สิ่งที่ชอบrainbow-delimiters:

ป้อนคำอธิบายรูปภาพที่นี่

นี่ทำให้ระดับการซ้อนของ paren ใด ๆ ชัดเจนและสแกนได้ง่าย

แม้ว่าจะมีปัญหาใหญ่อยู่หนึ่งอย่าง: การล้อเลียนทำให้เสียสมาธิอย่างน่าหัวเราะ มีความสมดุลของการเน้นที่นี่ rainbow-delimitersปกติจะใส่มากเน้น parens ที่ค่าใช้จ่ายส่วนที่เหลือของรหัสของคุณ! แต่ถ้าคุณลดโทนสีรุ้งลงก็จะสแกนยากขึ้น

หากคุณสามารถหาใบหน้าหนึ่งชุดที่มีความสมดุลย์ได้ดีก็ให้ใช้มัน

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

ป้อนคำอธิบายรูปภาพที่นี่

แต่เมื่อคุณวางจุดบน paren มันเจาะ parens เพื่อให้คุณสามารถดูระดับการซ้อน:

ป้อนคำอธิบายรูปภาพที่นี่

และนี่คือรหัสที่จะทำ:

(defvar rainbow-delimiters-switch nil
  "t if rainbow-delimiters are currently punched")
(defvar rainbow-delimiters-face-cookies nil
  "a list of face-remap-add-relative cookies to reset")

(make-variable-buffer-local 'rainbow-delimiters-switch)
(make-variable-buffer-local 'rainbow-delimiters-face-cookies)

(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
(add-hook 'text-mode-hook #'rainbow-delimiters-mode)

(with-eval-after-load 'rainbow-delimiters
  (set-face-foreground 'rainbow-delimiters-depth-1-face "#889899")
  (set-face-foreground 'rainbow-delimiters-depth-2-face "#9b7b6b")
  (set-face-foreground 'rainbow-delimiters-depth-3-face "#7b88a5")
  (set-face-foreground 'rainbow-delimiters-depth-4-face "#889899")
  (set-face-foreground 'rainbow-delimiters-depth-5-face "#839564")
  (set-face-foreground 'rainbow-delimiters-depth-6-face "#6391aa")
  (set-face-foreground 'rainbow-delimiters-depth-7-face "#9d748f")
  (set-face-foreground 'rainbow-delimiters-depth-8-face "#7b88a5")
  (set-face-foreground 'rainbow-delimiters-depth-9-face "#659896")

  (defun rainbow-delimiters-focus-on ()
    "Punch the rainbow-delimiters"
    (setq rainbow-delimiters-face-cookies
      (list
        (face-remap-add-relative 'rainbow-delimiters-depth-1-face
          '((:foreground "#3B9399") rainbow-delimiters-depth-1-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-2-face
          '((:foreground "#9B471D") rainbow-delimiters-depth-2-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-3-face
          '((:foreground "#284FA5") rainbow-delimiters-depth-3-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-4-face
          '((:foreground "#3B9399") rainbow-delimiters-depth-4-face))
            (face-remap-add-relative 'rainbow-delimiters-depth-5-face
          '((:foreground "#679519") rainbow-delimiters-depth-5-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-6-face
          '((:foreground "#0E73AA") rainbow-delimiters-depth-6-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-7-face
          '((:foreground "#9D2574") rainbow-delimiters-depth-7-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-8-face
          '((:foreground "#284FA5") rainbow-delimiters-depth-8-face))
        (face-remap-add-relative 'rainbow-delimiters-depth-9-face
          '((:foreground "#199893") rainbow-delimiters-depth-9-face)))
      rainbow-delimiters-switch t))

  (defun rainbow-delimiters-focus-off ()
    "Reset the rainbow-delimiters faces"
    (mapc #'face-remap-remove-relative rainbow-delimiters-face-cookies)
    (setq rainbow-delimiters-switch nil))

  (defun rainbow-delimiters-focus-on-maybe ()
    "Punch the rainbow-delimiters if the point is on a paren"
    (when (looking-at "[][(){}]")
      (unless (or rainbow-delimiters-switch (minibufferp))
        (rainbow-delimiters-focus-on))))

  (defun rainbow-delimiters-focus-off-maybe ()
    "Reset the rainbow-delimiters if the point is not on a paren"
    (unless (looking-at "[][(){}]")
      (when rainbow-delimiters-switch
        (rainbow-delimiters-focus-off))))

  (run-with-idle-timer 0.6 t 'rainbow-delimiters-focus-on-maybe)
  (run-with-idle-timer 0.1 t 'rainbow-delimiters-focus-off-maybe))

ที่นี่หนาว! เหตุผลใดที่คุณเลือกตัวคั่นแบบเรนโบว์บนไฮไลต์วงเล็บในการเริ่มต้นด้วย
ไทเลอร์

@ ไทเลอร์ไม่มีเหตุผลพิเศษแม้ว่าฉันจะยังคงติดอยู่กับตัวคั่นสายรุ้ง (แต่นั่นอาจเป็นเพราะฉันชินกับมัน) ฉันไม่เคยได้ยินชื่อไฮไลต์ - วงเล็บจนกระทั่งเมื่อไม่นานมานี้
PythonNut

4

หากคุณเยื้องรหัสของคุณแล้วคุณจะต้องเยื้องมันอย่างถูกต้อง นักพัฒนาเสียงกระเพื่อมมีความคาดหวังสิ่งที่เยื้องอย่างถูกต้องควรมีลักษณะ นี่ไม่ได้หมายความว่ารหัสจะเหมือนกันทุกประการ การฟอร์แมตโค้ดยังมีวิธีที่แตกต่างกัน

  • บรรทัดควรมีความยาวเท่าใด
  • วิธีการกระจายฟังก์ชั่น / โทรแมโครผ่านสาย?
  • ควรมีการเว้นวรรคกี่ย่อหน้า
(defadvice linum-update-window (around linum-dynamic activate)
   (let* ((w (length (number-to-string
      (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (concat " %" (number-to-string w) "d ")))
            ad-do-it))

ฉันคาดหวังว่าการเยื้องจะแสดงการกักกันในบางวิธี แต่ไม่ใช่ในรหัสของคุณ

โดยค่าเริ่มต้นรหัสของคุณอาจเยื้องเช่นนี้ คำตอบอื่น ๆ อธิบายว่าคุณสามารถทำได้ด้วยความช่วยเหลือของ Emacs:

(defadvice linum-update-window (around linum-dynamic activate)
  (let* ((w (length (number-to-string
                     (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (concat " %" (number-to-string w) "d ")))
    ad-do-it))

ฉันคาดหวังว่าletตัวแปรที่ถูกผูกไว้จะเริ่มต้นในคอลัมน์แนวตั้งเดียวกัน ฉันก็คาดหวังว่าร่างของletเยื้องจะน้อยลง เราเรียนรู้วิธีการletเยื้อง เมื่อคุณฝึกฝนเล็กน้อยแล้วมันเป็นรูปแบบภาพที่จดจำได้ง่าย

อาคารหลักบล็อกภาพในรหัสที่มีdefadvice, let*และพวงของฟังก์ชั่นการโทร defในชื่อบอกฉันว่ามันเป็นคำนิยามตามด้วยชื่อรายการอาร์กิวเมนต์และร่างกาย

ดังนั้นฉันชอบที่จะเห็น

defadvice name arglist
  body

let*จะเป็น: let*รายชื่อของการผูกและร่างกายที่

ดังนั้นฉันชอบที่จะเห็น:

let*  list of bindings
  body

รายละเอียดเพิ่มเติม:

let*   binding1
       binding2
       binding3
  body

ฟังก์ชั่นการโทรฉันชอบที่จะเห็น:

FUNCTIONNAME ARG1 ARG2 ARG3

หรือ

FUNCTIONNAME ARG1
             ARG2
             ARG3

หรือ

FUNCTIONNAME
  ARG1
  ARG2
  ARG3

ข้อใดที่ได้รับการใช้ขึ้นอยู่กับระยะเวลาของข้อโต้แย้ง เราไม่ต้องการให้เส้นยาวเกินไปและแต่ละอาร์กิวเมนต์บนเส้นของมันเองทำให้เรามีโครงสร้างมากขึ้น

ดังนั้นคุณต้องเขียนรหัสโดยใช้รูปแบบเหล่านั้นและคุณต้องตรวจสอบให้แน่ใจว่าผู้อ่านสามารถระบุรูปแบบเหล่านั้นในรหัสของคุณได้อย่างง่ายดาย

วงเล็บควรแนบโครงสร้างโดยตรง

(sin 10)

(sin
  10)

หลีกเลี่ยงตัวอย่างของช่องว่าง:

(  sin 10  )

หรือ

(
   sin
)

หรือ

(sin 10
)

ในเสียงกระเพื่อมวงเล็บไม่มีฟังก์ชั่นไวยากรณ์ภาษาพวกเขาเป็นส่วนหนึ่งของไวยากรณ์ของโครงสร้างข้อมูลรายการ (s- นิพจน์) ดังนั้นเราจึงเขียนรายการและจัดรูปแบบรายการ สำหรับการจัดรูปแบบเนื้อหาของรายการเราใช้ความรู้เกี่ยวกับภาษาการเขียนโปรแกรม Lisp letแสดงออกควรมีรูปแบบที่แตกต่างจากการเรียกฟังก์ชั่น ทั้งคู่ยังคงเป็นรายการและวงเล็บควรอยู่ในรายการโดยตรง มีตัวอย่างบางส่วนที่เหมาะสมที่จะมีวงเล็บเดียวในบรรทัด แต่ใช้บ่อยมาก

ใช้วงเล็บเพื่อสนับสนุนการค้นหาขอบเขตการแสดงออก ให้พวกเขาช่วยคุณย้ายจากลิสต์ไปยังลิสต์เพื่อแก้ไขลิสต์เพื่อตัด & คัดลอกลิสต์เพื่อแทนที่ลิสต์เพื่อเยื้อง / จัดรูปแบบลิสต์เลือกลิสต์ ...


2

สำหรับความช่วยเหลือเบื้องต้นเกี่ยวกับการเยื้องให้ใช้ TAB และ "CMq" ( indent-pp-sexp); การผูก "Cm" เพื่อnewline-and-indentช่วยให้คุณไม่ต้องกด TAB หลังจากขึ้นบรรทัดใหม่

คุณสามารถนำทางด้วย sexp ด้วย "CM-left / right / up / down / home / end" ซึ่งมีประโยชน์มาก

หากคุณกำลังกังวลเกี่ยวกับการรักษาความสมดุลวงเล็บใช้งานบางอย่างเช่นsmartparens (มันมากขึ้นอีกนิดว่าให้อภัยpareditซึ่งสมัยก่อนสามารถรู้สึกเหมือนสวมพระที่นั่งก) นอกจากนี้ยังมาพร้อมกับการผูกจำนวนมากสำหรับการนำทางและแก้ไขในระดับ sexp

สุดท้ายสำหรับการไฮไลต์ parens ให้เริ่มต้นโดยการเปิดตัวเลือก (เมนูตัวเลือก -> ไฮไลต์วงเล็บที่ตรงกันหรือshow-paren-mode.) คุณยังสามารถใช้แพ็คเกจใดแพ็คเกจหนึ่งที่ระบุโดยกฎหมายในความคิดเห็นของเขาเช่น "ไฮไลต์วงเล็บ -" หรือ "ตัวคั่นสายรุ้ง" "


1

นอกเหนือจากสิ่งที่ผู้อื่นให้ไว้เป็นคำตอบนี่คือ 2 เซ็นต์ของฉัน:

  • การเยื้องอัตโนมัติที่จัดทำโดยemacs-lisp-modeเป็นสิ่งจำเป็น
  • blink-matching-parenเปิดอยู่ (ไม่ใช่ - nil) โดยค่าเริ่มต้น ทิ้งไว้อย่างนั้น
  • ฉันใช้show-paren-modeเพื่อเน้น paren ซ้ายสอดคล้องกับ paren ขวาก่อนเคอร์เซอร์
  • ฉันลบและพิมพ์ paren ที่ถูกต้องอีกครั้งชั่วคราวก่อนเคอร์เซอร์ถ้าฉันต้องการดูที่ดีกว่าที่ paren ซ้ายที่ตรงกันอยู่

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

โดยเฉพาะอย่างยิ่งelectric-pair-modeคือสำหรับฉันรำคาญไม่สะดวก แต่บางคนก็รักมัน และฉันคิดว่ามันอาจจะมีประโยชน์ในบริบทการจับคู่อื่น ๆ นอกเหนือจากวงเล็บ Lisp (ฉันจินตนาการเช่นนั้น แต่ฉันไม่มั่นใจสำหรับกรณีการใช้งานเช่นนั้น)

คุณจะพบสิ่งที่ดีที่สุดสำหรับคุณ สิ่งสำคัญที่ฉันต้องการจะพูดคือ: (1) การเยื้องอัตโนมัติคือเพื่อนของคุณเช่นเดียวกับวิธีที่จะสังเกตเห็น paren ซ้ายที่ตรงกับ paren ที่ถูกต้องก่อนที่จะชี้

โดยเฉพาะอย่างยิ่งการเห็นว่าการเยื้องอัตโนมัติทำให้คุณสอนคุณทันทีว่าคุณไม่ต้องการที่จะวางคำอุปมาอีกต่อไป รูปแบบของการเข้ารหัสซึ่งแพร่หลายในภาษาอื่นนั้นเป็นที่น่ารำคาญ

นอกจากเยื้องอัตโนมัติที่คุณได้รับRETและได้รับความสะดวกสบายในการใช้TAB C-M-q(การใช้งานC-h kในemacs-lisp-modeการหาสิ่งที่คีย์เหล่านี้ทำ.)


1

ฉันสังเกตเห็นบางคนพูดถึงตัวคั่นรุ้งแล้วนั่นคือโหมดโปรดของฉันเมื่อแก้ไขรหัสเสียงกระเพื่อม

ที่จริงฉันรักวงเล็บสิ่งที่ดีที่สุดเกี่ยวกับ Lisp คือวงเล็บพวกนั้นสนุกที่จะจัดการกับมันถ้าคุณรู้วิธีการ:

  • ติดตั้งชั่วโหมดและปลั๊กอินชั่วร้ายโดยรอบเพื่อให้คุณสามารถแก้ไขได้อย่างง่ายดายวงเล็บเช่นกดci(จะลบทุกอย่างภายใน(), va(จะเลือกสิ่งที่ห่อด้วย "()" และ "()" ตัวเอง และคุณสามารถกด%เพื่อข้ามระหว่างวงเล็บที่จับคู่ได้

  • ใช้ flycheck หรือ flymake วงเล็บที่ไม่มีใครเทียบจะถูกขีดเส้นใต้ในเวลาจริง


0

sexpความยากลำบากที่นี่คือที่ที่คุณต้องการเพิ่มโค้ดบางส่วนก่อนและหลังการบางอย่าง ในสถานการณ์เช่นนี้ sexp (concat " %" (number-to-string w) "d ")คือ คุณต้องการแทรกคำสั่ง if- (if (> w 1)ก่อนหน้าและคำสั่ง else " %2d ")หลังจากนั้น

ส่วนสำคัญของความยากคือการแยกสิ่งนี้sexpโดยส่วนตัวผมใช้คำสั่งด้านล่างเพื่อแยกsexp

(defun isolate-sexp () (interactive)
       (save-excursion (forward-sexp) (if (not (eolp-almost))
               (split-line) nil)))
(defun eolp-almost () (interactive)
(save-excursion (while (equal (char-after) ? ) (forward-char 1))
        (if (eolp) t nil )      ))

เพียงแค่วางเคอร์เซอร์ที่จุดเริ่มต้นของการ(concat " %" (number-to-string w) "d ")คือในครั้งแรกแล้วใช้ด้านบน( isolate-sexpคุณได้รับ

(defadvice linum-update-window (around linum-dynamic activate)
   (let* ((w (length (number-to-string
      (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (concat " %" (number-to-string w) "d ")
                                  ))
            ad-do-it))

จากนั้นเพิ่มรหัสที่เหมาะสมก่อนและหลังนี้sexpคือ

(defadvice linum-update-window (around linum-dynamic activate)
   (let* ((w (length (number-to-string
      (+ (count-lines (point-min) (point-max)) 1))))
         (linum-format (if (> w 1) (concat " %" (number-to-string w) "d ") " %2d ")
                                  ))
            ad-do-it))

และ voila รหัสที่ได้รับในลักษณะนี้อาจไม่สวยงาม แต่โอกาสในการหลงทางมีน้อย

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