;;; font-lock.el --- Electric font lock mode
-;; Copyright (C) 1992-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1992-2016 Free Software Foundation, Inc.
;; Author: Jamie Zawinski
;; Richard Stallman
(MATCHER HIGHLIGHT ...)
(eval . FORM)
-where MATCHER can be either the regexp to search for, or the function name to
-call to make the search (called with one argument, the limit of the search;
-it should return non-nil, move point, and set `match-data' appropriately if
-it succeeds; like `re-search-forward' would).
-MATCHER regexps can be generated via the function `regexp-opt'.
+where MATCHER can be either the regexp to search for, or the
+function name to call to make the search (called with one
+argument, the limit of the search; it should return non-nil, move
+point, and set `match-data' appropriately if it succeeds; like
+`re-search-forward' would). MATCHER regexps can be generated via
+the function `regexp-opt'.
-FORM is an expression, whose value should be a keyword element, evaluated when
-the keyword is (first) used in a buffer. This feature can be used to provide a
-keyword that can only be generated when Font Lock mode is actually turned on.
+FORM is an expression, whose value should be a keyword element,
+evaluated when the keyword is (first) used in a buffer. This
+feature can be used to provide a keyword that can only be
+generated when Font Lock mode is actually turned on.
HIGHLIGHT should be either MATCH-HIGHLIGHT or MATCH-ANCHORED.
-For highlighting single items, for example each instance of the word \"foo\",
-typically only MATCH-HIGHLIGHT is required.
-However, if an item or (typically) items are to be highlighted following the
-instance of another item (the anchor), for example each instance of the
-word \"bar\" following the word \"anchor\" then MATCH-ANCHORED may be required.
+For highlighting single items, for example each instance of the
+word \"foo\", typically only MATCH-HIGHLIGHT is required.
+However, if an item or (typically) items are to be highlighted
+following the instance of another item (the anchor), for example
+each instance of the word \"bar\" following the word \"anchor\"
+then MATCH-ANCHORED may be required.
MATCH-HIGHLIGHT should be of the form:
(SUBEXP FACENAME [OVERRIDE [LAXMATCH]])
-SUBEXP is the number of the subexpression of MATCHER to be highlighted.
+SUBEXP is the number of the subexpression of MATCHER to be
+highlighted.
FACENAME is an expression whose value is the face name to use.
-Instead of a face, FACENAME can evaluate to a property list
-of the form (face FACE PROP1 VAL1 PROP2 VAL2 ...)
-in which case all the listed text-properties will be set rather than
-just FACE. In such a case, you will most likely want to put those
-properties in `font-lock-extra-managed-props' or to override
+Instead of a face, FACENAME can evaluate to a property list of
+the form (face FACE PROP1 VAL1 PROP2 VAL2 ...) in which case all
+the listed text-properties will be set rather than just FACE. In
+such a case, you will most likely want to put those properties in
+`font-lock-extra-managed-props' or to override
`font-lock-unfontify-region-function'.
-OVERRIDE and LAXMATCH are flags. If OVERRIDE is t, existing fontification can
-be overwritten. If `keep', only parts not already fontified are highlighted.
-If `prepend' or `append', existing fontification is merged with the new, in
-which the new or existing fontification, respectively, takes precedence.
-If LAXMATCH is non-nil, that means don't signal an error if there is
+OVERRIDE and LAXMATCH are flags. If OVERRIDE is t, existing
+fontification can be overwritten. If `keep', only parts not
+already fontified are highlighted. If `prepend' or `append',
+existing fontification is merged with the new, in which the new
+or existing fontification, respectively, takes precedence. If
+LAXMATCH is non-nil, that means don't signal an error if there is
no match for SUBEXP in MATCHER.
-For example, an element of the form highlights (if not already highlighted):
+For example, an element of the form highlights (if not already
+highlighted):
+
+ \"\\\\\\=<foo\\\\\\=>\"
+ Discrete occurrences of \"foo\" in the value of the variable
+ `font-lock-keyword-face'.
+
+ (\"fu\\\\(bar\\\\)\" . 1)
+ Substring \"bar\" within all occurrences of \"fubar\" in the
+ value of `font-lock-keyword-face'.
+
+ (\"fubar\" . fubar-face)
+ Occurrences of \"fubar\" in the value of `fubar-face'.
- \"\\\\\\=<foo\\\\\\=>\" discrete occurrences of \"foo\" in the value of the
- variable `font-lock-keyword-face'.
- (\"fu\\\\(bar\\\\)\" . 1) substring \"bar\" within all occurrences of \"fubar\" in
- the value of `font-lock-keyword-face'.
- (\"fubar\" . fubar-face) Occurrences of \"fubar\" in the value of `fubar-face'.
(\"foo\\\\|bar\" 0 foo-bar-face t)
- occurrences of either \"foo\" or \"bar\" in the value
- of `foo-bar-face', even if already highlighted.
+ Occurrences of either \"foo\" or \"bar\" in the value of
+ `foo-bar-face', even if already highlighted.
+
(fubar-match 1 fubar-face)
- the first subexpression within all occurrences of
- whatever the function `fubar-match' finds and matches
- in the value of `fubar-face'.
+ The first subexpression within all occurrences of whatever the
+ function `fubar-match' finds and matches in the value of
+ `fubar-face'.
MATCH-ANCHORED should be of the form:
(MATCHER PRE-MATCH-FORM POST-MATCH-FORM MATCH-HIGHLIGHT ...)
-where MATCHER is a regexp to search for or the function name to call to make
-the search, as for MATCH-HIGHLIGHT above, but with one exception; see below.
-PRE-MATCH-FORM and POST-MATCH-FORM are evaluated before the first, and after
-the last, instance MATCH-ANCHORED's MATCHER is used. Therefore they can be
-used to initialize before, and cleanup after, MATCHER is used. Typically,
-PRE-MATCH-FORM is used to move to some position relative to the original
-MATCHER, before starting with MATCH-ANCHORED's MATCHER. POST-MATCH-FORM might
-be used to move back, before resuming with MATCH-ANCHORED's parent's MATCHER.
-
-For example, an element of the form highlights (if not already highlighted):
-
- (\"\\\\\\=<anchor\\\\\\=>\" (0 anchor-face) (\"\\\\\\=<item\\\\\\=>\" nil nil (0 item-face)))
-
- discrete occurrences of \"anchor\" in the value of `anchor-face', and subsequent
- discrete occurrences of \"item\" (on the same line) in the value of `item-face'.
- (Here PRE-MATCH-FORM and POST-MATCH-FORM are nil. Therefore \"item\" is
- initially searched for starting from the end of the match of \"anchor\", and
- searching for subsequent instances of \"anchor\" resumes from where searching
- for \"item\" concluded.)
-
-The above-mentioned exception is as follows. The limit of the MATCHER search
-defaults to the end of the line after PRE-MATCH-FORM is evaluated.
-However, if PRE-MATCH-FORM returns a position greater than the position after
-PRE-MATCH-FORM is evaluated, that position is used as the limit of the search.
-It is generally a bad idea to return a position greater than the end of the
-line, i.e., cause the MATCHER search to span lines.
-
-These regular expressions can match text which spans lines, although
-it is better to avoid it if possible since updating them while editing
-text is slower, and it is not guaranteed to be always correct when using
-support modes like jit-lock or lazy-lock.
-
-This variable is set by major modes via the variable `font-lock-defaults'.
-Be careful when composing regexps for this list; a poorly written pattern can
-dramatically slow things down!
-
-A compiled keywords list starts with t. It is produced internally
-by `font-lock-compile-keywords' from a user-level keywords list.
-Its second element is the user-level keywords list that was
-compiled. The remaining elements have the same form as
-user-level keywords, but normally their values have been
+where MATCHER is a regexp to search for or the function name to
+call to make the search, as for MATCH-HIGHLIGHT above, but with
+one exception; see below. PRE-MATCH-FORM and POST-MATCH-FORM are
+evaluated before the first, and after the last, instance
+MATCH-ANCHORED's MATCHER is used. Therefore they can be used to
+initialize before, and cleanup after, MATCHER is used.
+Typically, PRE-MATCH-FORM is used to move to some position
+relative to the original MATCHER, before starting with
+MATCH-ANCHORED's MATCHER. POST-MATCH-FORM might be used to move
+back, before resuming with MATCH-ANCHORED's parent's MATCHER.
+
+For example, an element of the form highlights (if not already
+highlighted):
+
+ (\"\\\\\\=<anchor\\\\\\=>\" (0 anchor-face)
+ (\"\\\\\\=<item\\\\\\=>\" nil nil (0 item-face)))
+
+ Discrete occurrences of \"anchor\" in the value of
+ `anchor-face', and subsequent discrete occurrences of
+ \"item\" (on the same line) in the value of `item-face'.
+ (Here PRE-MATCH-FORM and POST-MATCH-FORM are nil. Therefore
+ \"item\" is initially searched for starting from the end of the
+ match of \"anchor\", and searching for subsequent instances of
+ \"anchor\" resumes from where searching for \"item\" concluded.)
+
+The above-mentioned exception is as follows. The limit of the
+MATCHER search defaults to the end of the line after
+PRE-MATCH-FORM is evaluated. However, if PRE-MATCH-FORM returns
+a position greater than the position after PRE-MATCH-FORM is
+evaluated, that position is used as the limit of the search. It
+is generally a bad idea to return a position greater than the end
+of the line, i.e., cause the MATCHER search to span lines.
+
+These regular expressions can match text which spans lines,
+although it is better to avoid it if possible since updating them
+while editing text is slower, and it is not guaranteed to be
+always correct when using support modes like jit-lock or
+lazy-lock.
+
+This variable is set by major modes via the variable
+`font-lock-defaults'. Be careful when composing regexps for this
+list; a poorly written pattern can dramatically slow things down!
+
+A compiled keywords list starts with t. It is produced
+internally by `font-lock-compile-keywords' from a user-level
+keywords list. Its second element is the user-level keywords
+list that was compiled. The remaining elements have the same
+form as user-level keywords, but normally their values have been
optimized.")
(defvar font-lock-keywords-alist nil
dollar-sign character. Hash characters in other contexts will still
follow whatever the syntax table says about the hash character.
- (\"\\\\('\\\\).\\\\('\\\\)\"
+ (\"\\\\(\\='\\\\).\\\\(\\='\\\\)\"
(1 \"\\\"\")
(2 \"\\\"\"))
- gives a pair single-quotes, which surround a single character, a SYNTAX of
- \"\\\"\" (meaning string quote syntax). Single-quote characters in other
+ gives a pair of apostrophes, which surround a single character, a
+ SYNTAX of \"\\\"\" (meaning string quote syntax). Apostrophes in other
+
contexts will not be affected.
This is normally set via `font-lock-defaults'.")
If this is nil, the major mode's syntax table is used.
This is normally set via `font-lock-defaults'.")
-(defvar font-lock-beginning-of-syntax-function nil
- "Non-nil means use this function to move back outside all constructs.
-When called with no args it should move point backward to a place which
-is not in a string or comment and not within any bracket-pairs (or else,
-a place such that any bracket-pairs outside it can be ignored for Emacs
-syntax analysis and fontification).
-
-If this is nil, Font Lock uses `syntax-begin-function' to move back
-outside of any comment, string, or sexp. This variable is semi-obsolete;
-we recommend setting `syntax-begin-function' instead.
-
-This is normally set via `font-lock-defaults'.")
-(make-obsolete-variable 'font-lock-beginning-of-syntax-function
- 'syntax-begin-function "23.3" 'set)
-
(defvar font-lock-mark-block-function nil
"Non-nil means use this function to mark a block of text.
When called with no args it should leave point at the beginning of any
This is used when turning off Font Lock mode.
This is normally set via `font-lock-defaults'.")
-(defvar font-lock-fontify-region-function 'font-lock-default-fontify-region
+(defvar font-lock-fontify-region-function #'font-lock-default-fontify-region
"Function to use for fontifying a region.
It should take two args, the beginning and end of the region, and an optional
third arg VERBOSE. If VERBOSE is non-nil, the function should print status
-messages. This is normally set via `font-lock-defaults'.")
+messages. This is normally set via `font-lock-defaults'.
+If it fontifies a larger region, it should ideally return a list of the form
+\(jit-lock-bounds BEG . END) indicating the bounds of the region actually
+fontified.")
(defvar font-lock-unfontify-region-function 'font-lock-default-unfontify-region
"Function to use for unfontifying a region.
"List of Font Lock mode related modes that should not be turned on.
Currently, valid mode names are `fast-lock-mode', `jit-lock-mode' and
`lazy-lock-mode'. This is normally set via `font-lock-defaults'.")
+(make-obsolete-variable 'font-lock-inhibit-thing-lock nil "25.1")
(defvar-local font-lock-multiline nil
"Whether font-lock should cater to multiline keywords.
For example:
- (font-lock-add-keywords 'c-mode
- '((\"\\\\\\=<\\\\(FIXME\\\\):\" 1 'font-lock-warning-face prepend)
- (\"\\\\\\=<\\\\(and\\\\|or\\\\|not\\\\)\\\\\\=>\" . 'font-lock-keyword-face)))
+ (font-lock-add-keywords \\='c-mode
+ \\='((\"\\\\\\=<\\\\(FIXME\\\\):\" 1 \\='font-lock-warning-face prepend)
+ (\"\\\\\\=<\\\\(and\\\\|or\\\\|not\\\\)\\\\\\=>\" . \\='font-lock-keyword-face)))
adds two fontification patterns for C mode, to fontify `FIXME:' words, even in
comments, and to fontify `and', `or' and `not' words as keywords.
For example:
- (add-hook 'c-mode-hook
+ (add-hook \\='c-mode-hook
(lambda ()
(font-lock-add-keywords nil
- '((\"\\\\\\=<\\\\(FIXME\\\\):\" 1 'font-lock-warning-face prepend)
+ \\='((\"\\\\\\=<\\\\(FIXME\\\\):\" 1 \\='font-lock-warning-face prepend)
(\"\\\\\\=<\\\\(and\\\\|or\\\\|not\\\\)\\\\\\=>\" .
- 'font-lock-keyword-face)))))
+ \\='font-lock-keyword-face)))))
The above procedure may fail to add keywords to derived modes if
some involved major mode does not follow the standard conventions.
(setq font-lock-removed-keywords-alist
(delq cell font-lock-removed-keywords-alist)))))))
-;; Written by Anders Lindgren <andersl@andersl.com>.
+;; Written by Anders Lindgren
;;
;; Case study:
;; (I) The keywords are removed from a major mode.
(defun font-lock-remove-keywords (mode keywords)
"Remove highlighting KEYWORDS for MODE.
-MODE should be a symbol, the major mode command name, such as `c-mode'
-or nil. If nil, highlighting keywords are removed for the current buffer.
+MODE should be a symbol, the major mode command name, such as
+`c-mode' or nil. If nil, highlighting keywords are removed for
+the current buffer.
+
+For a description of KEYWORDS, see `font-lock-add-keywords'.
To make the removal apply to modes derived from MODE as well,
pass nil for MODE and add the call to MODE-hook. This may fail
;; Don't fontify eagerly (and don't abort if the buffer is large).
(set (make-local-variable 'font-lock-fontified) t)
;; Use jit-lock.
- (jit-lock-register 'font-lock-fontify-region
+ (jit-lock-register #'font-lock-fontify-region
(not font-lock-keywords-only))
;; Tell jit-lock how we extend the region to refontify.
(add-hook 'jit-lock-after-change-extend-region-functions
(defun font-lock-flush (&optional beg end)
"Declare the region BEG...END's fontification as out-of-date.
-If the region is not specified, it defaults to the whole buffer."
+If the region is not specified, it defaults to the entire
+accessible portion of the current buffer."
(and font-lock-mode
font-lock-fontified
(funcall font-lock-flush-function
(defvar font-lock-ensure-function
(lambda (_beg _end)
- (unless font-lock-fontified (font-lock-default-fontify-buffer)))
+ (unless font-lock-fontified
+ (font-lock-default-fontify-buffer)
+ (unless font-lock-mode
+ ;; If font-lock is not enabled, we don't have the hooks in place to
+ ;; track modifications, so a subsequent call to font-lock-ensure can't
+ ;; assume that the fontification is still valid.
+ (setq font-lock-fontified nil))))
"Function to make sure a region has been fontified.
Called with two arguments BEG and END.")
(defun font-lock-ensure (&optional beg end)
"Make sure the region BEG...END has been fontified.
-If the region is not specified, it defaults to the whole buffer."
+If the region is not specified, it defaults to the entire accessible
+portion of the buffer."
(font-lock-set-defaults)
(funcall font-lock-ensure-function
(or beg (point-min)) (or end (point-max))))
(let ((changed nil))
(goto-char font-lock-beg)
(unless (bolp)
- (setq changed t font-lock-beg (line-beginning-position)))
+ (setq changed t font-lock-beg
+ (let ((inhibit-field-text-motion t))
+ (line-beginning-position))))
(goto-char font-lock-end)
(unless (bolp)
(unless (eq font-lock-end
(font-lock-fontify-syntactic-keywords-region start end)))
(unless font-lock-keywords-only
(font-lock-fontify-syntactically-region beg end loudly))
- (font-lock-fontify-keywords-region beg end loudly)))))
+ (font-lock-fontify-keywords-region beg end loudly)
+ `(jit-lock-bounds ,beg . ,end)))))
;; The following must be rethought, since keywords can override fontification.
;; ;; Now scan for keywords, but not if we are inside a comment now.
(point-min))))
(when (< end (point-max))
(setq end
- (if (get-text-property end 'font-lock-multiline)
- (or (text-property-any end (point-max)
- 'font-lock-multiline nil)
- (point-max))
+ (cond
+ ((get-text-property end 'font-lock-multiline)
+ (or (text-property-any end (point-max)
+ 'font-lock-multiline nil)
+ (point-max)))
+ ;; If `end' has been set by the function above, don't corrupt it.
+ (font-lock-extend-after-change-region-function end)
;; Rounding up to a whole number of lines should include the
;; line right after `end'. Typical case: the first char of
;; the line was deleted. Or a \n was inserted in the middle
;; of a line.
- (1+ end))))
+ (t (1+ end)))))
;; Finally, pre-enlarge the region to a whole number of lines, to try
;; and anticipate what font-lock-default-fontify-region will do, so as to
;; avoid double-redisplay.
(when (memq 'font-lock-extend-region-wholelines
font-lock-extend-region-functions)
(goto-char beg)
- (setq jit-lock-start (min jit-lock-start (line-beginning-position)))
+ (setq beg (min jit-lock-start (line-beginning-position)))
(goto-char end)
- (setq jit-lock-end
+ (setq end
(max jit-lock-end
- (if (bolp) (point) (line-beginning-position 2))))))))
+ (if (bolp) (point) (line-beginning-position 2)))))
+ (setq jit-lock-start beg
+ jit-lock-end end))))
(defun font-lock-fontify-block (&optional arg)
"Fontify some lines the way `font-lock-fontify-buffer' would.
If `font-lock-mark-block-function' non-nil and no ARG is given, it is used to
delimit the region to fontify."
(interactive "P")
- (let ((inhibit-point-motion-hooks t) font-lock-beginning-of-syntax-function
+ (let ((inhibit-point-motion-hooks t)
deactivate-mark)
;; Make sure we have the right `font-lock-keywords' etc.
(if (not font-lock-mode) (font-lock-set-defaults))
- (save-excursion
+ (save-mark-and-excursion
(save-match-data
(condition-case error-data
(if (or arg (not font-lock-mark-block-function))
(put-text-property start next prop value object)
(setq start (text-property-any next end prop nil object)))))
-;; For completeness: this is to `remove-text-properties' as `put-text-property'
-;; is to `add-text-properties', etc.
-;;(defun remove-text-property (start end property &optional object)
-;; "Remove a property from text from START to END.
-;;Argument PROPERTY is the property to remove.
-;;Optional argument OBJECT is the string or buffer containing the text.
-;;Return t if the property was actually removed, nil otherwise."
-;; (remove-text-properties start end (list property) object))
-
-;; For consistency: maybe this should be called `remove-single-property' like
-;; `next-single-property-change' (not `next-single-text-property-change'), etc.
-;;(defun remove-single-text-property (start end prop value &optional object)
-;; "Remove a specific property value from text from START to END.
-;;Arguments PROP and VALUE specify the property and value to remove. The
-;;resulting property values are not equal to VALUE nor lists containing VALUE.
-;;Optional argument OBJECT is the string or buffer containing the text."
-;; (let ((start (text-property-not-all start end prop nil object)) next prev)
-;; (while start
-;; (setq next (next-single-property-change start prop object end)
-;; prev (get-text-property start prop object))
-;; (cond ((and (symbolp prev) (eq value prev))
-;; (remove-text-property start next prop object))
-;; ((and (listp prev) (memq value prev))
-;; (let ((new (delq value prev)))
-;; (cond ((null new)
-;; (remove-text-property start next prop object))
-;; ((= (length new) 1)
-;; (put-text-property start next prop (car new) object))
-;; (t
-;; (put-text-property start next prop new object))))))
-;; (setq start (text-property-not-all next end prop nil object)))))
+(defun font-lock--remove-face-from-text-property (start
+ end
+ prop value &optional object)
+ "Remove a specific property value from text from START to END.
+Arguments PROP and VALUE specify the property and value to remove. The
+resulting property values are not `eq' to VALUE nor lists containing VALUE.
+Optional argument OBJECT is the string or buffer containing the text."
+ (let ((start (text-property-not-all start end prop nil object)) next prev)
+ (while start
+ (setq next (next-single-property-change start prop object end)
+ prev (get-text-property start prop object))
+ (cond ((or (atom prev)
+ (keywordp (car prev))
+ (eq (car prev) 'foreground-color)
+ (eq (car prev) 'background-color))
+ (when (eq value prev)
+ (remove-list-of-text-properties start next (list prop) object)))
+ ((memq value prev) ;Assume prev is not dotted.
+ (let ((new (remq value prev)))
+ (cond ((null new)
+ (remove-list-of-text-properties start next (list prop)
+ object))
+ ((= (length new) 1)
+ (put-text-property start next prop (car new) object))
+ (t
+ (put-text-property start next prop new object))))))
+ (setq start (text-property-not-all next end prop nil object)))))
;;; End of Additional text property functions.
\f
(cons t (cons keywords
(mapcar #'font-lock-compile-keyword keywords))))
(if (and (not syntactic-keywords)
- (let ((beg-function
- (or font-lock-beginning-of-syntax-function
- syntax-begin-function)))
+ (let ((beg-function syntax-begin-function))
(or (eq beg-function 'beginning-of-defun)
- (get beg-function 'font-lock-syntax-paren-check)))
+ (if (symbolp beg-function)
+ (get beg-function 'font-lock-syntax-paren-check))))
(not beginning-of-defun-function))
;; Try to detect when a string or comment contains something that
;; looks like a defun and would thus confuse font-lock.
(list (car selem))
(mapcar 'identity (car selem))))
(modify-syntax-entry char syntax font-lock-syntax-table)))))
- ;; Syntax function for syntactic fontification?
- (if (nth 4 defaults)
- (set (make-local-variable 'font-lock-beginning-of-syntax-function)
- (nth 4 defaults))
- (kill-local-variable 'font-lock-beginning-of-syntax-function))
+ ;; (nth 4 defaults) used to hold `font-lock-beginning-of-syntax-function',
+ ;; but that was removed in 25.1, so if it's a cons cell, we assume that
+ ;; it's part of the variable alist.
;; Variable alist?
- (dolist (x (nthcdr 5 defaults))
+ (dolist (x (nthcdr (if (consp (nth 4 defaults)) 4 5) defaults))
(set (make-local-variable (car x)) (cdr x)))
;; Set up `font-lock-keywords' last because its value might depend
- ;; on other settings (e.g. font-lock-compile-keywords uses
- ;; font-lock-beginning-of-syntax-function).
+ ;; on other settings.
(set (make-local-variable 'font-lock-keywords)
(font-lock-eval-keywords keywords))
;; Local fontification?