home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / help-lucid-emacs / text0604.txt < prev    next >
Encoding:
Text File  |  1993-07-14  |  11.2 KB  |  302 lines

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