]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/ada-mode/ada-mode.el
* ada-mode: Use lexical-binding since it requires Emacs-24.2 anyway
[gnu-emacs-elpa] / packages / ada-mode / ada-mode.el
old mode 100755 (executable)
new mode 100644 (file)
index 05360e0..9e0bdfc
@@ -1,12 +1,13 @@
-;;; ada-mode.el --- major-mode for editing Ada sources
+;;; ada-mode.el --- major-mode for editing Ada sources  -*- lexical-binding:t -*-
 ;;
-;;; Copyright (C) 1994, 1995, 1997 - 2014  Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1997 - 2015  Free Software Foundation, Inc.
 ;;
 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
 ;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
-;; Keywords FIXME: languages, ada ELPA broken for multiple keywords
-;; Version: 5.1.4
-;; package-requires: ((wisi "1.0.4") (cl-lib "0.4") (emacs "24.2"))
+;; Keywords: languages
+;;  ada
+;; Version: 5.1.8
+;; package-requires: ((wisi "1.1.1") (cl-lib "0.4") (emacs "24.2"))
 ;; url: http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html
 ;;
 ;; (Gnu ELPA requires single digits between dots in versions)
 (defun ada-mode-version ()
   "Return Ada mode version."
   (interactive)
-  (let ((version-string "5.1.4"))
+  (let ((version-string "5.1.8"))
     ;; must match:
     ;; ada-mode.texi
-    ;; README
+    ;; README-ada-mode
     ;; Version: above
     (if (called-interactively-p 'interactive)
        (message version-string)
@@ -195,8 +196,7 @@ Non-nil means automatically change case of preceding word while typing.
 Casing of Ada keywords is done according to `ada-case-keyword',
 identifiers are Mixed_Case."
   :type  'boolean
-  :group 'ada
-  :safe  'booleanp)
+  :safe  #'booleanp)
 (make-variable-buffer-local 'ada-auto-case)
 
 (defcustom ada-case-exception-file nil
@@ -214,8 +214,8 @@ character, and end either at the end of the word or at a _
 character.  Characters after the first word are ignored, and not
 preserved when the list is written back to the file."
   :type  '(repeat (file))
-  :group 'ada
-  :safe  'listp)
+  ;; :safe  #'listp    ;FIXME: is '("~/.emacs" "~/.bashrc" "/etc/passwd") safe?
+  )
 
 (defcustom ada-case-keyword 'downcase-word
   "Buffer-local value that may override project variable `case_keyword'.
@@ -223,19 +223,27 @@ Global value is default for project variable `case_keyword'.
 Function to call to adjust the case of Ada keywords."
   :type '(choice (const downcase-word)
                 (const upcase-word))
-  :group 'ada
-  :safe  'functionp)
+  ;; :safe #'functionp ; FIXME: `functionp' CANNOT be safe!
+  )
 (make-variable-buffer-local 'ada-case-keyword)
 
 (defcustom ada-case-identifier 'ada-mixed-case
   "Buffer-local value that may override project variable `case_keyword'.
 Global value is default for project variable `case_keyword'.
-Function to call to adjust the case of Ada keywords."
+Function to call to adjust the case of Ada keywords.
+Called with three args;
+start      - buffer pos of start of identifier
+end        - end of identifier
+force-case - if t, treat `ada-strict-case' as t"
   :type '(choice (const ada-mixed-case)
-                (const downcase-region)
-                (const upcase-region))
-  :group 'ada
-  :safe  'functionp)
+                (const ada-lower-case)
+                (const ada-upper-case))
+  ;; :safe #'functionp ; FIXME: `functionp' CANNOT be safe!
+  )
+;; we'd like to check that there are 3 args, since the previous
+;; release required 2 here. But there doesn't seem to be a way to
+;; access the arg count, which is only available for byte-compiled
+;; functions
 (make-variable-buffer-local 'ada-case-identifier)
 
 (defcustom ada-case-strict t
@@ -244,8 +252,7 @@ Global value is default for project variable `case_strict'.
 If non-nil, force Mixed_Case for identifiers.
 Otherwise, allow UPPERCASE for identifiers."
   :type 'boolean
-  :group 'ada
-  :safe  'booleanp)
+  :safe  #'booleanp)
 (make-variable-buffer-local 'ada-case-strict)
 
 (defcustom ada-language-version 'ada2012
@@ -256,36 +263,29 @@ indentation parser accepts."
                 (const ada95)
                 (const ada2005)
                 (const ada2012))
-  :group 'ada
-  :safe  'symbolp)
+  :safe  #'symbolp)
 (make-variable-buffer-local 'ada-language-version)
 
 (defcustom ada-fill-comment-prefix "-- "
   "Comment fill prefix."
-  :type 'string
-  :group 'ada)
-(make-variable-buffer-local 'ada-language-version)
+  :type 'string)
 
 (defcustom ada-fill-comment-postfix " --"
   "Comment fill postfix."
-  :type 'string
-  :group 'ada)
-(make-variable-buffer-local 'ada-language-version)
+  :type 'string)
 
 (defcustom ada-prj-file-extensions '("adp" "prj")
   "List of Emacs Ada mode project file extensions.
 Used when searching for a project file.
 Any file with one of these extensions will be parsed by `ada-prj-parse-file-1'."
-  :type 'list
-  :group 'ada)
+  :type 'list)
 
 (defcustom ada-prj-file-ext-extra nil
   "List of secondary project file extensions.
 Used when searching for a project file that can be a primary or
 secondary project file (referenced from a primary).  The user
 must provide a parser for a file with one of these extensions."
-  :type 'list
-  :group 'ada)
+  :type 'list)
 
 ;;;;; end of user variables
 
@@ -304,31 +304,20 @@ Values defined by cross reference packages.")
 
 ;;;; keymap and menus
 
-(defvar ada-ret-binding nil)
-(defvar ada-lfd-binding nil)
+(defvar ada-ret-binding 'ada-indent-newline-indent)
+(defvar ada-lfd-binding 'newline-and-indent)
 
-(defun ada-case-activate-keys ()
+(defun ada-case-activate-keys (map)
   "Modify the key bindings for all the keys that should adjust casing."
-  (interactive)
-  ;; We can't use post-self-insert-hook for \n, \r, because they are
-  ;; not self-insert.
-
-  ;; The 'or ...' is there to be sure that the value will not be
-  ;; changed again when this is called more than once, since we
-  ;; are rebinding the keys.
-  (or ada-ret-binding (setq ada-ret-binding (key-binding "\C-M")))
-  (or ada-lfd-binding (setq ada-lfd-binding (key-binding "\C-j")))
-
+  ;; we could just put these in the keymap below, but this is easier.
   (mapc (function
         (lambda(key)
           (define-key
-            ada-mode-map
+            map
             (char-to-string key)
             'ada-case-adjust-interactive)))
        '( ?_ ?% ?& ?* ?( ?) ?- ?= ?+
              ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n 32 ?\r ))
-
-  (define-key ada-mode-map [return] 'ada-case-adjust-interactive)
   )
 
 (defvar ada-mode-map
@@ -336,9 +325,11 @@ Values defined by cross reference packages.")
     ;; C-c <letter> are reserved for users
 
     ;; global-map has C-x ` 'next-error
-    (define-key map [return]    'ada-indent-newline-indent)
+    (define-key map [return]    'ada-case-adjust-interactive)
     (define-key map "\C-c`"     'ada-show-secondary-error)
     (define-key map "\C-c;"      (lambda () (error "use M-; instead"))) ; comment-dwim
+    (define-key map "\C-c<"     'ada-goto-declaration-start)
+    (define-key map "\C-c>"     'ada-goto-declaration-end)
     (define-key map "\C-c\M-`"          'ada-fix-compiler-error)
     (define-key map "\C-c\C-a"          'ada-align)
     (define-key map "\C-c\C-b"          'ada-make-subprogram-body)
@@ -350,9 +341,11 @@ Values defined by cross reference packages.")
     (define-key map "\C-c\C-i"          'ada-indent-statement)
     (define-key map "\C-c\C-m"   'ada-build-set-make)
     (define-key map "\C-c\C-n"          'ada-next-statement-keyword)
+    (define-key map "\C-c\M-n"          'ada-next-placeholder)
     (define-key map "\C-c\C-o"          'ada-find-other-file)
     (define-key map "\C-c\M-o"          'ada-find-other-file-noset)
     (define-key map "\C-c\C-p"          'ada-prev-statement-keyword)
+    (define-key map "\C-c\M-p"          'ada-prev-placeholder)
     (define-key map "\C-c\C-q"          'ada-xref-refresh)
     (define-key map "\C-c\C-r"          'ada-show-references)
     (define-key map "\C-c\M-r"          'ada-build-run)
@@ -365,6 +358,8 @@ Values defined by cross reference packages.")
     (define-key map "\C-c\M-y"   'ada-case-create-partial-exception)
     (define-key map [C-down-mouse-3] 'ada-popup-menu)
 
+    (ada-case-activate-keys map)
+
     map
   )  "Local keymap used for Ada mode.")
 
@@ -381,6 +376,7 @@ Values defined by cross reference packages.")
      ["Find and select project ..."   ada-build-prompt-select-prj-file t]
      ["Select project ..."            ada-prj-select                   t]
      ["Show project"                  ada-prj-show                     t]
+     ["Show project search path"      ada-prj-show-path                t]
     )
     ("Build"
      ["Next compilation error"     next-error                t]
@@ -396,14 +392,18 @@ Values defined by cross reference packages.")
     ("Navigate"
      ["Other file"                    ada-find-other-file          t]
      ["Other file don't find decl"    ada-find-other-file-noset    t]
+     ["Find file in project"          ada-find-file                t]
      ["Goto declaration/body"         ada-goto-declaration         t]
      ["Goto next statement keyword"   ada-next-statement-keyword   t]
-     ["Goto prev statement keyword"   ada-next-statement-keyword   t]
+     ["Goto declaration start"        ada-goto-declaration-start   t]
+     ["Goto declaration end"          ada-goto-declaration-end     t]
      ["Show parent declarations"      ada-show-declaration-parents t]
      ["Show references"               ada-show-references          t]
      ["Show overriding"               ada-show-overriding          t]
      ["Show overridden"               ada-show-overridden          t]
      ["Goto prev position"            ada-goto-previous-pos        t]
+     ["Next placeholder"              ada-next-placeholder    t]
+     ["Previous placeholder"          ada-prev-placeholder    t]
      )
     ("Edit"
      ["Expand skeleton"             ada-expand              t]
@@ -423,6 +423,7 @@ Values defined by cross reference packages.")
      ["Adjust case at point"        ada-case-adjust-at-point  t]
      ["Adjust case region"          ada-case-adjust-region    t]
      ["Adjust case buffer"          ada-case-adjust-buffer    t]
+     ["Show casing files list"      ada-case-show-files       t]
      )
     ("Misc"
      ["Show last parse error"         ada-show-parse-error         t]
@@ -430,7 +431,6 @@ Values defined by cross reference packages.")
      ["Refresh cross reference cache" ada-xref-refresh             t]
      ["Reset parser"                  ada-reset-parser             t]
      )))
-(ada-case-activate-keys)
 
 ;; This doesn't need to be buffer-local because there can be only one
 ;; popup menu at a time.
@@ -459,7 +459,7 @@ Values defined by cross reference packages.")
     ["Other File"                  ada-find-other-file        t]
     ["Other file don't find decl"  ada-find-other-file-noset  t]))
 
-(defun ada-popup-menu (position)
+(defun ada-popup-menu (_position)
   "Pops up a `ada-context-menu', with `ada-context-menu-on-identifer' set appropriately.
 POSITION is the location the mouse was clicked on.
 Sets `ada-context-menu-last-point' to the current position before
@@ -485,7 +485,7 @@ point is where the mouse button was clicked."
   (interactive "*")
   ;; point may be in the middle of a word, so insert newline first,
   ;; then go back and indent.
-  (newline)
+  (insert "\n")
   (forward-char -1)
   (funcall indent-line-function)
   (forward-char 1)
@@ -512,6 +512,28 @@ Function is called with no arguments.")
   (when ada-expand
     (funcall ada-expand)))
 
+(defvar ada-next-placeholder nil
+  ;; skeleton function
+  "Function to call to goto next placeholder.")
+
+(defun ada-next-placeholder ()
+  "Goto next placeholder.
+Placeholders are defined by the skeleton backend."
+  (interactive)
+  (when ada-next-placeholder
+    (funcall ada-next-placeholder)))
+
+(defvar ada-prev-placeholder nil
+  ;; skeleton function
+  "Function to call to goto previous placeholder.")
+
+(defun ada-prev-placeholder ()
+  "Goto previous placeholder.
+Placeholders are defined by the skeleton backend."
+  (interactive)
+  (when ada-prev-placeholder
+    (funcall ada-prev-placeholder)))
+
 ;;;; abbrev, align
 
 (defvar ada-mode-abbrev-table nil
@@ -569,7 +591,7 @@ Function is called with no arguments.")
      "return\\|"
      "type\\|"
      "when"
-     "\\)\\>\\)"))
+     "\\)\\>[^_]\\)")) ;; in case "_" has punctuation syntax
   "See the variable `align-region-separate' for more information.")
 
 (defun ada-align ()
@@ -606,8 +628,7 @@ Function is called with no arguments.")
   (ada-goto-open-paren)
   (funcall indent-line-function); so new list is indented properly
 
-  (let* ((inibit-modification-hooks t)
-        (begin (point))
+  (let* ((begin (point))
         (delend (progn (forward-sexp) (point))); just after matching closing paren
         (end (progn (backward-char) (forward-comment (- (point))) (point))); end of last parameter-declaration
         (multi-line (> end (save-excursion (goto-char begin) (line-end-position))))
@@ -629,9 +650,9 @@ Function is called with no arguments.")
   "Function to scan a region, return a list of subprogram parameter declarations (in inverse declaration order).
 Function is called with two args BEGIN END (the region).
 Each parameter declaration is represented by a list
-'((identifier ...) in-p out-p not-null-p access-p constant-p protected-p type default)."
-  ;; mode is 'in | out | in out | [not null] access [constant | protected]'
-  ;; IMPROVEME: handle single-line trailing comments, or longer comments, in paramlist?
+'((identifier ...) aliased-p in-p out-p not-null-p access-p constant-p protected-p type default)."
+  ;; Summary of Ada syntax for a parameter specification:
+  ;; ... : [aliased] {[in] | out | in out | [null_exclusion] access [constant | protected]} ...
   )
 
 (defun ada-scan-paramlist (begin end)
@@ -646,12 +667,14 @@ Each parameter declaration is represented by a list
        len
        (ident-len 0)
        (type-len 0)
+       (aliased-p nil)
        (in-p nil)
        (out-p nil)
        (not-null-p nil)
        (access-p nil)
        ident-col
        colon-col
+       in-col
        out-col
        type-col
        default-col)
@@ -673,18 +696,19 @@ Each parameter declaration is represented by a list
 
       ;; we align the defaults after the types that have defaults, not after all types.
       ;; "constant", "protected" are treated as part of 'type'
-      (when (nth 8 param)
+      (when (nth 9 param)
        (setq type-len
              (max type-len
-                  (+ (length (nth 7 param))
-                     (if (nth 5 param) 10 0); "constant "
-                     (if (nth 6 param) 10 0); protected
+                  (+ (length (nth 8 param))
+                     (if (nth 6 param) 10 0); "constant "
+                     (if (nth 7 param) 10 0); protected
                      ))))
 
-      (setq in-p (or in-p (nth 1 param)))
-      (setq out-p (or out-p (nth 2 param)))
-      (setq not-null-p (or not-null-p (nth 3 param)))
-      (setq access-p (or access-p (nth 4 param)))
+      (setq aliased-p (or aliased-p (nth 1 param)))
+      (setq in-p (or in-p (nth 2 param)))
+      (setq out-p (or out-p (nth 3 param)))
+      (setq not-null-p (or not-null-p (nth 4 param)))
+      (setq access-p (or access-p (nth 5 param)))
       )
 
     (let ((space-before-p (save-excursion (skip-chars-backward " \t") (not (bolp))))
@@ -707,16 +731,19 @@ Each parameter declaration is represented by a list
     ;; compute columns.
     (setq ident-col (current-column))
     (setq colon-col (+ ident-col ident-len 1))
-    (setq out-col (+ colon-col (if in-p 5 0))); ": in "
+    (setq in-col
+         (+ colon-col (if aliased-p 10 2))); ": aliased ..."
+    (setq out-col (+ in-col (if in-p 3 0))); ": [aliased] in "
     (setq type-col
-         (+ colon-col
+         (+ in-col
             (cond
-             (not-null-p 18);    ": not null access "
-             (access-p 9);        ": access"
-             ((and in-p out-p) 9); ": in out "
-             (out-p 6);           ": out "
-             (in-p 5);            ": in "
-             (t 2))));           ": "
+             ;; 'not null' without access is part of the type
+             ((and not-null-p access-p) 16); ": [aliased] not null access "
+             (access-p 7);         ": [aliased] access "
+             ((and in-p out-p) 7); ": [aliased] in out "
+             (in-p 3);             ": [aliased] in "
+             (out-p 4);            ": [aliased] out "
+             (t 0))));             ": [aliased] "
 
     (setq default-col (+ 1 type-col type-len))
 
@@ -735,29 +762,42 @@ Each parameter declaration is represented by a list
       (insert ": ")
 
       (when (nth 1 param)
-       (insert "in "))
+       (insert "aliased "))
 
+      (indent-to in-col)
       (when (nth 2 param)
+       (insert "in "))
+
+      (when (nth 3 param)
        (indent-to out-col)
        (insert "out "))
 
-      (when (nth 3 param)
-       (insert "not null "))
+      (when (and (nth 4 param) ;; not null
+                (nth 5 param)) ;; access
+       (insert "not null access"))
 
-      (when (nth 4 param)
-       (insert "access "))
+      (when (and (not (nth 4 param)) ;; not null
+                (nth 5 param)) ;; access
+       (insert "access"))
 
       (indent-to type-col)
-      (when (nth 5 param)
-       (insert "constant "))
+
+      (when (and (nth 4 param) ;; not null
+                (not (nth 5 param))) ;; access
+       (insert "not null "))
+
       (when (nth 6 param)
+       (insert "constant "))
+
+      (when (nth 7 param)
        (insert "protected "))
-      (insert (nth 7 param)); type
 
-      (when (nth 8 param); default
+      (insert (nth 8 param)); type
+
+      (when (nth 9 param); default
        (indent-to default-col)
        (insert ":= ")
-       (insert (nth 8 param)))
+       (insert (nth 9 param)))
 
       (if (zerop i)
          (insert ")")
@@ -792,26 +832,29 @@ Each parameter declaration is represented by a list
       (insert " : ")
 
       (when (nth 1 param)
-       (insert "in "))
+       (insert "aliased "))
 
       (when (nth 2 param)
-       (insert "out "))
+       (insert "in "))
 
       (when (nth 3 param)
-       (insert "not null "))
+       (insert "out "))
 
       (when (nth 4 param)
-       (insert "access "))
+       (insert "not null "))
 
       (when (nth 5 param)
-       (insert "constant "))
+       (insert "access "))
+
       (when (nth 6 param)
+       (insert "constant "))
+      (when (nth 7 param)
        (insert "protected "))
-      (insert (nth 7 param)); type
+      (insert (nth 8 param)); type
 
-      (when (nth 8 param); default
+      (when (nth 9 param); default
        (insert " := ")
-       (insert (nth 8 param)))
+       (insert (nth 9 param)))
 
       (if (zerop i)
          (if (= (char-after) ?\;)
@@ -845,14 +888,26 @@ Each parameter declaration is represented by a list
 
 (defvar ada-case-full-exceptions '()
   "Alist of words (entities) that have special casing, built from
-`ada-case-exception-file' full word exceptions. Indexed by
+project file casing file list full word exceptions. Indexed by
 properly cased word; value is t.")
 
 (defvar ada-case-partial-exceptions '()
   "Alist of partial words that have special casing, built from
-`ada-case-exception-file' partial word exceptions. Indexed by
+project casing files list partial word exceptions. Indexed by
 properly cased word; value is t.")
 
+(defun ada-case-show-files ()
+  "Show current casing files list."
+  (interactive)
+  (if (ada-prj-get 'casing)
+      (progn
+       (pop-to-buffer (get-buffer-create "*casing files*"))
+       (erase-buffer)
+       (dolist (file (ada-prj-get 'casing))
+         (insert (format "%s\n" file))))
+    (message "no casing files")
+    ))
+
 (defun ada-case-save-exceptions (full-exceptions partial-exceptions file-name)
   "Save FULL-EXCEPTIONS, PARTIAL-EXCEPTIONS to the file FILE-NAME."
   (with-temp-file (expand-file-name file-name)
@@ -882,18 +937,18 @@ Return (cons full-exceptions partial-exceptions)."
                (progn
                  (setq word (substring word 1))
                  (unless (assoc-string word partial-exceptions t)
-                   (add-to-list 'partial-exceptions (cons word t))))
+                   (push (cons word t) partial-exceptions)))
 
              ;; full word exception
              (unless (assoc-string word full-exceptions t)
-               (add-to-list 'full-exceptions (cons word t))))
+               (push (cons word t) full-exceptions)))
 
            (forward-line 1))
          )
        (cons full-exceptions partial-exceptions))
 
     ;; else file not readable; might be a new project with no
-    ;; exceptions yet, so just warn user, return empty pair
+    ;; exceptions yet, so just return empty pair
     (message "'%s' is not a readable file." file-name)
     '(nil . nil)
     ))
@@ -903,7 +958,7 @@ Return (cons full-exceptions partial-exceptions)."
 An item in both lists has the RESULT value."
   (dolist (item new)
     (unless (assoc-string (car item) result t)
-      (add-to-list 'result item)))
+      (push item result)))
   result)
 
 (defun ada-case-merge-all-exceptions (exceptions)
@@ -912,7 +967,7 @@ An item in both lists has the RESULT value."
   (setq ada-case-partial-exceptions (ada-case-merge-exceptions ada-case-partial-exceptions (cdr exceptions))))
 
 (defun ada-case-read-all-exceptions ()
-  "Read case exceptions from all files in `ada-case-exception-file',
+  "Read case exceptions from all files in project casing files,
 replacing current values of `ada-case-full-exceptions', `ada-case-partial-exceptions'."
   (interactive)
   (setq ada-case-full-exceptions '()
@@ -927,9 +982,11 @@ replacing current values of `ada-case-full-exceptions', `ada-case-partial-except
   "Add case exception WORD to EXCEPTIONS, replacing current entry, if any."
   (if (assoc-string word exceptions t)
       (setcar (assoc-string word exceptions t) word)
-    (add-to-list 'exceptions (cons word t)))
+    (push (cons word t) exceptions))
   exceptions)
 
+(defvar ada-prj-current-file)
+
 (defun ada-case-create-exception (&optional word file-name partial)
   "Define WORD as an exception for the casing system, save it in FILE-NAME.
 If PARTIAL is non-nil, create a partial word exception.  WORD
@@ -970,12 +1027,13 @@ list."
     (if (use-region-p)
        (setq word (buffer-substring-no-properties (region-beginning) (region-end)))
       (save-excursion
-       (skip-syntax-backward "w_")
-       (setq word
-             (buffer-substring-no-properties
-              (point)
-              (progn (skip-syntax-forward "w_") (point))
-              )))))
+       (let ((syntax (if partial "w" "w_")))
+         (skip-syntax-backward syntax)
+         (setq word
+               (buffer-substring-no-properties
+                (point)
+                (progn (skip-syntax-forward syntax) (point))
+                ))))))
 
   (let* ((exceptions (ada-case-read-exceptions file-name))
         (full-exceptions (car exceptions))
@@ -1005,7 +1063,8 @@ User is prompted to choose a file from project variable casing if it is a list."
 
 (defun ada-in-numeric-literal-p ()
   "Return t if point is after a prefix of a numeric literal."
-  (looking-back "\\([0-9]+#[0-9a-fA-F_]+\\)"))
+  ;; FIXME: this is actually a based numeric literal; excludes 1234
+  (looking-back "\\([0-9]+#[0-9a-fA-F_]+\\)" (line-beginning-position)))
 
 (defvar ada-keywords nil
   "List of Ada keywords for current `ada-language-version'.")
@@ -1017,11 +1076,17 @@ User is prompted to choose a file from project variable casing if it is a list."
               (point))))
     (member (downcase word) ada-keywords)))
 
-(defun ada-mixed-case (start end)
+(defun ada-lower-case (start end _force-case-strict)
+  (downcase-region start end))
+
+(defun ada-upper-case (start end _force-case-strict)
+  (upcase-region start end))
+
+(defun ada-mixed-case (start end force-case-strict)
   "Adjust case of region START END to Mixed_Case."
   (let ((done nil)
        next)
-    (if ada-case-strict
+    (if (or force-case-strict ada-case-strict)
        (downcase-region start end))
     (goto-char start)
     (while (not done)
@@ -1031,8 +1096,7 @@ User is prompted to choose a file from project variable casing if it is a list."
             (copy-marker (1+ end))))
 
       ;; upcase first char
-      (insert-char (upcase (following-char)) 1)
-      (delete-char 1)
+      (upcase-region (point) (1+ (point)))
 
       (goto-char next)
       (if (< (point) end)
@@ -1040,7 +1104,7 @@ User is prompted to choose a file from project variable casing if it is a list."
        (setq done t))
       )))
 
-(defun ada-case-adjust-identifier ()
+(defun ada-case-adjust-identifier (&optional force-case)
   "Adjust case of the previous word as an identifier.
 Uses `ada-case-identifier', with exceptions defined in
 `ada-case-full-exceptions', `ada-case-partial-exceptions'."
@@ -1063,7 +1127,7 @@ Uses `ada-case-identifier', with exceptions defined in
            (delete-region (point) end))
 
        ;; else apply ada-case-identifier
-       (funcall ada-case-identifier start end)
+       (funcall ada-case-identifier start end force-case)
 
        ;; apply partial-exceptions
        (goto-char start)
@@ -1090,7 +1154,8 @@ Uses `ada-case-identifier', with exceptions defined in
   "Adjust the case of the word before point.
 When invoked interactively, TYPED-CHAR must be
 `last-command-event', and it must not have been inserted yet.
-If IN-COMMENT is non-nil, adjust case of words in comments."
+If IN-COMMENT is non-nil, adjust case of words in comments and strings as code,
+and treat `ada-case-strict' as t in code.."
   (when (not (bobp))
     (when (save-excursion
            (forward-char -1); back to last character in word
@@ -1122,7 +1187,7 @@ If IN-COMMENT is non-nil, adjust case of words in comments."
           (save-excursion
             (skip-syntax-backward "w_")
             (eq (char-before) ?')))
-         (ada-case-adjust-identifier))
+         (ada-case-adjust-identifier in-comment))
 
         ((and
           (not in-comment)
@@ -1130,22 +1195,31 @@ If IN-COMMENT is non-nil, adjust case of words in comments."
           (ada-after-keyword-p))
          (funcall ada-case-keyword -1))
 
-        (t (ada-case-adjust-identifier))
+        (t (ada-case-adjust-identifier in-comment))
         ))
       )))
 
 (defun ada-case-adjust-at-point (&optional in-comment)
   "Adjust case of word at point, move to end of word.
-With prefix arg, adjust case even if in comment."
+With prefix arg, adjust case as code even if in comment;
+otherwise, capitalize words in comments."
   (interactive "P")
-  (when
-      (and (not (eobp))
-          ;; we use '(syntax-after (point))' here, not '(char-syntax
-          ;; (char-after))', because the latter does not respect
-          ;; ada-syntax-propertize.
-          (memq (syntax-class (syntax-after (point))) '(2 3)))
-    (skip-syntax-forward "w_"))
-  (ada-case-adjust nil in-comment))
+  (cond
+   ((and (not in-comment)
+        (ada-in-string-or-comment-p))
+    (skip-syntax-backward "w_")
+    (capitalize-word 1))
+
+   (t
+    (when
+       (and (not (eobp))
+            ;; we use '(syntax-after (point))' here, not '(char-syntax
+            ;; (char-after))', because the latter does not respect
+            ;; ada-syntax-propertize.
+            (memq (syntax-class (syntax-after (point))) '(2 3)))
+      (skip-syntax-forward "w_"))
+    (ada-case-adjust nil in-comment))
+   ))
 
 (defun ada-case-adjust-region (begin end)
   "Adjust case of all words in region BEGIN END."
@@ -1229,7 +1303,7 @@ Optional PLIST defaults to `ada-prj-current-project'."
 
       ;; no project, just use default vars
       ;; must match code in ada-prj-default
-      (cl-case plist
+      (cl-case prop
        (ada_compiler    ada-compiler)
        (auto_case       ada-auto-case)
        (case_keyword    ada-case-keyword)
@@ -1273,8 +1347,9 @@ Indexed by ada-xref-tool.  Called with one argument; the default
 project properties list. Function should add to the properties
 list and return it.")
 
-(defun ada-prj-default ()
+(defun ada-prj-default (&optional src-dir)
   "Return the default project properties list.
+If SRC-DIR is non-nil, use it as the default for src_dir.
 Include properties set via `ada-prj-default-compiler-alist',
 `ada-prj-default-xref-alist'."
 
@@ -1293,7 +1368,7 @@ Include properties set via `ada-prj-default-compiler-alist',
                         (list ada-case-exception-file))
       'path_sep        path-separator;; prj variable so users can override it for their compiler
       'proc_env        process-environment
-      'src_dir         (list ".")
+      'src_dir         (list (if src-dir src-dir "."))
       'xref_tool       ada-xref-tool
       ))
 
@@ -1323,6 +1398,7 @@ list. Parser must modify or add to the property list and return it.")
 (defun ada-parse-prj-file (prj-file)
   "Read Emacs Ada or compiler-specific project file PRJ-FILE, set project properties in `ada-prj-alist'."
   ;; Not called ada-prj-parse-file for Ada mode 4.01 compatibility
+  ;; FIXME: use the right name, add an alias
   (let ((project (ada-prj-default))
        (parser (cdr (assoc (file-name-extension prj-file) ada-prj-parser-alist))))
 
@@ -1426,9 +1502,9 @@ Return new value of PROJECT."
            (setq project (plist-put project 'case_strict (intern (match-string 2)))))
 
           ((string= (match-string 1) "casing")
-           (add-to-list 'casing
-                        (expand-file-name
-                         (substitute-in-file-name (match-string 2)))))
+            (cl-pushnew (expand-file-name
+                         (substitute-in-file-name (match-string 2)))
+                        casing :test #'equal))
 
           ((string= (match-string 1) "el_file")
            (let ((file (expand-file-name (substitute-in-file-name (match-string 2)))))
@@ -1437,9 +1513,9 @@ Return new value of PROJECT."
              (load-file file)))
 
           ((string= (match-string 1) "src_dir")
-           (add-to-list 'src_dir
-                        (file-name-as-directory
-                         (expand-file-name (match-string 2)))))
+            (cl-pushnew (file-name-as-directory
+                         (expand-file-name (match-string 2)))
+                        src_dir :test #'equal))
 
           ((string= (match-string 1) "xref_tool")
            (let ((xref (intern (match-string 2))))
@@ -1478,8 +1554,8 @@ Return new value of PROJECT."
       );; done reading file
 
     ;; process accumulated lists
-    (if casing (set 'project (plist-put project 'casing (reverse casing))))
-    (if src_dir (set 'project (plist-put project 'src_dir (reverse src_dir))))
+    (if casing (setproject (plist-put project 'casing (reverse casing))))
+    (if src_dir (setproject (plist-put project 'src_dir (reverse src_dir))))
 
     (when parse-final-compiler
       ;; parse-final-compiler may reference the "current project", so
@@ -1496,9 +1572,6 @@ Return new value of PROJECT."
     project
     ))
 
-(defvar ada-project-search-path nil
-  "Search path for finding Ada project files")
-
 (defvar ada-select-prj-compiler nil
   "Alist of functions to call for compiler specific project file selection.
 Indexed by project variable ada_compiler.")
@@ -1546,7 +1619,6 @@ Indexed by project variable xref_tool.")
   (ada-case-read-all-exceptions)
 
   (setq compilation-search-path (ada-prj-get 'src_dir))
-  (setq ada-project-search-path (ada-prj-get 'prj_dir))
 
   (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-select-prj-compiler))))
     (when func (funcall func)))
@@ -1557,6 +1629,19 @@ Indexed by project variable xref_tool.")
   ;; return 't', for decent display in message buffer when called interactively
   t)
 
+(defun ada-create-select-default-prj (&optional directory)
+  "Create a default project with src_dir set to DIRECTORY (default current directory), select it."
+  (let* ((dir (or directory default-directory))
+        (prj-file (expand-file-name "default_.adp" dir))
+        (project (ada-prj-default dir)))
+
+    (if (assoc prj-file ada-prj-alist)
+       (setcdr (assoc prj-file ada-prj-alist) project)
+      (add-to-list 'ada-prj-alist (cons prj-file project)))
+
+    (ada-select-prj-file prj-file)
+    ))
+
 (defun ada-prj-select ()
   "Select the current project file from the list of currently available project files."
   (interactive)
@@ -1568,6 +1653,16 @@ Indexed by project variable xref_tool.")
   (interactive)
   (message "current Emacs Ada mode project file: %s" ada-prj-current-file))
 
+(defvar ada-prj-show-path nil
+  ;; Supplied by compiler
+  "Function to show project search path used by compiler (and possibly xref tool)."
+  )
+
+(defun ada-prj-show-path ()
+  (interactive)
+  (when ada-prj-show-path
+    (funcall ada-prj-show-path)))
+
 (defvar ada-show-xref-tool-buffer nil
   ;; Supplied by xref tool
   "Function to show process buffer used by xref tool."
@@ -1594,7 +1689,7 @@ Indexed by project variable xref_tool.")
     (modify-syntax-entry ?\" "\"" table)
 
     ;; punctuation; operators etc
-    (modify-syntax-entry ?#  "w" table); based number - word syntax, since we don't need the number
+    (modify-syntax-entry ?#  "." table); based number - ada-wisi-number-literal-p requires this syntax
     (modify-syntax-entry ?&  "." table)
     (modify-syntax-entry ?*  "." table)
     (modify-syntax-entry ?+  "." table)
@@ -1653,10 +1748,10 @@ In particular, character constants are set to have string syntax."
               "\\|\\(--\\)"; 4: comment start
               )
              end t)
-       ;; The help for syntax-propertize-extend-region-functions
-       ;; implies that 'start end' will always include whole lines, in
-       ;; which case we don't need
-       ;; syntax-propertize-extend-region-functions
+       ;; syntax-propertize-extend-region-functions is set to
+       ;; syntax-propertize-wholelines by default. We assume no
+       ;; coding standard will permit a character literal at the
+       ;; start of a line (not preceded by whitespace).
        (cond
         ((match-beginning 1)
          (put-text-property
@@ -1733,15 +1828,17 @@ found.")
 
 (defun ada-file-name-from-ada-name (ada-name)
   "Return the filename in which ADA-NAME is found."
+  (ada-require-project-file)
   (funcall ada-file-name-from-ada-name ada-name))
 
 (defvar ada-ada-name-from-file-name nil
-  ;; depends on ada-compiler, per-project
+  ;; supplied by compiler
   "Function called with one parameter FILE-NAME, which is a library
 unit name; it should return the Ada name that should be found in FILE-NAME.")
 
 (defun ada-ada-name-from-file-name (file-name)
   "Return the ada-name that should be found in FILE-NAME."
+  (ada-require-project-file)
   (funcall ada-ada-name-from-file-name file-name))
 
 (defun ada-ff-special-extract-parent ()
@@ -1754,25 +1851,6 @@ unit name; it should return the Ada name that should be found in FILE-NAME.")
      ada-spec-suffixes)
     (error "parent '%s' not found; set project file?" ff-function-name))))
 
-(defun ada-ff-special-extract-separate ()
-  (let ((package-name (match-string 1)))
-    (save-excursion
-      (goto-char (match-end 0))
-      (when (eolp) (forward-char 1))
-      (skip-syntax-forward " ")
-      (looking-at
-       (concat "\\(function\\|package body\\|procedure\\|protected body\\|task body\\)\\s +"
-              ada-name-regexp))
-      (setq ff-function-name (match-string 0))
-      )
-    (file-name-nondirectory
-     (or
-      (ff-get-file-name
-       compilation-search-path
-       (ada-file-name-from-ada-name package-name)
-       ada-body-suffixes)
-      (error "package '%s' not found; set project file?" package-name)))))
-
 (defun ada-ff-special-with ()
   (let ((package-name (match-string 1)))
     (setq ff-function-name (concat "^package\\s-+" package-name "\\([^_]\\|$\\)"))
@@ -1800,10 +1878,6 @@ unit name; it should return the Ada name that should be found in FILE-NAME.")
                       ada-parent-name-regexp "\\(?:;\\|[ \t]+\\|$\\)")
               'ada-ff-special-extract-parent)
 
-        ;; A "separate" clause.
-        (cons (concat "^separate[ \t\n]*(" ada-name-regexp ")")
-              'ada-ff-special-extract-separate)
-
         ;; A "with" clause. Note that it may refer to a procedure body, as well as a spec
         (cons (concat "^\\(?:limited[ \t]+\\)?\\(?:private[ \t]+\\)?with[ \t]+" ada-name-regexp)
               'ada-ff-special-with)
@@ -1827,6 +1901,30 @@ other file.")
   (when ada-which-function
     (funcall ada-which-function)))
 
+(defvar ada-on-context-clause nil
+  ;; supplied by indentation engine
+  "Function called with no parameters; it should return non-nil
+  if point is on a context clause.")
+
+(defun ada-on-context-clause ()
+  "See `ada-on-context-clause' variable."
+  (interactive)
+  (when ada-on-context-clause
+    (funcall ada-on-context-clause)))
+
+(defvar ada-goto-subunit-name nil
+  ;; supplied by indentation engine
+  "Function called with no parameters; if the current buffer
+  contains a subunit, move point to the subunit name (for
+  `ada-goto-declaration'), return t; otherwise leave point alone,
+  return nil.")
+
+(defun ada-goto-subunit-name ()
+  "See `ada-goto-subunit-name' variable."
+  (interactive)
+  (when ada-goto-subunit-name
+    (funcall ada-goto-subunit-name)))
+
 (defun ada-add-log-current-function ()
   "For `add-log-current-defun-function'; uses `ada-which-function'."
   ;; add-log-current-defun is typically called with point at the start
@@ -1869,10 +1967,22 @@ set."
   (when (null (car compilation-search-path))
     (error "no file search path defined; set project file?"))
 
-  (unless (string= file-name
-                  (locate-file (file-name-nondirectory file-name)
-                               compilation-search-path))
-    (error "current file not part of current project; wrong project?")))
+  ;; file-truename handles symbolic links
+  (let* ((visited-file (file-truename file-name))
+         (found-file (locate-file (file-name-nondirectory visited-file)
+                                 compilation-search-path)))
+    (unless found-file
+      (error "current file not part of current project; wrong project?"))
+
+    (setq found-file (file-truename found-file))
+
+    ;; (nth 10 (file-attributes ...)) is the inode; required when hard
+    ;; links are present.
+    (let* ((visited-file-inode (nth 10 (file-attributes visited-file)))
+           (found-file-inode (nth 10 (file-attributes found-file))))
+      (unless (equal visited-file-inode found-file-inode)
+        (error "%s (opened) and %s (found in project) are two different files"
+               file-name found-file)))))
 
 (defun ada-find-other-file-noset (other-window)
   "Same as `ada-find-other-file', but preserve point in the other file,
@@ -1880,7 +1990,7 @@ don't move to corresponding declaration."
   (interactive "P")
   (ada-find-other-file other-window t))
 
-(defun ada-find-other-file (other-window &optional no-set-point)
+(defun ada-find-other-file (other-window &optional _no-set-point)
   "Move to the corresponding declaration in another file.
 
 - If region is active, assume it contains a package name;
@@ -1890,12 +2000,12 @@ don't move to corresponding declaration."
   subprogram declaration, position point on the corresponding
   parent package specification.
 
-- If point is in the start line of a separate body,
-  position point on the corresponding separate stub declaration.
-
 - If point is in a context clause line, position point on the
   first package declaration that is mentioned.
 
+- If point is in a separate body, position point on the
+  corresponding specification.
+
 - If point is in a subprogram body or specification, position point
   on the corresponding specification or body.
 
@@ -1919,18 +2029,34 @@ the other file."
   (interactive "P")
   (ada-check-current-project (buffer-file-name))
 
-  (if mark-active
-      (progn
-       (setq ff-function-name (buffer-substring-no-properties (point) (mark)))
-       (ff-get-file
-        compilation-search-path
-        (ada-file-name-from-ada-name ff-function-name)
-        ada-spec-suffixes
-        other-window)
-       (deactivate-mark))
-
-    ;; else use name at point
+  (cond
+   (mark-active
+    (setq ff-function-name (buffer-substring-no-properties (point) (mark)))
+    (ff-get-file
+     compilation-search-path
+     (ada-file-name-from-ada-name ff-function-name)
+     ada-spec-suffixes
+     other-window)
+    (deactivate-mark))
+
+   ((and (not (ada-on-context-clause))
+        (ada-goto-subunit-name))
+    (ada-goto-declaration other-window))
+
+   (t
     (ff-find-other-file other-window)))
+  )
+
+(defun ada-find-file (filename)
+  ;; we assume compliation-search-path is set, either by an
+  ;; ada-mode project, or by some other means.
+  ;; FIXME: option to filter with ada-*-suffixes?
+  (interactive (list (completing-read "File: "
+                                     (apply-partially
+                                      'locate-file-completion-table
+                                      compilation-search-path nil))))
+  (find-file (locate-file filename compilation-search-path))
+  )
 
 (defvar ada-operator-re
   "\\+\\|-\\|/\\|\\*\\*\\|\\*\\|=\\|&\\|abs\\|mod\\|rem\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>"
@@ -1938,41 +2064,41 @@ the other file."
 
 (defun ada-identifier-at-point ()
   "Return the identifier around point, move point to start of
-identifier.  May be an Ada identifier or operator function name."
+identifier.  May be an Ada identifier or operator."
 
   (when (ada-in-comment-p)
     (error "Inside comment"))
 
-  (let (identifier)
+  (skip-chars-backward "a-zA-Z0-9_<>=+\\-\\*/&")
 
-    (skip-chars-backward "a-zA-Z0-9_<>=+\\-\\*/&")
-
-    ;; Just in front of, or inside, a string => we could have an operator
+  ;; Just in front of, or inside, a string => we could have an
+  ;; operator function declaration.
+  (cond
+   ((ada-in-string-p)
     (cond
-     ((ada-in-string-p)
-      (cond
 
-       ((and (= (char-before) ?\")
-            (progn
-              (forward-char -1)
-              (looking-at (concat "\"\\(" ada-operator-re "\\)\""))))
-       (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
+     ((and (= (char-before) ?\")
+           (progn
+             (forward-char -1)
+             (looking-at (concat "\"\\(" ada-operator-re "\\)\""))))
+      (concat "\"" (match-string-no-properties 1) "\""))
 
-       (t
-       (error "Inside string or character constant"))
-       ))
+     (t
+      (error "Inside string or character constant"))
+     ))
 
-     ((and (= (char-after) ?\")
-          (looking-at (concat "\"\\(" ada-operator-re "\\)\"")))
-      (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
+   ((and (= (char-after) ?\")
+         (looking-at (concat "\"\\(" ada-operator-re "\\)\"")))
+    (concat "\"" (match-string-no-properties 1) "\""))
 
-     ((looking-at "[a-zA-Z0-9_]+")
-      (setq identifier (match-string-no-properties 0)))
+   ((looking-at "[a-zA-Z0-9_]+\\|[+\\-*/&=<>]")
+    (match-string-no-properties 0))
 
-     (t
-      (error "No identifier around"))
-     )))
+   (t
+    (error "No identifier around"))
+   ))
 
+;; FIXME: use find-tag-marker-ring, ring-insert, pop-tag-mark (see xref.el)
 (defvar ada-goto-pos-ring '()
   "List of positions selected by navigation functions. Used
 to go back to these positions.")
@@ -2078,18 +2204,18 @@ buffer in another window."
   (when (null ada-xref-other-function)
     (error "no cross reference information available"))
 
-    (let ((target
-          (funcall ada-xref-other-function
-                   (ada-identifier-at-point)
-                   (buffer-file-name)
-                   (line-number-at-pos)
-                   (1+ (current-column))
-                   )))
-
-      (ada-goto-source (nth 0 target)
-                      (nth 1 target)
-                      (nth 2 target)
-                      other-window)
+  (let ((target
+        (funcall ada-xref-other-function
+                 (ada-identifier-at-point)
+                 (buffer-file-name)
+                 (line-number-at-pos)
+                 (1+ (current-column))
+                 )))
+
+    (ada-goto-source (nth 0 target)
+                    (nth 1 target)
+                    (nth 2 target)
+                    other-window)
     ))
 
 (defvar ada-xref-parent-function nil
@@ -2284,6 +2410,7 @@ parameters.")
 
 (defun ada-goto-declaration-start ()
   "Call `ada-goto-declaration-start'."
+  (interactive)
   (when ada-goto-declaration-start
     (funcall ada-goto-declaration-start)))
 
@@ -2333,6 +2460,8 @@ Called with no parameters.")
   "See `ada-next-statement-keyword' variable."
   (interactive)
   (when ada-next-statement-keyword
+    (unless (region-active-p)
+      (push-mark))
     (funcall ada-next-statement-keyword)))
 
 (defvar ada-prev-statement-keyword nil
@@ -2346,6 +2475,8 @@ keyword in the previous statement or containing statement.")
   "See `ada-prev-statement-keyword' variable."
   (interactive)
   (when ada-prev-statement-keyword
+    (unless (region-active-p)
+      (push-mark))
     (funcall ada-prev-statement-keyword)))
 
 ;;;; code creation
@@ -2408,7 +2539,8 @@ The paragraph is indented on the first line."
           (not (looking-at "[ \t]*--")))
       (error "Not inside comment"))
 
-  (let* (indent from to
+  (let* ((inhibit-modification-hooks t) ;; don't run parser for font-lock; comment text is exposed
+        indent from to
         (opos (point-marker))
         ;; we bind `fill-prefix' here rather than in ada-mode because
         ;; setting it in ada-mode causes indent-region to use it for
@@ -2474,7 +2606,13 @@ The paragraph is indented on the first line."
            (forward-line))
          ))
 
-    (goto-char opos)))
+    (goto-char opos)
+
+    ;; we disabled modification hooks, so font-lock will not run to
+    ;; re-fontify the comment prefix; do that here.
+    (when (memq 'jit-lock-after-change after-change-functions)
+      (jit-lock-after-change from to 0))
+    ))
 
 ;;;; support for font-lock.el
 
@@ -2504,148 +2642,10 @@ The paragraph is indented on the first line."
 
 (defun ada-font-lock-keywords ()
   "Return Ada mode value for `font-lock-keywords', depending on `ada-language-version'."
+   ;; Grammar actions set `font-lock-face' property for all
+   ;; non-keyword tokens that need it.
   (list
-
-   ;; keywords followed by a name that should be in function-name-face.
-   (list
-    (apply
-     'concat
-     (append
-      '("\\<\\("
-       "accept\\|"
-       "entry\\|"
-       "function\\|"
-       "package[ \t]+body\\|"
-       "package\\|"
-       "pragma\\|"
-       "procedure\\|"
-       "task[ \t]+body\\|"
-       "task[ \t]+type\\|"
-       "task\\|"
-       )
-      (when (member ada-language-version '(ada95 ada2005 ada2012))
-       '("\\|"
-         "protected[ \t]+body\\|"
-         "protected[ \t]+function\\|"
-         "protected[ \t]+procedure\\|"
-         "protected[ \t]+type\\|"
-         "protected"
-         ))
-      (list
-       "\\)\\>[ \t]*"
-       ada-name-regexp "?")))
-    '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
-
-   ;; keywords followed by a name that should be in type-face.
-   (list (concat
-         "\\<\\("
-         "access[ \t]+all\\|"
-         "access[ \t]+constant\\|"
-         "access\\|"
-         "constant\\|"
-         "in[ \t]+reverse\\|"; loop iterator
-         "in[ \t]+not[ \t]+null\\|"
-         "in[ \t]+out[ \t]+not[ \t]+null\\|"
-         "in[ \t]+out\\|"
-         "in\\|"
-         ;; "return\\|" can't distinguish between 'function ... return <type>;' and 'return ...;'
-         ;; An indentation engine can, so a rule for this is added there
-         "of[ \t]+reverse\\|"
-         "of\\|"
-         "out\\|"
-         "subtype\\|"
-         "type"
-         "\\)\\>[ \t]*"
-         ada-name-regexp "?")
-        '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
-
-   ;; Keywords not treated elsewhere. After above so it doesn't
-   ;; override fontication of second or third word in those patterns.
-   (list (concat
-         "\\<"
-         (regexp-opt
-          (append
-           '("abort" "abs" "accept" "all"
-             "and" "array" "at" "begin" "case" "declare" "delay" "delta"
-             "digits" "do" "else" "elsif" "entry" "exception" "exit" "for"
-             "generic" "if" "in" "limited" "loop" "mod" "not"
-             "null" "or" "others" "private" "raise"
-             "range" "record" "rem" "renames" "reverse"
-             "select" "separate" "task" "terminate"
-             "then" "when" "while" "xor")
-           (when (member ada-language-version '(ada95 ada2005 ada2012))
-             '("abstract" "aliased" "requeue" "tagged" "until"))
-           (when (member ada-language-version '(ada2005 ada2012))
-             '("interface" "overriding" "synchronized"))
-           (when (member ada-language-version '(ada2012))
-             '("some"))
-           )
-          t)
-         "\\>")
-        '(0 font-lock-keyword-face))
-
-   ;; object and parameter declarations; word after ":" should be in
-   ;; type-face if not already fontified or an exception.
-   (list (concat
-         ":[ \t]*"
-         ada-name-regexp
-         "[ \t]*\\(=>\\)?")
-     '(1 (if (match-beginning 2)
-            'default
-          font-lock-type-face)
-        nil t))
-
-   ;; keywords followed by a name that should be in function-name-face if not already fontified
-   (list (concat
-         "\\<\\("
-         "end"
-         "\\)\\>[ \t]*"
-         ada-name-regexp "?")
-     '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
-
-   ;; Keywords followed by a name that could be a type or a function (generic instantiation).
-   (list (concat
-         "\\<\\("
-         "new"
-         "\\)\\>[ \t]*"
-         ada-name-regexp "?[ \t]*\\((\\)?")
-        '(1 font-lock-keyword-face)
-        '(2 (if (match-beginning 3)
-                font-lock-function-name-face
-              font-lock-type-face)
-            nil t))
-
-   ;; keywords followed by a name that should be in type-face if not already fontified (for subtypes)
-   ;; after "new" to handle "is new"
-   (list (concat
-         "\\<\\("
-         "is"
-         "\\)\\>[ \t]*"
-         ada-name-regexp "?")
-     '(1 font-lock-keyword-face) '(2 font-lock-type-face nil t))
-
-   ;; Keywords followed by a comma separated list of names which
-   ;; should be in constant-face, unless already fontified. Ada mode 4.01 used this.
-   (list (concat
-         "\\<\\("
-         "goto\\|"
-         "use\\|"
-         ;; don't need "limited" "private" here; they are matched separately
-         "with"; context clause
-         "\\)\\>[ \t]*"
-         "\\(\\(?:\\sw\\|[_., \t]\\)+\\>\\)?"; ada-name-regexp, plus ", \t"
-         )
-        '(1 font-lock-keyword-face) '(2 font-lock-constant-face nil t))
-
-   ;; statement labels
-   '("<<\\(\\sw+\\)>>" 1 font-lock-constant-face)
-
-   ;; based numberic literals
-   (list "\\([0-9]+#[0-9a-fA-F_]+#\\)" '(1 font-lock-constant-face t))
-
-   ;; numeric literals
-   (list "\\W\\([-+]?[0-9._]+\\)\\>" '(1 font-lock-constant-face))
-
+   (list (concat "\\<" (regexp-opt ada-keywords t) "\\>") '(0 font-lock-keyword-face))
    ))
 
 ;;;; ada-mode
@@ -2690,6 +2690,7 @@ The paragraph is indented on the first line."
 
   (set (make-local-variable 'require-final-newline) t)
 
+  ;; 'font-lock-defaults' is a confusing name; it's buffer local
   (setq font-lock-defaults
        '(ada-font-lock-keywords
          nil t
@@ -2733,6 +2734,8 @@ The paragraph is indented on the first line."
 
   (easy-menu-add ada-mode-menu ada-mode-map)
 
+  (setq ada-case-strict (ada-prj-get 'case_strict))
+
   (run-mode-hooks 'ada-mode-hook)
 
   ;; If global-font-lock is not enabled, ada-syntax-propertize is
@@ -2754,10 +2757,11 @@ The paragraph is indented on the first line."
   ;; This means to fully set ada-mode interactively, user must
   ;; do M-x ada-mode M-; (hack-local-variables)
 
-  (when global-font-lock-mode
-    ;; This calls ada-font-lock-keywords, which depends on
-    ;; ada-language-version
-    (font-lock-refresh-defaults))
+  ;; fill-region-as-paragraph in ada-fill-comment-paragraph does not
+  ;; call syntax-propertize, so set comment syntax on
+  ;; ada-fill-comment-prefix. In post-local because user may want to
+  ;; set it per-file.
+  (put-text-property 0 2 'syntax-table '(11 . nil) ada-fill-comment-prefix)
 
   (cl-case ada-language-version
    (ada83
@@ -2780,6 +2784,11 @@ The paragraph is indented on the first line."
                  ada-2005-keywords
                  ada-2012-keywords))))
 
+  (when global-font-lock-mode
+    ;; This calls ada-font-lock-keywords, which depends on
+    ;; ada-keywords
+    (font-lock-refresh-defaults))
+
   (when ada-goto-declaration-start
     (set (make-local-variable 'beginning-of-defun-function) ada-goto-declaration-start))
 
@@ -2800,9 +2809,8 @@ The paragraph is indented on the first line."
 
 (unless (featurep 'ada-xref-tool)
   (cl-case ada-xref-tool
-    ((nil 'gnat) (require 'ada-gnat-xref))
-    ('gnat_inspect (require 'gnat-inspect))
-    ('gpr_query (require 'gpr-query))
+    ((nil gnat) (require 'ada-gnat-xref))
+    (gpr_query (require 'gpr-query))
     ))
 
 (unless (featurep 'ada-compiler)