Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any interest in a :head selector? #172

Closed
pkazmier opened this issue Nov 3, 2020 · 7 comments
Closed

Is there any interest in a :head selector? #172

pkazmier opened this issue Nov 3, 2020 · 7 comments
Assignees
Milestone

Comments

@pkazmier
Copy link
Contributor

@pkazmier pkazmier commented Nov 3, 2020

I wrote the following to filter the first N or last N items from a grouping. Would this be worthwhile submitting a PR for? Please bear with me as I'm an elisp novice:

  (defun org-super-agenda--group-dispatch-head (items group)
    "Group N ITEMS that match selectors in (cdr GROUP) where N is the (car
GROUP). If N is positive, take the top N items. If N is negative, take the
botton N items."
    (-let* ((n (car group))
            ((name non-matching matching) (org-super-agenda--group-dispatch items (cdr group)))
            (pos-args (if (< n 0) (list n) (list 0 n)))
            (placement (if (< n 0) "Last" "First"))
            (name (format "%s %d %s" placement (abs n) name)))
      (list name non-matching (apply #'seq-subseq matching pos-args))))
  (setq org-super-agenda-group-types (plist-put org-super-agenda-group-types
                                                :head 'org-super-agenda--group-dispatch-head))

My use case is that I track various projects and todos assigned to members on my team. In addition, I hold bi-weekly 1:1s with each associate. In these meetings, I want a tailored Agenda view to show all relevant information I might need including easy access to the last 3 meetings with them. Thanks to this awesome package (and org-ql), this is what I've built:

Screen Shot 2020-11-03 at 11 23 30 AM

The key part is the "Last 3 Meetings" section which I was unable to figure out how to build without writing my own :head selector (like the Unix command). It lets you filter the first N or last N items from the list, and more importantly, it eats the remainder (does not pass along as a non-matching item).

And here is how I use this selector to build the view above:

  (defun one-on-one (shortcut name)
    (let ((tagname (downcase (s-replace " " "" name))))
      `(,shortcut ,(concat name " Meetings and Todos")
                  ((org-ql-block '(or (tags ,tagname) (heading ,(concat name " 1:1")))
                                 ((org-super-agenda-groups
                                   '((:name "Today" :scheduled today)
                                     (:name "Due today" :deadline today)
                                     (:name "Important" :priority "A")
                                     (:name "Overdue" :deadline past)
                                     (:name "Due soon" :deadline future)
                                     (:name "Scheduled" :scheduled future :order 99)
                                     (:name "Next" :todo "TODO")
                                     (:name "Waiting" :todo "WAIT")
                                     (:name "Projects" :todo ("PROJ"))
                                     (:name "Last 3 Meetings" :head (-3 :heading-regexp "1:1"))  ; Only show last 3 meetings!
                                     (:name "On-hold" :todo "HOLD" :order 100)))))))))

  (setq org-agenda-custom-commands
        `(("p" "My agenda view"
           ((agenda "")
            (alltodo "" ((org-agenda-overriding-header "")
                         (org-super-agenda-groups
                          '((:log t)  ; Automatically named "Log"
                            (:name "Today" :scheduled today)
                            (:habit t)
                            (:name "Due today" :deadline today)
                            (:name "Important" :priority "A")
                            (:name "Overdue" :deadline past)
                            (:name "Due soon" :deadline future)
                            (:name "Scheduled" :scheduled future :order 99)
                            (:name "Next" :todo "TODO")
                            (:name "Projects" :todo ("PROJ"))
                            (:name "Waiting" :todo "WAIT" :order 98)
                            (:name "On-hold" :todo "HOLD" :order 100)))))))
          ,(one-on-one "fa" "Alan")
          ,(one-on-one "fb" "Brian")
          ,(one-on-one "fg" "Greg")
          ,(one-on-one "fk" "Kyle")
          ;; many others omitted 
          ))
  (org-super-agenda-mode 1))
@alphapapa
Copy link
Owner

@alphapapa alphapapa commented Nov 3, 2020

Hi Pete,

You could have fooled me about your being an Elisp novice. This is very well done!

On one hand, I'd prefer to handle this kind of functionality by extending org-ql. However, it's not clear to me what the best way to do that would be. And, of course, that wouldn't do anything for Org Agenda views (i.e. ones that don't use org-ql).

So I think you're right that this would be useful to have in org-super-agenda. And the implementation is only a few lines of code!

Here are a few thoughts:

  1. We should be careful to document that ordering of entries is not guaranteed to be preserved (see other issues filed here about sorting), so taking the first or last N entries may not always show the expected entries.
  2. Since it can take from either end of the list, maybe it should be called :take (following the naming of, e.g. seq-take).

What do you think?

Thanks.

Loading

@pkazmier
Copy link
Contributor Author

@pkazmier pkazmier commented Nov 3, 2020

Thank you.

And, sure, I'll rename it to take. I didn't realize there was a seq-take, so that makes sense to me. I'll put a PR together later this week or weekend. I'll be sure to update the documentation to reflect the ordering you mention.

Thanks again for such an awesome set of packages!

Loading

@alphapapa
Copy link
Owner

@alphapapa alphapapa commented Nov 3, 2020

Thanks for the kind words. I'm looking forward to your PR. Please feel free to ping me if I overlook it or forget about it. As you can see from the PR list, there are some others I haven't gotten to yet... :)

Loading

@alphapapa
Copy link
Owner

@alphapapa alphapapa commented Nov 3, 2020

BTW, you may find this interesting: https://github.com/alphapapa/burly.el Yesterday I added Emacs bookmark support to org-ql and org-sidebar, so now Org QL View buffers can be bookmarked and restored with Burly. If you have any feedback, I'd appreciate it.

Loading

@sundbp
Copy link

@sundbp sundbp commented Nov 6, 2020

fwiw - this is a small tweak to deal with the cases where there are less number of matches than the number given as argument:

(defun org-super-agenda--group-dispatch-take (items group)
  "Group N ITEMS that match selectors in (cdr GROUP) where N is the (car
GROUP). If N is positive, take the top N items. If N is negative, take the
botton N items."
  (-let* ((n (car group))
          ((name non-matching matching) (org-super-agenda--group-dispatch items (cdr group)))
          (num-matches (length matching))
          (pos-args (if (< n 0) (list (max (- num-matches) n)) (list 0 (min num-matches n))))
          (placement (if (< n 0) "Last" "First"))
          (name (format "%s %d %s" placement (abs n) name)))
    (list name non-matching (apply #'seq-subseq matching pos-args))))
(setq org-super-agenda-group-types (plist-put org-super-agenda-group-types
                                                  :take 'org-super-agenda--group-dispatch-take))

Loading

@alphapapa
Copy link
Owner

@alphapapa alphapapa commented Nov 6, 2020

@sundbp

fwiw - this is a small tweak to deal with the cases where there are less number of matches than the number given as argument:

Thanks. Note that it would be preferable to avoid calling length. Since we use the dash library in this package, it would probably be better to replace seq-subseq with -take, which doesn't signal an error if the list is shorter than the number of items requested, e.g.

(-take 4 '(0 1 2))  ;;=> (0 1 2)

And -take-last can be used for the tail.

Loading

@sundbp
Copy link

@sundbp sundbp commented Nov 6, 2020

Loading

@alphapapa alphapapa self-assigned this Nov 11, 2020
@alphapapa alphapapa added this to the 1.2 milestone Nov 11, 2020
@alphapapa alphapapa removed this from the 1.2 milestone Nov 20, 2020
@alphapapa alphapapa added this to the 1.3 milestone Nov 20, 2020
@alphapapa alphapapa closed this in ab30080 Sep 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants