]> code.delx.au - gnu-emacs/blob - lisp/progmodes/prog-mode.el
Merge from emacs-24; up to 2014-07-08T06:24:07Z!eggert@cs.ucla.edu
[gnu-emacs] / lisp / progmodes / prog-mode.el
1 ;;; prog-mode.el --- Generic major mode for programming -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
4
5 ;; Maintainer: emacs-devel@gnu.org
6 ;; Keywords: internal
7 ;; Package: emacs
8
9 ;; This file is part of GNU Emacs.
10
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.
15
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.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Commentary:
25
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.
29
30 ;;; Code:
31
32 (eval-when-compile (require 'cl-lib))
33
34 (defgroup prog-mode nil
35 "Generic programming mode, from which others derive."
36 :group 'languages)
37
38 (defcustom prog-mode-hook nil
39 "Normal hook run when entering Text mode and many related modes."
40 :type 'hook
41 :options '(flyspell-prog-mode abbrev-mode flymake-mode linum-mode
42 prettify-symbols-mode)
43 :group 'prog-mode)
44
45 (defvar prog-mode-map
46 (let ((map (make-sparse-keymap)))
47 (define-key map [?\C-\M-q] 'prog-indent-sexp)
48 map)
49 "Keymap used for programming modes.")
50
51 (defun prog-indent-sexp (&optional defun)
52 "Indent the expression after point.
53 When interactively called with prefix, indent the enclosing defun
54 instead."
55 (interactive "P")
56 (save-excursion
57 (when defun
58 (end-of-line)
59 (beginning-of-defun))
60 (let ((start (point))
61 (end (progn (forward-sexp 1) (point))))
62 (indent-region start end nil))))
63
64 (defvar-local prettify-symbols-alist nil
65 "Alist of symbol prettifications.
66 Each element looks like (SYMBOL . CHARACTER), where the symbol
67 matching SYMBOL (a string, not a regexp) will be shown as
68 CHARACTER instead.")
69
70 (defun prettify-symbols--compose-symbol (alist)
71 "Compose a sequence of characters into a symbol.
72 Regexp match data 0 points to the chars."
73 ;; Check that the chars should really be composed into a symbol.
74 (let* ((start (match-beginning 0))
75 (end (match-end 0))
76 (syntaxes (if (eq (char-syntax (char-after start)) ?w)
77 '(?w ?_) '(?. ?\\)))
78 match)
79 (if (or (memq (char-syntax (or (char-before start) ?\s)) syntaxes)
80 (memq (char-syntax (or (char-after end) ?\s)) syntaxes)
81 ;; syntax-ppss could modify the match data (bug#14595)
82 (progn (setq match (match-string 0)) (nth 8 (syntax-ppss))))
83 ;; No composition for you. Let's actually remove any composition
84 ;; we may have added earlier and which is now incorrect.
85 (remove-text-properties start end '(composition))
86 ;; That's a symbol alright, so add the composition.
87 (compose-region start end (cdr (assoc match alist)))))
88 ;; Return nil because we're not adding any face property.
89 nil)
90
91 (defun prettify-symbols--make-keywords ()
92 (if prettify-symbols-alist
93 `((,(regexp-opt (mapcar 'car prettify-symbols-alist) t)
94 (0 (prettify-symbols--compose-symbol ',prettify-symbols-alist))))
95 nil))
96
97 (defvar-local prettify-symbols--keywords nil)
98
99 ;;;###autoload
100 (define-minor-mode prettify-symbols-mode
101 "Toggle Prettify Symbols mode.
102 With a prefix argument ARG, enable Prettify Symbols mode if ARG is
103 positive, and disable it otherwise. If called from Lisp, enable
104 the mode if ARG is omitted or nil.
105
106 When Prettify Symbols mode and font-locking are enabled, symbols are
107 prettified (displayed as composed characters) according to the rules
108 in `prettify-symbols-alist' (which see), which are locally defined
109 by major modes supporting prettifying. To add further customizations
110 for a given major mode, you can modify `prettify-symbols-alist' thus:
111
112 (add-hook 'emacs-lisp-mode-hook
113 (lambda ()
114 (push '(\"<=\" . ?≤) prettify-symbols-alist)))
115
116 You can enable this mode locally in desired buffers, or use
117 `global-prettify-symbols-mode' to enable it for all modes that
118 support it."
119 :init-value nil
120 (if prettify-symbols-mode
121 ;; Turn on
122 (when (setq prettify-symbols--keywords (prettify-symbols--make-keywords))
123 (font-lock-add-keywords nil prettify-symbols--keywords)
124 (setq-local font-lock-extra-managed-props
125 (cons 'composition font-lock-extra-managed-props))
126 (font-lock-flush))
127 ;; Turn off
128 (when prettify-symbols--keywords
129 (font-lock-remove-keywords nil prettify-symbols--keywords)
130 (setq prettify-symbols--keywords nil))
131 (when (memq 'composition font-lock-extra-managed-props)
132 (setq font-lock-extra-managed-props (delq 'composition
133 font-lock-extra-managed-props))
134 (with-silent-modifications
135 (remove-text-properties (point-min) (point-max) '(composition nil))))))
136
137 (defun turn-on-prettify-symbols-mode ()
138 (when (and (not prettify-symbols-mode)
139 (local-variable-p 'prettify-symbols-alist))
140 (prettify-symbols-mode 1)))
141
142 ;;;###autoload
143 (define-globalized-minor-mode global-prettify-symbols-mode
144 prettify-symbols-mode turn-on-prettify-symbols-mode)
145
146 ;;;###autoload
147 (define-derived-mode prog-mode fundamental-mode "Prog"
148 "Major mode for editing programming language source code."
149 (setq-local require-final-newline mode-require-final-newline)
150 (setq-local parse-sexp-ignore-comments t)
151 ;; Any programming language is always written left to right.
152 (setq bidi-paragraph-direction 'left-to-right))
153
154 (provide 'prog-mode)
155
156 ;;; prog-mode.el ends here