Today it occurred to me that numeric arguments 0 and 1 could be utilized for different purposes. For most commands they are meaningless which allows us to assign them a specific meaning ourselves. Here is one way, which uses numeric prefix 0 to projectize commands:
(setq lexical-binding t) (defun projectize-1 (cmd f &rest args) (if (eq cmd real-this-command) (let* ((proot (and (= 0 (prefix-numeric-value current-prefix-arg)) (locate-dominating-file "." ".git"))) (current-prefix-arg (and (not (= 0 (prefix-numeric-value current-prefix-arg))) current-prefix-arg)) (default-directory (or proot default-directory)) (buffer-file-name (or proot buffer-file-name))) ;; Update: simplified interactive call ;; thanks to /u/SlowValue (call-interactively f)) (apply f args))) (defun projectize (&rest cmds) (dolist (cmd cmds) (advice-add cmd :around (lambda (f &rest args) (interactive) (apply #'projectize-1 cmd f args))))) (global-set-key (kbd "C-c f") 'find-name-dired) (global-set-key (kbd "C-c r") 'rgrep) (global-set-key (kbd "C-c C-c") 'compile) (projectize #'find-name-dired #'rgrep #'compile)
Using this you can call C-0 C-c r or C-0 C-c f and will be prompted with the (git) project root (if it exists). This also works when you use C-0 M-x rgrep to call rgrep. The hack above should work for many other commands which prompt you for a directory.