Want to take your software engineering career to the next level? Join the mailing list for career tips & advice Click here


Quick access to project files in Emacs

Subscribe to updates I use find-file-in-project

Statistics on find-file-in-project

Number of watchers on Github 226
Number of open issues 10
Average time to close an issue 4 months
Main language Emacs Lisp
Average time to merge a PR 17 days
Open pull requests 0+
Closed pull requests 11+
Last commit over 2 years ago
Repo Created over 11 years ago
Repo Last Updated over 2 years ago
Size 284 KB
Organization / Authortechnomancy
Page Updated
Do you use find-file-in-project? Leave a review!
View open issues (10)
View find-file-in-project activity
View on github
Fresh, new opensource launches 🚀🚀🚀
Software engineers: It's time to get promoted. Starting NOW! Subscribe to my mailing list and I will equip you with tools, tips and actionable advice to grow in your career.
Evaluating find-file-in-project for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)
  • find-file-in-project v5.5.2


Find file/directory and review Diff/Patch/Commit quickly everywhere.

User Case One: Find file/directory quickly in current project. The project root is detected automatically if Git/Subversion/Mercurial is used.

User Case Two: Diff/patch files. Target files could be understand any Version Control Software (VCS) or there is no VCS at all. Please check =ffip-diff-*= commands.


  • Works perfectly on Windows64/Linux/Mac with minimum setup. Only dependency is =BSD/GNU Find=
  • Quick. Tested with 50,000+ files
  • You can speed up searching by tweaking =ffip-find-options= and =ffip-prune-patterns=
  • Work flawlessly with [[https://www.emacswiki.org/emacs/TrampMode][Tramp Mode]]



  • Install Place [[https://raw.githubusercontent.com/technomancy/find-file-in-project/master/find-file-in-project.el][find-file-in-project.el]] under your [[https://www.emacswiki.org/emacs/LoadPath][Load Path]]. Then add =(require 'find-file-in-project)= to your configuration.

It is also possible to use [[http://stable.melpa.org/#/find-file-in-project][melpa]]; however be aware that as of the time of this writing installation using =package.el= is [[https://glyph.twistedmatrix.com/2015/11/editor-malware.html][not recommended]] due to flaws in Emacs's TLS implementation.

[[https://github.com/abo-abo/swiper][Ivy-mode]] is the optional dependency which is installed automatically if you use melpa. If it is not found, ido will be used instead.

Since v3.7, Emacs 24.3 is required.

Users of Debian 10 and derivatives can install find-file-in-project with the following command: =sudo apt install elpa-find-file-in-project=

  • Setup ** Windows Windows setup is as easy as installing [[http://cygwin.com][Cygwin]] or [[https://msys2.github.io/][MYSYS2]] at default directory of any driver. =GNU Find= executable is detected automatically.

You can also manually specify the file path,

+begin_src elisp

(if (eq system-type 'windows-nt) (setq ffip-find-executable c:\\\\cygwin64\\\\bin\\\\find))


** Linux and OS X NO setup needed.

  • Usage Project root is automatically detected if Git/Mercurial/Subversion is used.

You can override the default root directory by setting =ffip-project-root=,

+begin_src elisp

(setq ffip-project-root ~/projs/PROJECT_DIR)


Per-project and per-directory setup is easy. Check Tips section for details. ** =M-x find-file-in-project-at-point= Guess the file name at point and try to find file. ** =M-x find-file-in-project-by-selected= Use the selected region as keyword to search file. If no region selected, you may provide the keyword which could contain wildcard.

If keyword contains line number like hello.txt:32 or hello.txt:32:, we will move to that line in opened file.

If parameter is passed , file will be opened in new window.

If you =(setq ffip-match-path-instead-of-filename t)= before =M-x find-file-in-project-by-selected=, we try to match selected text with any part of full path before displaying candidates. It's a little slower than the original setup.

It could replace old command =find-file-in-project= (or =ffip=) because it's more efficient. It was tested searching in 50K+ files without any performance issue. ** =M-x find-file-with-similar-name= Find file with similar name to current opened file.

The regular expression =ffip-strip-file-name-regex= is also used by =find-file-with-similar-name=. ** =M-x find-directory-in-project-by-selected= Use the selected region as keyword to find directory. If no region selected, you need provide the keyword. Keyword could contain wildcard character which passed to Find as value of =-iwholename= option

If parameter is passed , directory will be opened in new window. ** =M-x find-file-in-project= Starts search immediately. This command is slow if there 10K+ files because it use ONLY Emacs Lisp to filter candidates. You should always use =find-file-in-project-by-selected= unless in small project. ** =M-x ffip-create-project-file= Create =.dir-locals.el= which [[http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html][defines the same set of local variables to all the files in a certain directory and its subdirectory]].

You can use it to setup variables like =ffip-project-root=.

This command respects existing =.dir-locals.el=. So it will merge new setup into existing content.

See [[http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html][Emacs manual]] for technical details. ** =M-x find-file-in-current-directory= Like =M-x find-file-in-project= but find only in current directory. ** =M-x find-file-in-current-directory-by-selected= Like =M-x find-file-in-project-by-selected= but find only in current directory. ** =M-x ffip-show-diff= Execute selected backend from =ffip-diff-backends=.

The output of backend execution is in [[http://www.gnu.org/software/diffutils/manual/html_node/Unified-Format.html][Unified Diff Format]] and is inserted into =ffip-diff= buffer where you can press =o=, =C-c C-c=, =ENTER= , =M-x ffip-diff-find-file= to open the corresponding file.

=ffip-diff-find-file-before-hook= is called before =M-x ffip-diff-find-file=.

For example, you can =M-x ffip-show-diff= to view the git commit and open corresponding file.

If you use [[https://www.mercurial-scm.org/][Mercurial]], =M-x 5 ffip-show-diff=.

Please press =C-h v ffip-diff-backends= to view the available back-ends.

Other key bindings available in =ffip-diff= buffer, | key binding | command | |-------------+----------------| | p | diff-hunk-prev | | n | diff-hunk-next | | P | diff-file-prev | | N | diff-file-next |

Insert below code into ~/.emacs if you use evil-mode,

+begin_src elisp

(defun ffip-diff-mode-hook-setup () (evil-local-set-key 'normal p 'diff-hunk-prev) (evil-local-set-key 'normal n 'diff-hunk-next) (evil-local-set-key 'normal P 'diff-file-prev) (evil-local-set-key 'normal N 'diff-file-next) (evil-local-set-key 'normal (kbd RET) 'ffip-diff-find-file) (evil-local-set-key 'normal o 'ffip-diff-find-file)) (add-hook 'ffip-diff-mode-hook 'ffip-diff-mode-hook-setup)


You can customize the =ffip-diff-backends=,

+begin_src elisp

(setq ffip-diff-backends '(ffip-diff-backend-git-show-commit cd $(git rev-parse --show-toplevel) && git diff cd $(git rev-parse --show-toplevel) && git diff --cached ffip-diff-backend-hg-show-commit (Diff from `kill-ring' . (car kill-ring)) cd $(hg root) && hg diff svn diff))


** =M-x ffip-save-ivy-last= and =M-x ffip-ivy-resume= These two commands requires [[https://github.com/abo-abo/swiper][ivy-mode]].

=ffip-save-ivy-last= saves the most recent search result.

=ffip-ivy-resume= re-use the search result saved by =ffip-save-ivy-last=.

You can always use =ivy-resume= to re-use the most recent search result. ** =M-x find-relative-path= Find file/directory and copy its relative path into `kill-ring'.

File's path is copied by default. =C-u M-x find-relative-path= copy directory's path.

You can set =ffip-find-relative-path-callback= to format the string before copying.

+begin_src elisp

;; (setq ffip-find-relative-path-callback 'ffip-copy-reactjs-import) (setq ffip-find-relative-path-callback 'ffip-copy-org-file-link)


** =M-x ffip-diff-apply-hunk= Similar to =diff-apply-hunk=, it applies current hunk in =diff-mode= to the target file (please note =ffip-diff-mode= inherits from =diff-mode=).

The target file could be located by searching =(ffip-project-root)=. You can also apply extra operation on the file in =ffip-diff-apply-hunk-hook= before hunk applying actually happens.

For example, for files under [[https://www.perforce.com/][Perforce]] control,

+begin_src elisp

(defun p4-edit-file-and-make-buffer-writable(file) p4 edit FILE and make corresponding buffer writable. (shell-command (format p4 edit %s file)) ;; make sure the buffer is readable (let* ((buf (get-file-buffer file))) (if buf (with-current-buffer buf ;; turn off read-only since we've already `p4 edit' (read-only-mode -1))))) (defun ffip-diff-apply-hunk-hook-setup (file) (unless (featurep 'init-perforce) (require 'init-perforce)) (if (string-match-p /myproject/ file) (p4-edit-file-and-make-buffer-writable file))) (add-hook 'ffip-diff-apply-hunk-hook 'ffip-diff-apply-hunk-hook-setup)


** =ffip-split-window-horizontally= and =ffip-split-window-vertically= Find&Open file in split window.

  • Tips All tips are OPTIONAL. find-file-in-project works out of box in 99% cases. ** Use ido-mode instead of ivy #+begin_src elisp (ido-mode 1) (setq ffip-prefer-ido-mode t) #+end_src ** APIs
  • ffip-get-project-root-directory return the full path of current project ** Per-project setup using Emacs lisp Here is complete setup you could insert into =~/.emacs.d/init.el=, #+begin_src elisp ;; if the full path of current file is under SUBPROJECT1 or SUBPROJECT2 ;; OR if I'm reading my personal issue track document, (defun my-setup-develop-environment () (interactive) (when (ffip-current-full-filename-match-pattern-p \\(PROJECT_DIR\\|issue-track.org\\)) ;; Though PROJECT_DIR is team's project, I care only its sub-directory subproj1 (setq-local ffip-project-root~/projs/PROJECT_DIR/subproj1) ;; well, I'm not interested in concatenated BIG js file or file in dist/ (setq-local ffip-find-options-not -size +64k -not -iwholename '/dist/') ;; for this project, I'm only interested certain types of files (setq-local ffip-patterns '(.html" ".js" *.css *.java *.xml *.js)) ;; maybe you want to search files in bin' directory? (setq-local ffip-prune-patterns (delete "*/bin/*" ffip-prune-patterns)) ;; excludedist/' directory (add-to-list 'ffip-prune-patterns */dist/*)) ;; insert more WHEN statements below this line for other projects ) ;; most major modes inherit from prog-mode, so below line is enough (add-hook 'prog-mode-hook 'my-setup-develop-environment) #+end_src ** Per-directory setup using =.dir-locals.el= All variables may be overridden on a per-directory basis in your =.dir-locals.el=. See (info (Emacs) Directory Variables) for details.

You can place =.dir-locals.el= into your project root directory.

A sample =.dir-locals.el=,

+begin_src elisp

((nil . ((ffip-project-root . ~/projs/PROJECT_DIR) ;; ingore files bigger than 64k and directory dist/ (ffip-find-options . -not -size +64k -not -iwholename '*/dist/*') ;; only search files with following extensions (ffip-patterns . (*.html *.js *.css *.java *.xml *.js)) (eval . (progn (require 'find-file-in-project) ;; ingore directory .tox/ (setq ffip-prune-patterns ("*/.tox/*" ,@ffip-prune-patterns)) ;; Do NOT ignore directory "bin/" (setq ffip-prune-patterns(delete */bin/* ,@ffip-prune-patterns)))) )))


As we mentioned, =ffip-create-project-file= could create a minimum =.dir-locals.el= for you.

BTW, please use either per-directory setup or per-project setup, NOT both. ** Specify root directory on Windows

+begin_src elisp

(if (eq system-type 'windows-nt) ;; Native Windows (setq ffip-project-root C:/Users/myname/projs/myproj1) ;; Cygwin (setq ffip-project-root ~/projs/myprojs1))


** More keybinding tips =C-h i g (ivy) Enter= for more key-binding tips. ** Search and grep files under Git control Install [[https://github.com/abo-abo/swiper][counsel]].

Use =cousel-git= to find file and =counsel-git-grep= to grep. It's developed by the author of Ivy.

  • Development This program only uses =ivy-read= from ivy-mode.

DO NOT use other APIs from =ivy-mode=. The less APIs used, the more stable this package will be.

Run =tests/test.sh= before =git commit=.

  • Bug Report Check [[https://github.com/technomancy/find-file-in-project]].
  • License find-file-in-project is free software: you can redistribute it and/or modify it under the terms of the [[https://raw.githubusercontent.com/technomancy/find-file-in-project/master/LICENSE][GNU General Public License]] as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

find-file-in-project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [[https://raw.githubusercontent.com/technomancy/find-file-in-project/master/LICENSE][GNU General Public License]] for more details.

find-file-in-project open issues Ask a question     (View All Issues)
  • almost 4 years check all the file links exist in current buffer
find-file-in-project questions on Stackoverflow (View All Questions)
  • emacs find file in project on a big project
  • Icicles find file in project
  • Find file in project (visual studio)
find-file-in-project list of languages used
Other projects in Emacs Lisp