diff lisp/cedet/ede/autoconf-edit.el @ 104496:8c4870c15962

* cedet/ede.el, cedet/ede/*.el: New files. * cedet/cedet.el: Require ede. * cedet/semantic/symref/filter.el (semantic-symref-hits-in-region): Require semantic/idle.
author Chong Yidong <cyd@stupidchicken.com>
date Sun, 20 Sep 2009 15:06:05 +0000
parents
children 51ba3b848c03
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/cedet/ede/autoconf-edit.el	Sun Sep 20 15:06:05 2009 +0000
@@ -0,0 +1,424 @@
+;;; ede/autoconf-edit.el --- Keymap for autoconf
+
+;;; Copyright (C) 1998, 1999, 2000, 2009 Free Software Foundation, Inc.
+
+;; Author: Eric M. Ludlam <zappo@gnu.org>
+;; Keywords: project
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Autoconf editing and modification support, and compatibility layer
+;; for Emacses w/out autoconf mode built in.
+
+;;; Code:
+(require 'autoconf)
+
+(defvar autoconf-new-automake-string
+  "dnl Process this file with autoconf to produce a configure script
+
+AC_INIT(%s)
+AM_INIT_AUTOMAKE([%s], 0)
+AM_CONFIG_HEADER(config.h)
+
+dnl End the configure script.
+AC_OUTPUT(Makefile, [date > stamp-h] )\n"
+  "This string is used to initialize a new configure.in.
+The default is designed to be used with automake.
+The first %s will be filled with the test file.
+The second %s will be filled with the program name.")
+
+(defun autoconf-new-program (rootdir program testfile)
+  "Initialize a new configure.in in ROOTDIR for PROGRAM using TESTFILE.
+ROOTDIR is the root directory of a given autoconf controlled project.
+PROGRAM is the program to be configured.
+TESTFILE is the file used with AC_INIT.
+configure the initial configure script using `autoconf-new-automake-string'"
+  (interactive "DRoot Dir: \nsProgram: \nsTest File: ")
+  (if (bufferp rootdir)
+      (set-buffer rootdir)
+    (let ((cf1 (expand-file-name "configure.in" rootdir))
+	  (cf2 (expand-file-name "configure.ac" rootdir)))
+      (if (and (or (file-exists-p cf1) (file-exists-p cf2))
+	       (not (y-or-n-p (format "File %s exists.  Start Over? "
+				      (if (file-exists-p cf1)
+					  cf1 cf2)
+				      ))))
+	  (error "Quit"))
+      (find-file cf2)))
+  ;; Note, we only ask about overwrite if a string/path is specified.
+  (erase-buffer)
+  (insert (format autoconf-new-automake-string testfile program)))
+
+(defvar autoconf-preferred-macro-order
+  '("AC_INIT"
+    "AM_INIT_AUTOMAKE"
+    "AM_CONFIG_HEADER"
+    ;; Arg parsing
+    "AC_ARG_ENABLE"
+    "AC_ARG_WITH"
+    ;; Programs
+    "AC_PROG_MAKE_SET"
+    "AC_PROG_AWK"
+    "AC_PROG_CC"
+    "AC_PROG_CC_C_O"
+    "AC_PROG_CPP"
+    "AC_PROG_CXX"
+    "AC_PROG_CXXCPP"
+    "AC_ISC_POSIX"
+    "AC_PROG_F77"
+    "AC_PROG_GCC_TRADITIONAL"
+    "AC_PROG_INSTALL"
+    "AC_PROG_LEX"
+    "AC_PROG_LN_S"
+    "AC_PROG_RANLIB"
+    "AC_PROG_YACC"
+    "AC_CHECK_PROG"
+    "AC_CHECK_PROGS"
+    "AC_PROG_LIBTOOL"
+    ;; Libraries
+    "AC_CHECK_LIB"
+    "AC_PATH_XTRA"
+    ;; Headers
+    "AC_HEADER_STDC"
+    "AC_HEADER_SYS_WAIT"
+    "AC_HEADER_TIME"
+    "AC_HEADERS"
+    ;; Typedefs, structures
+    "AC_TYPE_PID_T"
+    "AC_TYPE_SIGNAL"
+    "AC_TYPE_UID_T"
+    "AC_STRUCT_TM"
+    ;; Compiler characteristics
+    "AC_CHECK_SIZEOF"
+    "AC_C_CONST"
+    ;; Library functions
+    "AC_CHECK_FUNCS"
+    "AC_TRY_LINK"
+    ;; System Services
+    ;; Other
+    "AM_PATH_LISPDIR"
+    "AM_INIT_GUILE_MODULE"
+    ;; AC_OUTPUT is always last
+    "AC_OUTPUT"
+    )
+  "List of macros in the order that they prefer to occur in.
+This helps when inserting a macro which doesn't yet exist
+by positioning it near other macros which may exist.
+From the autoconf manual:
+     `AC_INIT(FILE)'
+     checks for programs
+     checks for libraries
+     checks for header files
+     checks for typedefs
+     checks for structures
+     checks for compiler characteristics
+     checks for library functions
+     checks for system services
+     `AC_OUTPUT([FILE...])'")
+
+(defvar autoconf-multiple-macros
+  '("AC_ARG_ENABLE"
+    "AC_ARG_WITH"
+    "AC_CHECK_PROGS"
+    "AC_CHECK_LIB"
+    "AC_CHECK_SIZEOF"
+    "AC_TRY_LINK"
+    )
+  "Macros which appear multiple times.")
+
+(defvar autoconf-multiple-multiple-macros
+  '("AC_HEADERS" "AC_CHECK_FUNCS")
+  "Macros which appear multiple times, and perform multiple queries.")
+
+(defun autoconf-in-macro (macro)
+  "Non-nil if point is in a macro of type MACRO."
+  (save-excursion
+    (beginning-of-line)
+    (looking-at (concat "\\(A[CM]_" macro "\\|" macro "\\)"))))
+
+(defun autoconf-find-last-macro (macro)
+  "Move to the last occurance of MACRO in FILE, and return that point.
+The last macro is usually the one in which we would like to insert more
+items such as CHECK_HEADERS."
+  (let ((op (point)))
+    (goto-char (point-max))
+    (if (re-search-backward (concat "^" (regexp-quote macro) "\\s-*\\((\\|$\\)") nil t)
+	(progn
+	  (beginning-of-line)
+	  (point))
+      (goto-char op)
+      nil)))
+
+(defun autoconf-parameter-strip (param)
+  "Strip the parameter PARAM  of whitespace and misc characters."
+  (when (string-match "^\\s-*\\[?\\s-*" param)
+    (setq param (substring param (match-end 0))))
+  (when (string-match "\\s-*\\]?\\s-*$" param)
+    (setq param (substring param 0  (match-beginning 0))))
+  param)
+
+(defun autoconf-parameters-for-macro (macro)
+  "Retrieve the parameters to MACRO.
+Returns a list of the arguments passed into MACRO as strings."
+  (save-excursion
+    (when (autoconf-find-last-macro macro)
+      (forward-sexp 1)
+      (mapcar
+       #'autoconf-parameter-strip
+       (when (looking-at "(")
+	 (let* ((start (+ (point) 1))
+		(end (save-excursion
+		       (forward-sexp 1)
+		       (- (point) 1)))
+		(ans (buffer-substring-no-properties start end)))
+	   (split-string ans "," t)))))))
+
+(defun autoconf-position-for-macro (macro)
+  "Position the cursor where a new MACRO could be inserted.
+This will appear at the BEGINNING of the macro MACRO should appear AFTER.
+This is to make it compatible with `autoconf-find-last-macro'.
+Assume that MACRO doesn't appear in the buffer yet, so search
+the ordering list `autoconf-preferred-macro-order'."
+  ;; Search this list backwards.. heh heh heh
+  ;; This lets us do a reverse search easilly.
+  (let ((ml (member macro (reverse autoconf-preferred-macro-order))))
+    (if (not ml) (error "Don't know how to position for %s yet" macro))
+    (setq ml (cdr ml))
+    (goto-char (point-max))
+    (while (and ml (not (autoconf-find-last-macro (car ml))))
+      (setq ml (cdr ml)))
+    (if (not ml) (error "Could not find context for positioning %s" macro))))
+
+(defun autoconf-insert-macro-at-point (macro &optional param)
+  "Add MACRO at the current point with PARAM."
+  (insert macro)
+  (if param
+      (progn
+	(insert "(" param ")")
+	(if (< (current-column) 3) (insert " dnl")))))
+
+(defun autoconf-insert-new-macro (macro &optional param)
+  "Add a call to MACRO in the current autoconf file.
+Deals with macro order.  See `autoconf-preferred-macro-order' and
+`autoconf-multi-macros'.
+Optional argument PARAM is the parameter to pass to the macro as one string."
+  (cond ((member macro autoconf-multiple-macros)
+	 ;; This occurs multiple times
+	 (or (autoconf-find-last-macro macro)
+	     (autoconf-position-for-macro macro))
+	 (forward-sexp 2)
+	 (end-of-line)
+	 (insert "\n")
+	 (autoconf-insert-macro-at-point macro param))
+	((member macro autoconf-multiple-multiple-macros)
+	 (if (not param)
+	     (error "You must have a paramter for %s" macro))
+	 (if (not (autoconf-find-last-macro macro))
+	     (progn
+	       ;; Doesn't exist yet....
+	       (autoconf-position-for-macro macro)
+	       (forward-sexp 2)
+	       (end-of-line)
+	       (insert "\n")
+	       (autoconf-insert-macro-at-point macro param))
+	   ;; Does exist, can we fit onto the current line?
+	   (forward-sexp 2)
+	   (down-list -1)
+	   (if (> (+ (current-column) (length param))  fill-column)
+	       (insert " " param)
+	     (up-list 1)
+	     (end-of-line)
+	     (insert "\n")
+	     (autoconf-insert-macro-at-point macro param))))
+	((autoconf-find-last-macro macro)
+	 ;; If it isn't one of the multi's, it's a singleton.
+	 ;; If it exists, ignore it.
+	 nil)
+	(t
+	 (autoconf-position-for-macro macro)
+	 (forward-sexp 1)
+	 (if (looking-at "\\s-*(")
+	     (forward-sexp 1))
+	 (end-of-line)
+	 (insert "\n")
+	 (autoconf-insert-macro-at-point macro param))))
+
+(defun autoconf-find-query-for-header (header)
+  "Position the cursor where HEADER is queried."
+  (interactive "sHeader: ")
+  (let ((op (point))
+	(found t))
+    (goto-char (point-min))
+    (condition-case nil
+	(while (not
+		(progn
+		  (re-search-forward
+		   (concat "\\b" (regexp-quote header) "\\b"))
+		  (save-excursion
+		    (beginning-of-line)
+		    (looking-at "AC_CHECK_HEADERS")))))
+      ;; We depend on the search failing to exit our loop on failure.
+      (error (setq found nil)))
+    (if (not found) (goto-char op))
+    found))
+
+(defun autoconf-add-query-for-header (header)
+  "Add in HEADER to be queried for in our autoconf file."
+  (interactive "sHeader: ")
+  (or (autoconf-find-query-for-header header)
+      (autoconf-insert-new-macro "AC_CHECK_HEADERS" header)))
+
+
+(defun autoconf-find-query-for-func (func)
+  "Position the cursor where FUNC is queried."
+  (interactive "sFunction: ")
+  (let ((op (point))
+	(found t))
+    (goto-char (point-min))
+    (condition-case nil
+	(while (not
+		(progn
+		  (re-search-forward
+		   (concat "\\b" (regexp-quote func) "\\b"))
+		  (save-excursion
+		    (beginning-of-line)
+		    (looking-at "AC_CHECK_FUNCS")))))
+      ;; We depend on the search failing to exit our loop on failure.
+      (error (setq found nil)))
+    (if (not found) (goto-char op))
+    found))
+
+(defun autoconf-add-query-for-func (func)
+  "Add in FUNC to be queried for in our autoconf file."
+  (interactive "sFunction: ")
+  (or (autoconf-find-query-for-func func)
+      (autoconf-insert-new-macro "AC_CHECK_FUNCS" func)))
+
+(defvar autoconf-program-builtin
+  '(("AWK" . "AC_PROG_AWK")
+    ("CC" . "AC_PROG_CC")
+    ("CPP" . "AC_PROG_CPP")
+    ("CXX" . "AC_PROG_CXX")
+    ("CXXCPP" . "AC_PROG_CXXCPP")
+    ("F77" . "AC_PROG_F77")
+    ("GCC_TRADITIONAL" . "AC_PROG_GCC_TRADITIONAL")
+    ("INSTALL" . "AC_PROG_INSTALL")
+    ("LEX" . "AC_PROG_LEX")
+    ("LN_S" . "AC_PROG_LN_S")
+    ("RANLIB" . "AC_PROG_RANLIB")
+    ("YACC" . "AC_PROG_YACC")
+    )
+  "Association list of PROGRAM variables and their built-in MACRO.")
+
+(defun autoconf-find-query-for-program (prog)
+  "Position the cursor where PROG is queried.
+PROG is the VARIABLE to use in autoconf to identify the program.
+PROG excludes the _PROG suffix.  Thus if PROG were EMACS, then the
+variable in configure.in would be EMACS_PROG."
+  (let ((op (point))
+	(found t)
+	(builtin (assoc prog autoconf-program-builtin)))
+    (goto-char (point-min))
+    (condition-case nil
+	(re-search-forward
+	 (concat "^"
+		 (or (cdr-safe builtin)
+		     (concat "AC_CHECK_PROG\\s-*(\\s-*" prog "_PROG"))
+		 "\\>"))
+      (error (setq found nil)))
+    (if (not found) (goto-char op))
+    found))
+
+(defun autoconf-add-query-for-program (prog &optional names)
+  "Add in PROG to be queried for in our autoconf file.
+Optional NAMES is for non-built-in programs, and is the list
+of possible names."
+  (interactive "sProgram: ")
+  (if (autoconf-find-query-for-program prog)
+      nil
+    (let ((builtin (assoc prog autoconf-program-builtin)))
+      (if builtin
+	  (autoconf-insert-new-macro (cdr builtin))
+	;; Not built in, try the params item
+	(autoconf-insert-new-macro "AC_CHECK_PROGS" (concat prog "," names))
+	))))
+
+;;; Scrappy little changes
+;;
+(defvar autoconf-deleted-text nil
+  "Set to the last bit of text deleted during an edit.")
+
+(defvar autoconf-inserted-text nil
+  "Set to the last bit of text inserted during an edit.")
+
+(defmacro autoconf-edit-cycle (&rest body)
+  "Start an edit cycle, unsetting the modified flag if there is no change.
+Optional argument BODY is the code to execute which edits the autoconf file."
+  `(let ((autoconf-deleted-text nil)
+	 (autoconf-inserted-text nil)
+	 (mod (buffer-modified-p)))
+     ,@body
+     (if (and (not mod)
+	      (string= autoconf-deleted-text autoconf-inserted-text))
+	 (set-buffer-modified-p nil))))
+
+(defun autoconf-delete-parameter (index)
+  "Delete the INDEXth parameter from the macro starting on the current line.
+Leaves the cursor where a new parameter can be inserted.
+INDEX starts at 1."
+  (beginning-of-line)
+  (down-list 1)
+  (re-search-forward ", ?" nil nil (1- index))
+  (let ((end (save-excursion
+	       (re-search-forward ",\\|)" (save-excursion
+					    (end-of-line)
+					    (point)))
+	       (forward-char -1)
+	       (point))))
+    (setq autoconf-deleted-text (buffer-substring (point) end))
+    (delete-region (point) end)))
+
+(defun autoconf-insert (text)
+  "Insert TEXT."
+  (setq autoconf-inserted-text text)
+  (insert text))
+
+(defun autoconf-set-version (version)
+  "Set the version used with automake to VERSION."
+  (if (not (stringp version))
+      (signal 'wrong-type-argument '(stringp version)))
+  (if (not (autoconf-find-last-macro "AM_INIT_AUTOMAKE"))
+      (error "Cannot update version")
+    ;; Move to correct position.
+    (autoconf-edit-cycle
+     (autoconf-delete-parameter 2)
+     (autoconf-insert version))))
+
+(defun autoconf-set-output (outputlist)
+  "Set the files created in AC_OUTPUT to OUTPUTLIST.
+OUTPUTLIST is a list of strings representing relative paths
+to Makefiles, or other files using Autoconf substitution."
+  (if (not (autoconf-find-last-macro "AC_OUTPUT"))
+      (error "Cannot update version")
+    (autoconf-edit-cycle
+     (autoconf-delete-parameter 1)
+     (autoconf-insert (mapconcat (lambda (a) a) outputlist " ")))))
+
+(provide 'ede/autoconf-edit)
+
+;;; ede/autoconf-edit.el ends here