| 1 | ;;; ede/locate.el --- Locate support |
| 2 | |
| 3 | ;; Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: Eric M. Ludlam <eric@siege-engine.com> |
| 6 | |
| 7 | ;; This file is part of GNU Emacs. |
| 8 | |
| 9 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 10 | ;; it under the terms of the GNU General Public License as published by |
| 11 | ;; the Free Software Foundation, either version 3 of the License, or |
| 12 | ;; (at your option) any later version. |
| 13 | |
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | ;; GNU General Public License for more details. |
| 18 | |
| 19 | ;; You should have received a copy of the GNU General Public License |
| 20 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 21 | |
| 22 | ;;; Commentary: |
| 23 | ;; |
| 24 | ;; Support for various LOCATE type functions. |
| 25 | ;; |
| 26 | ;; A key feature of EDE is `ede-expand-filename', which allows a |
| 27 | ;; project to expand a filename reference in one file to some actual |
| 28 | ;; filename. |
| 29 | ;; |
| 30 | ;; In that way, you may #include <foo.h>, and without knowing how to |
| 31 | ;; read a Makefile, find it in <root>/include/foo.h. |
| 32 | ;; |
| 33 | ;; Some projects are regular, such as the Emacs project. Some |
| 34 | ;; projects are completely controlled by EDE, such sh the Project.ede |
| 35 | ;; based projects. |
| 36 | ;; |
| 37 | ;; For other projects, having a "quick hack" to support these location |
| 38 | ;; routines is handy. |
| 39 | ;; |
| 40 | ;; The baseclass `ede-locate-base' provides the abstract interface to |
| 41 | ;; finding files in a project. |
| 42 | ;; |
| 43 | ;; New location routines will subclass `ede-locate-base'. |
| 44 | ;; |
| 45 | ;; How to use: |
| 46 | ;; |
| 47 | ;; Configure `ede-locate-setup-options' to add the types of locate |
| 48 | ;; features you have available. EDE will then enable the correct one |
| 49 | ;; when it is available. |
| 50 | |
| 51 | (require 'ede) |
| 52 | (eval-when-compile (require 'data-debug) |
| 53 | (require 'eieio-datadebug) |
| 54 | (require 'cedet-global) |
| 55 | (require 'cedet-idutils) |
| 56 | (require 'cedet-cscope)) |
| 57 | |
| 58 | (require 'locate) |
| 59 | |
| 60 | ;;; Code: |
| 61 | (defcustom ede-locate-setup-options |
| 62 | '(ede-locate-base) |
| 63 | "List of locate objects to try out by default. |
| 64 | Listed in order of preference. If the first item cannot be used in |
| 65 | a particular project, then the next one is tried. |
| 66 | It is always assumed that `ede-locate-base' is at end of the list." |
| 67 | :group 'ede |
| 68 | :type '(repeat |
| 69 | (choice (const :tag "None" ede-locate-base) |
| 70 | (const :tag "locate" ede-locate-locate) |
| 71 | (const :tag "GNU Global" ede-locate-global) |
| 72 | (const :tag "ID Utils" ede-locate-idutils) |
| 73 | (const :tag "CScope" ede-locate-cscope))) |
| 74 | ) |
| 75 | |
| 76 | ;;;###autoload |
| 77 | (defun ede-enable-locate-on-project (&optional project) |
| 78 | "Enable an EDE locate feature on PROJECT. |
| 79 | Attempt to guess which project locate style to use |
| 80 | based on `ede-locate-setup-options'." |
| 81 | (interactive) |
| 82 | (let* ((proj (or project (ede-toplevel))) |
| 83 | (root (ede-project-root-directory proj)) |
| 84 | (opts ede-locate-setup-options) |
| 85 | (ans nil)) |
| 86 | (while (and opts (not ans)) |
| 87 | (when (ede-locate-ok-in-project (car opts) root) |
| 88 | ;; If interactive, check with the user. |
| 89 | (when (or (not (called-interactively-p 'any)) |
| 90 | (y-or-n-p (format "Set project locator to %s? " (car opts)))) |
| 91 | (setq ans (car opts)))) |
| 92 | (setq opts (cdr opts))) |
| 93 | ;; No match? Always create the baseclass for the hashing tool. |
| 94 | (when (not ans) |
| 95 | (when (called-interactively-p 'interactive) |
| 96 | (message "Setting locator to ede-locate-base")) |
| 97 | (setq ans 'ede-locate-base)) |
| 98 | (oset proj locate-obj (make-instance ans "Loc" :root root)) |
| 99 | (when (called-interactively-p 'interactive) |
| 100 | (message "Setting locator to %s." ans)) |
| 101 | )) |
| 102 | |
| 103 | ;;; LOCATE BASECLASS |
| 104 | ;; |
| 105 | ;; The baseclass for all location style queries. |
| 106 | (defclass ede-locate-base () |
| 107 | ((root :initarg :root |
| 108 | :documentation |
| 109 | "The root of these locat searches.") |
| 110 | (file :documentation |
| 111 | "The last file search for with EDE locate.") |
| 112 | (lastanswer :documentation |
| 113 | "The last answer provided by the locator.") |
| 114 | (hash :documentation |
| 115 | "Hash table of previously found files.") |
| 116 | ) |
| 117 | "Baseclass for LOCATE feature in EDE.") |
| 118 | |
| 119 | (defmethod initialize-instance ((loc ede-locate-base) &rest fields) |
| 120 | "Make sure we have a hash table." |
| 121 | ;; Basic setup. |
| 122 | (call-next-method) |
| 123 | ;; Make sure we have a hash table. |
| 124 | (oset loc hash (make-hash-table :test 'equal)) |
| 125 | ) |
| 126 | |
| 127 | (defmethod ede-locate-ok-in-project :static ((loc ede-locate-base) |
| 128 | root) |
| 129 | "Is it ok to use this project type under ROOT." |
| 130 | t) |
| 131 | |
| 132 | (defmethod ede-locate-file-in-hash ((loc ede-locate-base) |
| 133 | filestring) |
| 134 | "For LOC, is the file FILESTRING in our hashtable?" |
| 135 | (gethash filestring (oref loc hash))) |
| 136 | |
| 137 | (defmethod ede-locate-add-file-to-hash ((loc ede-locate-base) |
| 138 | filestring fullfilename) |
| 139 | "For LOC, add FILESTR to the hash with FULLFILENAME." |
| 140 | (puthash filestring fullfilename (oref loc hash))) |
| 141 | |
| 142 | (defmethod ede-locate-file-in-project ((loc ede-locate-base) |
| 143 | filesubstring |
| 144 | ) |
| 145 | "Locate with LOC occurances of FILESUBSTRING. |
| 146 | Searches are done under the current root of the EDE project |
| 147 | that crated this ede locat object." |
| 148 | (let ((ans (ede-locate-file-in-project-impl loc filesubstring)) |
| 149 | ) |
| 150 | (oset loc file filesubstring) |
| 151 | (oset loc lastanswer ans) |
| 152 | ans)) |
| 153 | |
| 154 | (defmethod ede-locate-file-in-project-impl ((loc ede-locate-base) |
| 155 | filesubstring |
| 156 | ) |
| 157 | "Locate with LOC occurances of FILESUBSTRING. |
| 158 | Searches are done under the current root of the EDE project |
| 159 | that crated this ede locat object." |
| 160 | nil |
| 161 | ) |
| 162 | |
| 163 | ;;; LOCATE |
| 164 | ;; |
| 165 | ;; Using the standard unix "locate" command. |
| 166 | ;; Since locate is system wide, we need to hack the search |
| 167 | ;; to restrict it to within just this project. |
| 168 | |
| 169 | (defclass ede-locate-locate (ede-locate-base) |
| 170 | () |
| 171 | "EDE Locator using the locate command. |
| 172 | Configure the Emacs `locate-program' variable to also |
| 173 | configure the use of EDE locate.") |
| 174 | |
| 175 | (defmethod ede-locate-ok-in-project :static ((loc ede-locate-locate) |
| 176 | root) |
| 177 | "Is it ok to use this project type under ROOT." |
| 178 | (or (featurep 'locate) (locate-library "locate")) |
| 179 | ) |
| 180 | |
| 181 | (defmethod ede-locate-file-in-project-impl ((loc ede-locate-locate) |
| 182 | filesubstring) |
| 183 | "Locate with LOC occurances of FILESUBSTRING under PROJECTROOT. |
| 184 | Searches are done under the current root of the EDE project |
| 185 | that crated this ede locat object." |
| 186 | ;; We want something like: |
| 187 | ;; /my/project/root*/filesubstring.c |
| 188 | (let* ((searchstr (concat (directory-file-name (oref loc root)) |
| 189 | "*/" filesubstring)) |
| 190 | (b (get-buffer-create "*LOCATE*")) |
| 191 | (cd default-directory) |
| 192 | ) |
| 193 | (with-current-buffer b |
| 194 | (setq default-directory cd) |
| 195 | (erase-buffer)) |
| 196 | (apply 'call-process locate-command |
| 197 | nil b nil |
| 198 | searchstr nil) |
| 199 | (with-current-buffer b |
| 200 | (split-string (buffer-string) "\n" t)) |
| 201 | ) |
| 202 | ) |
| 203 | |
| 204 | ;;; GLOBAL |
| 205 | ;; |
| 206 | (defclass ede-locate-global (ede-locate-base) |
| 207 | () |
| 208 | "EDE Locator using GNU Global. |
| 209 | Configure EDE's use of GNU Global through the cedet-global.el |
| 210 | variable `cedet-global-command'.") |
| 211 | |
| 212 | (defmethod initialize-instance ((loc ede-locate-global) |
| 213 | &rest slots) |
| 214 | "Make sure that we can use GNU Global." |
| 215 | (require 'cedet-global) |
| 216 | ;; Get ourselves initialized. |
| 217 | (call-next-method) |
| 218 | ;; Do the checks. |
| 219 | (cedet-gnu-global-version-check) |
| 220 | (let* ((default-directory (oref loc root)) |
| 221 | (root (cedet-gnu-global-root))) |
| 222 | (when (not root) |
| 223 | (error "Cannot use GNU Global in %s" |
| 224 | (oref loc root)))) |
| 225 | ) |
| 226 | |
| 227 | (defmethod ede-locate-ok-in-project :static ((loc ede-locate-global) |
| 228 | root) |
| 229 | "Is it ok to use this project type under ROOT." |
| 230 | (require 'cedet-global) |
| 231 | (cedet-gnu-global-version-check) |
| 232 | (let* ((default-directory root) |
| 233 | (newroot (cedet-gnu-global-root))) |
| 234 | newroot)) |
| 235 | |
| 236 | (defmethod ede-locate-file-in-project-impl ((loc ede-locate-global) |
| 237 | filesubstring) |
| 238 | "Locate with LOC occurances of FILESUBSTRING under PROJECTROOT. |
| 239 | Searches are done under the current root of the EDE project |
| 240 | that crated this ede locat object." |
| 241 | (require 'cedet-global) |
| 242 | (let ((default-directory (oref loc root))) |
| 243 | (cedet-gnu-global-expand-filename filesubstring))) |
| 244 | |
| 245 | ;;; IDUTILS |
| 246 | ;; |
| 247 | (defclass ede-locate-idutils (ede-locate-base) |
| 248 | () |
| 249 | "EDE Locator using IDUtils. |
| 250 | Configure EDE's use of IDUtils through the cedet-idutils.el |
| 251 | file name searching variable `cedet-idutils-file-command'.") |
| 252 | |
| 253 | (defmethod initialize-instance ((loc ede-locate-idutils) |
| 254 | &rest slots) |
| 255 | "Make sure that we can use IDUtils." |
| 256 | ;; Get ourselves initialized. |
| 257 | (call-next-method) |
| 258 | ;; Do the checks. |
| 259 | (require 'cedet-idutils) |
| 260 | (cedet-idutils-version-check) |
| 261 | (when (not (cedet-idutils-support-for-directory (oref loc root))) |
| 262 | (error "Cannot use IDUtils in %s" |
| 263 | (oref loc root))) |
| 264 | ) |
| 265 | |
| 266 | (defmethod ede-locate-ok-in-project :static ((loc ede-locate-idutils) |
| 267 | root) |
| 268 | "Is it ok to use this project type under ROOT." |
| 269 | (require 'cedet-idutils) |
| 270 | (cedet-idutils-version-check) |
| 271 | (when (cedet-idutils-support-for-directory root) |
| 272 | root)) |
| 273 | |
| 274 | (defmethod ede-locate-file-in-project-impl ((loc ede-locate-idutils) |
| 275 | filesubstring) |
| 276 | "Locate with LOC occurances of FILESUBSTRING under PROJECTROOT. |
| 277 | Searches are done under the current root of the EDE project |
| 278 | that crated this ede locat object." |
| 279 | (require 'cedet-idutils) |
| 280 | (let ((default-directory (oref loc root))) |
| 281 | (cedet-idutils-expand-filename filesubstring))) |
| 282 | |
| 283 | ;;; CSCOPE |
| 284 | ;; |
| 285 | (defclass ede-locate-cscope (ede-locate-base) |
| 286 | () |
| 287 | "EDE Locator using Cscope. |
| 288 | Configure EDE's use of Cscope through the cedet-cscope.el |
| 289 | file name searching variable `cedet-cscope-file-command'.") |
| 290 | |
| 291 | (defmethod initialize-instance ((loc ede-locate-cscope) |
| 292 | &rest slots) |
| 293 | "Make sure that we can use Cscope." |
| 294 | ;; Get ourselves initialized. |
| 295 | (call-next-method) |
| 296 | ;; Do the checks. |
| 297 | (cedet-cscope-version-check) |
| 298 | (when (not (cedet-cscope-support-for-directory (oref loc root))) |
| 299 | (error "Cannot use Cscope in %s" |
| 300 | (oref loc root))) |
| 301 | ) |
| 302 | |
| 303 | (defmethod ede-locate-ok-in-project :static ((loc ede-locate-cscope) |
| 304 | root) |
| 305 | "Is it ok to use this project type under ROOT." |
| 306 | (cedet-cscope-version-check) |
| 307 | (when (cedet-cscope-support-for-directory root) |
| 308 | root)) |
| 309 | |
| 310 | (defmethod ede-locate-file-in-project-impl ((loc ede-locate-cscope) |
| 311 | filesubstring) |
| 312 | "Locate with LOC occurances of FILESUBSTRING under PROJECTROOT. |
| 313 | Searches are done under the current root of the EDE project |
| 314 | that crated this ede locat object." |
| 315 | (let ((default-directory (oref loc root))) |
| 316 | (cedet-cscope-expand-filename filesubstring))) |
| 317 | |
| 318 | (provide 'ede/locate) |
| 319 | |
| 320 | ;; Local variables: |
| 321 | ;; generated-autoload-file: "loaddefs.el" |
| 322 | ;; generated-autoload-load-name: "ede/locate" |
| 323 | ;; End: |
| 324 | |
| 325 | ;; arch-tag: a04cb356-d11c-4f69-bd72-5a8a2aff708c |
| 326 | ;;; ede/locate.el ends here |