diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | doc/index.md | 1 | ||||
| -rw-r--r-- | doc/usage.md | 1 | ||||
| -rw-r--r-- | projectile.el | 82 |
5 files changed, 86 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index c9dba9f..bb02744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ * New command `projectile-run-term` (<kbd>C-c p x t</kbd>). * Let user unignore files in `.projectile` with the ! prefix. * Add a command to add all projects in a directory to the cache (`projectile-discover-projects-in-directory`). +* Add a command to list dirty version controlled projects (`projectile-browse-dirty-projects`). ### Changes @@ -44,6 +44,7 @@ it. Some of Projectile's features: * regenerate project etags or gtags (requires [ggtags](https://github.com/leoliu/ggtags)). * visit project in dired * run make in a project with a single key chord +* check for dirty repositories Here's a glimpse of Projectile in action: diff --git a/doc/index.md b/doc/index.md index e2d786d..2bb8198 100644 --- a/doc/index.md +++ b/doc/index.md @@ -34,6 +34,7 @@ it. Some of Projectile's features: * regenerate project etags or gtags (requires [ggtags](https://github.com/leoliu/ggtags)). * visit project in dired * run make in a project with a single key chord +* browse dirty version controlled projects Here's a glimpse of Projectile in action: diff --git a/doc/usage.md b/doc/usage.md index 9afa9dd..8b3ede1 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -34,6 +34,7 @@ Keybinding | Description <kbd>C-c p s g</kbd> | Run grep on the files in the project. <kbd>M-- C-c p s g</kbd> | Run grep on `projectile-grep-default-files` in the project. <kbd>C-c p v</kbd> | Run `vc-dir` on the root directory of the project. +<kbd>C-c p V</kbd> | Browse dirty version controlled projects. <kbd>C-c p b</kbd> | Display a list of all project buffers currently open. <kbd>C-c p 4 b</kbd> | Switch to a project buffer and show it in another window. <kbd>C-c p 4 C-o</kbd> | Display a project buffer in another window without selecting it. diff --git a/projectile.el b/projectile.el index 05ae86c..92d1732 100644 --- a/projectile.el +++ b/projectile.el @@ -984,6 +984,14 @@ Files are returned as relative paths to the project root." :group 'projectile :type 'string) +(defcustom projectile-vcs-dirty-state '("edited" "unregistered" "needs-update" "needs-merge" "unlocked-changes" "conflict") + "List of states checked by `projectile-browse-dirty-projects'. +Possible checked states are: +\"edited\", \"unregistered\", \"needs-update\", \"needs-merge\", unlocked-changes\" and \"conflict\", +as defined in `vc.el'." + :group 'projectile + :type '(repeat (string))) + (defun projectile-get-ext-command () "Determine which external command to invoke based on the project's VCS." (let ((vcs (projectile-project-vcs))) @@ -1084,6 +1092,74 @@ they are excluded from the results of this function." (when cmd (projectile-files-via-ext-command cmd)))) +(defun projectile-call-process-to-string (program &rest args) + "Invoke the executable PROGRAM with ARGS and return the output as a string." + (with-temp-buffer + (apply 'call-process program nil (current-buffer) nil args) + (buffer-string))) + +(defun projectile-shell-command-to-string (command) + "Try to run COMMAND without actually using a shell and return the output. + +The function `eshell-search-path' will be used to search the PATH +environment variable for an appropriate executable using the text +occuring before the first space. If no executable is found, +fallback to `shell-command-to-string'." + (cl-destructuring-bind + (the-command . args) (split-string command " ") + (let ((binary-path (eshell-search-path the-command))) + (if binary-path + (apply 'projectile-call-process-to-string binary-path args) + (shell-command-to-string command))))) + +(defun projectile-check-vcs-status (&optional PROJECT-PATH) + "Check the status of the current project. +If PROJECT-PATH is a project, check this one instead." + (let* ((PROJECT-PATH (or PROJECT-PATH (projectile-project-root))) + (project-status nil)) + (save-excursion + (vc-dir PROJECT-PATH) + ;; wait until vc-dir is done + (while (vc-dir-busy) (sleep-for 0 100)) + ;; check for status + (save-excursion + (save-match-data + (dolist (check projectile-vcs-dirty-state) + (goto-char (point-min)) + (when (search-forward check nil t) + (setq project-status (cons check project-status)))))) + (kill-buffer) + project-status))) + +(defun projectile-check-vcs-status-of-known-projects () + "Return the list of dirty projects. +The list is composed of sublists~: (project-path, project-status). +Raise an error if their is no dirty project." + (let ((projects projectile-known-projects) + (status ()) + (tmp-status nil)) + (dolist (project projects) + (condition-case nil + (setq tmp-status (projectile-check-vcs-status project)) + (error nil)) + (when tmp-status + (setq status (cons (list project tmp-status) status)))) + (when (= (length status) 0) + (message "No dirty projects has been found")) + status)) + +(defun projectile-browse-dirty-projects () + "Browse dirty version controlled projects." + (interactive) + (let ((status nil) + (mod-proj nil)) + (message "Checking for modifications in known projects...") + (setq status (projectile-check-vcs-status-of-known-projects)) + (while (not (= (length status) 0)) + (setq mod-proj (cons (car (pop status)) mod-proj))) + (projectile-vc + (projectile-completing-read "Select project: " mod-proj)))) + (defun projectile-files-via-ext-command (command) "Get a list of relative file names in the project root by executing COMMAND." (split-string (shell-command-to-string command) "\0" t)) @@ -3148,6 +3224,10 @@ is chosen." "Open project root in vc-dir or magit." (projectile-vc)) + (def-projectile-commander-method ?V + "Browse dirty projects" + (projectile-browse-dirty-projects)) + (def-projectile-commander-method ?r "Replace a string in the project." (projectile-replace)) @@ -3259,6 +3339,7 @@ is chosen." (define-key map (kbd "T") #'projectile-find-test-file) (define-key map (kbd "u") #'projectile-run-project) (define-key map (kbd "v") #'projectile-vc) + (define-key map (kbd "V") #'projectile-browse-dirty-projects) (define-key map (kbd "x e") #'projectile-run-eshell) (define-key map (kbd "x t") #'projectile-run-term) (define-key map (kbd "x s") #'projectile-run-shell) @@ -3296,6 +3377,7 @@ is chosen." ["Search in project (ag)" projectile-ag] ["Replace in project" projectile-replace] ["Multi-occur in project" projectile-multi-occur] + ["Browse dirty projects" projectile-browse-dirty-projects] "--" ["Run shell" projectile-run-shell] ["Run eshell" projectile-run-eshell] |
