From 93b725b6dc47ee7c1e600bdcacbdc426ca5a4c49 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Tue, 4 Feb 2025 17:29:26 +0100 Subject: [PATCH] update projectile Signed-off-by: Andreas Gerler --- .../projectile-autoloads.el | 6 +- .../projectile-pkg.el | 8 +- .../projectile.el | 339 +++++++++++------- 3 files changed, 214 insertions(+), 139 deletions(-) rename elpa/{projectile-20250106.1438 => projectile-20250204.1346}/projectile-autoloads.el (99%) rename elpa/{projectile-20250106.1438 => projectile-20250204.1346}/projectile-pkg.el (68%) rename elpa/{projectile-20250106.1438 => projectile-20250204.1346}/projectile.el (96%) diff --git a/elpa/projectile-20250106.1438/projectile-autoloads.el b/elpa/projectile-20250204.1346/projectile-autoloads.el similarity index 99% rename from elpa/projectile-20250106.1438/projectile-autoloads.el rename to elpa/projectile-20250204.1346/projectile-autoloads.el index 6b940e44..7865bd19 100644 --- a/elpa/projectile-20250106.1438/projectile-autoloads.el +++ b/elpa/projectile-20250204.1346/projectile-autoloads.el @@ -527,6 +527,10 @@ dirty project list. (fn &optional CACHED)" t) (autoload 'projectile-edit-dir-locals "projectile" "\ Edit or create a .dir-locals.el file of the project." t) +(autoload 'project-projectile "projectile" "\ +Return Projectile project of form ('projectile . root-dir) for DIR. + +(fn DIR)") (defvar projectile-mode nil "\ Non-nil if Projectile mode is enabled. See the `projectile-mode' command @@ -550,7 +554,7 @@ Otherwise behave as if called interactively. (fn &optional ARG)" t) (define-obsolete-function-alias 'projectile-global-mode 'projectile-mode "1.0") -(register-definition-prefixes "projectile" '("compilation-find-file-projectile-find-compilation-buffer" "def-projectile-commander-method" "delete-file-projectile-remove-from-cache" "project" "savehist-additional-variables")) +(register-definition-prefixes "projectile" '("compilation-find-file-projectile-find-compilation-buffer" "def-projectile-commander-method" "delete-file-projectile-remove-from-cache" "projectile-" "savehist-additional-variables")) ;;; End of scraped data diff --git a/elpa/projectile-20250106.1438/projectile-pkg.el b/elpa/projectile-20250204.1346/projectile-pkg.el similarity index 68% rename from elpa/projectile-20250106.1438/projectile-pkg.el rename to elpa/projectile-20250204.1346/projectile-pkg.el index 22a58069..24c37cb0 100644 --- a/elpa/projectile-20250106.1438/projectile-pkg.el +++ b/elpa/projectile-20250204.1346/projectile-pkg.el @@ -1,10 +1,10 @@ ;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "projectile" "20250106.1438" +(define-package "projectile" "20250204.1346" "Manage and navigate projects in Emacs easily." - '((emacs "25.1")) + '((emacs "26.1")) :url "https://github.com/bbatsov/projectile" - :commit "0404b9b6eeb0c6504337749a366fffd97de2bfbe" - :revdesc "0404b9b6eeb0" + :commit "1d02b6a391a81a0011aa16128170798bab6d7f3f" + :revdesc "1d02b6a391a8" :keywords '("project" "convenience") :authors '(("Bozhidar Batsov" . "bozhidar@batsov.dev")) :maintainers '(("Bozhidar Batsov" . "bozhidar@batsov.dev"))) diff --git a/elpa/projectile-20250106.1438/projectile.el b/elpa/projectile-20250204.1346/projectile.el similarity index 96% rename from elpa/projectile-20250106.1438/projectile.el rename to elpa/projectile-20250204.1346/projectile.el index 2c85ced4..dc7e626c 100644 --- a/elpa/projectile-20250106.1438/projectile.el +++ b/elpa/projectile-20250204.1346/projectile.el @@ -1,13 +1,13 @@ ;;; projectile.el --- Manage and navigate projects in Emacs easily -*- lexical-binding: t -*- -;; Copyright © 2011-2024 Bozhidar Batsov +;; Copyright © 2011-2025 Bozhidar Batsov ;; Author: Bozhidar Batsov ;; URL: https://github.com/bbatsov/projectile ;; Keywords: project, convenience -;; Package-Version: 20250106.1438 -;; Package-Revision: 0404b9b6eeb0 -;; Package-Requires: ((emacs "25.1")) +;; Package-Version: 20250204.1346 +;; Package-Revision: 1d02b6a391a8 +;; Package-Requires: ((emacs "26.1")) ;; This file is NOT part of GNU Emacs. @@ -28,12 +28,11 @@ ;;; Commentary: ;; -;; This library provides easy project management and navigation. The -;; concept of a project is pretty basic - just a folder containing -;; special file. Currently git, mercurial and bazaar repos are -;; considered projects by default. If you want to mark a folder -;; manually as a project just create an empty .projectile file in -;; it. See the README for more details. +;; Projectile is a project interaction library for Emacs. +;; It provides a powerful set of features operating at the project +;; level, as well as simple heuristics to identify projects. +;; +;; See the README and https://docs.projectile.mx for more details. ;; ;;; Code: @@ -43,7 +42,6 @@ (require 'ibuf-ext) (require 'compile) (require 'grep) -(require 'lisp-mnt) (eval-when-compile (require 'find-dired) (require 'subr-x)) @@ -138,10 +136,17 @@ default on all operating systems, except Windows." (defcustom projectile-enable-caching (eq projectile-indexing-method 'native) "When t enables project files caching. +Normally the cache lasts for the duration of your Emacs session. +If you want to cache to persist between Emacs sessions you +should set this option to `'persistent'. + Project caching is automatically enabled by default if you're using the native indexing method." :group 'projectile - :type 'boolean) + :type '(radio + (const :tag "Disabled" nil) + (const :tag "Transient" t) + (const :tag "Persistent" persistent))) (defcustom projectile-kill-buffers-filter 'kill-all "Determine which buffers are killed by `projectile-kill-buffers'. @@ -188,11 +193,21 @@ A value of nil means the cache never expires." (integer :tag "Seconds"))) (defcustom projectile-auto-discover t - "Whether to discover projects when `projectile-mode' is activated." + "Whether to discover projects when project switching commands are invoked. + +See also `projectile-project-search-path'." :group 'projectile :type 'boolean :package-version '(projectile . "2.3.0")) +(defcustom projectile-auto-cleanup-known-projects nil + "Whether to cleanup projects when project switching commands are invoked. + +See also `projectile-cleanup-known-projects'." + :group 'projectile + :type 'boolean + :package-version '(projectile . "2.9.0")) + (defcustom projectile-auto-update-cache t "Whether cache is automatically updated when files are opened or deleted." :group 'projectile @@ -225,9 +240,9 @@ When nil Projectile will consider the current directory the project root." :group 'projectile :type 'string) -(defcustom projectile-cache-file - (expand-file-name "projectile.cache" user-emacs-directory) - "The name of Projectile's cache file." +(defcustom projectile-cache-file ".projectile-cache.eld" + "The name of Projectile's cache. +It's relative to the project root." :group 'projectile :type 'string) @@ -393,7 +408,7 @@ is set to `alien'." (defcustom projectile-globally-unignored-files nil "A list of files globally unignored by projectile. -Regular expressions can be used. + Note that files aren't filtered if `projectile-indexing-method' is set to `alien'." :group 'projectile @@ -409,27 +424,26 @@ is set to `alien'." :type '(repeat string)) (defcustom projectile-globally-ignored-directories - '("^\\.idea$" - "^\\.vscode$" - "^\\.ensime_cache$" - "^\\.eunit$" - "^\\.git$" - "^\\.hg$" - "^\\.fslckout$" - "^_FOSSIL_$" - "^\\.bzr$" - "^_darcs$" - "^\\.pijul$" - "^\\.tox$" - "^\\.svn$" - "^\\.stack-work$" - "^\\.ccls-cache$" - "^\\.cache$" - "^\\.clangd$" - "^\\.sl$" - "^\\.jj$") + '(".idea" + ".vscode" + ".ensime_cache" + ".eunit" + ".git" + ".hg" + ".fslckout" + "_FOSSIL_" + ".bzr" + "_darcs" + ".pijul" + ".tox" + ".svn" + ".stack-work" + ".ccls-cache" + ".cache" + ".clangd" + ".sl" + ".jj") "A list of directories globally ignored by projectile. -Regular expressions can be used. Strings that don't start with * are only ignored at the top level of the project. Strings that start with * are ignored everywhere @@ -442,7 +456,9 @@ project, but not ./src/tmp. \"*tmp\" will ignore both ./tmp and ./src/tmp, but not ./not-a-tmp or ./src/not-a-tmp. Note that files aren't filtered if `projectile-indexing-method' -is set to `alien'." +is set to `alien'. + +See also `projectile-global-ignore-file-patterns'." :safe (lambda (x) (not (remq t (mapcar #'stringp x)))) :group 'projectile :type '(repeat string)) @@ -455,6 +471,21 @@ is set to `alien'." :type '(repeat string) :package-version '(projectile . "0.14.0")) +(defcustom projectile-global-ignore-file-patterns + nil + "A list of file regexp patterns ignored by Projectile. + +It complements `projectile-globally-ignored-files' and +`projectile-globally-ignored-directories'. See also +`projectile-ignored-file-p' and `projectile-ignored-directory-p'. + +Note that files aren't filtered if `projectile-indexing-method' +is set to `alien'." + :safe (lambda (x) (not (remq t (mapcar #'stringp x)))) + :group 'projectile + :type '(repeat string) + :package-version '(projectile . "2.9.0")) + (defcustom projectile-globally-ignored-modes '("erc-mode" "help-mode" @@ -599,10 +630,10 @@ project." (run-hooks 'projectile-idle-timer-hook))))))) :type 'boolean) -(defvar projectile-projects-cache nil +(defvar projectile-projects-cache (make-hash-table :test 'equal) "A hashmap used to cache project file names to speed up related operations.") -(defvar projectile-projects-cache-time nil +(defvar projectile-projects-cache-time (make-hash-table :test 'equal) "A hashmap used to record when we populated `projectile-projects-cache'.") (defvar projectile-project-root-cache (make-hash-table :test 'equal) @@ -1006,8 +1037,8 @@ The saved data can be restored with `projectile-unserialize'." "Timer for scheduling`projectile-file-exists-cache-cleanup'.") (defun projectile-file-exists-cache-cleanup () - "Removed timed out cache entries and reschedules or remove the -timer if no more items are in the cache." + "Remove timed out cache entries. +Also reschedule or remove the timer if no more items are in the cache." (let ((now (current-time))) (maphash (lambda (key value) (if (time-less-p (cdr value) now) @@ -1062,11 +1093,13 @@ to invalidate." (completing-read "Remove cache for: " (hash-table-keys projectile-projects-cache)) (projectile-acquire-root)))) + ;; reset the in-memory cache (setq projectile-project-root-cache (make-hash-table :test 'equal)) (remhash project-root projectile-project-type-cache) (remhash project-root projectile-projects-cache) (remhash project-root projectile-projects-cache-time) - (projectile-serialize-cache) + ;; reset the project's cache file + (projectile-serialize nil (projectile-project-cache-file project-root)) (when projectile-verbose (message "Invalidated Projectile cache for %s." (propertize project-root 'face 'font-lock-keyword-face)))) @@ -1083,10 +1116,16 @@ to invalidate." (defun projectile-cache-project (project files) "Cache PROJECTs FILES. The cache is created both in memory and on the hard drive." - (when projectile-enable-caching - (puthash project files projectile-projects-cache) - (puthash project (projectile-time-seconds) projectile-projects-cache-time) - (projectile-serialize-cache))) + (puthash project files projectile-projects-cache) + (puthash project (projectile-time-seconds) projectile-projects-cache-time) + (when (eq projectile-enable-caching 'persistent) + (projectile-serialize files (projectile-project-cache-file project)))) + +(defun projectile-load-project-cache (project-root) + "Load the cache file for PROJECT-ROOT in memory." + (when-let* ((cache-file (projectile-project-cache-file project-root))) + (when (file-exists-p cache-file) + (puthash project-root (projectile-unserialize cache-file) projectile-projects-cache)))) ;;;###autoload (defun projectile-purge-file-from-cache (file) @@ -1100,7 +1139,7 @@ The cache is created both in memory and on the hard drive." (if (projectile-file-cached-p file project-root) (progn (puthash project-root (remove file project-cache) projectile-projects-cache) - (projectile-serialize-cache) + (projectile-serialize project-cache (projectile-project-cache-file project-root)) (when projectile-verbose (message "%s removed from cache" file))) (error "%s is not in the cache" file)))) @@ -1133,10 +1172,15 @@ The cache is created both in memory and on the hard drive." (unless (or (projectile-file-cached-p current-file current-project) (projectile-ignored-directory-p (file-name-directory abs-current-file)) (projectile-ignored-file-p abs-current-file)) - (puthash current-project - (cons current-file (gethash current-project projectile-projects-cache)) - projectile-projects-cache) - (projectile-serialize-cache) + (let ((project-files (cons current-file (gethash current-project projectile-projects-cache))) + (cache-file (projectile-project-cache-file current-project))) + (puthash current-project project-files projectile-projects-cache) + ;; we serialize the cache with an idle time to avoid freezing the UI + ;; immediately after the new file was created + (run-with-idle-timer + 30 + nil + 'projectile-serialize project-files cache-file)) (message "File %s added to project %s cache." (propertize current-file 'face 'font-lock-keyword-face) (propertize current-project 'face 'font-lock-keyword-face))))))) @@ -1158,7 +1202,7 @@ The cache is created both in memory and on the hard drive." (defun projectile-maybe-invalidate-cache (force) "Invalidate if FORCE or project's dirconfig newer than cache." (when (or force (file-newer-than-file-p (projectile-dirconfig-file) - projectile-cache-file)) + (projectile-project-cache-file))) (projectile-invalidate-cache nil))) ;;;###autoload @@ -1170,6 +1214,9 @@ discover projects there." (interactive (list (read-directory-name "Starting directory: "))) + ;; set a default value for depth + (setq depth (or depth 1)) + (if (file-directory-p directory) (if (and (numberp depth) (> depth 0)) ;; Ignore errors when listing files in the directory, because @@ -1722,9 +1769,7 @@ If PROJECT is not specified the command acts on the current project." (string-prefix-p project-root (file-truename directory) (eq system-type 'windows-nt)))))) (defun projectile-ignored-buffer-p (buffer) - "Check if BUFFER should be ignored. - -Regular expressions can be use." + "Check if BUFFER should be ignored." (or (with-current-buffer buffer (cl-some @@ -1854,33 +1899,31 @@ projectile project root." (directory &optional ignored-directories local-directory globally-ignored-directories) "Check if DIRECTORY should be ignored. -Regular expressions can be used. Pre-computed lists of -IGNORED-DIRECTORIES and GLOBALLY-IGNORED-DIRECTORIES +Pre-computed lists of IGNORED-DIRECTORIES and GLOBALLY-IGNORED-DIRECTORIES and the LOCAL-DIRECTORY name may optionally be provided." (let ((ignored-directories (or ignored-directories (projectile-ignored-directories))) (globally-ignored-directories (or globally-ignored-directories (projectile-globally-ignored-directory-names))) (local-directory (or local-directory (file-name-nondirectory (directory-file-name directory))))) - (or (cl-some - (lambda (name) - (string-match-p name directory)) - ignored-directories) + (or (member directory ignored-directories) (cl-some (lambda (name) - (string-match-p name local-directory)) - globally-ignored-directories)))) + (string-match-p name directory)) + projectile-global-ignore-file-patterns) + (member local-directory globally-ignored-directories)))) (defun projectile-ignored-file-p (file &optional ignored-files) "Check if FILE should be ignored. -Regular expressions can be used. A pre-computed list of -IGNORED-FILES may optionally be provided." - (cl-some - (lambda (name) - (string-match-p name file)) - (or ignored-files (projectile-ignored-files)))) +A pre-computed list of IGNORED-FILES may optionally be provided." + (or + (member file (or ignored-files (projectile-ignored-files))) + (cl-some + (lambda (name) + (string-match-p name file)) + projectile-global-ignore-file-patterns))) (defun projectile-check-pattern-p (file pattern) - "Check if FILE meets PATTERN." + "Check if FILE matches globbing PATTERN." (or (string-suffix-p (directory-file-name pattern) (directory-file-name file)) (member file (file-expand-wildcards pattern t)))) @@ -1897,7 +1940,10 @@ PATTERNS should have the form: (ignored . unignored)" (cdr patterns))))) (defun projectile-ignored-files () - "Return list of ignored files." + "Return list of ignored files. + +That's a combination of the globally ignored files and +files ignored in a project's dirconfig." (projectile-difference (mapcar #'projectile-expand-root @@ -2127,7 +2173,11 @@ project-root for every file." ;; Use the cache, if requested and available. (when projectile-enable-caching - (setq files (gethash project-root projectile-projects-cache))) + (setq files (or (gethash project-root projectile-projects-cache) + ;; load the cache from disk only if persistent cache is + ;; enabled + (and (eq projectile-enable-caching 'persistent) + (projectile-load-project-cache project-root))))) ;; Calculate the list of files. (when (null files) @@ -2194,7 +2244,7 @@ project-root for every file." The list depends on `:related-files-fn' project option and `projectile-other-file-alist'. For the latter, FLEX-MATCHING can be used to match any basename." - (if-let ((plist (projectile--related-files-plist-by-kind file-name :other))) + (if-let* ((plist (projectile--related-files-plist-by-kind file-name :other))) (projectile--related-files-from-plist plist) (projectile--other-extension-files file-name (projectile-current-project-files) @@ -2652,7 +2702,7 @@ With a prefix arg INVALIDATE-CACHE invalidates the cache first." (defun projectile--related-files-plist (project-root file) "Return a plist containing all related files information for FILE. PROJECT-ROOT is the project root." - (if-let ((rel-path (if (file-name-absolute-p file) + (if-let* ((rel-path (if (file-name-absolute-p file) (file-relative-name file project-root) file)) (custom-function (funcall projectile-related-files-fn-function (projectile-project-type)))) @@ -2666,7 +2716,7 @@ PROJECT-ROOT is the project root." (defun projectile--related-files-plist-by-kind (file kind) "Return a plist containing :paths and/or :predicate of KIND for FILE." - (if-let ((project-root (projectile-project-root)) + (if-let* ((project-root (projectile-project-root)) (plist (projectile--related-files-plist project-root file)) (has-kind? (plist-member plist kind))) (let* ((kind-value (plist-get plist kind)) @@ -2701,7 +2751,7 @@ PROJECT-ROOT is the project root." (defun projectile--related-files-kinds(file) "Return a list o keywords meaning available related kinds for FILE." - (if-let ((project-root (projectile-project-root)) + (if-let* ((project-root (projectile-project-root)) (plist (projectile--related-files-plist project-root file))) (cl-loop for key in plist by #'cddr collect key))) @@ -2714,13 +2764,13 @@ PROJECT-ROOT is the project root." "Choose a file from files related to FILE as KIND. If KIND is not provided, a list of possible kinds can be chosen." (unless kind - (if-let ((available-kinds (projectile--related-files-kinds file))) + (if-let* ((available-kinds (projectile--related-files-kinds file))) (setq kind (if (= (length available-kinds) 1) (car available-kinds) (intern (projectile-completing-read "Kind :" available-kinds)))) (error "No related files found"))) - (if-let ((candidates (projectile--related-files file kind))) + (if-let* ((candidates (projectile--related-files file kind))) (projectile-expand-root (projectile--choose-from-candidates candidates)) (error "No matching related file as `%s' found for project type `%s'" @@ -2751,7 +2801,7 @@ If KIND is not provided, a list of possible kinds can be chosen." (defun projectile-related-files-fn-groups(kind groups) "Generate a related-files-fn which relates as KIND for files in each of GROUPS." (lambda (path) - (if-let ((group-found (cl-find-if (lambda (group) + (if-let* ((group-found (cl-find-if (lambda (group) (member path group)) groups))) (list kind (cl-remove path group-found :test 'equal))))) @@ -2836,8 +2886,8 @@ ones and overrule settings in the other lists." (while plists (setq ls (pop plists)) (while ls - (setq p (pop ls) v (pop ls)) - (setq rtn (plist-put rtn p v)))) + (setq p (pop ls) v (pop ls)) + (setq rtn (plist-put rtn p v)))) rtn)) (cl-defun projectile--build-project-plist @@ -3134,14 +3184,14 @@ it acts on the current project." (defun projectile--cmake-command-presets-shallow (filename command-type) "Get CMake COMMAND-TYPE presets from FILENAME." - (when-let ((preset (projectile--cmake-read-preset (projectile-expand-root filename)))) + (when-let* ((preset (projectile--cmake-read-preset (projectile-expand-root filename)))) (cl-remove-if (lambda (preset) (equal (gethash "hidden" preset) t)) (gethash (projectile--cmake-command-preset-array-id command-type) preset)))) (defun projectile--cmake-command-presets (filename command-type) "Get CMake COMMAND-TYPE presets from FILENAME. Follows included files." - (when-let ((preset (projectile--cmake-read-preset (projectile-expand-root filename)))) + (when-let* ((preset (projectile--cmake-read-preset (projectile-expand-root filename)))) (append (projectile--cmake-command-presets-shallow filename command-type) (mapcar @@ -3191,7 +3241,7 @@ select a name of a command preset, or opt a manual command by selecting `projectile--cmake-no-preset'. - Else `projectile--cmake-no-preset' is used." - (if-let ((use-presets (projectile--cmake-use-command-presets command-type)) + (if-let* ((use-presets (projectile--cmake-use-command-presets command-type)) (preset-names (projectile--cmake-command-preset-names command-type))) (projectile-completing-read "Use preset: " @@ -3490,6 +3540,13 @@ a manual COMMAND-TYPE command is created with :test "mill __.test" :test-suffix "Test") +(projectile-register-project-type 'bloop '(".bloop/bloop.settings.json") + :compile "bloop compile root" + :test "bloop test --propagate --reporter scalac root" + :src-dir "src/main/" + :test-dir "src/test/" + :test-suffix "Spec") + ;; Clojure (projectile-register-project-type 'lein-test '("project.clj") :project-file "project.clj" @@ -3509,13 +3566,7 @@ a manual COMMAND-TYPE command is created with (projectile-register-project-type 'clojure-cli '("deps.edn") :project-file "deps.edn" :test-suffix "_test") -(projectile-register-project-type 'bloop '(".bloop") - :project-file ".bloop" - :compile "bloop compile root" - :test "bloop test --propagate --reporter scalac root" - :src-dir "src/main/" - :test-dir "src/test/" - :test-suffix "Spec") + ;; Ruby (projectile-register-project-type 'ruby-rspec '("Gemfile" "lib" "spec") :project-file "Gemfile" @@ -3634,6 +3685,13 @@ a manual COMMAND-TYPE command is created with :test "zig build test" :run "zig build run") +;; Swift +(projectile-register-project-type 'swift-spm '("Package.swift") + :project-file "Package.swift" + :compile "swift build" + :test "swift test" + :run "swift run") + (defvar-local projectile-project-type nil "Buffer local var for overriding the auto-detected project type. Normally you'd set this from .dir-locals.el.") @@ -3665,7 +3723,7 @@ on the current project. The project type is cached for improved performance." (or (and (not dir) projectile-project-type) - (if-let ((project-root (projectile-project-root dir))) + (if-let* ((project-root (projectile-project-root dir))) (or (gethash project-root projectile-project-type-cache) (projectile-detect-project-type dir))))) @@ -3784,7 +3842,7 @@ Occurrences of the `projectile-default-src-directory' in the directory of IMPL-DIR-PATH are replaced with `projectile-default-test-directory'. Nil is returned if `projectile-default-src-directory' is not a substring of IMPL-DIR-PATH." - (when-let ((file (projectile--complementary-file + (when-let* ((file (projectile--complementary-file impl-dir-path (lambda (f) (when (string-match-p projectile-default-src-directory f) @@ -3802,7 +3860,7 @@ Occurrences of `projectile-default-test-directory' in the directory of TEST-DIR-PATH are replaced with `projectile-default-src-directory'. Nil is returned if `projectile-default-test-directory' is not a substring of TEST-DIR-PATH." - (when-let ((file (projectile--complementary-file + (when-let* ((file (projectile--complementary-file test-dir-path (lambda (f) (when (string-match-p projectile-default-test-directory f) @@ -3998,7 +4056,7 @@ concatenated with FILENAME-FN applied to the file name of FILE-PATH. If either function returns nil, return nil." (let ((filename (file-name-nondirectory file-path))) - (when-let ((complementary-filename (funcall filename-fn filename)) + (when-let* ((complementary-filename (funcall filename-fn filename)) (dir (funcall dir-fn (file-name-directory file-path)))) (concat (file-name-as-directory dir) complementary-filename)))) @@ -4007,7 +4065,7 @@ If either function returns nil, return nil." Return a path relative to the project root for the impl file of FILE-NAME using the src-dir and test-dir properties of the current project type which should be strings, nil returned if this is not the case." - (when-let ((complementary-file (projectile--complementary-file + (when-let* ((complementary-file (projectile--complementary-file file-name #'projectile--test-to-impl-dir #'projectile--impl-name-for-test-name))) @@ -4018,10 +4076,10 @@ should be strings, nil returned if this is not the case." Return a path relative to the project root for the test file of FILE-NAME using the src-dir and test-dir properties of the current project type which should be strings, nil returned if this is not the case." - (when-let (complementary-file (projectile--complementary-file - file-name - #'projectile--impl-to-test-dir - #'projectile--test-name-for-impl-name)) + (when-let* ((complementary-file (projectile--complementary-file + file-name + #'projectile--impl-to-test-dir + #'projectile--test-name-for-impl-name))) (file-relative-name complementary-file (projectile-project-root)))) (defun projectile--impl-file-from-src-dir-fn (test-file) @@ -4030,7 +4088,7 @@ Return the implementation file path for the absolute path TEST-FILE relative to the project root in the case the current project type's src-dir has been set to a custom function, return nil if this is not the case or the path points to a file that does not exist." - (when-let ((src-dir (projectile-src-directory (projectile-project-type)))) + (when-let* ((src-dir (projectile-src-directory (projectile-project-type)))) (when (functionp src-dir) (let ((impl-file (projectile--complementary-file test-file @@ -4044,7 +4102,7 @@ the path points to a file that does not exist." Return the test file path for the absolute path IMPL-FILE relative to the project root, in the case the current project type's test-dir has been set to a custom function, else return nil." - (when-let ((test-dir (projectile-test-directory (projectile-project-type)))) + (when-let* ((test-dir (projectile-test-directory (projectile-project-type)))) (when (functionp test-dir) (file-relative-name (projectile--complementary-file @@ -4137,12 +4195,12 @@ The precedence for determining implementation files to return is: (defun projectile-find-matching-test (impl-file) "Compute the name of the test matching IMPL-FILE." - (when-let ((candidates (projectile--find-matching-test impl-file))) + (when-let* ((candidates (projectile--find-matching-test impl-file))) (projectile--choose-from-candidates candidates))) (defun projectile-find-matching-file (test-file) "Compute the name of a file matching TEST-FILE." - (when-let ((candidates (projectile--find-matching-file test-file))) + (when-let* ((candidates (projectile--find-matching-file test-file))) (projectile--choose-from-candidates candidates))) (defun projectile-grep-default-files () @@ -4967,9 +5025,12 @@ directory to open." (lambda (f) (string-prefix-p project-root (expand-file-name f))) recentf-list))))) -(defun projectile-serialize-cache () - "Serializes the memory cache to the hard drive." - (projectile-serialize projectile-projects-cache projectile-cache-file)) +(defun projectile-project-cache-file (&optional project-root) + "The path to a project's cache file for PROJECT-ROOT. +Acts on the current project is not specified explicitly." + (if project-root + (expand-file-name projectile-cache-file project-root) + (projectile-expand-root projectile-cache-file))) (defvar projectile-configure-cmd-map (make-hash-table :test 'equal) @@ -5215,14 +5276,15 @@ project of that type" (defun projectile-compilation-dir () "Retrieve the compilation directory for this project." - (let* ((type (projectile-project-type)) - (directory (or projectile-project-compilation-dir + (let* ((project-root (projectile-acquire-root)) + (type (projectile-project-type project-root)) + (comp-dir (or projectile-project-compilation-dir (projectile-default-compilation-dir type)))) - (if directory + (if comp-dir (file-truename - (concat (file-name-as-directory (projectile-project-root)) - (file-name-as-directory directory))) - (projectile-project-root)))) + (concat (file-name-as-directory project-root) + (file-name-as-directory comp-dir))) + project-root))) (defun projectile-maybe-read-command (arg default-cmd prompt) "Prompt user for command unless DEFAULT-CMD is an Elisp function." @@ -5480,28 +5542,42 @@ An open project is a project with any open buffers." (delq nil (mapcar (lambda (buffer) (with-current-buffer buffer - (when-let ((project-root (projectile-project-root))) + (when-let* ((project-root (projectile-project-root))) (when (projectile-project-buffer-p buffer project-root) (abbreviate-file-name project-root))))) (buffer-list))))) (defun projectile--remove-current-project (projects) "Remove the current project (if any) from the list of PROJECTS." - (if-let ((project (projectile-project-root))) + (if-let* ((project (projectile-project-root))) (projectile-difference projects (list (abbreviate-file-name project))) projects)) (defun projectile--move-current-project-to-end (projects) "Move current project (if any) to the end of list in the list of PROJECTS." - (if-let ((project (projectile-project-root))) + (if-let* ((project (projectile-project-root))) (append (projectile--remove-current-project projects) (list (abbreviate-file-name project))) projects)) +(defun projectile--init-known-projects () + "Initialize the known projects. + +This might potentially clean up redundant projects +and discover new ones if `projectile-auto-discover' is enabled." + ;; load the known projects + (unless projectile-known-projects + (projectile-load-known-projects)) + (when projectile-auto-cleanup-known-projects + (projectile--cleanup-known-projects)) + (when (and projectile-auto-discover projectile-project-search-path) + (projectile-discover-projects-in-search-path))) + (defun projectile-relevant-known-projects () "Return a list of known projects." + (projectile--init-known-projects) (pcase projectile-current-project-on-switch ('remove (projectile--remove-current-project projectile-known-projects)) ('move-to-end (projectile--move-current-project-to-end projectile-known-projects)) @@ -5641,7 +5717,7 @@ Return a list of projects removed." (defun projectile-cleanup-known-projects () "Remove known projects that don't exist anymore." (interactive) - (if-let ((projects-removed (projectile--cleanup-known-projects))) + (if-let* ((projects-removed (projectile--cleanup-known-projects))) (message "Projects removed: %s" (mapconcat #'identity projects-removed ", ")) (message "No projects needed to be removed."))) @@ -6086,6 +6162,9 @@ thing shown in the mode line otherwise." (define-key map (kbd "f") #'projectile-find-file) (define-key map (kbd "g") #'projectile-find-file-dwim) (define-key map (kbd "F") #'projectile-find-file-in-known-projects) + ;; the h key is reserved for helm-projectile + ;; the binding below will be added when helm-projectile is enabled + ;; (define-key projectile-command-map (kbd "h") #'helm-projectile) (define-key map (kbd "i") #'projectile-invalidate-cache) (define-key map (kbd "I") #'projectile-ibuffer) (define-key map (kbd "j") #'projectile-find-tag) @@ -6107,9 +6186,14 @@ thing shown in the mode line otherwise." (define-key map (kbd "v") #'projectile-vc) (define-key map (kbd "V") #'projectile-browse-dirty-projects) ;; project lifecycle external commands - ;; TODO: Bundle those under some prefix key + (define-key map (kbd "c o") #'projectile-configure-project) + (define-key map (kbd "c c") #'projectile-compile-project) + (define-key map (kbd "c p") #'projectile-package-project) + (define-key map (kbd "c i") #'projectile-install-project) + (define-key map (kbd "c t") #'projectile-test-project) + (define-key map (kbd "c r") #'projectile-run-project) + ;; TODO: Legacy keybindings that will be removed in Projectile 3 (define-key map (kbd "C") #'projectile-configure-project) - (define-key map (kbd "c") #'projectile-compile-project) (define-key map (kbd "K") #'projectile-package-project) (define-key map (kbd "L") #'projectile-install-project) (define-key map (kbd "P") #'projectile-test-project) @@ -6260,6 +6344,7 @@ when opening new files." (concat root f)) (projectile-project-files root)))) +;;;###autoload (defun project-projectile (dir) "Return Projectile project of form ('projectile . root-dir) for DIR." (let ((root (projectile-project-root dir))) @@ -6288,20 +6373,6 @@ Otherwise behave as if called interactively. (projectile-mode ;; setup the commander bindings (projectile-commander-bindings) - ;; initialize the projects cache if needed - (unless projectile-projects-cache - (setq projectile-projects-cache - (or (projectile-unserialize projectile-cache-file) - (make-hash-table :test 'equal)))) - (unless projectile-projects-cache-time - (setq projectile-projects-cache-time - (make-hash-table :test 'equal))) - ;; load the known projects - (projectile-load-known-projects) - ;; update the list of known projects - (projectile--cleanup-known-projects) - (when projectile-auto-discover - (projectile-discover-projects-in-search-path)) (add-hook 'project-find-functions #'project-projectile) (add-hook 'find-file-hook 'projectile-find-file-hook-function) (add-hook 'projectile-find-dir-hook #'projectile-track-known-projects-find-file-hook t) -- 2.47.3