ไฮไลต์ตัวแปรเชลล์ภายในเครื่องหมายคำพูด


13

ในกลุ่มเอกสารต่อไปนี้จะทำให้$PWDบรรทัดบน 2 และ 3 เป็นสีในสองวิธีที่ต่างกัน:

#/bin/sh
echo "Current Directory: $PWD"
echo 'Current Directory: $PWD'

อินสแตนซ์แรกของ$PWDจะอยู่ในสีที่แตกต่างจากส่วนที่เหลือของสายมันสิ่งนี้ให้ข้อบ่งชี้ภาพที่ชัดเจนว่าตัวแปรจะขยายตัวมากกว่าถือว่าเป็นข้อความตัวอักษร ในทางตรงกันข้ามอินสแตนซ์ที่สองของ$PWDจะมีสีเหมือนกับส่วนที่เหลือของสตริงเนื่องจากเครื่องหมายคำพูดเดี่ยวทำให้ถือว่าเป็นข้อความตามตัวอักษร

มีโหมด emacs ที่มีอยู่แล้วหรือไม่ซึ่งให้ "การรับรู้ข้อความเปลือกหอย" ประเภทนี้?


1
แท้จริงนี้จะไม่เป็นชะมัดยากที่จะเพิ่มsh-mode? บางทีมันสามารถเพิ่มให้กับ Emacs ได้
PythonNut

คำตอบ:


11

รหัสด้านล่างใช้กฎตัวอักษรล็อคกับฟังก์ชั่นแทนการ regexp ฟังก์ชั่นการค้นหาสำหรับการเกิดขึ้น$VARแต่เฉพาะเมื่อพวกเขาอยู่ภายในสตริงที่ยกมาสองครั้ง ฟังก์ชั่นที่(syntax-ppss)ใช้ในการตรวจสอบนี้

กฎตัวอักษรล็อคใช้การprependตั้งค่าสถานะเพื่อเพิ่มตัวเองอยู่ด้านบนของการเน้นสตริงที่มีอยู่ (โปรดทราบว่าแพ็คเกจจำนวนมากใช้tสำหรับสิ่งนี้โชคไม่ดีที่สิ่งนี้จะเขียนทับทุกแง่มุมของการไฮไลต์ที่มีอยู่ตัวอย่างเช่นการใช้prependจะเก็บสีพื้นหลังของสตริง (หากมี) ในขณะที่เปลี่ยนสีพื้นหน้า)

(defun sh-script-extra-font-lock-is-in-double-quoted-string ()
  "Non-nil if point in inside a double-quoted string."
  (let ((state (syntax-ppss)))
    (eq (nth 3 state) ?\")))

(defun sh-script-extra-font-lock-match-var-in-double-quoted-string (limit)
  "Search for variables in double-quoted strings."
  (let (res)
    (while
        (and (setq res
                   (re-search-forward
                    "\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)"
                    limit t))
             (not (sh-script-extra-font-lock-is-in-double-quoted-string))))
    res))

(defvar sh-script-extra-font-lock-keywords
  '((sh-script-extra-font-lock-match-var-in-double-quoted-string
     (2 font-lock-variable-name-face prepend))))

(defun sh-script-extra-font-lock-activate ()
  (interactive)
  (font-lock-add-keywords nil sh-script-extra-font-lock-keywords)
  (if (fboundp 'font-lock-flush)
      (font-lock-flush)
    (when font-lock-mode
      (with-no-warnings
        (font-lock-fontify-buffer)))))

คุณสามารถเรียกใช้สิ่งนี้ได้โดยการเพิ่มฟังก์ชั่นสุดท้ายให้กับตะขอที่เหมาะสมตัวอย่างเช่น

(add-hook 'sh-mode-hook 'sh-script-extra-font-lock-activate)

สิ่งนี้ใช้งานได้สำหรับฉัน แต่ปล่อย "$" ด้วยการเน้นสตริง
erikstokes

เป็นการออกแบบเนื่องจากมันเป็นวิธีการที่ตัวแปรนอกสตริงได้รับการเน้น อย่างไรก็ตามสิ่งนี้สามารถเปลี่ยนแปลงได้ง่าย หากคุณแทนที่2ในกฎตัวอักษรล็อคด้วย0มันควรจะทำงาน (คุณอาจต้องขยาย regexp เพื่อรวมส่วนท้าย}เพื่อเน้น${FOO}อย่างถูกต้อง) หมายเลขนี้หมายถึงกลุ่มย่อย regexp ของการแข่งขัน0หมายความว่าการจับคู่ทั้งหมดควรเน้น
Lindydancer

บรรจุสิ่งนี้ในขณะที่เพิ่มสิ่งนี้ลงในที่เก็บ. emacs.d ของฉันหากใครสนใจ: github.com/moonlite/.emacs.d/blob/ ...... @Lindydancer GPLv3 + และคุณเป็นผู้แต่งในไฟล์นั้นหรือไม่? (ฉันจะผลักดันการอัปเดตหากไม่ได้)
Mattias Bengtsson

ฟังดูเข้าท่า. ฉันอาจไม่ต้องใช้เวลาเพื่อทำให้มันเป็นแพ็คเกจที่เหมาะสม อย่างไรก็ตามฉันต้องการให้คุณปล่อยที่อยู่อีเมลของฉันและเพิ่มบรรทัดลงในหน้า EmacsWiki ของฉัน ( emacswiki.org/emacs/AndersLindgren ) นอกจากนี้คุณสามารถลบเครื่องหมายลิขสิทธิ์เนื่องจากไม่จำเป็นและทำให้ซอร์สโค้ดไม่ใช่แบบ ASCII
Lindydancer

3

ฉันปรับปรุงคำตอบของ @ Lindydancer ด้วยวิธีต่อไปนี้:

  • Inlined sh-script-extra-font-lock-is-in-double-quoted-stringฟังก์ชั่นตามที่มันถูกใช้เพียงครั้งเดียว
  • การหลีกเลี่ยงการทำงานของตัวแปร
  • ตัวแปรที่เป็นตัวเลข ( $10, $1ฯลฯ ) เป็นไฮไลต์

ทำลายรหัส

(defun sh-script-extra-font-lock-match-var-in-double-quoted-string (limit)
  "Search for variables in double-quoted strings."
  (let (res)
    (while
        (and (setq res (progn (if (eq (get-byte) ?$) (backward-char))
                              (re-search-forward
                               "[^\\]\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\|[[:digit:]]+\\)"
                               limit t)))
             (not (eq (nth 3 (syntax-ppss)) ?\")))) res))

(defvar sh-script-extra-font-lock-keywords
  '((sh-script-extra-font-lock-match-var-in-double-quoted-string
     (2 font-lock-variable-name-face prepend))))

(defun sh-script-extra-font-lock-activate ()
  (interactive)
  (font-lock-add-keywords nil sh-script-extra-font-lock-keywords)
  (if (fboundp 'font-lock-flush)
      (font-lock-flush)
    (when font-lock-mode (with-no-warnings (font-lock-fontify-buffer)))))

[^\\\\]อาจจะเขียนเป็น[^\\]มันเป็นชุดของตัวละครที่ไม่ควรจับคู่และรหัสของคุณรวมถึงทับขวาสองครั้ง ในเวอร์ชั่นเก่าของ Emacs คุณต้องใช้font-lock-fontify-bufferรุ่นใหม่ที่คุณควรจะโทรหาfont-lock-flushและการโทรfont-lock-fontify-bufferจาก elisp จะถูกยกเลิก รหัสเดิมของฉันทำตามนี้รหัสของคุณไม่ได้ อย่างไรก็ตามอาจเป็นความคิดที่ดีกว่าที่จะโยกย้ายสิ่งนี้ไปยังไฟล์เก็บถาวร GitHub และเข้าร่วมความพยายาม
Lindydancer

@Lindydancer ไม่[^\\]รอด]หรือ นั่นเป็นวิธีที่ regex ทำงานใน Java อย่างที่ฉันรู้
Czipperz

@Lindydancer ดูเหมือนว่ามันไม่ได้เป็น Elisp ไม่ได้ช่วยให้คุณสามารถใช้ตัวอักษรหลบหนีอยู่ในกลุ่มตัวละคร
Czipperz

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