aboutsummaryrefslogtreecommitdiffhomepage
path: root/coq/coq-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'coq/coq-mode.el')
-rw-r--r--coq/coq-mode.el261
1 files changed, 261 insertions, 0 deletions
diff --git a/coq/coq-mode.el b/coq/coq-mode.el
new file mode 100644
index 00000000..f5d40027
--- /dev/null
+++ b/coq/coq-mode.el
@@ -0,0 +1,261 @@
+;;; 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>
+
+;; License: GPL (GNU GENERAL PUBLIC LICENSE)
+
+;;; 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" . ?λ)
+ ("->" . ?→)
+ ("<-" . ?←)
+ ("=>" . ?⇒)
+ ;; ("~>" . ?↝) ;; 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)
+
+ (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)
+
+ ;; 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