comp.lang.ada
 help / color / mirror / Atom feed
From: Stephen.leake@gsfc.nasa.gov
Subject: Re: Emacs Ada-Mode
Date: 1998/05/26
Date: 1998-05-26T00:00:00+00:00	[thread overview]
Message-ID: <uhg2d7zt3.fsf@ANARRES.i-did-not-set--mail-host-address--so-shoot-me> (raw)
In-Reply-To: x7vvhqzmnc1.fsf@pogner.demon.co.uk


Simon Wright <simon@pogner.demon.co.uk> writes:

> brianorpin@bigfoot.com (Brian Orpin) writes:
> 
> > Does anyone know if there is a more recent version of the Ada-Mode than
> > 2.23?
> > 
> > What I would like is an extension to the mode to align the colons in
> > record declarations.
> 
> Just to report experience so far, the 2.28 posted here seems to do
> this just fine under 19.34 (GNU Emacs 19.34.1 (i486-pc-linux-gnu, X
> toolkit))
<snip>

He asked about "record declarations", not "parameter lists". As it happens,
I've been working on a record declaration formatter, and given the three-day
weekend, it now seems to be working. Here's the elisp. I'll also post to
the ada mode mailing list.

(define-key ada-mode-map "\C-c\C-r" 'ada-format-record)


;;; format record

(defvar ada-record-start-re
  "\\<\\(is\\|abstract\\|tagged\\|limited\\|with\\)[ \t\n]+record\\>"
  "Regexp for the start of a record declaration.")

(defvar ada-record-end-re
  "\\<end[ \t\n]+record[ \t\n]*;"
  "Regexp for the end of a record declaration.")

(defvar ada-identifier-re
  "\\([a-zA-Z][a-zA-Z0-9_]*[a-zA-Z0-9]\\)"
  "Regexp for extracting an identifier")

(defvar ada-name-re
  "\\([a-zA-Z][a-zA-Z0-9_\\.\\']*[a-zA-Z0-9]\\)"
  "Regexp for extracting a fully qualified name (including attribute)")

(defvar ada-comment-re
  "[ \t\n]*\\(--.*$\\)"
  "Regexp for extracting a trailing comment")

(defvar ada-comment-line-re
  "^[ \t\n]*\\(--.*\\)$"
  "Regexp for matching a comment line (with no code)")

(defvar ada-whitespace-re
  "[ \t\n]*"
  "Regexp matching Ada whitespace (sans new-page)")

(defun ada-forward-comment-end ()
  "Move forward to end of current multi-line comment"
  (while
      (progn
	(goto-end-line)
	(save-excursion
	  (forward-char 1)
	  (looking-at ada-comment-line-re)))))

(defun ada-format-record ()
  "Reformats a record type declaration.
Warning:    1) only single line trailing comments are preserved
            2) If the syntax is incorrect (especially, if there are
               semicolons missing), it can get totally confused !
In such a case, use `undo', correct the syntax and try again."

  (interactive)
  (let ((begin nil)
	(begin-mark nil)
        (end nil)
	(end-mark nil)
        (delend nil)
        (record nil)
	(match-cons nil))
    (unwind-protect
        (progn 
          (set-syntax-table ada-mode-symbol-syntax-table)

          ;; check if really inside record
          (or (ada-in-record-p)
              (error "not in record"))
          ;;
          ;; find start of current record
          ;;
          (setq match-cons (ada-search-ignore-string-comment ada-record-start-re t nil nil))
          (setq begin (cdr match-cons))
	  (setq begin-mark (copy-marker begin))

          ;;
          ;; find end of record
          ;;
          (setq match-cons (ada-search-ignore-string-comment ada-record-end-re nil nil nil))
          (setq delend (1+ (point)))
	  (setq end-mark (copy-marker (1+ delend)))

          ;; find end of last component declaration
	  (ada-search-ignore-string-comment ada-record-end-re t nil nil)
          (ada-search-ignore-string-comment "[^ \t\n]" t nil nil)
          (forward-char 1)
          (setq end (point))

          ;; build a list of all elements of the record
          (setq record (ada-scan-record (1+ begin) end))

          ;; delete the original record
          (delete-region begin (1- delend))

          ;; insert the new record
          (goto-char begin)
          (ada-insert-record record))

      ;; indent multi-line default expressions and comments
      ;; we use markers, because begin, end positions may be invalid at this point.
      (ada-indent-region begin-mark end-mark)

      (goto-char begin-mark)
      
      ;; restore syntax-table
      (set-syntax-table ada-mode-syntax-table)
      )))

(defun ada-scan-record (begin end)
  ;; Scans a record  between BEGIN and END and returns a list
  ;; of its contents.
  ;; The list has the following format:
  ;;
  ;; nth contents
  ;; 0	 Name of Component
  ;; 1	 Type and constraint
  ;; 2   type-length
  ;; 3   Default-Exp      
  ;; 4   exp-length 
  ;; 5   comment-on-newline-p
  ;; 6   Comment
  ;;
  ;; type-length, exp-length give correct indentation even for multi-line types and expressions.


  (let ((record (list))
        (comp (list))
        component-start
        semipos
        match-cons
	start-column)

    (goto-char begin)
    
    ;; loop for all components
    (while (progn
	     (ada-goto-next-non-ws)
	     (setq component-start (point))
	     (< component-start end))
      
      ;; find last character of component-declaration
      (setq match-cons (ada-search-ignore-string-comment "[ \t\n]*;" nil end t))
      (goto-char component-start)
      (setq semipos (car match-cons))

      ;; read name(s) of component(s)
      (looking-at (concat ada-identifier-re "[ \t\n]*\\(:[ \t\n]*\\)"))

      (setq comp (list (buffer-substring (match-beginning 1) (match-end 1))))
      (goto-char (match-end 2)) ; start of type name

      ;; read subtype of component (with constraint)
      (setq start-column (current-column))
      (looking-at ada-name-re)
      (goto-char (match-end 0))
      (if (save-match-data (looking-at (concat ada-whitespace-re "(")))
	  (forward-sexp))
      (setq comp
	    (append comp
		    (list
		     (buffer-substring (match-beginning 0)
				       (point))
		     (max 0 (- (current-column) start-column)))))

      ;; read default-expression, if there is one
      (setq start-column (current-column))
      (setq comp
            (append comp
		    (if (looking-at "[ \t\n]*\\(:=\\)")
			(progn
			  (goto-char semipos)
			  (list
			   (buffer-substring (match-beginning 1) (point)) ; doesn't include semicolon!
			   (max 0 (- (current-column) start-column))))
		      (list nil 0))))

      ;; read comment, if there is one
      (goto-char (1+ semipos))
      (setq comp
            (append comp
                     (if (looking-at ada-comment-re)
			 (let ((comment-start (match-beginning 1))
			       (new-line (looking-at "[ \t]*$")))
			   (ada-forward-comment-end)
			   (list new-line
				 (buffer-substring comment-start (point))))
		       (list nil nil))))
      
      ;; add this component-declaration to the list
      (setq record (append record (list comp)))

      ) ; end of loop

    (reverse record)))


(defun ada-insert-record (record)
  ;; Inserts a formatted RECORD in the buffer.
  ;; See doc of `ada-scan-record' for the format.
  (let ((i (length record))
	(name-max-length 0)
	(type-max-length 0)
	(exp-max-length 0)
        type-start-col
        exp-start-col
	comment-start-col
        (column nil)
        (orgpoint 0)
        (firstcol nil)
	component)

    ;; newline after 'is record', indent first component
    (ada-indent-newline-indent)

    ;; determine starting columns for each field.
    (setq firstcol (current-column))
    (while (not (zerop i))
      (setq i (1- i))
      (setq component (nth i record))

      (setq name-max-length (max name-max-length (length (nth 0 component))))

      ;; include ' : ' in type length
      (setq type-max-length (max type-max-length (+ 3 (nth 2 component))))

      ;; include '; ' in expression length
      (setq exp-max-length (max exp-max-length (+ 2 (nth 4 component))))
      
      ) ; end while

    (setq type-start-col (+ firstcol 1 name-max-length))
    (setq exp-start-col (+ type-start-col type-max-length))
    (setq comment-start-col (+ exp-start-col exp-max-length))
      
    (setq i (length record))

    ;; Insert all components. Components in 'record' are in reverse order
    (while (not (zerop i))
      (setq i (1- i))
      (setq column firstcol)

      (setq component (nth i record))
      
      ;; insert component name and type
      (insert (nth 0 component))
      (indent-to type-start-col)
      (insert ": ")
      (insert (nth 1 component))

      ;; insert default-expression (if any)
      (if (nth 3 component)
          (progn
            (indent-to exp-start-col)
            (insert (nth 3 component))
	    ))
      
      (insert ";")
      
      ;; insert comment (if any)
      (if (nth 6 component)
          (progn
	    (if (nth 5 component)
		(ada-indent-newline-indent)
	      (indent-to comment-start-col))
            (insert (nth 6 component))))

      (newline-and-indent)
      ) ; end of loop

    (insert "end record;")
    (ada-indent-current)
    ))

(defun ada-in-record-p ()
  ;; Returns t if point is inside a record type declaration
  (interactive)
  (save-excursion
    (and
     (re-search-backward (concat "\\<end\\(;\\|\\>\\)\\|\\(" ada-record-start-re "\\)") nil t)
     (not (looking-at "end")))))

;;; end format record




  parent reply	other threads:[~1998-05-26  0:00 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <356680b9.18964466@news.geccs.gecm.com>
1998-05-19  0:00 ` Emacs Ada-Mode David C. Hoos, Sr.
1998-05-19  0:00   ` David  Weller
1998-05-19  0:00   ` John McCabe
1998-05-19  0:00 ` Philippe Waroquiers
1998-05-20  0:00   ` Scott Evans
     [not found]   ` <356283c4.2281076@news.geccs.gecm.com>
1998-05-20  0:00     ` John McCabe
1998-05-21  0:00 ` Simon Wright
     [not found]   ` <35693157.3762034@news.geccs.gecm.com>
1998-05-22  0:00     ` Mattias Sj�sv�rd
1998-05-26  0:00   ` Stephen.leake [this message]
1998-05-26  0:00 ` Matthew Heaney
2006-08-18 12:07 Emacs ada-mode Stephen Leake
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox