From 6ffcf45767543c72e817d9de8bca9db9156a48be Mon Sep 17 00:00:00 2001 From: Eric Danan Date: Wed, 18 Jul 2018 17:42:46 +0200 Subject: [PATCH] cp-org-capture: offer both project-specific and regular templates The regular templates determined by the variables `org-capture-templates` and `org-capture-templates-contexts` are now added to the project-specific templates. If not inside a project, the project templates are ignored. Thus `counsel-projectile-org-capture` can now systematically be used instead of `org-capture` or `counsel-org-capture`. --- README.md | 23 +++++++----- counsel-projectile.el | 84 ++++++++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 52efbf9..51e9515 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ New commands: | :------------------- | :------------------------------- | :-------------------------------------------------- | | C-c p SPC | `counsel-projectile` | Jump to a project buffer or file, or switch project | | C-c p s r | `counsel-projectile-rg` | Search project with rg | -| C-c p O c | `counsel-projectile-org-capture` | Org-capture into project | +| C-c p O c | `counsel-projectile-org-capture` | Capture into project | | C-c p O a | `counsel-projectile-org-capture` | Open project agenda | ## The `counsel-projectile` command Default key binding: C-c p SPC. @@ -117,7 +117,8 @@ This command is a replacement for `projectile-switch-project`. It adds the possi | x s | Invoke shell from the project root | | x e | Invoke eshell from the project root | | x t | Invoke term from the project root | -| O | Org-capture into project: call `counsel-projectile-org-capture` (see below) | +| O c | Capture into project: call `counsel-projectile-org-capture` (see below) | +| O a | Open project agenda: call `counsel-projectile-org-agenda` (see below) | ## The `counsel-projectile-find-file` command Default key binding: C-c p f. @@ -173,7 +174,9 @@ This command is similar to `counsel-projectile-grep` (see above) but uses `rg` ( ## The `counsel-projectile-org-capture` command Default key binding: C-c p O c. -This command lets you capture something (a note, todo item, ...) into the current project using org-mode's `org-capture` (actually `counsel-org-capture`) command. Like `org-capture`, it first lets you select a capture template then file the newly captured information. By default, there is a single template storing the captured information into file `notes.org` in the project root directory, under headline `Tasks`. +This command is a replacement for `org-capture` (or `counsel-org-capture`) offering project-specific capture templates, in addition to the regular templates available from `org-capture`. By default, there is a single project template, named `[] Tasks`, which stores the captured information under headline `Tasks` in file `/notes.org`. + +If not inside a project, the project templates are ignored and only the regular ones are offered. So you may want to systematically use `counsel-projectile-org-capture` isntead of `org-capture` or `counsel-org-capture` (you may also want to give it a global key binding, such as `C-c c`). ## The `counsel-projectile-org-agenda` command Default key binding: C-c p O a. @@ -217,9 +220,12 @@ Extra actions can be added to these lists or, alternatively, can be set through - change the index of the default action. See its docstring for details. ## Setting `counsel-projectile-org-capture` templates -The available capture templates for `counsel-projectile-org-capture` are read from the variable `counsel-projectile-org-capture-templates`. This variable has the same format as the variable `org-capture-templates`, except that in all strings of in an entry’s target slot, all instances of `${root}` and `${name}` are replaced with the current project root and name, respectively. +The project-specific capture templates for `counsel-projectile-org-capture` are read from the variable `counsel-projectile-org-capture-templates`. This variable has the same format as the variable `org-capture-templates`, except that in a template's name or target, the placeholders `${root}` and +`${name}` can be used to stand for the current project root and +name, respectively. -The default value contains a single template, whose target is: +The default value contains a single template, whose name is +`[${name}] Task` and whose target is: ```emacs-lisp (file+headline "${root}/notes.org}" "Tasks") @@ -227,15 +233,16 @@ The default value contains a single template, whose target is: This points to headline `Tasks` in file `notes.org` in the project root directory (one file per project). -Another example of a valid target is: +Two other examples of valid targets are: ```emacs-lisp +(file+headline "${root}/${name}.org}" "Tasks") (file+olp "~/notes.org" "${root}" "Tasks") ``` -This points to outline path `/Tasks` in file `~/notes.org` (same file for all projects). +The first one is similar to the default value's target, except that the file is named after the project name (this can be handy if you use org-mode's agenda since the project name is then displayed as category). The second one points to outline path `/Tasks` in file `~/notes.org` (same file for all projects). -Templates contexts are read from the variable `counsel-projectile-org-capture-templates-contexts`, which has the same format as `org-capture-templates-contexts` +Project-specific template contexts are read from the variable `counsel-projectile-org-capture-templates-contexts`, which has the same format as `org-capture-templates-contexts` ## Removing the current project or buffer from the list of candidates By default, when calling `counsel-projectile-switch-project`, the current project (if any) is included in the candidates list and preselected. Similarly, when calling `counsel-projectile-switch-to-buffer`, the current buffer is included in the candidates list and preselected. If you prefer removing these elements from the candidate lists of these commands, you can set the variables `counsel-projectile-remove-current-project` and `counsel-projectile-remove-current-buffer` accordingly. ## Initial input for the project search commands diff --git a/counsel-projectile.el b/counsel-projectile.el index fb60326..b99a5e3 100644 --- a/counsel-projectile.el +++ b/counsel-projectile.el @@ -781,16 +781,18 @@ is called with a prefix argument." (defvar org-capture-templates-contexts) (defcustom counsel-projectile-org-capture-templates - '(("t" "Task" entry (file+headline "${root}/notes.org" "Tasks") + '(("t" "[${name}] Task" entry (file+headline "${root}/notes.org" "Tasks") "* TODO %?\n %u\n %a")) - "Templates for the creation of new entries with `counsel-projectile-org-capture'. + "Project-specific templates for the creation of new entries +with `counsel-projectile-org-capture'. The format is the same as in `org-capture-templates', except that -in all strings of in an entry's target slot, all instances of -\"${root}\" and \"${name}\" are replaced with the current project -root and name, respectively. +in a template's name or target, the placeholders \"${root}\" and +\"${name}\" can be used to stand for the current project root and +name, respectively. -The default value contains a single template, whose target is: +The default value contains a single template, whose name is +\"[${name}] Task\" and whose target is: \(file+headline \"${root}/notes.org}\" \"Tasks\"\) @@ -912,44 +914,54 @@ The format is the same as in `org-capture-templates-contexts'." ;;;###autoload (defun counsel-projectile-org-capture (&optional from-buffer) - "Org-capture into the current project. + "Capture into the current project. -The capture templates are read from the variables -`counsel-projectile-org-capture-templates' and -`counsel-projectile-org-capture-templates-contexts'. +This command is a replacement for `org-capture' (or +`counsel-org-capture') offering project-specific capture +templates, in addition to the regular templates available from +`org-capture'. These project templates, which are \"expanded\" +relatively to the current project, are determined by the +variables `counsel-projectile-org-capture-templates' and +`counsel-projectile-org-capture-templates-contexts'. See the +former variable in particular for details. Optional argument FROM-BUFFER specifies the buffer from which to capture." (interactive) (require 'org-capture) - (let* ((root (projectile-project-root)) + (let* ((root (ignore-errors (projectile-project-root))) (name (projectile-project-name)) + (org-capture-templates-contexts + (append (when root + counsel-projectile-org-capture-templates-contexts) + org-capture-templates-contexts)) (org-capture-templates - (cl-loop - for template in counsel-projectile-org-capture-templates - collect (cl-loop - for item in template - if (= (cl-position item template) 3) ;; template's target - collect (cl-loop - for x in item - if (stringp x) - collect (replace-regexp-in-string - "\\${[^}]+}" - (lambda (s) - (pcase s - ("${root}" root) - ("${name}" name))) - x) - else - collect x) - else - collect item))) - (org-capture-templates-contexts counsel-projectile-org-capture-templates-contexts) - (ivy--prompts-list ivy--prompts-list)) - (ivy-set-prompt 'counsel-org-capture - (lambda () - (ivy-add-prompt-count - (projectile-prepend-project-name (ivy-state-prompt ivy-last))))) + (append + (when root + (cl-loop + with replace-fun = `(lambda (string) + (replace-regexp-in-string + "\\${[^}]+}" + (lambda (s) + (pcase s + ("${root}" ,root) + ("${name}" ,name))) + string)) + for template in counsel-projectile-org-capture-templates + collect (cl-loop + for item in template + if (= (cl-position item template) 1) ;; template's name + collect (funcall replace-fun item) + else if (= (cl-position item template) 3) ;; template's target + collect (cl-loop + for x in item + if (stringp x) + collect (funcall replace-fun x) + else + collect x) + else + collect item))) + org-capture-templates))) (with-current-buffer (or from-buffer (current-buffer)) (counsel-org-capture))))