Sort today's habits by priority in main agenda view - org-mode

I'd like to sort today's habits by priority in the main agenda view. I haven't yet found a way to do it. Here is what I've got in my custom.el (everything else is how I want it but the priority-down doesn't seem to work on habits the way I expect: A's before B's before C's):
'(org-agenda-sorting-strategy
(quote
((agenda time-up habit-up priority-down category-keep)
(todo priority-down category-keep)
(tags priority-down category-keep)
(search category-keep))))

Turns out org-habit-get-priority is called by org-agenda-get-scheduled in org-agenda.el. I copy org-agenda-get-scheduled and override it with a small change:
'priority (+ 94 (- 5 diff) (org-get-priority txt)) ;; (if habitp
;; (org-habit-get-priority habitp)
;; (+ 94 (- 5 diff) (org-get-priority txt)))
and voilá. It would be nice if org-habit-get-priority was a pluggable function that we could provide and if we didn't, it'd use the default as provided.

Related

Elisp: How to push-back to a list

Is there a way to push-back to a list in elisp?
The closest thing I found was
(add-to-list 'myList myValue t) ;; t tells it to put to back of the list
The problem, however, is that add-to-list enforces uniqueness. The other alternative is (push 'myList myVal) but that can only push to the front of a list. I tried using (cons myList myVal) but IIRC that returns something other than a list.
The only thing that has worked is
(setq myList (append myList (list myVal)))
but that syntax is hideous and feels like a lot of extra work to do something simple.
Is there a faster way to push to the back of a list. It's clearly possible as seen in (add-to-list), but is there a way to do it without enforcing uniqueness?
In other words, a good old push-back function like with C++ and the <List> class
Lisp lists vs "lists" in other languages
Lisp lists are chains of cons cells ("linked lists"), not specialized sequential containers like in C, and not a weird blend of lists and vectors like in Perl and Python.
This beautiful approach allows the same methodology to be applied to code and data, creating a programmable programming language.
The reasons Lisp does not have a "push-back" function are that
it does not need it :-)
it is not very well defined
No need
Adding to the end is linear in the length of the list, so, for
accumulation, the standard pattern is to combine
push while iterating and
nreverse when done.
Not well defined
There is a reason why add-to-list takes a symbol as the argument (which makes it useless for programming).
What happens when you are adding to an empty list?
You need to modify the place where the list is stored.
What happens when the list shares structure with another object?
If you use
(setq my-list (nconc my-list (list new-value)))
all the other objects are modified too.
If you write, like you suggested,
(setq my-list (append my-list (list new-value)))
you will be allocating (length my-list) cells on each addition.
Try this:
(defun prueba ()
(interactive)
(let ((mylist '(1 2 3)))
(message "mylist -> %s" mylist)
(add-to-list 'mylist 1 t)
(message "mylist -> %s" mylist)
(setq mylist '(1 2 3))
(add-to-list 'mylist 1 t '(lambda (a1 a2) nil))
(message "mylist -> %s" mylist)
))
adding a compare function that always returns nil as the fourth argument to add-to-list allows you
to add duplicates.

Emacs org-mode delete contents of a tree (or copy structure of tree without content)

I am trying to make a Natural Planning Tree (following advices from Getting Things Done by David Allen) which looks something like:
* Natural Planning Model
** ITEM 1
*** Purpose and Principles (Why)
*** Outcome Visioning
*** Brainstorming
*** Organizing
*** Identifying next actions
** ITEM 2...
** ITEM 3...
I would like to copy the outline structure of ITEM 1 to new ITEMS. But the problem is that I have already filled a lot of information inside the subtree for ITEM 1.
My general question is: Is there a way to delete the contents of a tree but not it's headers (the rows that start with *)? Similarly, is there a way to copy the structure of a tree without it's contents?
I don't recall a command that does this in Org, but you could make
your own pretty easily.
(defun org-copy-subtree-headings-as-kill ()
"Copy headings of current subtree as kill."
(interactive)
(save-excursion
(org-back-to-heading)
(let* ((el (org-element-at-point))
(beg (org-element-property :begin el))
(end (org-element-property :end el))
(tree (buffer-substring-no-properties beg end)))
(with-temp-buffer
(insert tree)
(goto-char (point-min))
(while (not (eobp))
(if (looking-at-p "^\\*")
(forward-line)
(delete-region (point-at-bol) (1+ (point-at-eol)))))
(kill-new (buffer-string))))))
Also, if these headings are often the same set of headings, you could
use a yasnippet template.
To delete the content from the current tree (instead of copying the headings), you could just narrow to the subtree and call keep-lines with ^\*.

How can I mark Org habits as done in the past

I regularly mark habits as DONE the day after the activity was done. The habits module automatically updates a bunch of dates in the metadata when I do this, but the date is always today. So then, I have to manually edit the SCHEDULED, LOGBOOK, and LAST_REPEAT states.
Is there a way to mark a habit as DONE for a day in the past? So instead of doing C-c C-t d (I have "d" set up as "DONE") I could get a prompt which asked me for a date.
I've wanted to do this for some time, too, and your question inspired me to finally figure it out.
There is a function called "org-todo-yesterday." By default, it's not mapped to any keys, but you could always call it with M-x org-todo-yesterday (or map it if you're using it a lot). For me, it breaks because it calls "third" which isn't a defined function in my install.
For a more generic function that prompts us for the date and marks things as done at that time, we can add this function (inspired by org-todo-yesterday) to our emacs init file. It will act as if you finished things at 23:59 on the target date, which is hopefully good enough.
(defun dk/org-todo-custom-date (&optional arg)
"Like org-todo-yesterday, but prompt the user for a date. The time
of change will be 23:59 on that day"
(interactive "P")
(let* ((hour (nth 2 (decode-time
(org-current-time))))
(daysback (- (date-to-day (current-time-string)) (org-time-string-to-absolute (org-read-date))))
(org-extend-today-until (+ 1 (* 24 (- daysback 1)) hour))
(org-use-effective-time t)) ; use the adjusted timestamp for logging
(if (eq major-mode 'org-agenda-mode)
(org-agenda-todo arg)
(org-todo arg))))
Will this work? This simply completes the habit and reschedule it for today
(defun org-todo-yesterday2 (&optional arg)
(interactive "P")
(org-todo-yesterday arg)
(org-schedule arg (format-time-string "%Y-%m-%d")
)
)

How to distinguish between different overlays at point

ORIGINAL QUESTION:  I'm looking for some assistance, please, to distinguish between overlays that may exist at point. If the overlays-at point is made with the lawlist-red-face then do X. If the overlays-at point is made with calendar-holiday-marker, then do Y. The overlays are made with these two functions.
(calendar-mark-visible-date (car holiday) lawlist-red-face)
(calendar-mark-visible-date (car holiday) calendar-holiday-marker)
EDIT (January 1, 2014):  #Drew wrote a nice test for this in calendar+.el ( http://www.emacswiki.org/emacs/calendar%2B.el ):
(when
(memq lawlist-red-face
(mapcar (function (lambda (ovr)
(overlay-get ovr 'face))) (overlays-at (point))))
... )
EDIT (February 13, 2014):  The above-listed snippet can also be used in conjunction with something like (while (re-search-backward "[0-9]" nil t) to create a combined list of dates with overlays -- month, day and year are extracted with calendar-extract-day, calendar-extract-month and calendar-extract-year -- the date is obtained with (calendar-cursor-to-nearest-date):
;; modified with the help of #phils based on comments down below.
(setq lawlist-mouse-marked
(append lawlist-mouse-marked
`((holiday-sexp '(list ,month ,day ,year) ""))))
That list can then be used with something like calendar-holiday-list (or the modified code below) to remark dates on a new calendar layout after it has been generated. This is useful if the user has manually marked dates (e.g., with the mouse) and wants those dates to reappear after scrolling the calendar forwards / backwards. The library holidays.el contains the function holiday-sexp which uses a filtering function holiday-filter-visible-calendar to edit the list of dates so that only those that are visible on the new calendar get marked:
(dolist (holiday
(let (res h err)
(sort
(dolist (p lawlist-mouse-marked res)
(if (setq h (eval p))
(setq res (append h res))))
'calendar-date-compare)))
(calendar-mark-visible-date (car holiday) lawlist-mouse-calendar-face))
Ok, let's try to figure this out (without really knowing anything about the calendar).
(overlays-at) returns a list of overlays. I will keep this simple and only handle the first, if you want to examine all of them, simply loop over them until you find one that is suitable.
Also, the face property can be more complex than simply the name of the face, if that is the case you would need to handle that as well.
But anyway, here is a simple piece of code that (hopefully) does what you want:
(let ((overlays (overlays-at (point))))
(if overlays
(let ((face (overlay-get (car overlays) 'face)))
(cond ((eq face 'lawlist-red-face)
;; Do something
)
((eq face 'holiday)
;; Do another thing
)
(t
;; Do something else)))))

How could I implement the push macro?

Can someone help me understand how push can be implemented as a macro? The naive version below evaluates the place form twice, and does so before evaluating the element form:
(defmacro my-push (element place)
`(setf ,place (cons ,element ,place)))
But if I try to fix this as below then I'm setf-ing the wrong place:
(defmacro my-push (element place)
(let ((el-sym (gensym))
(place-sym (gensym)))
`(let ((,el-sym ,element)
(,place-sym ,place))
(setf ,place-sym (cons ,el-sym ,place-sym)))))
CL-USER> (defparameter *list* '(0 1 2 3))
*LIST*
CL-USER> (my-push 'hi *list*)
(HI 0 1 2 3)
CL-USER> *list*
(0 1 2 3)
How can I setf the correct place without evaluating twice?
Doing this right seems to be a little more complicated. For instance, the code for push in SBCL 1.0.58 is:
(defmacro-mundanely push (obj place &environment env)
#!+sb-doc
"Takes an object and a location holding a list. Conses the object onto
the list, returning the modified list. OBJ is evaluated before PLACE."
(multiple-value-bind (dummies vals newval setter getter)
(sb!xc:get-setf-expansion place env)
(let ((g (gensym)))
`(let* ((,g ,obj)
,#(mapcar #'list dummies vals)
(,(car newval) (cons ,g ,getter))
,#(cdr newval))
,setter))))
So reading the documentation on get-setf-expansion seems to be useful.
For the record, the generated code looks quite nice:
Pushing into a symbol:
(push 1 symbol)
expands into
(LET* ((#:G906 1) (#:NEW905 (CONS #:G906 SYMBOL)))
(SETQ SYMBOL #:NEW905))
Pushing into a SETF-able function (assuming symbol points to a list of lists):
(push 1 (first symbol))
expands into
(LET* ((#:G909 1)
(#:SYMBOL908 SYMBOL)
(#:NEW907 (CONS #:G909 (FIRST #:SYMBOL908))))
(SB-KERNEL:%RPLACA #:SYMBOL908 #:NEW907))
So unless you take some time to study setf, setf expansions and company, this looks rather arcane (it may still look so even after studying them). The 'Generalized Variables' chapter in OnLisp may be useful too.
Hint: if you compile your own SBCL (not that hard), pass the --fancy argument to make.sh. This way you'll be able to quickly see the definitions of functions/macros inside SBCL (for instance, with M-. inside Emacs+SLIME). Obviously, don't delete those sources (you can run clean.sh after install.sh, to save 90% of the space).
Taking a look at how the existing one (in SBCL, at least) does things, I see:
* (macroexpand-1 '(push 1 *foo*))
(LET* ((#:G823 1) (#:NEW822 (CONS #:G823 *FOO*)))
(SETQ *FOO* #:NEW822))
T
So, I imagine, mixing in a combination of your version and what this generates, one might do:
(defmacro my-push (element place)
(let ((el-sym (gensym))
(new-sym (gensym "NEW")))
`(let* ((,el-sym ,element)
(,new-sym (cons ,el-sym ,place)))
(setq ,place ,new-sym)))))
A few observations:
This seems to work with either setq or setf. Depending on what problem you're actually trying to solve (I presume re-writing push isn't the actual end goal), you may favor one or the other.
Note that place does still get evaluated twice... though it does at least do so only after evaluating element. Is the double evaluation something you actually need to avoid? (Given that the built-in push doesn't, I'm left wondering if/how you'd be able to... though I'm writing this up before spending terribly much time thinking about it.) Given that it's something that needs to evaluate as a "place", perhaps this is normal?
Using let* instead of let allows us to use ,el-sym in the setting of ,new-sym. This moves where the cons happens, such that it's evaluated in the first evaluation of ,place, and after the evaluation of ,element. Perhaps this gets you what you need, with respect to evaluation ordering?
I think the biggest problem with your second version is that your setf really does need to operate on the symbol passed in, not on a gensym symbol.
Hopefully this helps... (I'm still somewhat new to all this myself, so I'm making some guesses here.)