@@ -796,6 +796,7 @@ top level functions only."
796796 (add-hook 'completion-at-point-functions #'ess-r-package-completion nil 'local )
797797 (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local )
798798 (add-hook 'xref-backend-functions #'ess-r-xref-backend nil 'local )
799+ (add-hook 'project-find-functions #'ess-r-project -90 'local )
799800
800801 (if (fboundp 'ess-add-toolbar ) (ess-add-toolbar))
801802 ; ; imenu is needed for `which-function'
@@ -822,6 +823,64 @@ top level functions only."
822823;;;### autoload
823824(add-to-list 'auto-mode-alist '(" CITATION\\ '" . ess-r-mode))
824825
826+
827+ ; ;;*;;; Project detection
828+
829+ (defvar-local ess-r-project--info-cache nil
830+ " Current package info cache.
831+ See `ess-r-project-info' for its structure." )
832+
833+ (defun ess-r-project (&optional dir )
834+ " Return the current project as an Emacs project instance.
835+ R project is a directory XYZ containing either .Rprofile,
836+ DESCRIPTION or XYZ.Rproj file. Return a list of the form (:name
837+ \" XYZ\" :root \" /path/to/project\" ). If DIR is provided, the
838+ project is searched from that directory instead of
839+ `default-directory' ."
840+ (let ((info (ess-r-project-info dir)))
841+ (when (car info)
842+ (cons 'ess-r-project (plist-get info :root )))))
843+
844+ ; ; FIXME: remove when emacs 27 is dropped
845+ (unless (eval-when-compile
846+ (get 'project-roots 'byte-obsolete-info ))
847+ (cl-defmethod project-roots ((project (head ess-r-project)))
848+ " Return the project root for ESS R projects."
849+ (list (cdr project))))
850+
851+ (cl-defmethod project-root ((project (head ess-r-project)))
852+ " Return the project root for ESS R projects."
853+ (cdr project))
854+
855+ (defun ess-r-project-info (&optional dir )
856+ " Get the description of the R project in directory DIR.
857+ Return an plist with the keys :name and :root. When not in a
858+ project return '(nil). This value is cached buffer-locally for
859+ efficiency reasons."
860+ (let ((do-cache (null dir)))
861+ (if (and do-cache ess-r-project--info-cache)
862+ ess-r-project--info-cache
863+ (setq dir (or dir (buffer-file-name ) default-directory))
864+ (let ((out (or
865+ (unless (file-remote-p dir)
866+ (let ((dir (locate-dominating-file
867+ dir
868+ (lambda (dir )
869+ (or (file-exists-p (expand-file-name " .Rprofile" dir))
870+ (file-exists-p (expand-file-name " DESCRIPTION" dir))
871+ (let ((nm (file-name-nondirectory (directory-file-name dir))))
872+ (file-exists-p (expand-file-name (concat nm " .Rproj" ) dir))))))))
873+ (when dir
874+ (let ((dir (directory-file-name dir)))
875+ (unless (member dir (list " ~" (getenv " HOME" )))
876+ (list :name (file-name-nondirectory dir)
877+ :root (expand-file-name dir)))))))
878+ '())))
879+ (when do-cache
880+ (setq ess-r-project--info-cache out))
881+ out))))
882+
883+
825884
826885; ;*;; Miscellaneous
827886
@@ -2405,6 +2464,7 @@ state.")
24052464 (add-hook 'completion-at-point-functions 'ess-r-object-completion nil 'local )
24062465 (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local )
24072466 (add-hook 'xref-backend-functions #'ess-r-xref-backend nil 'local )
2467+ (add-hook 'project-find-functions #'ess-r-project -90 'local )
24082468 ; ; eldoc
24092469 (ess--setup-eldoc #'ess-r-eldoc-function )
24102470 ; ; auto-complete
0 commit comments