Mercurial > hg > xemacs-beta
diff lisp/modes/c-fill.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/modes/c-fill.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,272 @@ +;;; C comment mode - An auto-filled comment mode for gnu c-mode. +;;; +;;; Author: Robert Mecklenburg +;;; Computer Science Dept. +;;; University of Utah +;;; From: mecklen@utah-gr.UUCP (Robert Mecklenburg) +;;; Also hartzell@Boulder.Colorado.EDU +;;; (c) 1986, University of Utah +;;; +;;; Everyone is granted permission to copy, modify and redistribute +;;; this file, provided the people they give it to can. + +;;; Synched up with: Not in FSF. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; I have written a "global comment" minor-mode which performs auto-fill, +;;; fill-paragraph, and auto-indentation functions. This function only +;;; works for comments which occupy an entire line (not comments to the +;;; right of code). The mode has several options set through variables. +;;; If the variable c-comment-starting-blank is non-nil multi-line +;;; comments come out like this: +;;; +;;; /* +;;; * Your favorite +;;; * multi-line comment. +;;; */ +;;; +;;; otherwise they look like this: +;;; +;;; /* Your Favorite +;;; * multi-line comment. +;;; */ +;;; +;;; If the variable c-comment-hanging-indent is non-nil K&R style comments +;;; are indented automatically like this: +;;; +;;; /* my_func - For multi-line comments with hanging indent +;;; * the text is lined up after the dash. +;;; */ +;;; +;;; otherwise the text "the text" (!) is lined up under my_func. If a +;;; comment fits (as typed) on a single line it remains a single line +;;; comment even if c-comment-starting-blank is set. If +;;; c-comment-indenting is non-nil hitting carriage return resets the +;;; indentation for the next line to the current line's indentation +;;; (within the comment) like this: +;;; +;;; /* Typing along merrily.... +;;; * Now I indent with spaces, when I hit return +;;; * the indentation is automatically set to +;;; * ^ here. +;;; */ +;;; +;;; Due to my lack of understanding of keymaps this permanently resets M-q +;;; to my own fill function. I would like to have the comment mode +;;; bindings only in comment mode but I can't seem to get that to work. +;;; If some gnu guru can clue me in, I'd appreciate it. +;;; +(defvar c-comment-starting-blank t + "*Controls whether global comments have an initial blank line.") +(defvar c-comment-indenting t + "*If set global comments are indented to the level of the previous line.") +(defvar c-comment-hanging-indent t + "*If true, comments will be automatically indented to the dash.") +(defvar c-hang-already-done t + "If true we have performed the haning indent already for this comment.") + + +;;; +;;; c-comment-map - This is a sparse keymap for comment mode which +;;; gets inserted when c-comment is called. +;;; +(defvar c-comment-mode-map () + "Keymap used in C comment mode.") +(if c-comment-mode-map + () + (setq c-comment-mode-map (copy-keymap c-mode-map)) + (define-key c-comment-mode-map "\e\r" 'newline) + (define-key c-comment-mode-map "\eq" 'set-fill-and-fill) + (define-key c-comment-mode-map "\r" 'set-fill-and-return)) + +;;; +;;; c-comment - This is a filled comment mode which can format +;;; indented text, do hanging indents, and symetric +;;; placement of comment delimiters. +;;; +(defun c-comment () + "Edit a C comment with filling and indentation. +This performs hanging indentation, symmetric placement of delimiters, + and Indented-Text mode style indentation. Type 'M-x apropos +c-comment' for information on options." + (interactive) + (let + ;; Save old state. + ((auto-fill-function (if c-comment-indenting + 'do-indented-auto-fill 'do-auto-fill)) +; (comment-start nil) + (comment-multi-line t) + (comment-start-skip "/*\\*+[ ]*") + (paragraph-start-ref paragraph-start) + fill-prefix paragraph-start paragraph-separate opoint) + + ;; Determine if we are inside a comment. + (setq in-comment + (save-excursion + (and (re-search-backward "/\\*\\|\\*/" 0 t) + (string= "/*" (buffer-substring (point) (+ (point) 2)))))) + + ;; Indent the comment and set the fill prefix to comment continuation + ;; string. If we are already in a comment get the indentation on + ;; the current line. + (setq c-hang-already-done nil) + + ;; Set the beginning of the comment and insert the blank line if needed. + (use-local-map c-comment-mode-map) + (if (not in-comment) + (progn (c-indent-line) + (insert "/* ") + (setq fill-prefix (get-current-fill (point))) + (recursive-edit) + + ;; If the comment fits on one line, place the close + ;; comment at the end of the line. Otherwise, newline. + (setq opoint (point)) + (if (and (save-excursion (beginning-of-line) + (search-forward "/*" opoint t)) + (<= (+ (current-column) 3) 79)) + (insert " */") + (insert "\n*/")) + + (c-indent-line)) + (progn (setq fill-prefix (get-current-fill (point))) + (recursive-edit) + (search-forward "*/" (buffer-size) t) + (forward-line 1))) + + ;; If starting blank enabled, insert a newline, etc., but only if + ;; this comment requires multiple lines. + (if c-comment-starting-blank + (save-excursion + (setq opoint (point)) + (forward-line -1) + (if (or (null (search-forward "/*" opoint t)) + (null (search-forward "*/" opoint t))) + (progn + (search-backward "/*") + (re-search-forward comment-start-skip opoint t) + (setq fill-prefix (get-current-fill (point))) + (if (not (looking-at "\n")) + (insert ?\n fill-prefix)))))) +; (indent-new-comment-line)))))) + + ;; Move cursor to indentation. + (c-indent-line) + (use-local-map c-mode-map) + ) + ) + + +;;; +;;; set-fill-and-fill - Get the current fill for this line and fill +;;; the paragraph. +;;; +(defun set-fill-and-fill (arg) + "Get the fill-prefix and fill the current paragraph." + + (interactive "P") + (setq fill-prefix (get-current-fill (point))) + (fill-paragraph arg)) + +;;; +;;; set-fill-and-return - Set the current fill prefix and +;;; indent-new-comment-line. +;;; +(defun set-fill-and-return () + "Set the current fill prefix and move to the next line." + + (interactive) + (if c-comment-indenting + (setq fill-prefix (get-current-fill (point)))) + (insert ?\n fill-prefix)) + +;;; +;;; do-indented-auto-fill - Perform the auto-fill function, but get +;;; the fill-prefix first. +;;; +(defun do-indented-auto-fill () + "Perform auto-fill, but get fill-prefix first." + + (let ((opoint (point))) + (save-excursion + (move-to-column (1+ fill-column)) + (skip-chars-backward "^ \t\n") + (if (bolp) + (re-search-forward "[ \t]" opoint t)) + ;; If there is a space on the line before fill-point, + ;; and nonspaces precede it, break the line there. + (if (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + + ;; If we are wrapping to a new line, figure out the indentation on + ;; the current line first. + (progn + (setq fill-prefix (get-current-fill opoint)) + (insert ?\n fill-prefix))))) +; (indent-new-comment-line))))) + ) + + +;;; +;;; get-current-fill - Get the fill-prefix for the current line. This +;;; assumes that the valid fill prefix is between +;;; (beginning-of-line) and (point). +;;; +(defun get-current-fill (pnt) + "Get the current fill prefix. +A valid fill prefix must be between the beginning of the line and point." + + (let ((opoint pnt) fill last-char) + (save-excursion + (beginning-of-line) + (setq fill + (buffer-substring (point) + (progn + (re-search-forward comment-start-skip opoint t) + (point)))) + + ;; Be sure there is trailing white space. + (setq last-char (substring fill (1- (length fill)) (length fill))) + (if (and (not (string= " " last-char)) + (not (string= " " last-char))) + (setq fill (concat fill " "))) + + (setq fill (replace-letter fill "/" " ")) + + ;; Get the hanging indentation if we haven't already. + (if (and c-comment-hanging-indent (not c-hang-already-done)) + (let ((curr (point)) + (opnt (progn (end-of-line) (point)))) + (beginning-of-line) + (if (search-forward " - " opnt t) + (progn + (setq fill (concat fill (make-string (- (point) curr) 32))) + (setq c-hang-already-done t))))) + + ;; Set the paragraph delimiters. + (setq paragraph-start (concat paragraph-start-ref + "\\|^" + (regexp-quote + (substring fill + 0 (1- (length fill)))) + "$")) + (setq paragraph-separate paragraph-start)) + fill) + ) + + +;;; +;;; replace-letter - Given a string, an old letter and a new letter, +;;; perform the substitution. +;;; +(defun replace-letter (str old-letter new-letter) + (let (new-str c + (sp 0) + (size (length str))) + (while (< sp size) + (setq c (substring str sp (1+ sp))) + (setq new-str (concat new-str (if (string= c old-letter) new-letter c))) + (setq sp (1+ sp))) + new-str))