The Wayback Machine - https://web.archive.org/web/20201120031715/https://github.com/bbatsov/projectile/issues/1596
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

projectile-find-dir returns only terminal directories, not all directories in a project #1596

Open
zeus-hammer opened this issue Nov 6, 2020 · 3 comments

Comments

@zeus-hammer
Copy link

@zeus-hammer zeus-hammer commented Nov 6, 2020

Expected behavior

I expect projectile-find-dir to return a list of all directories within a project.

Actual behavior

projectile-find-dir returns directories under which there is a file that projectile is tracking directly underneath the directory. Directories which contain only sub-directories are not available in completion.

Steps to reproduce the problem

Consider the directory structure below:

root/
    src/
        ComponentA/
                      a.cc
        ComponentB/
                      b.cc
        ComponentC/
                      c.cc
    config/
            config_file_1
            config_file_2

When using projectile-find-dir within root, the path root/src is not listed. The paths listed are:

root/src/ComponentA
root/src/ComponentB
root/src/ComponentC
root/config

Environment & Version information

Projectile version information

Projectile 20201030.1132

Emacs version

GNU Emacs 26.3 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.18.9)

Operating system

Ubuntu 16.04 (4.4.0-139-generic)

@zeus-hammer
Copy link
Author

@zeus-hammer zeus-hammer commented Nov 6, 2020

The crux of the issue is in projectile.el.

In this function:

;;;; Find directory in project functionality
(defun projectile--find-dir (invalidate-cache &optional dired-variant)
  "Jump to a project's directory using completion.

With INVALIDATE-CACHE invalidates the cache first.  With DIRED-VARIANT set to a
defun, use that instead of `dired'.  A typical example of such a defun would be
`dired-other-window' or `dired-other-frame'"
  (projectile-maybe-invalidate-cache invalidate-cache)
  (let* ((project (projectile-ensure-project (projectile-project-root)))
         (dir (projectile-complete-dir project))
         (dired-v (or dired-variant #'dired)))
    (funcall dired-v (expand-file-name dir project))
    (run-hooks 'projectile-find-dir-hook)))

projectile-complete-dir eventually calls projectile-project-dirs, which does the following:

(defun projectile-project-dirs (project)
  "Return a list of dirs for PROJECT."
  (delete-dups
   (delq nil
         (mapcar #'file-name-directory
                 (projectile-project-files project)))))

As you can see, it's simply listing all the projectile tracked files in the project and slicing off the file name from the path, leaving us with the directory path. This misses out on directories which only have directories as children.

@zeus-hammer
Copy link
Author

@zeus-hammer zeus-hammer commented Nov 6, 2020

I'm working on hacking this up on my local copy, but it's inelegant and doesn't take advantage of projectile's caching. I will likely substitute this for #'file-name-directory and flatten the whole list. I can help with this issue as well, I just don't know the best way to go about it as there are multiple routes. My hack would likely be untenable for large projects.

(defun get-dirs-from-path (path)
  (let ((directories '()))
        (while (not (or (equal path "/") (equal path "~")))
          (setq path (file-name-directory (directory-file-name path)))
          (message "path: %s" path)
          (nconc directories 'path)
          )
        )
)
@zeus-hammer
Copy link
Author

@zeus-hammer zeus-hammer commented Nov 6, 2020

I'm working on hacking this up on my local copy, but it's inelegant and doesn't take advantage of projectile's caching. I will likely substitute this for #'file-name-directory and flatten the whole list. I can help with this issue as well, I just don't know the best way to go about it as there are multiple routes. My hack would likely be untenable for large projects.

(defun get-dirs-from-path (path)
  (let ((directories '()))
        (while (not (or (equal path "/") (equal path "~")))
          (setq path (file-name-directory (directory-file-name path)))
          (message "path: %s" path)
          (nconc directories 'path)
          )
        )
)

I just realized this won't work, as it'll go all the way up to the root of the fs. You'd need to pass in the project path and go up to that as the root. Either way, you'd almost certainly want to look top down

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
1 participant
You can’t perform that action at this time.