LCOV - code coverage report
Current view: top level - lisp/progmodes - prog-mode.el (source / functions) Hit Total Coverage
Test: tramp-tests-after.info Lines: 3 81 3.7 %
Date: 2017-08-30 10:12:24 Functions: 1 11 9.1 %

          Line data    Source code
       1             : ;;; prog-mode.el --- Generic major mode for programming  -*- lexical-binding: t -*-
       2             : 
       3             : ;; Copyright (C) 2013-2017 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             :                    (require 'subr-x))
      34             : 
      35             : (defgroup prog-mode nil
      36             :   "Generic programming mode, from which others derive."
      37             :   :group 'languages)
      38             : 
      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)
      45             : 
      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.")
      51             : 
      52             : (defvar prog-indentation-context nil
      53             :   "When non-nil, provides context for indenting embedded code chunks.
      54             : 
      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 also consists
      57             : of plain C code.  This variable enables the major 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.
      60             : 
      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.
      64             : 
      65             : The non-nil value should be a list of the form:
      66             : 
      67             :    (FIRST-COLUMN (START . END) PREVIOUS-CHUNKS)
      68             : 
      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).
      72             : 
      73             : START and END specify the region of the code chunk.  END can be
      74             : nil, which stands for the value of `point-max'.  The function
      75             : `prog-widen' uses this to restore restrictions imposed by the
      76             : sub-mode's indentation engine.
      77             : 
      78             : PREVIOUS-CHUNKS, if non-nil, provides the indentation engine of
      79             : the sub-mode with the virtual context of the code chunk.  Valid
      80             : values are:
      81             : 
      82             :  - A string containing text which the indentation engine can
      83             :    consider as standing in front of the code chunk.  To cache the
      84             :    string's calculated syntactic information for repeated calls
      85             :    with the same string, the sub-mode can add text-properties to
      86             :    the string.
      87             : 
      88             :    A typical use case is for grammars with code chunks which are
      89             :    to be indented like function bodies -- the string would contain
      90             :    the corresponding function preamble.
      91             : 
      92             :  - A function, to be called with the start position of the current
      93             :    chunk.  It should return either the region of the previous chunk
      94             :    as (PREV-START . PREV-END), or nil if there is no previous chunk.
      95             : 
      96             :    A typical use case are literate programming sources -- the
      97             :    function would successively return the previous code chunks.")
      98             : 
      99             : (defun prog-indent-sexp (&optional defun)
     100             :   "Indent the expression after point.
     101             : When interactively called with prefix, indent the enclosing defun
     102             : instead."
     103             :   (interactive "P")
     104           0 :   (save-excursion
     105           0 :     (when defun
     106           0 :       (end-of-line)
     107           0 :       (beginning-of-defun))
     108           0 :     (let ((start (point))
     109           0 :           (end (progn (forward-sexp 1) (point))))
     110           0 :       (indent-region start end nil))))
     111             : 
     112             : (defun prog-first-column ()
     113             :   "Return the indentation column normally used for top-level constructs."
     114           0 :   (or (car prog-indentation-context) 0))
     115             : 
     116             : (defun prog-widen ()
     117             :   "Remove restrictions (narrowing) from current code chunk or buffer.
     118             : This function should be used instead of `widen' in any function used
     119             : by the indentation engine to make it respect the value of
     120             : `prog-indentation-context'.
     121             : 
     122             : This function (like `widen') is useful inside a
     123             : `save-restriction' to make the indentation correctly work when
     124             : narrowing is in effect."
     125           0 :   (let ((chunk (cadr prog-indentation-context)))
     126           0 :     (if chunk
     127             :         ;; No call to `widen' is necessary here, as narrow-to-region
     128             :         ;; changes (not just narrows) the existing restrictions
     129           0 :         (narrow-to-region (car chunk) (or (cdr chunk) (point-max)))
     130           0 :       (widen))))
     131             : 
     132             : 
     133             : (defvar-local prettify-symbols-alist nil
     134             :   "Alist of symbol prettifications.
     135             : Each element looks like (SYMBOL . CHARACTER), where the symbol
     136             : matching SYMBOL (a string, not a regexp) will be shown as
     137             : CHARACTER instead.
     138             : 
     139             : CHARACTER can be a character, or it can be a list or vector, in
     140             : which case it will be used to compose the new symbol as per the
     141             : third argument of `compose-region'.")
     142             : 
     143             : (defun prettify-symbols-default-compose-p (start end _match)
     144             :   "Return true iff the symbol MATCH should be composed.
     145             : The symbol starts at position START and ends at position END.
     146             : This is the default for `prettify-symbols-compose-predicate'
     147             : which is suitable for most programming languages such as C or Lisp."
     148             :   ;; Check that the chars should really be composed into a symbol.
     149           0 :   (let* ((syntaxes-beg (if (memq (char-syntax (char-after start)) '(?w ?_))
     150           0 :                            '(?w ?_) '(?. ?\\)))
     151           0 :          (syntaxes-end (if (memq (char-syntax (char-before end)) '(?w ?_))
     152           0 :                            '(?w ?_) '(?. ?\\))))
     153           0 :     (not (or (memq (char-syntax (or (char-before start) ?\s)) syntaxes-beg)
     154           0 :              (memq (char-syntax (or (char-after end) ?\s)) syntaxes-end)
     155           0 :              (nth 8 (syntax-ppss))))))
     156             : 
     157             : (defvar-local prettify-symbols-compose-predicate
     158             :   #'prettify-symbols-default-compose-p
     159             :   "A predicate for deciding if the currently matched symbol is to be composed.
     160             : The matched symbol is the car of one entry in `prettify-symbols-alist'.
     161             : The predicate receives the match's start and end positions as well
     162             : as the match-string as arguments.")
     163             : 
     164             : (defun prettify-symbols--compose-symbol (alist)
     165             :   "Compose a sequence of characters into a symbol.
     166             : Regexp match data 0 specifies the characters to be composed."
     167             :   ;; Check that the chars should really be composed into a symbol.
     168           0 :   (let ((start (match-beginning 0))
     169           0 :         (end (match-end 0))
     170           0 :         (match (match-string 0)))
     171           0 :     (if (and (not (equal prettify-symbols--current-symbol-bounds (list start end)))
     172           0 :              (funcall prettify-symbols-compose-predicate start end match))
     173             :         ;; That's a symbol alright, so add the composition.
     174           0 :         (with-silent-modifications
     175           0 :           (compose-region start end (cdr (assoc match alist)))
     176           0 :           (add-text-properties
     177           0 :            start end
     178           0 :            `(prettify-symbols-start ,start prettify-symbols-end ,end)))
     179             :       ;; No composition for you.  Let's actually remove any
     180             :       ;; composition we may have added earlier and which is now
     181             :       ;; incorrect.
     182           0 :       (remove-text-properties start end '(composition
     183             :                                           prettify-symbols-start
     184           0 :                                           prettify-symbols-end))))
     185             :   ;; Return nil because we're not adding any face property.
     186             :   nil)
     187             : 
     188             : (defun prettify-symbols--make-keywords ()
     189           0 :   (if prettify-symbols-alist
     190           0 :       `((,(regexp-opt (mapcar 'car prettify-symbols-alist) t)
     191           0 :          (0 (prettify-symbols--compose-symbol ',prettify-symbols-alist))))
     192           0 :     nil))
     193             : 
     194             : (defvar-local prettify-symbols--keywords nil)
     195             : 
     196             : (defvar-local prettify-symbols--current-symbol-bounds nil)
     197             : 
     198             : (defcustom prettify-symbols-unprettify-at-point nil
     199             :   "If non-nil, show the non-prettified version of a symbol when point is on it.
     200             : If set to the symbol `right-edge', also unprettify if point
     201             : is immediately after the symbol.  The prettification will be
     202             : reapplied as soon as point moves away from the symbol.  If
     203             : set to nil, the prettification persists even when point is
     204             : on the symbol."
     205             :   :version "25.1"
     206             :   :type '(choice (const :tag "Never unprettify" nil)
     207             :                  (const :tag "Unprettify when point is inside" t)
     208             :                  (const :tag "Unprettify when point is inside or at right edge" right-edge))
     209             :   :group 'prog-mode)
     210             : 
     211             : (defun prettify-symbols--post-command-hook ()
     212           0 :   (cl-labels ((get-prop-as-list
     213             :                (prop)
     214           0 :                (remove nil
     215           0 :                        (list (get-text-property (point) prop)
     216           0 :                              (when (and (eq prettify-symbols-unprettify-at-point 'right-edge)
     217           0 :                                         (not (bobp)))
     218           0 :                                (get-text-property (1- (point)) prop))))))
     219             :     ;; Re-apply prettification to the previous symbol.
     220           0 :     (when (and prettify-symbols--current-symbol-bounds
     221           0 :                (or (< (point) (car prettify-symbols--current-symbol-bounds))
     222           0 :                    (> (point) (cadr prettify-symbols--current-symbol-bounds))
     223           0 :                    (and (not (eq prettify-symbols-unprettify-at-point 'right-edge))
     224           0 :                         (= (point) (cadr prettify-symbols--current-symbol-bounds)))))
     225           0 :       (apply #'font-lock-flush prettify-symbols--current-symbol-bounds)
     226           0 :       (setq prettify-symbols--current-symbol-bounds nil))
     227             :     ;; Unprettify the current symbol.
     228           0 :     (when-let ((c (get-prop-as-list 'composition))
     229           0 :                (s (get-prop-as-list 'prettify-symbols-start))
     230           0 :                (e (get-prop-as-list 'prettify-symbols-end))
     231           0 :                (s (apply #'min s))
     232           0 :                (e (apply #'max e)))
     233           0 :       (with-silent-modifications
     234           0 :         (setq prettify-symbols--current-symbol-bounds (list s e))
     235           0 :         (remove-text-properties s e '(composition))))))
     236             : 
     237             : ;;;###autoload
     238             : (define-minor-mode prettify-symbols-mode
     239             :   "Toggle Prettify Symbols mode.
     240             : With a prefix argument ARG, enable Prettify Symbols mode if ARG is
     241             : positive, and disable it otherwise.  If called from Lisp, enable
     242             : the mode if ARG is omitted or nil.
     243             : 
     244             : When Prettify Symbols mode and font-locking are enabled, symbols are
     245             : prettified (displayed as composed characters) according to the rules
     246             : in `prettify-symbols-alist' (which see), which are locally defined
     247             : by major modes supporting prettifying.  To add further customizations
     248             : for a given major mode, you can modify `prettify-symbols-alist' thus:
     249             : 
     250             :   (add-hook \\='emacs-lisp-mode-hook
     251             :             (lambda ()
     252             :               (push \\='(\"<=\" . ?≤) prettify-symbols-alist)))
     253             : 
     254             : You can enable this mode locally in desired buffers, or use
     255             : `global-prettify-symbols-mode' to enable it for all modes that
     256             : support it."
     257             :   :init-value nil
     258           0 :   (if prettify-symbols-mode
     259             :       ;; Turn on
     260           0 :       (when (setq prettify-symbols--keywords (prettify-symbols--make-keywords))
     261           0 :         (font-lock-add-keywords nil prettify-symbols--keywords)
     262           0 :         (setq-local font-lock-extra-managed-props
     263           0 :                     (append font-lock-extra-managed-props
     264             :                             '(composition
     265             :                               prettify-symbols-start
     266           0 :                               prettify-symbols-end)))
     267           0 :         (when prettify-symbols-unprettify-at-point
     268           0 :           (add-hook 'post-command-hook
     269           0 :                     #'prettify-symbols--post-command-hook nil t))
     270           0 :         (font-lock-flush))
     271             :     ;; Turn off
     272           0 :     (remove-hook 'post-command-hook #'prettify-symbols--post-command-hook t)
     273           0 :     (when prettify-symbols--keywords
     274           0 :       (font-lock-remove-keywords nil prettify-symbols--keywords)
     275           0 :       (setq prettify-symbols--keywords nil))
     276           0 :     (when (memq 'composition font-lock-extra-managed-props)
     277           0 :       (setq font-lock-extra-managed-props (delq 'composition
     278           0 :                                                 font-lock-extra-managed-props))
     279           0 :       (with-silent-modifications
     280           0 :         (remove-text-properties (point-min) (point-max) '(composition nil))))))
     281             : 
     282             : (defun turn-on-prettify-symbols-mode ()
     283           0 :   (when (and (not prettify-symbols-mode)
     284           0 :              (local-variable-p 'prettify-symbols-alist))
     285           0 :     (prettify-symbols-mode 1)))
     286             : 
     287             : ;;;###autoload
     288             : (define-globalized-minor-mode global-prettify-symbols-mode
     289             :   prettify-symbols-mode turn-on-prettify-symbols-mode)
     290             : 
     291             : ;;;###autoload
     292             : (define-derived-mode prog-mode fundamental-mode "Prog"
     293             :   "Major mode for editing programming language source code."
     294          69 :   (setq-local require-final-newline mode-require-final-newline)
     295          69 :   (setq-local parse-sexp-ignore-comments t)
     296             :   ;; Any programming language is always written left to right.
     297          69 :   (setq bidi-paragraph-direction 'left-to-right))
     298             : 
     299             : (provide 'prog-mode)
     300             : 
     301             : ;;; prog-mode.el ends here

Generated by: LCOV version 1.12