[gnu.emacs] Several questions

wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (10/22/88)

In article <670@pcsbst.UUCP> pcsbst!jkh@pcsbst.UUCP (Jordan K. Hubbard) writes:
>Has anyone written a reasonably intelligent C beautifier in elisp?
>I'm talking about something that has some knowledge of C expressions
>and operators and tries to do things like multi-expression lines into
>single lines [...] and proper spacing of operators (I.E. A[0]=f*(g-1)
>becomes A[0] = f * (g - 1)

Here is a function "M-x cindent" that should do the trick.  Basically
it calls Unix indent(1) on the buffer's file.  (I can't remember if
indent is included in System V(anilla), but if not, you might check to
see if Berkeley has released it into Generally-Useful-Domain yet.  I
have heard mumblings that lots of good code is being sprung free.)

-wolfgang

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;									     ;;
;;	File:     unix.el						     ;;
;;	Author:   Wolfgang Rupprecht					     ;;
;;	Created:  Wed Jan 20 12:24:16 EST 1988				     ;;
;;	Contents: some useful unix interface routines for gnueamcs           ;;
;;									     ;;
;;	Copyright (c) 1988 Wolfgang Rupprecht.				     ;;
;;									     ;;
;;	$Log$								     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Copyright (c) 1988 Wolfgang Rupprecht

;; GNU Emacs and this file unix.el, are distributed in the hope
;; that they will be useful, but WITHOUT ANY WARRANTY.  No author or
;; distributor accepts responsibility to anyone for the consequences of
;; using them or for whether they serve any particular purpose or work at
;; all, unless he says so in writing.  Refer to the GNU Emacs General
;; Public License for full details.

;; Everyone is granted permission to copy, modify and redistribute GNU
;; Emacs and unix.el, but only under the conditions described in the
;; GNU Emacs General Public License.  A copy of this license is supposed
;; to have been given to you along with GNU Emacs so you can know your
;; rights and responsibilities.  It should be in a file named COPYING.
;; Among other things, the copyright notice and this notice must be
;; preserved on all copies.

(autoload 'compile1 "compile")

(defun lint (buffer)
  "Run lint(1) on specified buffer and collect output in a buffer.
While lint runs asynchronously, you can use the \\[next-error] command
to find the text that lint gripes refer to."
  (interactive "bbuffer to lint ")
  (save-excursion
    (switch-to-buffer buffer t)
    (save-buffer buffer)
    (compile1 (concat lint-command " " buffer-file-name)
	      "No more lint gripes" "lint")))

(defvar lint-command "lint -abchx"
  "The command and command-line switches that are passed to the shell
when lint-ing a buffer via the lint-buffer command.")

(defun cindent (buffer)
  "Reformat the specified BUFFER using the Unix indent(1) program.
Selects the specified buffer, and saves it to disk, displays new version.
M-x revert-buffer and M-x undo work as expected. User may opt not to save
the newly indented buffer."
  (interactive "bbuffer to indent ")
  (switch-to-buffer buffer)
  (let ((auto-save-file-name (make-auto-save-file-name))
	(opoint (point))
	;; /bin/csh doesn't work for the following line due to '#' beeing a 
	;; comment-start char. 'indent /tmp/foo.c /tmp/#foo.c#'
	;; best just to use the /bin/sh as the shell.
	(shell-file-name "/bin/sh"))	; shell-command uses shell-file-name
    (save-buffer)
    (shell-command  (concat cindent-command
			    " " buffer-file-name
			    " " auto-save-file-name) nil)
    (if (file-exists-p auto-save-file-name)
	(progn
	  (erase-buffer)
	  (insert-file auto-save-file-name)
	  (goto-char (min opoint (point-max))))
      (error "indent failed to produce the output file"))))

(defvar cindent-command "indent -l80 -bl -bc -v"
  "The command and command-line switches that are passed to the shell when
indenting a buffer via cindent-buffer.")

(defun diff (buf &optional nocontext) 
"Take the diff(1) of a BUFFER and its oldest backup file. With prefix
arg, (or optional flag if noninteractive) does an normal non-context
diff. This option is required for \\[show-diff]."
  (interactive "bBuffer: \nP")
  (switch-to-buffer buf)
  (let*
      ((file-base-name (file-name-nondirectory buffer-file-name))
       (back-list
	 (file-name-all-completions file-base-name default-directory))
       (back-name (oldest-file back-list)))
    (if (string-equal back-name file-base-name)
	(message "No older backup of %s found." file-base-name)
      (compile1 (format "diff %s %s %s"
			(if nocontext "-r" "-c")
			back-name file-base-name)
		"Use show-diff to move to diffs"
		"diff"))))

(defun oldest-file (list)
  "Return the oldest file, from the LIST of files."
  (let ((oldest (car list)))
    (if list (setq list (cdr list)))
    (while list
      (if (file-newer-than-file-p oldest (car list))
	  (setq oldest (car list)))
      (setq list (cdr list)))
    oldest))

(defun grep (command)
  "Run grep, with user-specified args, and collect output in a buffer.
While grep runs asynchronously, you can use the \\[next-error] command
to find the text that grep hits refer to."
  (interactive (list (read-input "Run grep (with args): "
				 (concat (symbol-around-point) " "
					 (other-possibly-interesting-files)))))
  (compile1 (concat "grep -n " command " /dev/null")
	    "No more grep hits" "grep"))

(defun gid (command)
  "Run gid, with user-specified args, and collect output in a buffer.
While gid runs asynchronously, you can use the \\[next-error] command
to find the text that gid hits refer to.  Gid is Greg Mcgary's
pre-digested-grep program, like ctags, but for grep."
  (interactive (list (read-input "Run gid (with args): "
				 (symbol-around-point))))
  (compile1 (concat "gid " command)
	    "No more gid hits" "gid"))

(defun other-possibly-interesting-files ()
  "Return a sh-regexp for other files that may be of interest for
the purpose of grep-ing."
  (if (equal major-mode 'c-mode)
      "*.h *.c"				;for .h and .c files
    (concat "*" 
	    (if buffer-file-name
		(let ((basename (file-name-sans-versions
				 (file-name-nondirectory buffer-file-name))))
		  (if (string-match "[^.]\\(\\.[^.]+\\)$" basename)
		      (substring basename
				 (match-beginning 1) (match-end 1)))
		  )))))

(defun word-around-point ()
  "Return the word around the point as a string."
  (save-excursion
    (let (beg)
      (if (not (looking-at "\\<"))
	  (forward-word -1))
      (setq beg (point))
      (forward-word 1)
      (buffer-substring beg (point)))))

(defun symbol-around-point ()
  "Return the symbol around the point as a string."
  (save-excursion
    (if (not (looking-at "\\s_\\|\\sw")) ; if not in a symbol
	(re-search-backward "\\s_\\|\\sw" nil t)) ; go into prev. one
    (buffer-substring
      (progn (forward-sexp 1) (point))
      (progn (backward-sexp 1) (point)))))


Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
TEL: (617) 267-4365	UUCP:  mit-eddie!mgm.mit.edu!wolfgang