Subject: Re: bug#41572: 28.0.50; [PATCH] Support plain project marked with file .emacs-project

From: Dmitry Gutov <[email-masked]>
Date: Sun, 26 Sep 2021 02:13:39 +0300

On 01.10.2020 06:11, Lars Ingebrigtsen wrote:
> If I'm skimming this thread correctly, there wasn't much enthusiasm for
> the proposed new functionality, so I'm closing this bug report.  If
> there's further progress to be made here, please respond to the debbugs
> address and we'll reopen.

There are valid issues here, but there was no clear picture of how to 
solve them best. But it would be good to try to do that (at least to 
some extent) before Emacs 28 is released.

The first issue is that projects that don't use any of the supported VCS 
are not recognized at all.

Since these days most large projects do use version control, we can 
expect that projects which do not, should be relatively small. And our 
find-based implementation will generally be fast enough. Also, looking 
at the home-grown project definitions out there, people often don't 
bother with the 'ignores' method, so maybe a backend which provides no 
way to specify them will still cover most of the needs. It could be 
extended with such feature later anyway.

Patch adding such backend with a customizable list of "markers" is 
attached. I wasn't sure whether to add support for wildcards there, 
because file-expand-wildcards does not optimize for the trivial case, 
and directory-files is slower than file-exists-p. I'm mostly worried 
about Tramp performance here, but some pathologically huge directory 
could be a problem as well, IDK.

project-fallback-markers only includes .dir-locals.el, but it can be 
easily customized. Not sure if it should include other standard file 
names, such as Makefile, Gemfile, mix.exs, and so on. The first version 
doesn't have them.

Another question is the name. 'plain' sounds not very descriptive. I've 
considered 'fallback' and 'novc', eventually settling on the former.

Opinions welcome, though.
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 57a961c260..8eee0c7d27 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -165,7 +165,7 @@ project
   :version "28.1"
   :group 'tools)
 
-(defvar project-find-functions (list #'project-try-vc)
+(defvar project-find-functions (list #'project-try-vc #'project-try-fallback)
   "Special hook to find the project containing a given directory.
 Each functions on this hook is called in turn with one
 argument, the directory in which to look, and should return
@@ -662,6 +662,27 @@ project-buffers
         (push buf bufs)))
     (nreverse bufs)))
 
+(defcustom project-fallback-markers '(".dir-locals.el")
+  "List of file name to use as fallback project root markers.
+
+Each entry should be a relative file name (no directory part).
+
+The fallback project backend detects a project as a directory
+containing one of these files."
+  :type 'list)
+
+(defun project-try-fallback (dir)
+  (let ((root (locate-dominating-file dir #'project-fallback--root-p)))
+    (and root (cons 'fallback root))))
+
+(defun project-fallback--root-p (dir)
+  (let ((default-directory dir))
+    (seq-some (lambda (marker) (file-exists-p marker))
+              project-fallback-markers)))
+
+(cl-defmethod project-root ((project (head fallback)))
+  (cdr project))
+
 
 ;;; Project commands