1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
;;; coq-mode.el --- Major mode for Coq proof assistant -*- lexical-binding:t -*-
;; This file is part of Proof General.
;; Portions © Copyright 1994-2012 David Aspinall and University of Edinburgh
;; Portions © Copyright 2003, 2012, 2014, 2018 Free Software Foundation, Inc.
;; Portions © Copyright 2001-2017 Pierre Courtieu
;; Portions © Copyright 2010, 2016 Erik Martin-Dorel
;; Portions © Copyright 2011-2013, 2016-2017 Hendrik Tews
;; Portions © Copyright 2015-2017 Clément Pit-Claudel
;; Authors: Healfdene Goguen, Pierre Courtieu
;; Maintainer: Pierre Courtieu <Pierre.Courtieu@cnam.fr>
;; SPDX-License-Identifier: GPL-3.0-or-later
;;; Commentary:
;;
;;; Code:
(unless (locate-library "coq-mode")
(add-to-list 'load-path
(expand-file-name
(file-name-directory (or load-file-name buffer-file-name)))))
;; (if t (require 'coq nil 'noerror))
(require 'coq-smie)
(require 'coq-syntax) ;For font-lock-keywords
(defgroup coq-mode ()
"Major mode to edit Coq code."
:group 'programming)
;; prettify is in emacs > 24.4
;; FIXME: this should probably be done like for smie above.
(defvar coq-may-use-prettify (fboundp 'prettify-symbols-mode))
(defcustom coq-prog-name
(or (if (executable-find "coqtop") "coqtop")
(let ((exec-path (append exec-path '("C:/Program Files/Coq/bin"))))
(executable-find "coqtop"))
"coqtop")
"Name of program to run as Coq.
On Windows with latest Coq package you might need something like:
C:/Program Files/Coq/bin/coqtop.opt.exe
instead of just \"coqtop\".
This must be a single program name with no arguments. See option
`coq-prog-args' to manually adjust the arguments to the Coq process.
See also `coq-prog-env' to adjust the environment."
:type 'string
:group 'coq
:group 'coq-mode)
(defun get-coq-library-directory ()
(let ((default-directory
(if (file-accessible-directory-p default-directory)
default-directory
"/")))
(or (ignore-errors (car (process-lines coq-prog-name "-where")))
"/usr/local/lib/coq")))
(defconst coq-library-directory (get-coq-library-directory) ;; FIXME Should be refreshed more often
"The coq library directory, as reported by \"coqtop -where\".")
(defcustom coq-tags (expand-file-name "/theories/TAGS" coq-library-directory)
"The default TAGS table for the Coq library."
:type 'string)
(defcustom coq-use-pg t
"If non-nil, activate the ProofGeneral backend."
:type 'boolean)
;; prettify is in emacs > 24.4
(defvar prettify-symbols-alist)
(defconst coq-prettify-symbols-alist
'(;;("not" . ?¬)
("/\\" . ?∧)
;; ("/\\" . ?⋀)
("\\/" . ?∨)
;; ("\\/" . ?⋁)
("forall" . ?∀)
;; ("forall" . ?Π)
("fun" . ?λ)
("exists" . ?∃)
("->" . ?→)
("<-" . ?←)
("=>" . ?⇒)
;; ("~>" . ?↝) ;; less desirable
;; ("-<" . ?↢) ;; Paterson's arrow syntax
;; ("-<" . ?⤙) ;; nicer but uncommon
("::" . ?∷)
))
(defvar coq-mode-map
(let ((map (make-sparse-keymap)))
map)
"Keymap for `coq-mode'.")
(defvar coq-mode-syntax-table
(let ((st (make-syntax-table)))
(modify-syntax-entry ?\$ "." st)
(modify-syntax-entry ?\/ "." st)
(modify-syntax-entry ?\\ "." st)
(modify-syntax-entry ?+ "." st)
(modify-syntax-entry ?- "." st)
(modify-syntax-entry ?= "." st)
(modify-syntax-entry ?% "." st)
(modify-syntax-entry ?< "." st)
(modify-syntax-entry ?> "." st)
(modify-syntax-entry ?\& "." st)
(modify-syntax-entry ?_ "_" st) ; beware: word consituent EXCEPT in head position
(modify-syntax-entry ?\' "_" st) ; always word constituent
(modify-syntax-entry ?∀ "." st)
(modify-syntax-entry ?∃ "." st)
(modify-syntax-entry ?λ "." st) ;; maybe a bad idea... lambda is a letter
(modify-syntax-entry ?\| "." st)
;; Should maybe be "_" but it makes coq-find-and-forget (in coq.el) bug,
;; hence the coq-with-altered-syntax-table to put "." into "_" class
;; temporarily.
(modify-syntax-entry ?\. "." st)
(modify-syntax-entry ?\* ". 23n" st)
(modify-syntax-entry ?\( "()1" st)
(modify-syntax-entry ?\) ")(4" st)
st))
;; FIXME, deal with interactive "Definition"
(defvar coq-outline-regexp
;; (concat "(\\*\\|"
(concat "[ ]*" (regexp-opt
'(
"Ltac" "Corr" "Modu" "Sect" "Chap" "Goal"
"Definition" "Lemm" "Theo" "Fact" "Rema"
"Mutu" "Fixp" "Func")
t)))
(defvar coq-outline-heading-end-regexp "\\.[ \t\n]")
(defun coq-near-comment-region ()
"Return a list of the forme (BEG END).
BEG,END being is the comment region near position PT.
Return nil if PT is not near a comment.
Near here means PT is either inside or just aside of a comment."
(save-excursion
(let ((pos (point))
(ppss (syntax-ppss (1- (point)))))
(unless (nth 4 ppss)
;; We're not squarely inside a comment, nor at its end.
;; But we may still be at the beginning of a comment.
(setq ppss (syntax-ppss
(+ pos (if (looking-at comment-start-skip) 2 1)))))
(when (nth 4 ppss)
(goto-char (nth 8 ppss))
(list (point)
(progn (forward-comment 1) (point)))))))
(defun coq-fill-paragraph-function (_n)
"Coq mode specific fill-paragraph function. Fills only comment at point."
(let ((reg (coq-near-comment-region)))
(when reg
(fill-region (car reg) (cadr reg))))
t);; true to not fallback to standard fill function
;; TODO (but only for paragraphs in comments)
;; Should recognize coqdoc bullets, stars etc... Unplugged for now.
(defun coq-adaptive-fill-function ()
(let ((reg (coq-near-comment-region)))
(save-excursion
(goto-char (car reg))
(re-search-forward "\\((\\*+ ?\\)\\( *\\)")
(let* ((cm-start (match-string 1))
(cm-prefix (match-string 2)))
(concat (make-string (length cm-start) ? ) cm-prefix)))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.v\\'" . coq-mode))
(defun coq--parent-mode ()
(if coq-use-pg (proof-mode) (prog-mode)))
;;;###autoload
(define-derived-mode coq-mode coq--parent-mode "Coq"
"Major mode for Coq scripts.
\\{coq-mode-map}"
;; SMIE needs this.
(set (make-local-variable 'parse-sexp-ignore-comments) t)
;; Coq error messages are thrown off by TAB chars.
(set (make-local-variable 'indent-tabs-mode) nil)
;; Coq defninition never start by a parenthesis
(set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
;; do not break lines in code when filling
(set (make-local-variable 'fill-nobreak-predicate)
(lambda () (not (nth 4 (syntax-ppss)))))
;; coq mode specific indentation function
(set (make-local-variable 'fill-paragraph-function)
#'coq-fill-paragraph-function)
;; TODO (but only for paragraphs in comments)
;; (set (make-local-variable 'paragraph-start) "[ ]*\\((\\**\\|$\\)")
;; (set (make-local-variable 'paragraph-separate) "\\**) *$\\|$")
;; (set (make-local-variable 'adaptive-fill-function)
;; #'coq-adaptive-fill-function)
(setq-local comment-start "(*")
(setq-local comment-end "*)")
(set (make-local-variable 'comment-start-skip) "(\\*+ *")
(set (make-local-variable 'comment-end-skip) " *\\*+)")
(smie-setup coq-smie-grammar #'coq-smie-rules
:forward-token #'coq-smie-forward-token
:backward-token #'coq-smie-backward-token)
(add-hook 'smie-indent-functions #'coq-smie--args nil t)
;; old indentation code.
;; (require 'coq-indent)
;; (setq
;; ;; indentation is implemented in coq-indent.el
;; indent-line-function #'coq-indent-line
;; proof-indent-any-regexp coq-indent-any-regexp
;; proof-indent-open-regexp coq-indent-open-regexp
;; proof-indent-close-regexp coq-indent-close-regexp)
;; (set (make-local-variable 'indent-region-function) #'coq-indent-region)
;; we can cope with nested comments
(set (make-local-variable 'comment-quote-nested) nil)
;; FIXME: have abbreviation without holes
;(if coq-use-editing-holes (holes-mode 1))
(if (fboundp 'holes-mode) (holes-mode 1))
;; Setup Proof-General interface to Coq.
(if coq-use-pg (coq-pg-setup))
;; font-lock
(setq-local font-lock-defaults '(coq-font-lock-keywords-1))
;; outline
(setq-local outline-regexp coq-outline-regexp)
(setq-local outline-heading-end-regexp coq-outline-heading-end-regexp)
;; tags
(if (file-exists-p coq-tags)
(set (make-local-variable 'tags-table-list)
(cons coq-tags tags-table-list)))
(set (make-local-variable 'blink-matching-paren-dont-ignore-comments) t)
(when coq-may-use-prettify
(set (make-local-variable 'prettify-symbols-alist)
coq-prettify-symbols-alist)))
(provide 'coq-mode)
;; Local Variables: ***
;; fill-column: 79 ***
;; indent-tabs-mode: nil ***
;; coding: utf-8 ***
;; End: ***
;;; coq-mode.el ends here
|