In Emacs is there a way to syntax-highlight the parentheses of quoted and backquoted sexps differently than the parens of other sexps so they stand out? e.g. I want these parens to be a different color than other parens:
(foo `(bar (baz)) quux)
^ ^
Have a look at mic-paren, a minor mode built as an extension to the packages paren.el and stig-paren.el for Emacs. It features recognition of "escaped" sexps.
Now for special highlighting : if you look at the code, the behaviour of quoted sexp matching is governed by the variable paren-match-quoted-paren. When finding a couple of match sexps, the typeface change is made using statements such as:
(mic-overlay-put mic-paren-backw-overlay 'face paren-mismatch-face)
(with similar alternatives for matched, unmatched). It shouldn't be too hard to define an alternative font (similarly to what is done with paren-mismatch-face), and replace those typeface-changing statements by functions that use your alternative font if paren-match-quoted-paren is true.
Note: updated links to refer to latest version
You can apply the following patch to mic-paren (follow link for latest version, 3.8) to get what you want. Customize the newly created face paren-face-quoted-match which is glaringly set up to have a green foreground and orange background for testing purposes.
Now when you're next to a matched set of parenthesis preceded by a single open quote `, you'll get the quoted face. This example uses an orange background and green foreground - most likely colors you'll want to change.
Here's a picture of it in action:
alt text http://img262.imageshack.us/img262/8866/quoted.png
--- orig-mic-paren.el 2009-11-11 17:02:42.000000000 -0800
+++ mic-paren.el 2009-11-11 17:05:35.306263000 -0800
## -561,4 +561,16 ##
:group 'mic-paren-matching)
+(defface paren-face-quoted-match
+ '((((class color)) (:foreground "green" :background "orange"))
+ (t (:reverse-video t)))
+ ""
+ :group 'faces
+ :group 'mic-paren-matching)
+
+(defcustom paren-quoted-match-face 'paren-face-quoted-match
+ "Mic-paren face used for a quoted paren"
+ :type 'face
+ :group 'mic-paren-matching)
+
;;; End of User Options
;;; ======================================================================
## -1052,5 +1064,9 ##
face (if mismatch
paren-mismatch-face
- paren-match-face)
+ (save-excursion
+ (if (progn (goto-char (- (min (point) opos) 1))
+ (looking-at "`"))
+ paren-quoted-match-face
+ paren-match-face)))
visible (when (pos-visible-in-window-p opos)
(save-excursion
To apply the patch, cut/paste the patch chunk to a file named mic.patch, and run the following:
patch mic-paren.el mic.patch
Related
I am trying to write an Emacs major mode but it is not working; specifically, my keywords are not being displayed in keyword font face. I have tried to follow the tutorials but I must be doing something wrong. I know a little Lisp but I do not know Emacs scripting.
My Emacs mode script:
;; emacs mode for OldRope
;; does no work for some reason
(setq oldrope-directive-keywords-regexp (regexp-opt '("page" "link" "goto" "act" "end" "div" "span" "include")))
(defvar oldrope-font-lock-defaults '((
(oldrope-directive-keywords-regexp . font-lock-keyword-face))))
(define-derived-mode oldrope-mode fundamental-mode
"oldrope mode"
"Major mode for editing OldRope games"
(setq comment-start "/*")
(setq comment-end "*/")
(setq font-lock-defaults oldrope-font-lock-defaults))
(provide 'oldrope-mode)
Test file:
$[page start]$ Hello $[link]$ Click me $[act]$ That is right. $[end]$
(For context, this is part of https://github.com/martinellison/oldrope but that is not really relevant to the question).
You need this - the rest is OK:
(defvar oldrope-font-lock-defaults
`(((,oldrope-directive-keywords-regexp . font-lock-keyword-face))))
By simply quoting the list you were not evaluating oldrope-directive-keywords-regexp - your quoted list just had that symbol as its car.
Using either backquote (`) plus comma (,) or (list (list (cons oldrope-directive-keywords-regexp 'font-lock-keyword-face))) you evaluate that variable and use its value in the resulting list.
I want the sequence // to start a comment when it is at the beginning of a line. But inside of a line it should not start any comments.
// this is a comment
This is a URL: http://example.com
Is it possible?
I'd do it this way:
(defvar my-foo-mode-syntax-table
(let ((st (make-syntax-table)))
;; Add other entries appropriate for my-foo-mode.
(modify-syntax-entry ?/ ". 12" st)
(modify-syntax-entry ?\n "> " st)
st))
(defvar my-foo-font-lock-keywords
;; Add other rules appropriate for my-foo-mode.
())
(define-derived-mode my-foo-mode nil "My-Foo"
(setq-local font-lock-keywords '(my-foo-font-lock-keywords))
;; Add other settings appropriate for my-foo-mode.
(setq-local syntax-propertize-function
(syntax-propertize-rules ("./\\(/+\\)" (1 ".")))))
Notice: No need for any special font-lock rule since font-lock automatically highlights comments for you, based on the syntax-tables.
You can do this by writing a syntax-propertize-function
I have written an example major mode that shows this below.
Emacs built in parsing will call your syntax-propertize-function so that it can manually set the syntax-table text property on lines starting with //.
(define-derived-mode my-syntax-test-mode fundamental-mode
"A major mode where // denotes a comment but only if it is at the beginning of a line."
:syntax-table (make-syntax-table)
(setq mode-name "my syntax test")
;; our mode will use `apply-my-custom-syntax-table-appropriately' to manually set
;; the syntax-table text property on lines starting with //"
(setq syntax-propertize-function 'apply-my-custom-syntax-table-appropriately)
;; change `comment-dwim` to handle this type of comments correctly
(local-set-key [remap comment-dwim] 'my-comment-dwim))
(defvar my-custom-syntax-table
;; syntax table where // starts a comment and \n ends it
(let ((table (make-syntax-table)))
(modify-syntax-entry ?/ "< 1" table)
(modify-syntax-entry ?/ "< 2" table)
(modify-syntax-entry ?\n "> " table)
table))
(defun apply-my-custom-syntax-table-appropriately (beg end)
(save-excursion
(save-restriction
(widen)
(goto-char beg)
;; for every line between points BEG and END
(while (and (not (eobp)) (< (point) end))
(beginning-of-line)
;; if it starts with a //
(when (looking-at "^//")
;; remove current syntax-table property
(remove-text-properties (1- (line-beginning-position))
(1+ (line-end-position))
'(syntax-table))
;; set syntax-table property to our custom one
;; for the whole line including the beginning and ending newlines
(add-text-properties (1- (line-beginning-position))
(1+ (line-end-position))
(list 'syntax-table my-custom-syntax-table)))
(forward-line 1)))))
(defun my-comment-dwim (arg)
(interactive "*P")
(require 'newcomment)
(save-excursion
(let ((comment-start "//") (comment-end "")
(comment-column 0)
;; don't indent comments
(comment-style 'plain))
;; create the region containing current line if there is no active region
(unless (use-region-p)
(end-of-line)
(push-mark (line-beginning-position))
(setq mark-active t))
(comment-dwim nil))))
Answer: Use regexps
Short and simple
(define-derived-mode my-foo-mode prog-mode "My-Foo"
(setq-local font-lock-keywords t)
(setq-local syntax-propertize-function
(syntax-propertize-rules
((rx line-start (* whitespace) (group "//")) (1 "<"))
((rx (group "\n")) (1 ">")))))
That is all you need, but read on if you'd like to know more.
Explanation
This is based on #stefan's excellent solution which uses syntax-propertize-function to add to a syntax-table. While simpler isn't always better, #stefan's answer does more than what the original question asked for, so I've created this answer for people who only need a small hint or who just want to modify an existing mode.
It turns out directly manipulating a syntax table is unnecessary since the function syntax-propertize-rules makes it easy to map from regular expressions to syntax classes. For example, the syntax class < means "start of comment" and > means "end of comment". (See the Emacs lisp manual.)
I set font-lock-keywords to t as that is the minimum needed to enable syntax highlighting. If you are editing an existing mode, it likely already sets that variable and will not need to be changed.
And, finally, I use Emacs' rx function because it makes regular expressions sane in Lisp. (If you like Lisp, regular expressions, and sanity, I highly recommend using rx.)
About syntax-propertize-rules
I was going to link to the documentation for syntax-propertize-rules, but the Emacs manual does not (as of Emacs 28.1) even mention it. Until that gets remedied, I'll paste here the builtin documentation from C-hf:
syntax-propertize-rules is a Lisp macro in ‘syntax.el’.
(syntax-propertize-rules &rest RULES)
Probably introduced at or before Emacs version 24.1.
Make a function that applies RULES for use in
‘syntax-propertize-function’. The function will scan the buffer,
applying the rules where they match. The buffer is scanned a single
time, like "lex" would, rather than once per rule.
Each RULE can be a symbol, in which case that symbol’s value should
be, at macro-expansion time, a precompiled set of rules, as returned
by ‘syntax-propertize-precompile-rules’.
Otherwise, RULE should have the form (REGEXP HIGHLIGHT1 ...
HIGHLIGHTn), where REGEXP is an expression (evaluated at time of
macro-expansion) that returns a regexp, and where HIGHLIGHTs have the
form (NUMBER SYNTAX) which means to apply the property SYNTAX to the
chars matched by the subgroup NUMBER of the regular expression, if
NUMBER did match. SYNTAX is an expression that returns a value to
apply as ‘syntax-table’ property. Some expressions are handled
specially:
if SYNTAX is a string, then it is converted with ‘string-to-syntax’;
if SYNTAX has the form (prog1 EXP . EXPS) then the value returned by EXP will be applied to the buffer before running EXPS and if EXP is
a string it is also converted with ‘string-to-syntax’. The SYNTAX
expression is responsible to save the ‘match-data’ if needed for
subsequent HIGHLIGHTs. Also SYNTAX is free to move point, in which
case RULES may not be applied to some parts of the text or may be
applied several times to other parts.
Note: back-references in REGEXPs do not work.
The following code fails to highlight 23's in 23-23 if pasted and evaluated in the scratch buffer, but not if done in a text buffer.
;; Example 1
'(1234 23 23-23 end)
(progn
(font-lock-add-keywords nil
`(("\\b23\\b"
(0 'success))
"end"))
(font-lock-fontify-buffer))
Why does it fail when M-x isearch-forward-regexp RET \b23\b still matches 23's in 23-23?
Even if I change to the following code, only the first 23 in 23-23 gets highlighted.
;;; Example 2
'(1234 23 23-23 end)
(progn
(font-lock-add-keywords nil
`((,(rx (or word-boundary
"-")
(group "23")
(or word-boundary
"-"))
(1 'success))
"end"))
(font-lock-fontify-buffer))
Side note: "end" is there so that I can detect if the highlighter for 23 is ill formed. If it is ill formed or signals errors silently, end won't get highlighted.
;;; Example 3 (with xy instead of 23. also passing t and 'append.)
;;; if evaluated in the scratch buffer, it doesn't highlight xy in xy-xy
'(wxyz xy xy-xy end)
(progn
(font-lock-add-keywords nil
`(("\\bxy\\b"
(0 'success t))
"end")
'append)
(font-lock-fontify-buffer))
The fact that it does not in buffer *scratch* suggests that it is a problem with the current mode. There are two main possibilities:
What #wvcvw suggested: check what the syntax class of chars 2 and 3 is.
The font-lock-keywords already defined for the mode interact with your code -- e.g., they override it. Try adding 'APPEND as a third arg to font-lock-add-keywords. Try adding t as a HIGHLIGHT expression to your highlighter sexp (see the doc). That should let your highlighting override any that might already be there otherwise.
BTW, you say it does not work in a "text buffer", but what does that mean? From emacs -Q, evaluating your code in a buffer in text-mode shows that it does work. Investigate what your "text buffer" mode is and try the suggestions above (both bullets if necessary, but try the second one first).
After highlighting text in an emacs buffer using a regexp (1), it's easy enough to write the setting in the file (2), but I am missing a third step for persistence.
(1) Set
Doing M-s h r (highlight-regexp) and, say, \{.*\} followed by italic will highlight everything between curly braces in that style.
(2) Write
Subsequently calling C-x w b (hi-lock-write-interactive-patterns) will write the string
# Hi-lock: (("\\{.*\\}" (0 (quote italic) t)))
in the buffer, after asking for the comment string (I used #).
(3) Re-use
What is the third step needed to make this highlighting persistent, i.e., to make it survive saving/loading the file from disk?
If you C-h f hi-lock-write-interactive-pattern, you'll see in the help buffer a link to hi-lock.el. Often Lisp libraries have some usage information at the beginning of the file and it's handy to check.
In this case, it tells how to make it persistent:
;; To enable the use of patterns found in files (presumably placed
;; there by hi-lock) include the following in your init file:
;;
;; (setq hi-lock-file-patterns-policy 'ask)
;;
;; If you get tired of being asked each time a file is loaded replace
;; `ask' with a function that returns t if patterns should be read.
How about the possibility of creating a function that has a hook relating to the file you want to load -- e.g., a text-mode-hook or perhaps a specific file hook (if something like that exists)?
;; M-x ae-hi-lock-features
(global-hi-lock-mode 1)
(defface af-bold-yellow-box '((t (:background "black"
:foreground "yellow"
:underline "red"
:height 200
:bold t
))) "yellow-box-face")
(defun z-hi-lock-quizzes ()
;; this next line is necessary to correct sloppy hi-locking
(if (not hi-lock-mode)
(progn (hi-lock-mode -1)
(hi-lock-mode 1))
(hi-lock-mode)
(hi-lock-mode))
(highlight-regexp "^%-\\*-mode:LaTeX.*$" (quote hi-conceal-content));
(highlight-regexp "^%-#-(.+$" (quote hi-lock-page-break));
(highlight-regexp "food" (quote af-bold-yellow-box));
)
(defun ae-hi-lock-features ()
(interactive)
(z-hi-lock-quizzes)
;; ... call other functions ...
)
(add-hook 'text-mode-hook 'ae-hi-lock-features)
https://www.gnu.org/software/emacs/manual/html_node/emacs/Highlight-Interactively.html
C-x w i
Extract regexp/face pairs from comments in the current buffer (hi-lock-find-patterns).
Thus, you can enter patterns interactively
with highlight-regexp, store them into the file with
hi-lock-write-interactive-patterns, edit them (perhaps including
different faces for different parenthesized parts of the match), and
finally use this command (hi-lock-find-patterns) to have Hi Lock
highlight the edited patterns.
I'm using EmacsForMacOsX, v23.3.1, and I wonder how I can change the color for floating point values celsiusFloat = (5.0/9.0); to be a different color than those I get from my current color-theme-billw theme for integers age = 23;.
I doubt that StackOverflow colours them differently.
EDIT:
My initial approach to add a regex for the floating point d*\.d* in cc-mode.el was apparently not the way Emacs work with syntax highlighting (also known as font locking) - further research has led me to the following website: http://www.gnu.org/software/emacs/elisp/html_node/Customizing-Keywords.html
Edit 2:
I seem to have found my answer at http://www.emacswiki.org/emacs/AddKeywords and http://www.gnu.org/software/emacs/manual/html_node/emacs/Font-Lock.html#Font-Lock
(add-hook 'c-mode-hook
(lambda ()
(font-lock-add-keywords nil
'(("[0-9]+\\.[0-9]+" 1 font-lock-warning-face t)))))
I found a solution at: http://hbfs.wordpress.com/2010/03/02/adding-keywords-in-emacs/
First:
(make-face 'font-lock-special-macro-face) ;; Create a new face
(set-face-foreground 'font-lock-special-macro-face "pink") ;; Set the colour
Then we proceed to add regular expressions to the list of keywords and associate each regexp with a face:
(defun add-custom-keyw()
"adds a few special keywords for c and c++ modes"
;
(font-lock-add-keywords nil
'(
("[0-9]+\\.[0-9]+" . 'font-lock-special-macro-face )
; more of those would go here
)
)
)
Last we hook it to our mode:
(add-hook 'c-mode-hook 'add-custom-keyw)