org-deadline -- change all in selected block in one fell swoop - emacs

Could someone please steer me in the right direction towards automating this function so that I only type the date one time (or select it with the mouse from the built-in popup calendar) and hit the return key, and then it repeats the process all by itself until finished.
(setq org-loop-over-headlines-in-active-region t)
(defun change-all-deadlines ()
"Change all deadlines in the group of tasks that are selected / highlighted."
(interactive)
(org-deadline)
(org-map-entries)
(let (new-date
(minibuffer-message "Please insert the new date, and then press RET to continue.")
[User enters (with choice to use built-in calendar popup): July 5, 2013]
(format "%s" (new-date))
[Then magic happens automatically -- :)]
(minibuffer-message "Congratulations -- all dates have been changed to %s." new-date))))
EDIT: Here is the main function from .../lisp/org.el
(defun org-deadline (&optional remove time)
"Insert the \"DEADLINE:\" string with a timestamp to make a deadline.
With argument REMOVE, remove any deadline from the item.
With argument TIME, set the deadline at the corresponding date. TIME
can either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
(interactive "P")
(if (and (org-region-active-p) org-loop-over-headlines-in-active-region)
(let ((cl (if (eq org-loop-over-headlines-in-active-region 'start-level)
'region-start-level 'region))
org-loop-over-headlines-in-active-region)
(org-map-entries
`(org-deadline ',remove ,time)
org-loop-over-headlines-in-active-region
cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
(let* ((old-date (org-entry-get nil "DEADLINE"))
(repeater (and old-date
(string-match
"\\([.+-]+[0-9]+[hdwmy]\\(?:[/ ][-+]?[0-9]+[hdwmy]\\)?\\) ?"
old-date)
(match-string 1 old-date))))
(if remove
(progn
(when (and old-date org-log-redeadline)
(org-add-log-setup 'deldeadline nil old-date 'findpos
org-log-redeadline))
(org-remove-timestamp-with-keyword org-deadline-string)
(message "Item no longer has a deadline."))
(org-add-planning-info 'deadline time 'closed)
(when (and old-date org-log-redeadline
(not (equal old-date
(substring org-last-inserted-timestamp 1 -1))))
(org-add-log-setup 'redeadline nil old-date 'findpos
org-log-redeadline))
(when repeater
(save-excursion
(org-back-to-heading t)
(when (re-search-forward (concat org-deadline-string " "
org-last-inserted-timestamp)
(save-excursion
(outline-next-heading) (point)) t)
(goto-char (1- (match-end 0)))
(insert " " repeater)
(setq org-last-inserted-timestamp
(concat (substring org-last-inserted-timestamp 0 -1)
" " repeater
(substring org-last-inserted-timestamp -1))))))
(message "Deadline on %s" org-last-inserted-timestamp)))))

The following code should do the trick. It's just a matter of asking the time separately and them passing it yourself to the org-deadline function.
(defun org/deadline (remove)
"like `org-deadline', except ask only once."
(interactive "P")
(unless remove (with-temp-buffer (org-time-stamp nil)))
(org-deadline remove org-last-inserted-timestamp))
(global-set-key [remap org-deadline] 'org/deadline)
EDIT: Simplified the function.

Related

Forward sentence by comma by partial sentence in org

Strike M-e in org which invokes org-forward-sentence and thus move point to end of the sentence.
I desire to move by comma. When refer to org-forward-sentence, notice the last two lines of
(let ((sentence-end (concat (sentence-end) "\\|^\\*+ .*$")))
(call-interactively #'forward-sentence)))))))
From the completed definition.
(defun org-forward-sentence (&optional _arg)
"Go to end of sentence, or end of table field.
This will call `forward-sentence' or `org-table-end-of-field',
depending on context."
(interactive)
(if (and (org-at-heading-p)
(save-restriction (skip-chars-forward " \t") (not (eolp))))
(save-restriction
(narrow-to-region (line-beginning-position) (line-end-position))
(call-interactively #'forward-sentence))
(let* ((element (org-element-at-point))
(contents-end (org-element-property :contents-end element))
(table (org-element-lineage element '(table) t)))
(if (and table
(>= (point) (org-element-property :contents-begin table))
(< (point) contents-end))
(call-interactively #'org-table-end-of-field)
(save-restriction
(when (and contents-end
(> (point-max) contents-end)
;; Skip blank lines between elements.
(< (org-element-property :end element)
(save-excursion (goto-char contents-end)
(skip-chars-forward " \r\t\n"))))
(narrow-to-region (org-element-property :contents-begin element)
contents-end))
;; End of heading is considered as the end of a sentence.
(let ((sentence-end (concat (sentence-end) "\\|^\\*+ .*$")))
(call-interactively #'forward-sentence)))))))
Then changed dot to comma
(let ((sentence-end (concat (sentence-end) "\\|^\\*+ ,*$"))) ;;changee . to ,
(call-interactively #'forward-sentence)))))))
However, it proved wrong.
Where should I change within the original function.
Define it as
(def org-forward-partial-sentence (&optional arg)
and (global-set-key "\C-m"
That . has special meaning in a regex context, see (emacs)Regexps in the manual.
A very simplistic modification could be,
(concat (sentence-end) "\\|^\\*+ .*$\\|,")
to move to , as well.
Instead of changing the entire function, you could just let bind sentence-end around org-forward-sentence, eg.
(defun my-org-forward-sentence ()
(interactive)
(let ((sentence-end (concat (sentence-end) "\\|,")))
(call-interactively #'org-forward-sentence)))

Emacs -- calculating new window-start/end without redisplay

Is it possible to calculate a new window-start/end without a redisplay occurring? If so, then an example would be greatly appreciated. If not, then what is the best way to approximate it?
Example:  We want to move to a new area of the buffer somewhere off screen, and place overlays when we get there. We might be using page-down or scroll-down or paragraph-down or end-of-buffer. When we get to that new point, we want to calculate the new window-start and the new window-end. However, we want to avoid a momentary naked looking buffer without any overlays. Ideally, the redisplay would occur once those overlays are added. I want to restrict new overlays to the new region based upon the new window-start/end.
Point-Min:  point = 1
Old Window Start:  point = 1000
Old Window End:  point = 1500
New Window Start:  point = 3500
New Window End: point = 4000
Point-Max:  point = 6000
Problem: When using the post-command-hook to try and calculate the new window-start and new window-end, the previous display positions are being used instead -- i.e., the old window-start and the old window-end.
Here is a sample of the project I am working on. Absent fixing the window-start \ window-end problem, I get the following error:
Error in post-command-hook (my-eol-ruler-function):
(error "Invalid search bound (wrong side of point)")`.
The error happens when going from (point-min) to the end of the buffer with the interactive function end-of-buffer. In the context of this error, (point-max) is beyond the old window-end.
EDIT:  Updated code to include a message: (message "point: %s | window-start: %s | window-end: %s | point-max: %s" (point) (window-start) (window-end) (point-max) ). The message is used to demonstrate that the new window-start and new window-end are not calculated within the post-command-hook because a redisplay has not yet occurred. However, I am trying to avoid a redisplay until after the new overlays have been placed -- otherwise, a naked buffer without overlays is visible for a split second.
(defvar my-eol-ruler nil
"A horizontal ruler stretching from eol (end of line) to the window edge.")
(make-variable-buffer-local 'my-eol-ruler)
(defvar my-eol-pilcrow nil
"A pilcrow symbol placed at the end of every line except the current line.")
(make-variable-buffer-local 'my-eol-pilcrow)
(defun my-eol-ruler-function ()
(let* (
(opoint (point))
(window-width (window-width))
(window-start (window-start))
(window-end (window-end))
(col-eovl
(save-excursion
(vertical-motion 1)
(skip-chars-backward " \r\n" (- (point) 1))
(- (current-column) (progn (vertical-motion 0) (current-column)))))
(my-current-line-length (- (- window-width col-eovl) 3))
(pilcrow
(propertize (char-to-string ?\u00B6)
'face '(:foreground "white")
'cursor t))
(pilcrow-underlined
(propertize (char-to-string ?\u00B6)
'face '(:foreground "white" :underline "yellow")
'cursor t))
(underline (propertize (char-to-string ?\u2009)
'display `(space :width ,my-current-line-length)
'face '(:underline "yellow")
'cursor t)))
(when (or my-eol-ruler my-eol-pilcrow)
(dolist (description `(
,my-eol-ruler
,my-eol-pilcrow ))
(remove-overlays (point-min) (point-max)
'after-string description)) )
(setq my-eol-ruler (concat pilcrow-underlined underline))
(setq my-eol-pilcrow pilcrow)
(save-excursion
(end-of-line)
(overlay-put (make-overlay (point) (point))
'after-string my-eol-ruler ) )
(message "point: %s | window-start: %s | window-end: %s | point-max: %s"
(point)
(window-start)
(window-end)
(point-max) )
(save-excursion
(goto-char window-end)
(while (re-search-backward "\n" window-start t)
(let* (
(pbol (point-at-bol))
(pbovl (save-excursion (vertical-motion 0) (point)))
(peol (point))
(peol-pbol-region-p
(if (region-active-p)
(= peol pbol)))
(eol-inside-region-p
(if (region-active-p)
(and
(<= reg-beg peol)
(> reg-end peol))))
(col-eovl
(save-excursion
(vertical-motion 1)
(skip-chars-backward " \r\n" (- (point) 1))
(- (current-column) (progn (vertical-motion 0) (current-column)))))
(my-last-column (current-column))
(window-width-bug-p (= my-last-column (- window-width 1)))
(shazbot-pbol
(save-excursion
(end-of-line)
(re-search-backward "\s\\|\t" pbol t) (+ (point) 1)))
(wrapped-window-width-bug-p (= col-eovl (- window-width 1))) )
(when
(or
(< opoint pbol)
(> opoint peol))
(overlay-put (make-overlay peol peol) 'after-string my-eol-pilcrow))))) ))
(add-hook 'post-command-hook 'my-eol-ruler-function)
Beginning of the buffer, before the error occurs.
End of the buffer -- the error occurs when executing the interactive function end-of-buffer from a point at the beginning of the buffer.
Error in post-command-hook (my-eol-ruler-function):
(error "Invalid search bound (wrong side of point)")
See also Emacs bug tracker feature request #22404 (which has not yet been implemented, but the mailing archive contains a rough draft rudimentary patch that creates a new hook for this specific issue): https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22404
Minor-mode for testing window-start and window-end BEFORE visual redisplay.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; test-mode
;; A minor-mode for testing `window-start` / `window-end` BEFORE visual redisplay.
(defvar test-this-command nil
"This local variable is set within the `post-command-hook`; and,
is also used by the `window-scroll-functions` hook.")
(make-variable-buffer-local 'test-this-command)
(defun test-post-command-hook-fn ()
"A function attached to the `post-command-hook`."
(setq test-this-command this-command)
(test-demo-fn))
(defun test-window-scroll-functions-fn (win _start)
"A function attached to the `window-scroll-functions` hook."
(test-demo-fn))
(defun test-demo-fn ()
"This is a test-mode demonstration function."
(when
(and
test-mode
test-this-command
(window-live-p (get-buffer-window (current-buffer)))
(not (minibufferp))
(pos-visible-in-window-p (point)
(get-buffer-window (current-buffer) (selected-frame)) t))
(let* (
(selected-window (selected-window))
(window-start (window-start selected-window))
(window-end (window-end selected-window t)) )
(message "window-start: %s | window-end: %s" window-start window-end)
(setq test-this-command nil) )))
(define-minor-mode test-mode
"A minor-mode for testing `window-start` / `window-end` BEFORE visual redisplay."
:init-value nil
:lighter " TEST"
:keymap nil
:global nil
:group nil
(cond
(test-mode
(set (make-local-variable 'scroll-conservatively) 101)
(add-hook 'post-command-hook 'test-post-command-hook-fn nil t)
(add-hook 'window-scroll-functions 'test-window-scroll-functions-fn nil t)
(when (called-interactively-p 'any)
(message "Turned ON `test-mode`.")))
(t
(kill-local-variable 'scroll-conservatively)
(kill-local-variable 'test-this-command)
(remove-hook 'post-command-hook 'test-post-command-hook-fn t)
(remove-hook 'window-scroll-functions 'test-window-scroll-functions-fn t)
(when (called-interactively-p 'any)
(message "Turned OFF `test-mode`.") ))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Offhand, I'd say that the error is raised because you pass a BOUND arg to a search function. For example:
(re-search-backward "\n" window-start t)
(re-search-backward "\s\\|\t" pbol t)
Check your values of window-start and pbol. Remember that when you search backward the bound must not be greater than the current position (point).
I think you want to use jit-lock-register instead of post-command-hook. This way, the redisplay code will call you back once it has decided of a window-start and you'll be able to add the overlays you want before the buffer's content is displayed.

How to search for a complete org headline that was saved as a variable

The function (org-heading-components) and (org-element-property) produce integers for the number of stars and also for the priority. I'd like to store the entire headline as a variable and then use re-search-forward (or a similar function) to go back to that heading, but I foresee the problem that will occur when it cannot find an integer. I need to store the whole heading as a variable, because I often have todo entries with duplicate titles but the other components are diferent.
For example, the following todo:
** Active [#A] Ask the geniuses on stackoverflow how to do this. :lawlist:
when evaluated with (org-heading-components) looks like this:
(2 2 "Active" 65 "Ask the geniuses on stackoverflow how to do this." ":lawlist:")
So, when storing that as a variable and later using re-search-forward there will be problems because 2 2 is not the same as **, and 65 is not the same as [#A].
(defun lawlist ()
(interactive)
(let* (
(beg (point))
(complete-heading (org-heading-components) ))
* * *
(goto-char (point-min))
(re-search-forward complete-heading nil t) ))
You should be able to convert the output as follows:
The first # is the current level (# of stars)
The second number is the reduced headline level, applicable if org-odd-levels-only is set, but this is not regarding output.
Todo keyword
Priority character (65 is ASCII code for A)
Headline text
Tags or nil
The following will return the headline string as shown in the buffer. It will not work with re-search-forward but will work with search-forward (It does not escape any characters).
(defun zin/search-test ()
(interactive)
(let ((head (org-element-interpret-data (org-element-at-point))))
(message "%s" (format "%s" (car (split-string head "\n"))))))
This does not set it to any variable, you'll have to wrap it in an appropriate function that will set your desired variable. Then use (search-forward <var> nil t) to match it, without it erroring out if it cannot find it.
There's a brilliant part of org that might suit you: org-id-copy and
org-id-goto. It works with precision across buffers and sessions:
org-id-copy produces a string. You can feed that string to
org-id-goto which will take you to that heading. Even if you've
closed the original buffer. Even if you've restarted Emacs.
EDIT (December 15, 2013):  Updated solution based upon the variable org-heading-regexp (defined within org.el) and a modification thereof to include (if it exists) a second line containing a deadline - i.e., lawlist-org-heading-regexp. The revision also includes a nifty function regexp-quote that was just taught to me by #Drew over on superuser: https://superuser.com/questions/688781/how-to-highlight-string-and-unhighlight-string-in-buffer-make-overlay?noredirect=1#comment874515_688781  (buffer-substring-no-properties beg end) is used to set the string as a variable.
EDIT (December 17, 2013):   Added isearch-highlight and isearch-dehighlight, and commented out highlight-regexp and unhighlight-regexp. When moving the point around with more complex functions, highlight-regexp does not reliably highlight the entire string -- this may be because the screen has not refreshed, or it may also be caused by other factors -- e.g., hl-line-mode, etc.) -- placing various sit-for 0 did not fix the issue with highlight-regexp -- isearch-highlight works better.
EDIT (January 6, 2014):  See also this related thread for a complete regexp to match any element of the entire todo from stars through to the end of the notes:  https://stackoverflow.com/a/20960301/2112489
(require 'org)
(defvar lawlist-org-heading-regexp
"^\\(\\*+\\)\\(?: +\\(.*?\\)\\)?[ \t]*\\(\n.*DEADLINE.*$\\)"
"Match headline, plus second line with a deadline.")
(defun example ()
(interactive)
(switch-to-buffer (get-buffer-create "foo"))
(org-mode)
(insert "* Example\n\n")
(insert "** Active [#A] This is an active todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-15 Sun 08:00> SCHEDULED: <2013-12-15 Sun>\n\n")
(insert "** Next-Action [#B] This is an inactive todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-16 Mon 08:00> SCHEDULED: <2013-12-16 Mon>")
(goto-char (point-min))
(sit-for 2)
(re-search-forward (regexp-quote "** Active [#A] "))
(sit-for 2)
(let ((init-pos (point)))
(org-back-to-heading t)
(let* (
lawlist-item-whole
lawlist-item-partial
(beg (point)))
(if (and
(looking-at org-heading-regexp)
(and (looking-at lawlist-org-heading-regexp) (match-string 3)))
(re-search-forward lawlist-org-heading-regexp nil t)
(re-search-forward org-heading-regexp nil t))
(let ((end (point)))
(setq lawlist-item-whole (buffer-substring-no-properties beg end))
(setq lawlist-item-partial (buffer-substring-no-properties beg init-pos))
(re-search-backward (regexp-quote lawlist-item-whole) nil t)
;; (highlight-regexp (regexp-quote lawlist-item-whole))
(isearch-highlight beg end)
(sit-for 2)
;; (unhighlight-regexp (regexp-quote lawlist-item-whole))
(isearch-dehighlight)
(re-search-forward (regexp-quote lawlist-item-partial) nil t)
(sit-for 2)
(kill-buffer "foo")))))
EDIT (October 27, 2013):  Prior solution that is being preserved temporarily as a historical part of the evolution process towards a final answer. However, it is no longer a preferred method.
(defun lawlist-org-heading-components ()
(org-back-to-heading t)
(if (let (case-fold-search) (looking-at org-complex-heading-regexp))
(concat
(cond
((equal (org-match-string-no-properties 1) "**")
"^[*][*]")
((equal (org-match-string-no-properties 1) "*")
"^[*]"))
(cond
((and (match-end 2) (aref (match-string 2) 1))
(concat " " (org-match-string-no-properties 2))))
(cond
((and (match-end 3) (aref (match-string 3) 2))
(concat " \\" (org-match-string-no-properties 3))))
(cond
((and (match-end 4) (aref (match-string 4) 3))
(concat " " (org-match-string-no-properties 4))))
(cond
((and (match-end 5) (aref (match-string 5) 4))
(concat " " (org-match-string-no-properties 5)))))))

Define a copy-section command in Emacs

I would like to set up a command that put the content of the lines between two § characters without moving the point (not including the lines containg the §).
Here is my current attempt
(defun copy-section ()
"Copy current section, that is lines between two §."
(interactive)
(save-excursion
(when (not (search-backward-regexp "§" nil t))
(goto-char (point-min)) )
(forward-line 1)
(when (not (search-forward-regexp "§" nil t))
(goto-char (point-max)) )
(move-beginning-of-line nil)
(kill-ring-save (mark) (point)) ) )
It works well but the remarks in the documentation about moving around the mark being bad style make me think taht there is a better way to achieve the same result.
Does saving position into variable (which I do not know how to do it) allows for a cleaner function.
Part of the code above comes from ergoemacs.
No "regexp" form needed as only a char is looked for
(defun copy-section ()
"Copy current section, that is lines between two §."
(interactive)
(save-excursion
(let* ((start (and (search-backward "§" nil t)
(forward-line 1)
(point)))
(end (progn (and start (search-forward "§" nil t))
(forward-line -1)
(end-of-line)
(point))))
(and start end (kill-new (buffer-substring-no-properties start end))))))
This version saves the beginning and end of your section in temporary local variables, and doesn't use the mark at all:
(defun copy-section ()
"Copy current page as defined by form feed characters."
(interactive)
(let (start end)
(save-excursion
(when (not (search-backward-regexp "§" nil t))
(goto-char (point-min)) )
(forward-line 1)
(setq start (point))
(when (not (search-forward-regexp "§" nil t))
(goto-char (point-max)) )
(move-beginning-of-line nil)
(setq end (point))
(kill-ring-save start end))))

How do I get the region (selection) programmatically in Emacs Lisp?

I need to access the selection in Emacs buffer.
I have found this article How do I access the contents of the current region in Emacs Lisp?
and it helps me a lot.
But there is a problem. The first time I select (highlight) a region, it works okay, but when I press C-g, and move cursor normally to another place without highlighting any chars, I got a string from last mark to the current point while I expect an empty one.
Actually I need to implement a function which will return the current selection (highlighted) as a string, or empty string if nothing is highlighted. The following code may express me more clearly.
(defun get-search-term ()
(interactive)
(let (
(selection (buffer-substring-no-properties (region-beginning) (region-end))))
(if (= (length selection) 0)
(message "empty string")
(message selection))))
Any suggestions? Thanks a lot!
"r" specification of interactive is dumb. You're seeing why.
(defun get-search-term (beg end)
"message region or \"empty string\" if none highlighted"
(interactive (if (use-region-p)
(list (region-beginning) (region-end))
(list (point-min) (point-min))))
(let ((selection (buffer-substring-no-properties beg end)))
(if (= (length selection) 0)
(message "empty string")
(message selection))))
I don't mean "dumb" as in stupid and not useful; just that it doesn't care
about whether the mark is active or not. I think it predates
transient-mark-mode.
EDIT: Using (point-min) twice above makes the code harder to understand
when re-reading. Here is a better implementation:
(defun get-search-term (beg end)
"message region or \"empty string\" if none highlighted"
(interactive (if (use-region-p)
(list (region-beginning) (region-end))
(list nil nil)))
(message "%s" (if (and beg end)
(buffer-substring-no-properties beg end)
"empty string")))
Check variable mark-active eg. C-h v mark-active
==> mark-active is a variable defined in `C source code'.
Its value is nil
Local in buffer Apropos; global value is nil
Automatically becomes buffer-local when set in any fashion.
Documentation:
Non-nil means the mark and region are currently active in this buffer.
(defun get-search-term ()
(interactive)
(if mark-active
(let (
(selection (buffer-substring-no-properties (region-beginning) (region-end))))
(if (= (length selection) 0)
(message "empty string")
(message selection))
)
(error "mark not active"))
)