org-mode: Getting logbook notes - emacs

I figured out how to get entries I want using org-agenda-get-day-entries but that only returns the headline and its properties for each entry. Is there any way to access the LOGBOOK of the corresponding entry and in particular any notes stored there? I'd like to get the date each note was made as well so I can filter them.
The documentation on the elements API isn't great and I'm not sure I can even use it given a list of headlines.

You can parse the drawer at point with org-element-property-drawer-parser:
(defun org-get-logbook-notes ()
(save-excursion
(unless (org-at-heading-p)
(outline-previous-heading))
(when (re-search-forward ":LOGBOOK:" (save-excursion
(outline-next-heading)
(point))
t)
(let* ((elt (org-element-property-drawer-parser nil))
(beg (org-element-property :contents-begin elt))
(end (org-element-property :contents-end elt)))
(buffer-substring-no-properties beg end)))))

The accepted answer is great, but in the spirit of providing alternatives, the org-ml project provides a functional API implemented over the org element API.
It contains a number of conveniences for working with org files, and is idiomatically similar to other modern Emacs packages like dash, with which the user may already be familiar. In this case, using the org-ml-headline-get-logbook-items function might be preferable to finding and parsing the logbook by hand.
OTOH, it doesn't ship by default with Emacs, which may be a consideration.

Related

Easiest Regexp for words-with-dashes-but-no-whitespace

What is the most convenient regexp for selecting text like "words-with-dashes-but-no-whitespace", when the goal is to select just this but no whitespace?
I used (search-forward-regexp "\\s-") but I believe this could be easier.
I mainly would like this for selecting the word at point including dashes, and using buffer-substring-no-properties to set it as a variable.
EDIT: Answer was given by artscan in a comment. Using (current-word) solves this.
But now this: how to delete this (current-word) including-dashes-that-is?
I use so far (delete-backward-char (string-width (current-word))
To answer the second question, try:
(let ((bounds (bounds-of-thing-at-point 'symbol)))
(when bounds
(delete-region (car bounds) (cdr bounds))))
It's less dependent on point location than (delete-backward-char ...).

How can I trigger an event when a Yasnippet macro can fire?

I love yasnippet, but it requires time to memorize. What I'd like to do is change the cursor color when I am at a point that can expand a macro (and back again when there is no macro). However, from what I remember about how yasnippet works, that might not exactly be performant.
A friend suggested that what I want here is a yasnippet-can-fire-p, but I'm still not sure as to the best way to go about doing this. What's the cleanest path towards implementing this that won't drive my sistem to a grinding halt?
Took some time to find the function that did the checking whether or not it can expand, but was 'lucky' enough to find it eventually.
The key is that this function would normally expand, or otherwise, perform the fallback behavior. I cloned this function and set the cursor colors in those places instead.
And, surprisingly, it actually does not slow down at all.
;; It will test whether it can expand, if yes, cursor color -> green.
(defun yasnippet-can-fire-p (&optional field)
(interactive)
(setq yas--condition-cache-timestamp (current-time))
(let (templates-and-pos)
(unless (and yas-expand-only-for-last-commands
(not (member last-command yas-expand-only-for-last-commands)))
(setq templates-and-pos (if field
(save-restriction
(narrow-to-region (yas--field-start field)
(yas--field-end field))
(yas--current-key))
(yas--current-key))))
(set-cursor-color (if (and templates-and-pos (first templates-and-pos))
"green" "red"))))
; As pointed out by Dmitri, this will make sure it will update color when needed.
(add-hook 'post-command-hook 'yasnippet-can-fire-p)
Added this to my lisp collection (I was actually thinking that this would be useful as well).
Update: In latest version of yasnippet [from august 2014, from 0.8.1], yas--current-key function has been renamed into yas--templates-for-key-at-point. cf Issue

Highlighting symbols automatically in Emacs

I am looking for a way to highlight symbols automatically, possibly using the package highlight-symbol.el (link).
I was wondering, is there a way so that, the first argument of all (setq ) will get automatically highlighted?
(setq thisshouldbehighlighted 1)
..and all the subsequent times when that symbol has been used / will be used.
First of all, the following code is based on version 1.2 of highlight-symbol. Older versions lack the function highlight-symbol-add-symbol.
The basic approach is to search the buffer for "(setq ". The actual regular expression is a bit more complex, as it allows whitespace and handles defvar and defcustom.
(defun highlight-all-symbols ()
(interactive)
(save-excursion
(highlight-symbol-mode 1)
(goto-char (point-min))
(while (re-search-forward (concat "([ \t\n]*"
"\\_<\\(?:"
"setq\\|defvar\\|defcustom"
"\\)\\_>[ \t\n]*"
"\\(\\_<\\(?:\\sw\\|\\s_\\)+\\_>\\)")
nil t)
(highlight-symbol-add-symbol (concat "\\_<"
(regexp-quote (match-string 1))
"\\_>")))))
You'll probably want to include the code in a mode hook
(add-hook 'emacs-lisp-mode-hook 'highlight-all-symbols)
Of course, simply highlighting all symbols set with setq can't be a perfect solution, as it ignores variable namespaces. Handling this correctly is a much bigger task, though, as it requires parsing the code. If you want to go down that rabbit hole, this might give you an idea, but I'm afraid it's not particularly documented.

Insert yasnippet by name

I want to insert a specific yasnippet as part of a function in emacs-lisp. Is there a way to do that?
The only command that seems related is yas/insert-snippet, but it simply opens a popup with all the options and the documentation doesn't say anything about bypassing the popup by specifing the snippet name.
yas/insert-snippet is indeed just a thin wrapper around yas/expand-snippet for interactive use. However, the internal structures are... interesting. Judging from the source code the following does work for me when I want to expand the "defun" snippet in elisp-mode:
(yas/expand-snippet
(yas/template-content (cdar (mapcan #'(lambda (table)
(yas/fetch table "defun"))
(yas/get-snippet-tables)))))
As the author of yasnippet, I think you'd rather not rely on internal details of yasnippet's interesting data structures, which may change in the future. I would do this based on the documentation of yas/insert-snippet and yas/prompt-functions:
(defun yas/insert-by-name (name)
(flet ((dummy-prompt
(prompt choices &optional display-fn)
(declare (ignore prompt))
(or (find name choices :key display-fn :test #'string=)
(throw 'notfound nil))))
(let ((yas/prompt-functions '(dummy-prompt)))
(catch 'notfound
(yas/insert-snippet t)))))
(yas/insert-by-name "defun")
I'm just getting into yasnippet and I wanted to automatically insert one of my snippets upon opening a new file for certain modes. That led me to here but I've generated a slightly different solution. Providing yet another alternative: ("new-shell" is the name of my personal snippet for providing a new shell script template)
(defun jsm/new-file-snippet (key)
"Call particular yasnippet template for newly created
files. Use by adding a lambda function to the particular mode
hook passing the correct yasnippet key"
(interactive)
(if (= (buffer-size) 0)
(progn
(insert key)
(call-interactively 'yas-expand))))
(add-hook 'sh-mode-hook '(lambda () (jsm/new-file-snippet "new-shell")))
IMO, my solution is a tad less susceptible to breaking should yasnippet change dramatically.
This is 2022 now, so we can simply do the following :
(yas-expand-snippet (yas-lookup-snippet "name-of-your-snippet"))
See the documentation

Emacs: highlighting TODO *only* in comments

This question is related to another one, Emacs :TODO indicator at left side. I recently came across a minor mode I like a lot called FixmeMode. It supports auto highlighting of TODO marks, and navigating between them. However, I think it makes more sense to recognize the "TODO" strings only in comments, rather than polluting the whole file. Is it possible?
Check out the library fic-mode.el, it has been verified in C++ and Emacs-Lisp.
It was written specifically to answer this question.
The installation is like any standard package:
(require 'fic-mode)
(add-hook 'c++-mode-hook 'turn-on-fic-mode)
Though Wei Hu did ask for an easy way to add it to multiple modes, so here goes:
(defun add-something-to-mode-hooks (mode-list something)
"helper function to add a callback to multiple hooks"
(dolist (mode mode-list)
(add-hook (intern (concat (symbol-name mode) "-mode-hook")) something)))
(add-something-to-mode-hooks '(c++ tcl emacs-lisp) 'turn-on-fic-mode)
It's possible but quite a bit trickier. Fixme mode uses font-lock to do its highlighting, so it works on an as-you-type basis to highlight the keywords. Font-lock hooks in at a very low level, basically running after every change is made to the buffer's contents. It is highly optimized, though, which allows it to appear instantaneous on modern computers.
The TODO indicator in the left fringe is static. Execute the function and all current TODO's are highlighted; change the buffer (adding or removing TODO's) does not change the fringe indicator; that's only changed when the function runs again.
Your approach would have to get into syntax tables, determining first when you're in a comment and then looking for the keywords. The tricky part comes in doing this interactively (i.e. as you type). You should be able to hook into the font-lock constructs to do this, but the function you provide to search for the comment syntax table and then for the keywords better be very efficient, as it will be run each and every time a buffer changes (though it will only run on the changed region, I think). You would want to stuff all of this in font-lock-syntactic-keywords rather than font-lock-keywords because the syntactic-keyword pass happens before the syntactic pass (which happens before the keyword pass), and you need to set TODO inside comments before comments themselves are set.
Sorry it's not a full working-code answer.....
Maybe this will help: there's a fn c-in-literal in
cc-mode, and a similar csharp-in-literal in csharp mode. The
return value is c if in a C-style comment, c++ if in a C++
style comment. You could add that to the code at
Emacs :TODO indicator at left side
to get what you want.
(defun annotate-todo ()
"put fringe marker on TODO: lines in the curent buffer"
(interactive)
(let (lit)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "TODO:" nil t)
(progn
(setq lit (c-in-literal)) ;; or csharp-in-literal
(if (or (eq lit 'c) (eq lit 'c++))
(let ((overlay (make-overlay (- (point) 5) (point))))
(overlay-put overlay 'before-string
(propertize "A"
'display
'(left-fringe ;; right
horizontal-bar
better-fringes-important-bitmap))))))))))
https://github.com/tarsius/hl-todo seems to do exactly what you want. I just tried it and love it.