Document reserved keys
[emacs.git] / lisp / progmodes / prog-mode.el
blob19269766c9038f72d6ebc0741d756c0bcf67d56c
1 ;;; prog-mode.el --- Generic major mode for programming -*- lexical-binding: t -*-
3 ;; Copyright (C) 2013-2018 Free Software Foundation, Inc.
5 ;; Maintainer: emacs-devel@gnu.org
6 ;; Keywords: internal
7 ;; Package: emacs
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24 ;;; Commentary:
26 ;; This major mode is mostly intended as a parent of other programming
27 ;; modes. All major modes for programming languages should derive from this
28 ;; mode so that users can put generic customization on prog-mode-hook.
30 ;;; Code:
32 (eval-when-compile (require 'cl-lib)
33 (require 'subr-x))
35 (defgroup prog-mode nil
36 "Generic programming mode, from which others derive."
37 :group 'languages)
39 (defcustom prog-mode-hook nil
40 "Normal hook run when entering programming modes."
41 :type 'hook
42 :options '(flyspell-prog-mode abbrev-mode flymake-mode linum-mode
43 prettify-symbols-mode)
44 :group 'prog-mode)
46 (defvar prog-mode-map
47 (let ((map (make-sparse-keymap)))
48 (define-key map [?\C-\M-q] 'prog-indent-sexp)
49 map)
50 "Keymap used for programming modes.")
52 (defvar prog-indentation-context nil
53 "When non-nil, provides context for indenting embedded code chunks.
55 There are languages where part of the code is actually written in
56 a sub language, e.g., a Yacc/Bison or ANTLR grammar can also include
57 JS or Python code. This variable enables the primary mode of the
58 main language to use the indentation engine of the sub-mode for
59 lines in code chunks written in the sub-mode's language.
61 When a major mode of such a main language decides to delegate the
62 indentation of a line/region to the indentation engine of the sub
63 mode, it should bind this variable to non-nil around the call.
65 The non-nil value should be a list of the form:
67 (FIRST-COLUMN . REST)
69 FIRST-COLUMN is the column the indentation engine of the sub-mode
70 should use for top-level language constructs inside the code
71 chunk (instead of 0).
73 REST is currently unused.")
75 (defun prog-indent-sexp (&optional defun)
76 "Indent the expression after point.
77 When interactively called with prefix, indent the enclosing defun
78 instead."
79 (interactive "P")
80 (save-excursion
81 (when defun
82 (end-of-line)
83 (beginning-of-defun))
84 (let ((start (point))
85 (end (progn (forward-sexp 1) (point))))
86 (indent-region start end nil))))
88 (defun prog-first-column ()
89 "Return the indentation column normally used for top-level constructs."
90 (or (car prog-indentation-context) 0))
92 (defvar-local prettify-symbols-alist nil
93 "Alist of symbol prettifications.
94 Each element looks like (SYMBOL . CHARACTER), where the symbol
95 matching SYMBOL (a string, not a regexp) will be shown as
96 CHARACTER instead.
98 CHARACTER can be a character, or it can be a list or vector, in
99 which case it will be used to compose the new symbol as per the
100 third argument of `compose-region'.")
102 (defun prettify-symbols-default-compose-p (start end _match)
103 "Return true iff the symbol MATCH should be composed.
104 The symbol starts at position START and ends at position END.
105 This is the default for `prettify-symbols-compose-predicate'
106 which is suitable for most programming languages such as C or Lisp."
107 ;; Check that the chars should really be composed into a symbol.
108 (let* ((syntaxes-beg (if (memq (char-syntax (char-after start)) '(?w ?_))
109 '(?w ?_) '(?. ?\\)))
110 (syntaxes-end (if (memq (char-syntax (char-before end)) '(?w ?_))
111 '(?w ?_) '(?. ?\\))))
112 (not (or (memq (char-syntax (or (char-before start) ?\s)) syntaxes-beg)
113 (memq (char-syntax (or (char-after end) ?\s)) syntaxes-end)
114 (nth 8 (syntax-ppss))))))
116 (defvar-local prettify-symbols-compose-predicate
117 #'prettify-symbols-default-compose-p
118 "A predicate for deciding if the currently matched symbol is to be composed.
119 The matched symbol is the car of one entry in `prettify-symbols-alist'.
120 The predicate receives the match's start and end positions as well
121 as the match-string as arguments.")
123 (defun prettify-symbols--compose-symbol (alist)
124 "Compose a sequence of characters into a symbol.
125 Regexp match data 0 specifies the characters to be composed."
126 ;; Check that the chars should really be composed into a symbol.
127 (let ((start (match-beginning 0))
128 (end (match-end 0))
129 (match (match-string 0)))
130 (if (and (not (equal prettify-symbols--current-symbol-bounds (list start end)))
131 (funcall prettify-symbols-compose-predicate start end match))
132 ;; That's a symbol alright, so add the composition.
133 (with-silent-modifications
134 (compose-region start end (cdr (assoc match alist)))
135 (add-text-properties
136 start end
137 `(prettify-symbols-start ,start prettify-symbols-end ,end)))
138 ;; No composition for you. Let's actually remove any
139 ;; composition we may have added earlier and which is now
140 ;; incorrect.
141 (remove-text-properties start end '(composition
142 prettify-symbols-start
143 prettify-symbols-end))))
144 ;; Return nil because we're not adding any face property.
145 nil)
147 (defun prettify-symbols--make-keywords ()
148 (if prettify-symbols-alist
149 `((,(regexp-opt (mapcar 'car prettify-symbols-alist) t)
150 (0 (prettify-symbols--compose-symbol ',prettify-symbols-alist))))
151 nil))
153 (defvar-local prettify-symbols--keywords nil)
155 (defvar-local prettify-symbols--current-symbol-bounds nil)
157 (defcustom prettify-symbols-unprettify-at-point nil
158 "If non-nil, show the non-prettified version of a symbol when point is on it.
159 If set to the symbol `right-edge', also unprettify if point
160 is immediately after the symbol. The prettification will be
161 reapplied as soon as point moves away from the symbol. If
162 set to nil, the prettification persists even when point is
163 on the symbol."
164 :version "25.1"
165 :type '(choice (const :tag "Never unprettify" nil)
166 (const :tag "Unprettify when point is inside" t)
167 (const :tag "Unprettify when point is inside or at right edge" right-edge))
168 :group 'prog-mode)
170 (defun prettify-symbols--post-command-hook ()
171 (cl-labels ((get-prop-as-list
172 (prop)
173 (remove nil
174 (list (get-text-property (point) prop)
175 (when (and (eq prettify-symbols-unprettify-at-point 'right-edge)
176 (not (bobp)))
177 (get-text-property (1- (point)) prop))))))
178 ;; Re-apply prettification to the previous symbol.
179 (when (and prettify-symbols--current-symbol-bounds
180 (or (< (point) (car prettify-symbols--current-symbol-bounds))
181 (> (point) (cadr prettify-symbols--current-symbol-bounds))
182 (and (not (eq prettify-symbols-unprettify-at-point 'right-edge))
183 (= (point) (cadr prettify-symbols--current-symbol-bounds)))))
184 (apply #'font-lock-flush prettify-symbols--current-symbol-bounds)
185 (setq prettify-symbols--current-symbol-bounds nil))
186 ;; Unprettify the current symbol.
187 (when-let* ((c (get-prop-as-list 'composition))
188 (s (get-prop-as-list 'prettify-symbols-start))
189 (e (get-prop-as-list 'prettify-symbols-end))
190 (s (apply #'min s))
191 (e (apply #'max e)))
192 (with-silent-modifications
193 (setq prettify-symbols--current-symbol-bounds (list s e))
194 (remove-text-properties s e '(composition))))))
196 ;;;###autoload
197 (define-minor-mode prettify-symbols-mode
198 "Toggle Prettify Symbols mode.
199 With a prefix argument ARG, enable Prettify Symbols mode if ARG is
200 positive, and disable it otherwise. If called from Lisp, enable
201 the mode if ARG is omitted or nil.
203 When Prettify Symbols mode and font-locking are enabled, symbols are
204 prettified (displayed as composed characters) according to the rules
205 in `prettify-symbols-alist' (which see), which are locally defined
206 by major modes supporting prettifying. To add further customizations
207 for a given major mode, you can modify `prettify-symbols-alist' thus:
209 (add-hook \\='emacs-lisp-mode-hook
210 (lambda ()
211 (push \\='(\"<=\" . ?≤) prettify-symbols-alist)))
213 You can enable this mode locally in desired buffers, or use
214 `global-prettify-symbols-mode' to enable it for all modes that
215 support it."
216 :init-value nil
217 (if prettify-symbols-mode
218 ;; Turn on
219 (when (setq prettify-symbols--keywords (prettify-symbols--make-keywords))
220 (font-lock-add-keywords nil prettify-symbols--keywords)
221 (setq-local font-lock-extra-managed-props
222 (append font-lock-extra-managed-props
223 '(composition
224 prettify-symbols-start
225 prettify-symbols-end)))
226 (when prettify-symbols-unprettify-at-point
227 (add-hook 'post-command-hook
228 #'prettify-symbols--post-command-hook nil t))
229 (font-lock-flush))
230 ;; Turn off
231 (remove-hook 'post-command-hook #'prettify-symbols--post-command-hook t)
232 (when prettify-symbols--keywords
233 (font-lock-remove-keywords nil prettify-symbols--keywords)
234 (setq prettify-symbols--keywords nil))
235 (when (memq 'composition font-lock-extra-managed-props)
236 (setq font-lock-extra-managed-props (delq 'composition
237 font-lock-extra-managed-props))
238 (with-silent-modifications
239 (remove-text-properties (point-min) (point-max) '(composition nil))))))
241 (defun turn-on-prettify-symbols-mode ()
242 (when (and (not prettify-symbols-mode)
243 (local-variable-p 'prettify-symbols-alist))
244 (prettify-symbols-mode 1)))
246 ;;;###autoload
247 (define-globalized-minor-mode global-prettify-symbols-mode
248 prettify-symbols-mode turn-on-prettify-symbols-mode)
250 ;;;###autoload
251 (define-derived-mode prog-mode fundamental-mode "Prog"
252 "Major mode for editing programming language source code."
253 (setq-local require-final-newline mode-require-final-newline)
254 (setq-local parse-sexp-ignore-comments t)
255 ;; Any programming language is always written left to right.
256 (setq bidi-paragraph-direction 'left-to-right))
258 (provide 'prog-mode)
260 ;;; prog-mode.el ends here