Warning, /sdk/kde-dev-scripts/kde-emacs/sourcepair.el is written in an unsupported language. File is not indexed.
0001 ;; sourcepair.el --- Load the corresponding C/C++ header or source file for the current buffer.
0002 ;;
0003 ;; Copyright (C) 2007 Mohamed Hendawi
0004 ;;
0005 ;; Emacs Lisp Archive Entry
0006 ;; Filename: sourcepair.el
0007 ;; Version: 1.01
0008 ;; Keywords: c languages oop
0009 ;; Author: Mohamed Hendawi <moedev *AT* hendawi *DOT* com>
0010 ;; Description: Load the corresponding C/C++ header or source file for the current buffer.
0011 ;; URL: http://www.hendawi.com/emacs/sourcepair.el
0012 ;; Compatibility: Emacs20, Emacs21
0013 ;;
0014 ;; $Id: sourcepair.el,v 1.15 2007/10/22 11:41:24 moe Exp $
0015 ;;
0016 ;; This program is free software; you can redistribute it and/or
0017 ;; modify it under the terms of the GNU General Public License as
0018 ;; published by the Free Software Foundation; either version 2 of
0019 ;; the License, or (at your option) any later version.
0020 ;;
0021 ;; This program is distributed in the hope that it will be useful,
0022 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
0023 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0024 ;; GNU General Public License for more details.
0025 ;;
0026 ;; You should have received a copy of the GNU General Public
0027 ;; License along with this program; if not, write to the Free
0028 ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
0029 ;; MA 02110-1301 USA
0030 ;;
0031 ;; This code is inspired by a similar function written by Abiyu Diro.
0032 ;; Thanks to Jesper Pedersen for idea and initial implementation of
0033 ;; support for private header files.
0034 ;;
0035 ;;; Commentary:
0036 ;;
0037 ;; This Emacs lisp file provides the function "sourcepair-load" which will load
0038 ;; the corresponding header or source file for the current buffer. For example,
0039 ;; if you are looking at the file FooParser.cpp and enter M-x sourcepair-load
0040 ;; (or whatever keybinding you've set), the file FooParser.h will be loaded.
0041 ;; It also works the other way as well. To use it put this file somewhere
0042 ;; in your lisp library path and then add something like this to your .emacs
0043 ;; file:
0044 ;;
0045 ;; (load-file "sourcepair.el")
0046 ;;
0047 ;; KEYBINDINGS:
0048 ;;
0049 ;; You should set a keybinding to use this function easily. For example, I add
0050 ;; the following to my .emacs file:
0051 ;;
0052 ;; (define-key global-map "\C-xz" 'sourcepair-load)
0053 ;;
0054 ;;
0055 ;; GLOBAL VARIABLES:
0056 ;;
0057 ;; There are six global variables that can be used to adjust how the function
0058 ;; works:
0059 ;;
0060 ;; sourcepair-source-extensions :
0061 ;;
0062 ;; A list containing the recognized extensions for source files. By default
0063 ;; this is set to ( ".cpp" ".cxx" ".cc" ".c" ). For example: with the default
0064 ;; setting if you are looking at "foo.h", the function will look for
0065 ;; "foo.cpp", "foo.cxx", "foo.cc" or "foo.c" in that order in the
0066 ;; directories specified by sourcepair-source-path.
0067 ;;
0068 ;; sourcepair-header-extensions :
0069 ;;
0070 ;; A list containing the recognized extensions for header files. By default
0071 ;; this is set to ( ".h" ".hpp" ".hh" ). For example: with the default
0072 ;; setting if you are looking at "foo.cpp", the function will look for
0073 ;; "foo.h", "foo.hpp" or "foo.hh" in that order in the directories specified
0074 ;; by sourcepair-header-path.
0075 ;;
0076 ;; sourcepair-source-path :
0077 ;;
0078 ;; A list containing the path's to search for source files. By default this
0079 ;; is set to ( "." ) which means source files will only be searched for in
0080 ;; the current directory. Paths that end in "/*" will be searched
0081 ;; recursively. For example, if you specified sourcepair-source-path as
0082 ;; ( "." "../*" ) the function will look for source files first in the
0083 ;; current directory, and then in the parent directory, and then in any
0084 ;; subdirectories of the parent directory.
0085 ;;
0086 ;; sourcepair-header-path :
0087 ;;
0088 ;; Similar to sourcepair-source-path except for header files.
0089 ;;
0090 ;; sourcepair-recurse-ignore :
0091 ;;
0092 ;; A list containing directories to ignore when recursively searching
0093 ;; subdirectories for header or source files. By default this is set
0094 ;; to ( "CVS" )
0095 ;;
0096 ;; sourcepair-private-header-suffixes :
0097 ;;
0098 ;; A list containing suffixes that will be ignored when searching
0099 ;; for the corresponding source file for a given header file. This
0100 ;; allows supporting "private header files". For example, Foo.cpp
0101 ;; has a public interface in "Foo.h" and a private interface in
0102 ;; "Foo_p.h". By default this is set to ( "_p" "_impl" ).
0103 ;;
0104 ;; For example, in my .emacs file I have the following:
0105 ;;
0106 ;; (setq sourcepair-source-path '( "." "../*" ))
0107 ;; (setq sourcepair-header-path '( "." "include" "../include" "../*"))
0108 ;; (setq sourcepair-recurse-ignore '( "CVS" "Obj" "Debug" "Release" ))
0109
0110 ;;; Code:
0111
0112 (defcustom sourcepair-source-extensions '( ".cpp" ".CPP" ".Cpp" ".cxx" ".CXX" ".cc" ".CC" ".c" ".C" ".c++" ".C++")
0113 "*List of recognized extensions for source files.
0114
0115 This variable is used by `sourcepair-load'. The value should be a list
0116 containing the recognized extensions for source files. For example: if the
0117 value is ( \".cpp\" \".cxx\" \".cc\" \".C\" \".c\" ), and you are looking at
0118 \"foo.h\", `sourcepair-load' will look for \"foo.cpp\", \"foo.cxx\",
0119 \"foo.cc\" or \"foo.c\" in that order in the directories specified by
0120 `sourcepair-source-path'."
0121 :type '(repeat string)
0122 :group 'sourcepair)
0123
0124 (defcustom sourcepair-header-extensions '( ".h" ".H" ".hpp" ".HPP" ".Hpp" ".hh" ".HH" ".hxx" ".HXX")
0125 "*List of recognized extensions for header files.
0126
0127 This variable is used by `sourcepair-load'. The value should be a list
0128 containing the recognized extensions for header files. For example: if the
0129 value is (\".h\" \".hpp\" \".hh\" ), and you are looking at \"foo.cpp\",
0130 `sourcepair-load' will look for \"foo.h\", \"foo.hpp\" or \"foo.hh\" in that
0131 order in the directories specified by `sourcepair-header-path'."
0132 :type '(repeat string)
0133 :group 'sourcepair)
0134
0135 (defcustom sourcepair-private-header-suffixes '( "_p" "_impl" )
0136 "*List of recognized suffixes for 'private' header files.
0137
0138 This variable is used by `sourcepair-load' to help support 'private header
0139 files'. The value should be a list containing recognized suffixes that will
0140 be ignored when searching for the corresponding source file for a given
0141 header file. For example, Foo.cpp is an implementation of what is in
0142 Foo_p.h. If you set this variable to include (\"_p\") and you are looking
0143 at \"Foo_p.h\" or \"Foo.h\", `sourcepair-load' will load the file \"Foo.cpp\".
0144
0145 "
0146 :type '(repeat-string)
0147 :group 'sourcepair)
0148
0149 (defcustom sourcepair-source-path '( "." )
0150 "*List of directories to search for corresponding source file.
0151
0152 This variable is used by `sourcepair-load'. The value should be a list
0153 containing the directories to search for source files. By default this is set
0154 to ( \".\" ) which means source files will only be searched for in the current
0155 directory. Paths that end in \"/*\" will be searched recursively. For
0156 example, if you specified `sourcepair-source-path' as ( \".\" \"../*\" )
0157 `sourcepair-load' will look for source files first in the current directory,
0158 and then in the parent directory, and then in any subdirectories of the parent
0159 directory."
0160 :type '(repeat string)
0161 :group 'sourcepair)
0162
0163 (defcustom sourcepair-header-path '( "." )
0164 "*List of directories to search for corresponding header file.
0165
0166 This is similar to `sourcepair-source-path' except for header files. See the
0167 documentation for `sourcepair-source-path' for more info."
0168 :type '(repeat string)
0169 :group 'sourcepair)
0170
0171 (defcustom sourcepair-recurse-ignore '( "CVS" )
0172 "*List of directories to ignore when recursively searching subdirectories.
0173
0174 This variable is used by `sourcepair-load'. The value should be a list
0175 containing the names of directories to ignore when `sourcepair-load' is
0176 recursively searching subdirectories for header or source files. By default
0177 this is set to ( \"CVS\" )"
0178 :type '(repeat string)
0179 :group 'sourcepair)
0180
0181 (defun sourcepair-header-file-p (filename)
0182 "Return t if argument is a C/C++ header file, nil otherwise
0183
0184 This function returns t if the filename specified is a C/C++ header
0185 file, or nil otherwise. Header files are identified by extension via
0186 the variable `sourcepair-header-extensions'."
0187
0188 (let* ((extension (concat (member ?. (append filename nil))))
0189 (basename (substring filename 0 (- 0 (length extension)))))
0190 (if (member extension sourcepair-header-extensions)
0191 t
0192 nil)))
0193
0194
0195 (defun sourcepair-source-file-p (filename)
0196 "Return t if argument is a C/C++ source file, nil otherwise
0197
0198 This function returns t if the filename specified is a C/C++ source file,
0199 or nil otherwise. Source files are identified by extension via the
0200 variable `sourcepair-source-extensions'."
0201
0202 (let* ((extension (concat (member ?. (append filename nil))))
0203 (basename (substring filename 0 (- 0 (length extension)))))
0204 (if (member extension sourcepair-source-extensions)
0205 t
0206 nil)))
0207
0208
0209 (defun sourcepair-remove-private-suffixes (basename)
0210 (car (delete 'nil (append (mapcar '(lambda (suffix)
0211 (if (string= (substring basename (- (length basename) (length suffix))) suffix)
0212 (substring basename 0 (- (length basename) (length suffix)))))
0213 sourcepair-private-header-suffixes)
0214 (list basename)))))
0215
0216 (defun sourcepair-analyze-filename (filename)
0217 (let* ((extension (concat (member ?. (append filename nil))))
0218 (basename (substring filename 0 (- 0 (length extension)))))
0219
0220 (if (member extension sourcepair-header-extensions)
0221 (progn (setq basename (sourcepair-remove-private-suffixes basename))
0222 (cons sourcepair-source-path (mapcar '(lambda (arg) (concat basename arg)) sourcepair-source-extensions)))
0223 (if (member extension sourcepair-source-extensions)
0224 (cons sourcepair-header-path
0225 (apply 'append
0226 (mapcar '(lambda (suffix) (mapcar '(lambda (ext) (concat basename suffix ext)) sourcepair-header-extensions))
0227 (append '("") sourcepair-private-header-suffixes))))))))
0228
0229 (defun sourcepair-find-one-of (path choices recurse)
0230 (catch 'matching-filename
0231 (if (file-directory-p path)
0232 (let ((possible-filenames choices)
0233 (matching-filename nil)
0234 (files-in-directory nil))
0235
0236 ;; Check if there's a match in this directory
0237 (while possible-filenames
0238 (let ((possible-filename (expand-file-name (car possible-filenames) path)))
0239 (if (file-exists-p possible-filename)
0240 (throw 'matching-filename possible-filename)
0241 (setq possible-filenames (cdr possible-filenames)))))
0242
0243 ;; Recursively search subdirectories
0244 (if (not (eq recurse nil))
0245 (progn
0246 (setq files-in-directory (directory-files path nil "^[^\\.]"))
0247 (while files-in-directory
0248 (let ((possible-subdir (car files-in-directory)))
0249 (if (not (member possible-subdir sourcepair-recurse-ignore))
0250 (progn
0251 (setq possible-subdir (expand-file-name possible-subdir path))
0252 (if (file-directory-p possible-subdir)
0253 (progn
0254 (message "Checking %s" possible-subdir)
0255 (setq matching-filename
0256 (sourcepair-find-one-of possible-subdir choices t))
0257 (if (not (eq matching-filename nil))
0258 (throw 'matching-filename matching-filename))))))
0259 (setq files-in-directory (cdr files-in-directory))))))))
0260 ;; Return nil if nothing found
0261 nil))
0262
0263 (defun sourcepair-matching-file-for-file (filename)
0264 (catch 'found-matching-file
0265 (let* ((temp (sourcepair-analyze-filename (file-name-nondirectory filename)))
0266 (search-path (car temp))
0267 (possible-filenames (cdr temp)))
0268 (if (= (length possible-filenames) 0)
0269 (message "%s is not a recognized source or header file (consider updating sourcepair-source-extensions or sourcepair-header-extensions)" (buffer-name))
0270 (progn
0271 (while search-path
0272 (let ((path-to-check (car search-path))
0273 (matching-filename nil))
0274 (if (and (> (length path-to-check) 3)
0275 (equal (substring path-to-check -2) "/*"))
0276 (setq matching-filename (sourcepair-find-one-of (substring path-to-check 0 -2)
0277 possible-filenames
0278 t))
0279 (setq matching-filename
0280 (sourcepair-find-one-of path-to-check possible-filenames nil)))
0281
0282 (if (eq matching-filename nil)
0283 (setq search-path (cdr search-path))
0284 (throw 'found-matching-file matching-filename))))
0285
0286 nil)))))
0287
0288 (defun sourcepair-load ()
0289 "Load the corresponding C/C++ header or source file for the current buffer.
0290
0291 This function can be invoked by \\[sourcepair-load]. It will load the the
0292 corresponding header or source file for the current buffer. For example, if
0293 you are looking at the file FooParser.cpp and press \\[sourcepair-load], the
0294 file FooParser.h will be loaded. It also works the other way as well.
0295
0296 There are six global variables that can be used to adjust how the function
0297 works:
0298
0299 `sourcepair-source-extensions'
0300 `sourcepair-header-extensions'
0301 `sourcepair-source-path'
0302 `sourcepair-header-path'
0303 `sourcepair-recurse-ignore'
0304 `sourcepair-private-header-suffixes'
0305
0306 See the documentation for these variables for more info.
0307 "
0308
0309 (interactive)
0310
0311 (let ((file (sourcepair-matching-file-for-file (buffer-file-name))))
0312 (if file
0313 (find-file file)
0314 (message (concat "No matching file for " (buffer-name)
0315 " (consider updating sourcepair-source-path, sourcepair-header-path)")))))
0316
0317 (defun sourcepair-jump-to-headerfile (prefix)
0318 "Jump to header file for class at point"
0319 (interactive "P")
0320 (save-excursion
0321 (let* ((word-at-point (if prefix
0322 (read-from-minibuffer "Class: ")
0323 (current-word)))
0324 (file1 (sourcepair-matching-file-for-file (concat word-at-point ".cpp" )))
0325 (file (if file1 file1 (sourcepair-matching-file-for-file (concat (downcase word-at-point) ".cpp" )))))
0326 (if file
0327 (find-file file)
0328 (message "Sorry couldn't find include file for class")))))
0329
0330 (defun sourcepair-yank-advice ()
0331 "Advice function called after a yank.
0332
0333 This function is called when advising the yank function. If you are
0334 looking at a header file and paste a method declaration that was copied
0335 from a source file, this function will remove the class prefix (e.g.
0336 \"Foo::\"), add a semicolon at the end of the declaration and reindent the
0337 region. If you paste something other than a method declaration this
0338 function will just reindent the region.
0339 "
0340 (if (member major-mode '(c-mode c++-mode))
0341 (if (sourcepair-header-file-p (buffer-name))
0342 (let* ((this-buffer-name (buffer-name))
0343 (extension (concat (member ?. (append this-buffer-name nil))))
0344 (basename (substring this-buffer-name 0 (- 0 (length extension))))
0345 (class-prefix (concat basename "::"))
0346 (begin-point (region-beginning))
0347 (end-point (region-end))
0348 (region-len (- end-point begin-point)))
0349 (save-excursion
0350 (set-window-point nil (- (point) region-len))
0351 (if (re-search-forward class-prefix end-point t)
0352 (progn
0353 (replace-match "" nil t)
0354 (set-window-point nil (- end-point (length class-prefix) 1))
0355 (re-search-backward "[^ ]")
0356 (set-window-point nil (+ (point) 1))
0357 (insert ";")
0358 (indent-region (region-beginning) (region-end) nil)
0359 (message "Removed class prefix when pasting"))
0360 (indent-region begin-point end-point nil))))
0361 (indent-region (region-beginning) (region-end) nil))))
0362
0363 ; This allows (require 'sourcepair)
0364 (provide 'sourcepair)
0365
0366 ;;; sourcepair.el ends here
0367