Làm nổi bật các biến shell trong dấu ngoặc kép


13

Trong vim, tài liệu sau đây sẽ làm cho $PWDdòng trên 2 và 3 được tô màu theo hai cách khác nhau:

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

Ví dụ đầu tiên $PWDsẽ có màu khác với phần còn lại của chuỗi. Nó cho thấy một dấu hiệu trực quan rõ ràng rằng biến sẽ được mở rộng, thay vì được coi là văn bản bằng chữ. Ngược lại, phiên bản thứ hai của $PWDsẽ được tô màu giống như phần còn lại của chuỗi, bởi vì các dấu ngoặc đơn làm cho nó được coi là văn bản bằng chữ.

Có bất kỳ chế độ emacs hiện có nào cung cấp loại "nhận thức trích dẫn vỏ" này không?


1
Chắc chắn, điều này sẽ không quá khó để thêm vào sh-mode? Có lẽ nó có thể được thêm vào chính Emacs.
PythonNut

Câu trả lời:


11

Mã dưới đây sử dụng quy tắc khóa phông chữ với hàm thay vì regrec, hàm tìm kiếm các lần xuất hiện $VARnhưng chỉ khi chúng nằm trong chuỗi trích dẫn kép. Các chức năng (syntax-ppss)được sử dụng để xác định điều này.

Quy tắc khóa phông chữ sử dụng prependcờ để thêm chính nó vào đầu tô sáng chuỗi hiện có. (Lưu ý rằng nhiều gói sử dụng tcho việc này. Thật không may, điều này ghi đè lên tất cả các khía cạnh của tô sáng hiện có. Ví dụ: sử dụng prependsẽ giữ lại màu nền của chuỗi (nếu có) trong khi thay thế màu nền trước.)

(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)))))

Bạn có thể gọi sử dụng điều này bằng cách thêm chức năng cuối cùng vào một hook phù hợp, ví dụ:

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

Điều này làm việc cho tôi, nhưng để lại "$" với chuỗi tô sáng.
erikstokes

Đó là do thiết kế, vì đó là cách một biến bên ngoài chuỗi được tô sáng. Tuy nhiên, điều này có thể dễ dàng thay đổi. Nếu bạn thay thế 2quy tắc khóa phông chữ bằng quy tắc 0thì nó sẽ hoạt động. (Bạn có thể cần phải mở rộng regrec để bao gồm một dấu }để làm nổi bật ${FOO}chính xác.) Số này đề cập đến nhóm phụ regrec của trận đấu, 0có nghĩa là toàn bộ trận đấu phải được tô sáng.
Lindydancer

Đóng gói lên này khi thêm này để kho .emacs.d tôi nếu anyones quan tâm: github.com/moonlite/.emacs.d/blob/... @Lindydancer Is GPLv3 + và bạn là tác giả trong đó tập tốt? (Tôi sẽ đẩy một bản cập nhật nếu không).
Mattias Bengtsson

Âm thanh tốt. Tôi có lẽ sẽ không có thời gian để biến nó thành một gói phù hợp. Tuy nhiên, tôi muốn bạn bỏ địa chỉ email của tôi và thay vào đó thêm một dòng vào trang EmacsWiki của tôi ( emacswiki.org/emacs/AndersLindgren ). Ngoài ra, bạn có thể xóa dấu hiệu bản quyền vì nó không cần thiết và nó làm cho mã nguồn không phải là ascii.
Lindydancer

3

Tôi đã cải thiện câu trả lời của @ Lindydancer theo những cách sau:

  • Inlined các sh-script-extra-font-lock-is-in-double-quoted-stringchức năng, vì nó chỉ được sử dụng một lần
  • Thoát khỏi các công trình biến.
  • Biến số ( $10, $1, vv) được đánh dấu.

Phá mã

(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)))))

[^\\\\]thể được viết dưới dạng [^\\], đó là một tập hợp các ký tự không được khớp và mã của bạn bao gồm dấu gạch chéo ngược hai lần. Trong các phiên bản Emacs cũ hơn phải sử dụng font-lock-fontify-buffer, trong phiên bản mới hơn, bạn phải gọi font-lock-flushvà gọi font-lock-fontify-buffertừ elisp bị từ chối. Mã ban đầu của tôi theo sau này, mã của bạn không. Dù sao, có thể là một ý tưởng tốt hơn để di chuyển cái này sang kho lưu trữ GitHub và tham gia nỗ lực.
Lindydancer

@Lindydancer Không [^\\]thoát khỏi ]? Đó là cách regex hoạt động trong Java như tôi biết.
Czipperz

@Lindydancer Có vẻ như không phải vì ELisp không cho phép bạn sử dụng các ký tự thoát trong các nhóm nhân vật .
Czipperz

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.