home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / me34src.zip / me3 / mutt / package / cmode.mut < prev    next >
Text File  |  1995-01-14  |  13KB  |  445 lines

  1. ;; cmode.mut : an electric C mode
  2.  
  3. ;;   Electric C mode is designed to help keep your C code formatted "as you
  4. ;; code".  You don't have to remember anything special - as you type, what
  5. ;; you type is looked at and may trigger certain actions.  This is a
  6. ;; minimalist C mode ment to enable you to keep your C code formatted in a
  7. ;; consistant manner.  The only extensive help is for comments.
  8.  
  9. ;; Characters that trigger formatting:
  10. ;;  "{": When a "{" is pressed, one of the following will happen:
  11. ;;     - If the space bar is pressed, "{ }" is generated and the cursor is
  12. ;;     put between the braces.
  13. ;;     - If Enter is pressed:
  14. ;;       And the rest of the line is blank, you will get something like:
  15. ;;        if (a) {        or  if (a)
  16. ;;          cursor        {
  17. ;;        }              cursor
  18. ;;                }
  19. ;;       depending on where the "{" was.  The cursor is indented by the
  20. ;;       amount specified by "INDENT-LEVEL".
  21. ;;     If the rest of the line was not blank, a newline-and-indent is
  22. ;;       done and the text after the { is indented.
  23. ;;       For example:
  24. ;;        if (a) foo(): if a "{ Enter" is done before the foo()
  25. ;;        you will get:
  26. ;;        if (a) {
  27. ;;          foo()
  28. ;;     - Otherwise, a "{" is inserted.
  29. ;;  Backspace:  Behaves like backspacing over spaces even when backspacing
  30. ;;    over tabs.
  31. ;;  Newline (control-J):  Used to give some white space after a variable
  32. ;;    declaration block.  The cursor is left at the same column as the start
  33. ;;    of the declarations.
  34. ;;    int j;    => int j;
  35. ;;           blank line
  36. ;;           cursor
  37. ;;  "/": Comment assistance.
  38. ;;     - If "*" is pressed and the rest of the line is blank and there is
  39. ;;     text to the left of the "/", "/* */" is generated and the cursor
  40. ;;     is put in the middle of the comment.  This is for end of line
  41. ;;     comments like:  if (a) foobar();    /* comment */
  42. ;;     - If "*" is pressed and the entire line is blank, block comment mode
  43. ;;     is entered.  In this mode, your comment will autowrap at the
  44. ;;     COMMENT-WRAP-COLUMN.  When you hit Enter or autowrap, stars are
  45. ;;     put in the proper place, whitespace is added to match the
  46. ;;     previous comment line.  If you press Enter "/", comment mode will
  47. ;;     terminate.  "*/" or "*" blanks "/" will also terminate comment
  48. ;;     mode.  If you want to get out of comment mode without using the
  49. ;;     above, press M-; or execute "nocomment".
  50. ;;     Examples:
  51. ;;        /*
  52. ;;             * Comment
  53. ;;         *   Indented a bit
  54. ;;         *   Next line follows the indent.
  55. ;;         */
  56. ;;        /*
  57. ;;        ** Another comment style
  58. ;;        */
  59. ;;     - Otherwise, a "/" is inserted.
  60. ;;  Meta-;
  61. ;;    If in block comment mode, turn off comment mode.
  62. ;;    If the cursor is on a line that is part of a block comment, start up
  63. ;;      block comment mode.  This is very handy for adding to an existing
  64. ;;      block comment.
  65. ;;  Meta-J:  Format a C block comment.
  66. ;;    If you munge a block comment and want to set it right, use this.
  67. ;;    This formats all the lines between the dot and mark inclusive.
  68. ;;    Put the region around the comment (or the part of the comment you want
  69. ;;      to format) and press M-J.  The comment is commented in the format of
  70. ;;      comment mode.
  71. ;;    Notes:
  72. ;;    To make sure that line breaks are preserved, insert blank lines at
  73. ;;      the breaks.  The blank lines will be deleted after the comment
  74. ;;      is formatted.
  75. ;;    To change the indent level of the block, indent the first line of
  76. ;;      the region to where you want.
  77. ;;  Control-U Meta-J: Format a C boxed comment.
  78. ;;    Same as format block comment except the comment is boxed:
  79. ;;    /********************************
  80. ;;     *   Comment            *
  81. ;;     ********************************/
  82. ;;  You can convert between boxed and block comments by just reformatting.
  83.  
  84. ;; C Durland    Public Domain
  85.  
  86.  
  87. (const
  88.   INDENT-LEVEL        2    ;; spaces to indent a {} block
  89.   COMMENT-WRAP-COLUMN  76    ;; where to word wrap in comment mode
  90.   TAB-SIZE        0    ;; 0 means use tabs else n spaces for each tab
  91.  
  92.   C-STARS " *"        ;; comment body stars: " *"  or "**".
  93.   COMET   " */"        ;; comment end stars:  " */" or "*/".
  94.  
  95.     ;; number of blank lines before and after text in boxed comment
  96.   BOXED-COMMENT-SPACE        1    ;; blank lines between box and text
  97.   BOXED-COMMENT-TRAILING-BLANKS 1    ;; blanks between text and *
  98.   BOXED-COMMENT-EDGE-STARS    "*"    ;; right edge stars: "*" or "**"
  99.  
  100.   ENTER-KEY-ACTION "newline-and-indent"    ;; newline-and-indent or newline
  101. )
  102.  
  103. (int
  104.   indent-level comment-wrap-column
  105.   boxed-comment-space boxed-comment-trailing-blanks
  106. )
  107. (string c-stars comet boxed-comment-edge-stars enter-key-action)
  108.  
  109. (include me.mh)
  110.  
  111. (int C-mode-keymap C-comment-keymap)
  112.  
  113. (defun
  114.   MAIN
  115.   {
  116.     (bind-key (C-mode-keymap (create-keymap))
  117.     ENTER-KEY-ACTION    "C-m"
  118.     "C-mode-{"        "{"
  119.     "after-declare"        "C-j"
  120.     "Dr.commento"        "/"
  121.     "BS-untabify"        "C-h"
  122.     "format-C-comment"    "M-j"
  123.     "Nurse-commento"    "M-;")
  124.  
  125.     (bind-key (C-comment-keymap (create-keymap))
  126.     "Dr.CR"            "C-m"
  127.     "C-mode-/"        "/"
  128.     "nocomment"        "M-;"
  129.     "format-C-comment"    "M-j"
  130.     "BS-untabify"        "C-h"
  131.     )
  132.   }
  133.   c-mode    ; set up electric C mode
  134.   {
  135.     (clear-modes)
  136.  
  137.     (install-keymap C-mode-keymap LOCAL-KEYMAP)
  138.  
  139.     (create-buffer-var NUMBER "comment-offset")
  140.  
  141.     (major-mode "C")
  142.  
  143.     (tab-stops TAB-SIZE)
  144.     (c-mode-etc INDENT-LEVEL COMMENT-WRAP-COLUMN C-STARS COMET)
  145.     (c-mode-boxed BOXED-COMMENT-SPACE BOXED-COMMENT-TRAILING-BLANKS
  146.           BOXED-COMMENT-EDGE-STARS)
  147.  
  148.     (if (pgm-exists "c-mode-hook") (floc "c-mode-hook"()))
  149.  
  150.     (enter-key-action (key-bound-to "C-m"))
  151.   }
  152.   c-mode-etc (int indent comment-wrap) (string stars comets)
  153.   {
  154.     (indent-level indent)
  155.     (comment-wrap-column comment-wrap)
  156.     (c-stars stars)
  157.     (comet comets)
  158.   }
  159.   c-mode-boxed (int comment-space trailing-blanks) (string edge-stars)
  160.   {
  161.     (boxed-comment-space        comment-space)
  162.     (boxed-comment-trailing-blanks    trailing-blanks)
  163.     (boxed-comment-edge-stars        edge-stars)
  164.   }
  165. )
  166.  
  167. (include bs_untab.mut)
  168. (include block.mut)
  169.  
  170. (defun
  171.   "C-mode-{"    ; handle {
  172.   {
  173.     (int key n)
  174.  
  175.     (insert-text "{")(update)
  176.     (switch (key (get-key))
  177.       Space-bar        ;  try for { . } else just insert a blank
  178.     {
  179.       (if (looking-at '\ *$')    ; only whitespace 'til end of line
  180.         { (insert-text "  }")(previous-character)(previous-character) }
  181.         (insert-text " ")
  182.       )
  183.     }
  184.       Enter-key
  185.         {
  186.       (newline-and-indent)(n (current-column))
  187.       (if (looking-at '\ *$')    ; white space to end of line
  188.       {
  189.         (insert-text "}")
  190.         (beginning-of-line)(open-line)
  191.       })
  192.       (to-col (+ n indent-level))
  193.     }
  194.       default (exe-key key)
  195.     )
  196.   }
  197.   after-declare        ; properly indent after a var declare
  198.   {
  199.     (newline-and-indent)(beginning-of-line)(open-line)
  200.     (forward-line 1)(end-of-line)
  201.   }
  202. )
  203.  
  204. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  205. ;;;;;;;;;;;;; Comment mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  206. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  207.  
  208. (defun
  209.   Dr.commento        ; handle "/" & start up comment mode if need be
  210.   {
  211.     (int key col)
  212.  
  213.     (insert-text "/")(update)
  214.     ;; Check to see if starting a comment.  No "*" => no comment
  215.     (if (!= (key (get-key)) 0x2A) { (exe-key key)(done) } )
  216.     ;; check to see if this is a comment block
  217.     (insert-text "*")
  218.     (col (current-column))(beginning-of-line)
  219.     (if (not (looking-at '\ */\*\ *$'))    ; ws/*ws
  220.     {        ; its not a comment block - give them "/*   */"
  221.       (current-column col)
  222.       (if (looking-at '\ *$')    ; only if at end of line
  223.     { (insert-text "  */")(arg-prefix 3)(previous-character) } )
  224.       (done)
  225.     })
  226.     (current-column col)    ;; move back to where we started
  227.     (insert-text " ")        ;; make it look like "/* "
  228.     (start-block-comment col)
  229.   }
  230.   Nurse-commento    ;; Reenter block comment mode
  231.   {
  232.     (int col)
  233.  
  234.     (col (current-column))(beginning-of-line)
  235.     (if (or
  236.       (looking-at '\ *\*')        ;; [ws]*
  237.       (looking-at '\ */\*'))    ;; [ws]/*
  238.       {
  239.     (search-forward '*')
  240.     (start-block-comment (current-column))
  241.     (beginning-of-line)
  242.     (if (looking-at '.*\*/')        ;; [stuff]*/
  243.     {
  244.       (msg 'Notice that trailing "*/"!')
  245.     })
  246.       }
  247.       {
  248.     (msg "Not in a block comment!")
  249.       })
  250.     (current-column col)
  251.   }
  252.   start-block-comment (int col)    HIDDEN        ;; turn on block comment mode
  253.   {
  254.     (buffer-var "comment-offset" (- col 2))
  255.     (word-wrap comment-wrap-column)
  256.     (install-keymap C-comment-keymap LOCAL-KEYMAP)
  257.     (minor-mode "Dr. Commento")
  258.   }
  259.   nocomment                ;; Turn off comment mode
  260.   {
  261.     (install-keymap C-mode-keymap LOCAL-KEYMAP)
  262.     (minor-mode "")
  263.     (word-wrap 0)
  264.   }
  265.   Dr.CR                ;; handle Enter while in comment mode
  266.   {
  267.     (open-line)(beginning-of-line)
  268.         ;; Note: save ws after *'s so can preserve indent.
  269.     (if (looking-at '\ *.\ *\*+\(\ *\)') ; [ws]/*[ws] | ws*[*...][ws]
  270.       {
  271.     (forward-line 1)
  272.     (to-col (buffer-var "comment-offset"))
  273.     (insert-text c-stars (get-matched '\1'))    ;; match prev indent
  274.       }
  275.       {        ;; probably should handle this case better
  276.     (forward-line 1)
  277.     (msg "Your not in a comment block!")
  278.       })
  279.   }
  280.   C-mode-/            ;; handle "/" in comment mode
  281.   {
  282.     (int col)
  283.  
  284.     (col (current-column))
  285.     (previous-character)
  286.     (if (looking-at '\*')        ;; "*/" => ending comment
  287.       { (nocomment)(goto ick) })
  288.     (beginning-of-line)
  289.     (if (looking-at '\ *\*+\ *$')    ;; [ws]*[*...][ws]/
  290.     {
  291.       (current-column (buffer-var "comment-offset"))
  292.       (cut-line)
  293.       (insert-text comet)
  294.       (nocomment)
  295.       (done)
  296.     })
  297.   (label ick)
  298.     (current-column col)(insert-text "/")
  299.   }
  300. )
  301.  
  302. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  303. ;;;;;;;; Format block comment ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  304. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  305.  
  306. (defun
  307.   add-stars (int n) HIDDEN
  308.   {
  309.     (int j)
  310.  
  311.     (j (+ n 1))
  312.     (while (!= 0 (-= j 1)) (insert-text "*"))
  313.   }
  314.   format-C-comment
  315.   {
  316.     (bool start-comment end-comment boxed-comment)
  317.     (int offset j)
  318.     (int code-buffer scrbuf bag-id)
  319.  
  320.     (boxed-comment (arg-flag))
  321.  
  322.     (start-comment (end-comment FALSE))
  323.  
  324.     (code-buffer (current-buffer))
  325.     (delete-region-as-block)
  326.  
  327.     (current-buffer (scrbuf (create-buffer scratch-buffer)))
  328.  
  329.     (insert-bag CUT-BUFFER)
  330.  
  331.     (beginning-of-buffer)
  332.     (if (re-search-forward '^\ */\*')    ; ^[ws]/*
  333.       {
  334.     (start-comment TRUE)
  335.     (offset (- (current-column) 2))
  336.     (beginning-of-line)
  337.     (re-search-replace '^\ */\*+' "")  ; get rid of ^[ws]/*[*...]
  338.       }
  339.       {
  340.     (if (search-forward c-stars)
  341.       (offset (- (current-column) 2))
  342.       {
  343.         ; else get the block offset from left margin
  344.         (beginning-of-line)
  345.         (while (is-space) (next-character))
  346.         (offset (current-column))
  347.       }
  348.     )
  349.       }
  350.     )
  351.  
  352.     (beginning-of-buffer)
  353.     (if (re-search-forward '\*/\ *$')    ; */[ws]$
  354.     {
  355.       (end-comment TRUE)
  356.       (beginning-of-line)
  357.       (re-search-replace '\ *\*+/\ *$' "")    ; get rid of [ws]*[*...]/[ws]$
  358.     })
  359.     (beginning-of-buffer)
  360.     (re-search-replace '^\ *\*+' "")    ; get rid of [white-space]*[*...]
  361.  
  362.     (beginning-of-buffer)
  363.     (re-search-replace '\ *\*+$' "")    ; get rid of [white-space]*[*...]$
  364.  
  365.     (msg "Formatting comment ...")
  366.     (beginning-of-buffer)
  367.     (adjust-lines
  368.       10000
  369.       (- comment-wrap-column offset 1
  370.     (if boxed-comment
  371.       (+ (length-of boxed-comment-edge-stars)
  372.          boxed-comment-trailing-blanks)
  373.       0
  374.     ))
  375.       FALSE
  376.     )
  377.     (beginning-of-buffer)
  378.     
  379.     ; put /*, * and */ in front of text
  380.     (if start-comment
  381.     {
  382.       (to-col offset)(insert-text '/*')
  383.       (if boxed-comment
  384.       {
  385.     (if (not (looking-at '\ *$')) (open-line))
  386.     (add-stars (- comment-wrap-column (current-column)))
  387.     (insert-text boxed-comment-edge-stars)
  388.     (j boxed-comment-space)
  389.     (while (<= 0 (-= j 1))
  390.     {
  391.       (newline-and-indent)(insert-text c-stars)
  392.       (to-col comment-wrap-column)(insert-text boxed-comment-edge-stars)
  393.     })
  394.       })
  395.       (forward-line 1)
  396.     })
  397.     (while (not (EoB))
  398.     {
  399.       (if (looking-at '^$')
  400.         { (arg-prefix 1)(cut-line)(continue) }        ; remove blank lines
  401.     {        ; else prepend *
  402.       (to-col offset)(insert-text c-stars)
  403.       (if boxed-comment
  404.           {
  405.         (end-of-line) (to-col comment-wrap-column)
  406.         (insert-text boxed-comment-edge-stars)
  407.       })
  408.     }
  409.       )
  410.       (forward-line 1)
  411.     })
  412.     (if end-comment
  413.     {
  414.       (to-col offset)
  415.       (if boxed-comment
  416.     {
  417.       (j boxed-comment-space)
  418.       (while (<= 0 (-= j 1))
  419.       {
  420.         (insert-text c-stars)
  421.         (to-col comment-wrap-column)(insert-text boxed-comment-edge-stars)
  422.         (newline)(to-col offset)
  423.       })
  424.       (insert-text c-stars)
  425.       (add-stars (- comment-wrap-column (current-column)))
  426.       (insert-text boxed-comment-edge-stars "/")
  427.     }
  428.     (insert-text comet)
  429.       )
  430.     })
  431.  
  432.     ;; replace comment
  433.     (beginning-of-buffer)(set-mark)(end-of-buffer)
  434.     (append-to-bag (bag-id (create-bag)) APPEND-REGION)
  435.  
  436.     (msg "Comment formatted.")
  437.  
  438.     (current-buffer code-buffer)
  439.     (insert-bag bag-id)
  440.  
  441.     ; clean up
  442.     (free-buffer scrbuf)(free-bag bag-id)
  443.   }
  444. )
  445.