2012-02-26 52 views
12

一些背景知識,我對Emacs Lisp很感興趣,並寫了很多關於它的內容。然而,我從來沒有寫過一個主要的模式,所以我對字體鎖定機制的工作原理相當陌生。emacs:有沒有多行字體鎖定的明確例子?

對於我目前的項目,我想添加內聯javascript和css突出顯示爲html-mode。目前,我在MMM模式下這樣做,但它體積龐大,我沒有使用它的其他功能,所以我只想做一個小模式,甚至只是一個黑客,我可以將其添加到sgml-mode-hook只是突出顯示。

我發現這本手冊的section,它極其缺少一個例子,這個emacswiki page破碎的代碼。

有人能告訴我一個清楚的例子,說明這是如何做到的嗎?

編輯:我應該澄清,我不希望在javascript/css塊內看到模式特定的字體鎖定。唯一的要求是我可以通過對他們應用不同的面部來看到這些塊。

回答

6

在下面的示例中,我使用字體鎖定關鍵字的「錨定」形式,它允許您搜索多於當前行。 「訣竅」是「pre」鉤子做兩件事:1)它允許你將點定位到搜索的開始位置; 2)它允許你通過返回結束位置來限制搜索。在下面的例子中,我使用了第二個屬性。

請注意,這只是一個概念驗證。您需要確保將font-lock-multiline變量和font-lock關鍵字應用於正確的緩衝區。

(defun my-end-of-paragraph-position (&rest foo) 
    "Return position of next empty line." 
    (save-excursion 
    (while (not (or (eobp)    ; Stop at end of buffer. 
        (and (bolp)  ; Or at an empty line. 
         (eolp)))) 
     (forward-line)) 
    (point))) 

(setq font-lock-multiline t) 

(font-lock-add-keywords nil 
         '(("^FOO" 
          (0 font-lock-keyword-face) ;; Face for FOO 
          ("BAR" 
          (my-end-of-paragraph-position) 
          nil 
          (0 font-lock-variable-name-face))))) 

下面,BAR的前兩行會高亮顯示,但不是最後:

FOO BAR BAR BAR BAR 
BAR BAR BAR BAR 

BAR BAR BAR BAR 
+1

在這個[thread](http://lists.gnu.org/archive/html/help-gnu-emacs/2004-09/msg00534.html)中,Stefan Monnier說font-lock-multi-line是適合那些通常是單線的事物,但偶爾會多線。註釋? – 2012-03-04 17:25:10

+0

那麼,Stefan Monnier是關於任何與字體鎖相關的權威參考,所以他的任何建議都值得關注。正如他所說,使用句法系統是實現它的一種方法。另一個是使用「匹配函數」而不是正則表達式,它可以匹配整個塊。您應該將我的答案看作是對問題的直接回答(提供多行字體鎖定功能的示例),並且可能不是以最佳方式完成原始海報問及的任何答案。 – Lindydancer 2012-03-04 17:43:57

3

它可能不是最好的例子,但你可以看看如何haml-mode已經解決了這個問題在子模式區域中突出顯示語法。這是blog post的高級描述。

請注意,當前的haml-mode在Emacs 24兼容性方面存在一些問題,但有幾個叉具有此問題的修復程序。

關於多行字體鎖定,我想你可能會問錯誤的問題。但基本上,這解決了如果用戶在多行句法結構的中間或末尾進行編輯時該怎麼做的問題。最初,字體鎖從點的位置開始對緩衝區進行再加密。兩個默認的font-lock-extend-region-functions,font-lock-extend-region-wholelinesfont-lock-extend-region-multiline,將重新定位區域的開始移動到行的開頭,然後可能在更遠的某處,具體取決於font-lock-multiline屬性。如果您需要繼續向上移動,則可以將其他函數添加到font-lock-region-functions,或者確保在解析某些結構時以編程方式回溯,這些結構位於font-lock-region-functionsyntax-propertize-function之內。

後一種方法的一個例子是Ruby的heredoc和Emacs中繼中的ruby-syntax-propertize-heredoc。它在ruby-syntax-propertize-function的兩個地方被調用。當我們已經在heredoc文字中,然後是任何後續的heredocs時,第一次處理這種情況。

4

我將概述一個簡單的主要模式,用於突出顯示<style>(CSS)和 <script>(JavaScript等)塊。爲了得到多字體鎖 工作還算不錯,你需要通過設置 font-lock-multilinet先啓用它,寫一個函數添加到 font-lock-extend-region-functions這將延長相關 搜索區域包含較大的文本塊。然後,你需要 寫多行匹配器 - 正則表達式或函數 - 和 將它們添加到font-lock-defaults

這是一個基本的主要模式定義名稱的字體鎖定 關鍵字列表(在這裏,test-font-lock-keywords),使 多字型鎖,並增加了該地區的擴展功能 test-font-lock-extend-region

(define-derived-mode test-mode html-mode "Test" 
    "Major mode for highlighting JavaScript and CSS blocks." 
    ;; Basic font lock 
    (set (make-local-variable 'font-lock-defaults) 
     '(test-font-lock-keywords)) 
    ;; Multiline font lock 
    (set (make-local-variable 'font-lock-multiline) t) 
    (add-hook 'font-lock-extend-region-functions 
      'test-font-lock-extend-region)) 

區域擴展功能應該是這個樣子:

(defun test-font-lock-extend-region() 
    "Extend the search region to include an entire block of text." 
    ;; Avoid compiler warnings about these global variables from font-lock.el. 
    ;; See the documentation for variable `font-lock-extend-region-functions'. 
    (eval-when-compile (defvar font-lock-beg) (defvar font-lock-end)) 
    (save-excursion 
    (goto-char font-lock-beg) 
    (let ((found (or (re-search-backward "\n\n" nil t) (point-min)))) 
     (goto-char font-lock-end) 
     (when (re-search-forward "\n\n" nil t) 
     (beginning-of-line) 
     (setq font-lock-end (point))) 
     (setq font-lock-beg found)))) 

此功能着眼於全局變量font-lock-begfont-lock-end,其中包含起始和 結束位置的搜索區域,和擴展區域以包含文本的整個塊 (由空行分隔,或"\n\n")。

既然Emacs會搜索較大區域的匹配,我們 需要設置test-font-lock-keywords列表。有兩個 合理的好方法去匹配多行結構: 一個正則表達式,將跨線匹配和一個匹配的功能 函數。我會舉兩個例子。這個關鍵字列表包含 一個正則表達式匹配<style>塊和函數 匹配<script>塊:

(defvar test-font-lock-keywords 
    (list 
    (cons test-style-block-regexp 'font-lock-string-face) 
    (cons 'test-match-script-blocks '((0 font-lock-keyword-face))) 
    ) 
    "Font lock keywords for inline JavaScript and CSS blocks.") 

在列表中的第一項是直接的:正則表達式 和麪部用於突出,經常的比賽表達。 第二個看起來有點複雜,但可以概括爲 ,爲函數指定的 匹配數據中定義的不同組指定不同的面。在這裏,我們只使用font-lock-keyword-face突出顯示 組0(整個比賽)。 (用於 這些匹配的相關文件是在 Emacs手冊的Search-based fontification部分。)

匹配<style>塊基本正則表達式是:

(defconst test-style-block-regexp 
    "<style>\\(.\\|\n\\)*</style>" 
    "Regular expression for matching inline CSS blocks.") 

注意,我們必須把\n因爲.不是 匹配換行符。

匹配功能,而另一方面,需要尋找用於第一 <script>塊,該區域從點到單個給定 說法,last

(defun test-match-script-blocks (last) 
    "Match JavaScript blocks from the point to LAST." 
    (cond ((search-forward "<script" last t) 
     (let ((beg (match-beginning 0))) 
      (cond ((search-forward-regexp "</script>" last t) 
        (set-match-data (list beg (point))) 
        t) 
       (t nil)))) 
     (t nil))) 

這個函數設置匹配數據,它是 begin-0 end-0 begin-1 end-1 ...的形式的列表,其給出了第0組,第一組等的開始和結束 。在這裏,我們只對 給出了匹配的整個塊的界限,但您可以做些更復雜的操作,比如爲標籤和 內容設置不同的面。

如果結合所有這些代碼到一個單一的文件並運行 ​​,它應該工作的突出這兩種類型的塊 。雖然我相信這可以做到這一點,但如果有更多有效或正確的解決方法,我也會好奇 。