123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- (require 'ede)
- (declare-function ede-locate-file-in-hash "ede/locate")
- (declare-function ede-locate-add-file-to-hash "ede/locate")
- (declare-function ede-locate-file-in-project "ede/locate")
- (declare-function ede-locate-flush-hash "ede/locate")
- (defvar ede--disable-inode nil
- "Set to 't' to simulate systems w/out inode support.")
- (defun ede-find-file (file)
- "Find FILE in project. FILE can be specified without a directory.
- There is no completion at the prompt. FILE is searched for within
- the current EDE project."
- (interactive "sFile: ")
- (let ((fname (ede-expand-filename (ede-current-project) file))
- )
- (unless fname
- (error "Could not find %s in %s"
- file
- (ede-project-root-directory (ede-current-project))))
- (find-file fname)))
- (defun ede-flush-project-hash ()
- "Flush the file locate hash for the current project."
- (interactive)
- (require 'ede/locate)
- (let* ((loc (ede-get-locator-object (ede-current-project))))
- (ede-locate-flush-hash loc)))
- (defmethod ede-project-root ((this ede-project-placeholder))
- "If a project knows its root, return it here.
- Allows for one-project-object-for-a-tree type systems."
- (oref this rootproject))
- (defmethod ede-project-root-directory ((this ede-project-placeholder)
- &optional file)
- "If a project knows its root, return it here.
- Allows for one-project-object-for-a-tree type systems.
- Optional FILE is the file to test. It is ignored in preference
- of the anchor file for the project."
- (file-name-directory (expand-file-name (oref this file))))
- (defmethod ede--project-inode ((proj ede-project-placeholder))
- "Get the inode of the directory project PROJ is in."
- (if (slot-boundp proj 'dirinode)
- (oref proj dirinode)
- (oset proj dirinode (ede--inode-for-dir (oref proj :directory)))))
- (defmethod ede-find-subproject-for-directory ((proj ede-project-placeholder)
- dir)
- "Find a subproject of PROJ that corresponds to DIR."
- (if ede--disable-inode
- (let ((ans nil))
-
- (ede-map-subprojects
- proj
- (lambda (SP)
- (when (not ans)
- (if (string= (file-truename dir) (oref SP :directory))
- (setq ans SP)
- (ede-find-subproject-for-directory SP dir)))))
- ans)
-
- (let ((ans nil)
- (inode (ede--inode-for-dir dir)))
- (ede-map-subprojects
- proj
- (lambda (SP)
- (when (not ans)
- (if (equal (ede--project-inode SP) inode)
- (setq ans SP)
- (ede-find-subproject-for-directory SP dir)))))
- ans)))
- (defvar ede-inode-directory-hash (make-hash-table
-
- :test 'equal)
- "A hash of directory names and inodes.")
- (defun ede--put-inode-dir-hash (dir inode)
- "Add to the EDE project hash DIR associated with INODE."
- (when (fboundp 'puthash)
- (puthash dir inode ede-inode-directory-hash)
- inode))
- (defun ede--get-inode-dir-hash (dir)
- "Get the EDE project hash DIR associated with INODE."
- (when (fboundp 'gethash)
- (gethash dir ede-inode-directory-hash)
- ))
- (defun ede--inode-for-dir (dir)
- "Return the inode for the directory DIR."
- (let ((hashnode (ede--get-inode-dir-hash (expand-file-name dir))))
- (or hashnode
- (if ede--disable-inode
- (ede--put-inode-dir-hash dir 0)
- (let ((fattr (file-attributes dir)))
- (ede--put-inode-dir-hash dir (nth 10 fattr))
- )))))
- (defun ede-directory-get-open-project (dir &optional rootreturn)
- "Return an already open project that is managing DIR.
- Optional ROOTRETURN specifies a symbol to set to the root project.
- If DIR is the root project, then it is the same."
- (let* ((inode (ede--inode-for-dir dir))
- (ft (file-name-as-directory (expand-file-name dir)))
- (proj (ede--inode-get-toplevel-open-project inode))
- (ans nil))
-
- (when (not proj)
- (setq proj (ede-directory-get-toplevel-open-project ft)))
-
- (setq ans proj)
-
- (when rootreturn (set rootreturn proj))
-
- (when (and proj (or ede--disable-inode
- (not (equal inode (ede--project-inode proj)))))
- (setq ans (ede-find-subproject-for-directory proj ft)))
- ans))
- (defun ede--inode-get-toplevel-open-project (inode)
- "Return an already open toplevel project that is managing INODE.
- Does not check subprojects."
- (when (or (and (numberp inode) (/= inode 0))
- (consp inode))
- (let ((all ede-projects)
- (found nil)
- )
- (while (and all (not found))
- (when (equal inode (ede--project-inode (car all)))
- (setq found (car all)))
- (setq all (cdr all)))
- found)))
- (defun ede-directory-get-toplevel-open-project (dir)
- "Return an already open toplevel project that is managing DIR."
- (let ((ft (file-name-as-directory (expand-file-name dir)))
- (all ede-projects)
- (ans nil))
- (while (and all (not ans))
-
- (let ((pd (oref (car all) :directory))
- )
- (cond
-
- ((string= pd ft)
- (setq ans (car all)))
-
- ((string-match (concat "^" (regexp-quote pd)) ft)
- (setq ans (car all)))
-
- ((let ((pin (ede--project-inode (car all)))
- (inode (ede--inode-for-dir dir)))
- (and (not (eql pin 0)) (equal pin inode)))
- (setq ans (car all)))
-
- ((let ((ftn (file-truename ft))
- (ptd (file-truename (oref (car all) :directory))))
- (string-match (concat "^" (regexp-quote ptd)) ftn))
- (setq ans (car all)))
- ))
- (setq all (cdr all)))
- ans))
- (defvar ede-project-directory-hash (make-hash-table
-
- :test 'equal)
- "A hash of directory names and associated EDE objects.")
- (defun ede-project-directory-remove-hash (dir)
- "Reset the directory hash for DIR.
- Do this whenever a new project is created, as opposed to loaded."
-
- (when (fboundp 'remhash)
- (remhash (file-name-as-directory dir) ede-project-directory-hash)
-
- (let ((match (concat "^" (regexp-quote dir))))
- (maphash (lambda (K O)
- (when (string-match match K)
- (remhash K ede-project-directory-hash)))
- ede-project-directory-hash))
- ))
- (defun ede-directory-project-from-hash (dir)
- "If there is an already loaded project for DIR, return it from the hash."
- (when (fboundp 'gethash)
- (gethash dir ede-project-directory-hash nil)))
- (defun ede-directory-project-add-description-to-hash (dir desc)
- "Add to the EDE project hash DIR associated with DESC."
- (when (fboundp 'puthash)
- (puthash dir desc ede-project-directory-hash)
- desc))
- (defun ede-directory-project-p (dir &optional force)
- "Return a project description object if DIR has a project.
- Optional argument FORCE means to ignore a hash-hit of 'nomatch.
- This depends on an up to date `ede-project-class-files' variable.
- Any directory that contains the file .ede-ignore will always
- return nil."
- (when (not (file-exists-p (expand-file-name ".ede-ignore" dir)))
- (let* ((dirtest (expand-file-name dir))
- (match (ede-directory-project-from-hash dirtest)))
- (cond
- ((and (eq match 'nomatch) (not force))
- nil)
- ((and match (not (eq match 'nomatch)))
- match)
- (t
- (let ((types ede-project-class-files)
- (ret nil))
-
- (while (and types (not ret))
- (if (ede-dir-to-projectfile (car types) dirtest)
- (progn
-
- (require (oref (car types) file))
- (setq ret (car types))))
- (setq types (cdr types)))
- (ede-directory-project-add-description-to-hash dirtest (or ret 'nomatch))
- ret))))))
- (defun ede-toplevel-project-or-nil (dir)
- "Starting with DIR, find the toplevel project directory, or return nil.
- nil is returned if the current directory is not a part of a project."
- (let* ((ans (ede-directory-get-toplevel-open-project dir)))
- (if ans
- (oref ans :directory)
- (if (ede-directory-project-p dir)
- (ede-toplevel-project dir)
- nil))))
- (defun ede-toplevel-project (dir)
- "Starting with DIR, find the toplevel project directory."
- (if (and (string= dir default-directory)
- ede-object-root-project)
-
- (oref ede-object-root-project :directory)
-
- (let* ((thisdir (ede-directory-project-p dir))
- (ans (ede-directory-get-toplevel-open-project dir)))
- (if (and ans
- (or (not thisdir)
- (and (object-of-class-p
- ans (oref thisdir :class-sym)))
- ))
- (oref ans :directory)
- (let* ((toppath (expand-file-name dir))
- (newpath toppath)
- (proj (ede-directory-project-p dir))
- (ans nil))
- (if proj
-
- (setq ans (ede-project-root-directory proj)))
-
-
-
-
- (while (and (not ans) newpath proj)
- (setq toppath newpath
- newpath (ede-up-directory toppath))
- (when newpath
- (setq proj (ede-directory-project-p newpath)))
- (when proj
-
- (setq ans (ede-project-root-directory proj)))
- )
- (or ans toppath))))))
- (defmethod ede-convert-path ((this ede-project) path)
- "Convert path in a standard way for a given project.
- Default to making it project relative.
- Argument THIS is the project to convert PATH to."
- (let ((pp (ede-project-root-directory this))
- (fp (expand-file-name path)))
- (if (string-match (regexp-quote pp) fp)
- (substring fp (match-end 0))
- (let ((pptf (file-truename pp))
- (fptf (file-truename fp)))
- (if (string-match (regexp-quote pptf) fptf)
- (substring fptf (match-end 0))
- (error "Cannot convert relativize path %s" fp))))))
- (defmethod ede-convert-path ((this ede-target) path &optional project)
- "Convert path in a standard way for a given project.
- Default to making it project relative.
- Argument THIS is the project to convert PATH to.
- Optional PROJECT is the project that THIS belongs to. Associating
- a target to a project is expensive, so using this can speed things up."
- (let ((proj (or project (ede-target-parent this))))
- (if proj
- (let ((p (ede-convert-path proj path))
- (lp (or (oref this path) "")))
-
-
- (if (string-match (concat "^" (regexp-quote lp)) p)
- (substring p (length lp))
- p))
- (error "Parentless target %s" this))))
- (defun ede-get-locator-object (proj)
- "Get the locator object for project PROJ.
- Get it from the toplevel project. If it doesn't have one, make one."
-
-
- (let ((top (ede-toplevel proj)))
- (when (not (slot-boundp top 'locate-obj))
- (ede-enable-locate-on-project top))
- (oref top locate-obj)
- ))
- (defmethod ede-expand-filename ((this ede-project) filename &optional force)
- "Return a fully qualified file name based on project THIS.
- FILENAME should be just a filename which occurs in a directory controlled
- by this project.
- Optional argument FORCE forces the default filename to be provided even if it
- doesn't exist.
- If FORCE equals 'newfile, then the cache is ignored and a new file in THIS
- is returned."
- (require 'ede/locate)
- (let* ((loc (ede-get-locator-object this))
- (ha (ede-locate-file-in-hash loc filename))
- (ans nil)
- )
-
-
-
-
-
-
-
-
-
- (cond
-
-
- ((and ha (not (eq ha 'nomatch)))
- (setq ans ha))
-
-
-
- ((and (eq ha 'nomatch) (not (eq force 'newfile)))
- nil)
-
-
- (t
- (let ((calc (ede-expand-filename-impl this filename)))
- (if calc
- (progn
- (ede-locate-add-file-to-hash loc filename calc)
- (setq ans calc))
-
-
-
- (when (not force)
- (ede-locate-add-file-to-hash loc filename 'nomatch))))
- ))
-
-
-
- (when (and force (not ans))
- (let ((dir (ede-project-root-directory this)))
- (setq ans (expand-file-name filename dir))))
- ans))
- (defmethod ede-expand-filename-impl ((this ede-project) filename &optional force)
- "Return a fully qualified file name based on project THIS.
- FILENAME should be just a filename which occurs in a directory controlled
- by this project.
- Optional argument FORCE forces the default filename to be provided even if it
- doesn't exist."
- (let ((loc (ede-get-locator-object this))
- (path (ede-project-root-directory this))
- (proj (oref this subproj))
- (found nil))
-
- (setq found (or (ede-expand-filename-local this filename)
- (ede-expand-filename-impl-via-subproj this filename)))
-
- (when (not found)
- (require 'ede/locate)
- (setq found (car (ede-locate-file-in-project loc filename))))
-
- found))
- (defmethod ede-expand-filename-local ((this ede-project) filename)
- "Expand filename locally to project THIS with filesystem tests."
- (let ((path (ede-project-root-directory this)))
- (cond ((file-exists-p (expand-file-name filename path))
- (expand-file-name filename path))
- ((file-exists-p (expand-file-name (concat "include/" filename) path))
- (expand-file-name (concat "include/" filename) path)))))
- (defmethod ede-expand-filename-impl-via-subproj ((this ede-project) filename)
- "Return a fully qualified file name based on project THIS.
- FILENAME should be just a filename which occurs in a directory controlled
- by this project."
- (let ((proj (list (ede-toplevel this)))
- (found nil))
-
- (while (and (not found) proj)
- (let ((thisproj (car proj)))
- (setq proj (append (cdr proj) (oref thisproj subproj)))
- (setq found (when thisproj
- (ede-expand-filename-local thisproj filename)))
- ))
-
- found))
- (defmethod ede-expand-filename ((this ede-target) filename &optional force)
- "Return a fully qualified file name based on target THIS.
- FILENAME should be a filename which occurs in a directory in which THIS works.
- Optional argument FORCE forces the default filename to be provided even if it
- doesn't exist."
- (ede-expand-filename (ede-target-parent this) filename force))
- (defun ede-up-directory (dir)
- "Return a dir that is up one directory.
- Argument DIR is the directory to trim upwards."
- (let* ((fad (directory-file-name dir))
- (fnd (file-name-directory fad)))
- (if (string= dir fnd)
-
- nil
- fnd)))
- (provide 'ede/files)
|