home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / misc / comm-regn.el < prev    next >
Encoding:
Text File  |  1990-03-21  |  10.7 KB  |  286 lines

  1. ;From ark1!nems!mimsy!haven!umbc3!kochab.cs.umbc.edu!cdwilli Sat Dec  9 23:50:48 EST 1989
  2. ;Article 1011 of comp.emacs:
  3. ;Path: ark1!nems!mimsy!haven!umbc3!kochab.cs.umbc.edu!cdwilli
  4. ;>From: cdwilli@kochab.cs.umbc.edu
  5. ;Newsgroups: comp.emacs
  6. ;Subject: Commenting and Uncommenting C and Lisp in Gnu Emacs...
  7. ;Message-ID: <2601@umbc3.UMBC.EDU>
  8. ;Date: 8 Dec 89 03:02:56 GMT
  9. ;Sender: newspost@umbc3.UMBC.EDU
  10. ;Reply-To: cdwilli@kochab.cs.umbc.edu ()
  11. ;Distribution: na
  12. ;Organization: University of Maryland Baltimore County
  13. ;Lines: 271
  14. ;
  15. ;
  16. ;
  17. ;Have you ever wanted to comment out a block of C or Lisp code
  18. ;while using GNU EMACS?  Two functions, (comment-region) and
  19. ;(uncomment-region), make this easy.  In C, they check for nesting
  20. ;of comments as well as unbalanced delimiters.  Try them out by
  21. ;marking a region of code, then typing M-x comment-region, M-x
  22. ;uncomment-region.
  23.  
  24. ;;; COMMENT-REGION -- The user sets the mark (CTRL-@), then moves the
  25. ;;; point (cursor) to another place in the buffer.  He then types M-x
  26. ;;; comment-region.  The area between the mark and the cursor is
  27. ;;; commented in the appropriate style depending on what mode the
  28. ;;; buffer is in (currently Lisp, EMACS Lisp, and C modes are working).
  29. ;;; UNCOMMENT-REGION -- Does the reverse of comment-region.
  30. ;;;
  31. ;;; HOW TO USE THESE FUNCTIONS:
  32. ;;; Type M-x load-file <return>, give the name of this file and
  33. ;;; <return>.  Now, if you want to comment some code, move the cursor
  34. ;;; to a point in the buffer, then set a mark (CTRL-@).  Move the
  35. ;;; cursor again to specify a region to comment, then type M-x
  36. ;;; comment-region <return>.
  37. ;;; To uncomment code, specify a region as described above, then type
  38. ;;; M-x uncomment-region <return>.
  39.  
  40. ;;; Lisp commenting works line-by-line, commenting out whole lines at
  41. ;;; a time.  C commenting, on ;the other hand, looks for uncommented
  42. ;;; regions within the whole region to be commented (the C compiler
  43. ;;; doesn't allow nesting of comments, so we have to search for any
  44. ;;; comments already in the region).
  45.  
  46. ;;; TO DO:  This program can be extended to include GNU's
  47. ;;; fortran-comment-region.  One needs to write a
  48. ;;; fortran-uncomment-region as well.
  49.  
  50. (defun comment-region ()
  51.   "Insert the proper comment characters into the region of a program.
  52. Used to comment blocks of Lisp or C code."
  53.   (interactive)
  54.   (let ((start-position (make-marker))
  55.     (end-position (make-marker)))
  56.     (set-marker start-position (mark))
  57.     (set-marker end-position (point))
  58.     (cond ((or (eq major-mode 'lisp-mode) (eq major-mode 'emacs-lisp-mode))
  59.        (comment-lines start-position end-position 'comment-lisp-line)
  60.        (goto-char (marker-position end-position)))
  61.       ((eq major-mode 'c-mode)
  62.        (c-comment-region start-position end-position))
  63.       (t (error "Don't know how to comment %s mode." major-mode)))))
  64.  
  65. (defun uncomment-region ()
  66.   "Remove comment delimiters from a region of code.  Works with
  67. comments created by function comment-region.  Lisp or C."
  68.   (interactive)
  69.     (let ((start-position (make-marker))
  70.       (end-position (make-marker))
  71.       (final-position (make-marker)))
  72.       (set-marker start-position (mark))
  73.       (set-marker end-position (point))
  74.       (set-marker final-position end-position)
  75.       (cond ((or (eq major-mode 'lisp-mode) (eq major-mode 'emacs-lisp-mode))
  76.          (comment-lines start-position end-position 'uncomment-lisp-line)
  77.          (goto-char (marker-position end-position)))
  78.         ((eq major-mode 'c-mode)
  79.          (c-uncomment-region start-position end-position))
  80.         (t (error "Don't know how to uncomment %s mode." major-mode)))))
  81.  
  82. ;;; ****************************************************************
  83. ;;; LISP COMMENTING AND UNCOMMENTING FUNCTIONS
  84. ;;; ****************************************************************
  85.  
  86. ;;; Loop through, commenting each line.
  87. (defun comment-lines (start-position end-position comment-function)
  88.   (save-excursion
  89.   (let ((number-of-lines-to-comment (count-lines start-position end-position)))
  90.     (goto-char start-position)
  91.     (while (> number-of-lines-to-comment 0)
  92.       (beginning-of-line)
  93.       (funcall comment-function)
  94.       (setq number-of-lines-to-comment
  95.         (- number-of-lines-to-comment 1))
  96.       (go-to-next-line start-position end-position)))))
  97.  
  98. ;;; Go forward or backward one line, depending on values of start and end.
  99. (defun go-to-next-line (start end)
  100.   (cond ((< start end) (next-line 1))
  101.     ((> start end) (next-line -1))))
  102.  
  103. ;;; Comment the current-line using Lisp commenting rules.
  104.  (defun comment-lisp-line ()
  105.    (beginning-of-line)
  106.    (insert ";;; "))
  107.  
  108. (defun uncomment-lines (start-position end-position uncomment-function)
  109.   (save-excursion
  110.     (let ((number-of-lines-to-uncomment
  111.        (count-lines start-position end-position)))
  112.       (goto-char start-position)
  113.       (while (> number-of-lines-to-uncomment 0)
  114.     (beginning-of-line)
  115.     (funcall uncomment-function)
  116.     (setq number-of-lines-to-uncomment
  117.           (- number-of-lines-to-uncomment 1))
  118.     (go-to-next-line start-position end-position)))))
  119.  
  120.  
  121. ;;; Replace all semicolons at the beginning of the line up to a space.
  122. ;;; If a space is left after the point, delete that, too.
  123. (defun uncomment-lisp-line ()
  124.   (beginning-of-line)
  125.   (delete-semicolons (point))
  126.   (if (string-equal (char-to-string (char-after (point)))
  127.             " ")
  128.       (delete-char 1)))
  129.  
  130. (defun delete-semicolons (point)
  131.   (while (string-equal (char-to-string (char-after (point)))
  132.                ";")
  133.     (delete-char 1)))
  134.  
  135. ;;;****************************************************************
  136. ;;; C COMMENTING AND UNCOMMENTING FUNCTIONS.
  137. ;;;****************************************************************
  138. (defun c-comment-region (start end)
  139.   ;; If region has been marked from the bottom to the top of the buffer,
  140.   ;; switch to start and end points.
  141.   (if (> start end)
  142.       (let ((temp start))
  143.     (setq start end)
  144.     (setq end temp)))
  145.   ;; Check for nothing marked.  If something marked, check whether the
  146.   ;; region contains any comments already.  If it doesn't, do a simple
  147.   ;; comment of a region.  If it does, check whether it has any
  148.   ;; unbalanced or unnested comments.
  149.   (if (not (= start end))        ;No commenting an empty region.
  150.       (cond ((not (c-comments-present-p start end))
  151.          (simple-c-comment start end))
  152.         ((and (balanced-unnested-c-comments-p "/*$" "$*/" start end)
  153.           (balanced-unnested-c-comments-p "/*" "*/" start end))
  154.          (c-comment-uncommented-regions start end)))))
  155.  
  156. ;;; This is the mate to c-comment-region.  It first checks for
  157. ;;; unbalanced and nested comment delimiters, then, if all is well, it
  158. ;;; deletes all occurrences of "/*$" and "$*/".
  159. (defun c-uncomment-region (start end)
  160.   ;; If region has been marked from the bottom to the top of the
  161.   ;; buffer, switch start and end points.
  162.   (if (> start end)
  163.       (let ((temp start))
  164.     (setq start end)
  165.     (setq end temp)))
  166.   (if (not (= start end))
  167.       (cond ((not (c-comments-present-p start end))
  168.          (message "No comments in region."))
  169.         ((and (balanced-unnested-c-comments-p
  170.            "/*$" "$*/" start end)
  171.           (balanced-unnested-c-comments-p
  172.            "/*" "*/" start end))
  173.          (c-uncomment-commented-regions start end)))))
  174.  
  175. (defun c-uncomment-commented-regions (start end)
  176.   "Takes two markers that delimit a region and removes any C comment
  177.    delimiters involving $."
  178.   (let ((original-point (point-marker)))
  179.     (goto-char (marker-position start))
  180.     (while (search-forward "/*$" end t)
  181.       (goto-char (- (point) 3))
  182.       (delete-char 3)
  183.       (cond
  184.        ((search-forward "$*/" (marker-position end) t)
  185.     (goto-char (- (point) 3))
  186.     (delete-char 3))
  187.        (t (error "Unbalanced C delimiters.  Missing %s." "$*/"))))
  188.     (goto-char (marker-position original-point))))
  189.   
  190.           
  191. (defun c-comments-present-p (start end)
  192.   (or (first-string-occurrence "/*" start end)
  193.       (first-string-occurrence "*/" start end)))
  194.  
  195. (defun first-string-occurrence (string start end)
  196.   (let (string-present)
  197.     (if (markerp start)
  198.     (goto-char (marker-position start))
  199.       (goto-char start))
  200.     (if (markerp end)
  201.     (setq string-present (search-forward string (marker-position
  202.                              end) t))
  203.       (setq string-present (search-forward string end t)))
  204.     (if string-present
  205.     (setq string-present (point)))
  206.     string-present))
  207.       
  208. (defun c-comment-uncommented-regions (start end)
  209.   (let ((m1 (make-marker))
  210.     (m2 (make-marker)))
  211.     (set-marker m1 start)
  212.     (set-marker m2 end)
  213.     (while (not (= m1 m2))
  214.       (let ((m3 (make-marker)))
  215.     ;; Find the beginning of a comment.
  216.     (set-marker m3 (first-string-occurrence "/*" m1 m2))
  217.     (cond ((marker-position m3)
  218.            (set-marker m3 (- m3 2))
  219.            (simple-c-comment m1 m3)
  220.            (set-marker m1 (first-string-occurrence "*/" m3 m2))
  221.            (if (not (marker-position m1))
  222.            (setq m1 m2)))
  223.           (t (simple-c-comment m1 m2)
  224.          (setq m1 m2)))))))
  225.  
  226. ;;; Place "/*$" at the beginning of region and "$*/" at the end.
  227. ;;; Leave the point as it was.
  228. (defun simple-c-comment (start end)
  229.   "Takes two markers that delimit region.  Comments a region with C
  230. comment delimiters.  Assumes no comments already in region."
  231.   (let ((original-point (point-marker))
  232.     (begin-comment "/*$")
  233.     (end-comment "$*/"))
  234.     (goto-char (marker-position start))
  235.     (skip-chars-forward "[\t\n ]*" (marker-position end))
  236.     (set-marker start (point))
  237.     (cond ((not (= start end))
  238.        (insert begin-comment)
  239.        (goto-char (marker-position end))
  240.        (skip-chars-backward "[\t\n ]*")
  241.        (insert end-comment)
  242.        (goto-char (point)))
  243.       (t nil))))
  244.  
  245. (defun balanced-unnested-c-comments-p (left right start end)
  246.   (balanced-but-unnested-aux left right start end))
  247.  
  248. (defun balanced-but-unnested-aux (first second start end)
  249.   (let* ((first-delimiter-list
  250.       (find-closest-string start end first second))
  251.      (first-delimiter (car first-delimiter-list))
  252.      (first-delimiter-location (car (cdr first-delimiter-list))))
  253.     (if first-delimiter
  254.     (if (string-equal first-delimiter first)
  255.         (let* ((next-delimiter-list
  256.             (find-closest-string
  257.              first-delimiter-location end first second))
  258.            (next-delimiter (car next-delimiter-list))
  259.            (next-delimiter-location (car (cdr next-delimiter-list))))
  260.           (if next-delimiter-list
  261.           (if (string-equal next-delimiter second)
  262.               (balanced-but-unnested-aux
  263.                first second next-delimiter-location end)
  264.             (error "Unbalanced delimiters.  Extra %s." first))
  265.           (error "Unbalanced delimiters. %s missing." second)))
  266.       (error "Unbalanced delimiters. %s missing." first))          
  267.       t)))
  268.           
  269. (defun find-closest-string (start end &rest string-list)
  270.   (let ((closest (+ end 1))
  271.     (current-string ""))
  272.     (while string-list
  273.       (let ((distance (first-string-occurrence (car string-list)
  274.                            start end)))
  275.     (if distance
  276.         (if (< distance closest)
  277.         (progn
  278.           (setq closest distance)
  279.           (setq current-string (car string-list)))))
  280.     (setq string-list (cdr string-list))))
  281.     (if (null-string current-string)
  282.     nil
  283.       (list current-string closest))))
  284.  
  285. (defun null-string (s) (string-equal "" s))
  286.