http://stable.melpa.org/packages/find-file-in-project
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.
Features:
- 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
andffip-prune-patterns
- Work flawlessly with Tramp Mode
Screenshot:
Place find-file-in-project.el under your Load Path. Then add (require 'find-file-in-project)
to your configuration.
It is also possible to use melpa; however be aware that as of the time of this writing installation using package.el
is not recommended due to flaws in Emacs’s TLS implementation.
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
Windows setup is as easy as installing Cygwin or MYSYS2 at default directory of any driver. GNU Find
executable is detected automatically.
You can also manually specify the file path,
(if (eq system-type 'windows-nt)
(setq ffip-find-executable "c:\\\\cygwin64\\\\bin\\\\find"))
NO setup needed.
Project root is automatically detected if Git/Mercurial/Subversion is used.
You can override the default root directory by setting ffip-project-root
,
(setq ffip-project-root "~/projs/PROJECT_DIR")
Per-project and per-directory setup is easy. Check “Tips” section for details.
Guess the file name at point and try to find file.
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.
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
.
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.
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.
Create .dir-locals.el
which ”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 Emacs manual for technical details.
Like M-x find-file-in-project
but find only in current directory.
Like M-x find-file-in-project-by-selected
but find only in current directory.
Execute selected backend from ffip-diff-backends
.
The output of backend execution is in 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 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,
(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
,
(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"))
These two commands requires 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.
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.
;; (setq ffip-find-relative-path-callback 'ffip-copy-reactjs-import)
(setq ffip-find-relative-path-callback 'ffip-copy-org-file-link)
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 Perforce control,
(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)
Find&Open file in split window.
All tips are OPTIONAL. find-file-in-project works out of box in 99% cases.
(ido-mode 1)
(setq ffip-prefer-ido-mode t)
- “ffip-get-project-root-directory” return the full path of current project
Here is complete setup you could insert into ~/.emacs.d/init.el
,
;; 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))
;; exclude `dist/' 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)
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
,
((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.
(if (eq system-type 'windows-nt)
;; Native Windows
(setq ffip-project-root "C:/Users/myname/projs/myproj1")
;; Cygwin
(setq ffip-project-root "~/projs/myprojs1"))
C-h i g (ivy) Enter
for more key-binding tips.
Install counsel.
Use cousel-git
to find file and counsel-git-grep
to grep. It’s developed by the author of Ivy.
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
.
Check https://github.com/technomancy/find-file-in-project.
find-file-in-project is free software: you can redistribute it and/or modify it under the terms of the 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 GNU General Public License for more details.