locate.el 11 KB

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