emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Org-remember-handler fix for empty remember buffer
@ 2009-06-04 17:45 Ryan C. Thompson
  2009-06-07 14:18 ` Carsten Dominik
  2009-06-08 17:45 ` Carsten Dominik
  0 siblings, 2 replies; 5+ messages in thread
From: Ryan C. Thompson @ 2009-06-04 17:45 UTC (permalink / raw)
  To: emacs-orgmode

Hi,

I ran into a problem with org's remember functionality, and found a fix 
for it. The problem is that if you attempt to either abort or remember 
an empty buffer (that is, a buffer containing only whitespace and 
comments), then org-mode hits an error and fails to do either, leaving 
the buffer annoyingly open.

The bug is in the loop that deletes trailing comments and whitespace. If 
the buffer is empty, then this loop reaches the first line, and attempts 
to delete a region starting at position zero, which causes the error. 
Here is the modified function definition that checks for this condition.

As a bonus, the function also auto-aborts instead of saving if the 
buffer is empty.

Thank you,

Ryan Thompson



;; Fix for empty remember buffer.
(defun org-remember-handler ()
  "Store stuff from remember.el into an org file.
When the template has specified a file and a headline, the entry is filed
there, or in the location defined by `org-default-notes-file' and
`org-remember-default-headline'.

If no defaults have been defined, or if the current prefix argument
is 1 (so you must use `C-1 C-c C-c' to exit remember), an interactive
process is used to select the target location.

When the prefix is 0 (i.e. when remember is exited with `C-0 C-c C-c'),
the entry is filed to the same location as the previous note.

When the prefix is 2 (i.e. when remember is exited with `C-2 C-c C-c'),
the entry is filed as a subentry of the entry where the clock is
currently running.

When `C-u' has been used as prefix argument, the note is stored and emacs
moves point to the new location of the note, so that editing can be
continued there (similar to inserting \"%&\" into the template).

Before storing the note, the function ensures that the text has an
org-mode-style headline, i.e. a first line that starts with
a \"*\".  If not, a headline is constructed from the current date and
some additional data.

If the variable `org-adapt-indentation' is non-nil, the entire text is
also indented so that it starts in the same column as the headline
\(i.e. after the stars).

See also the variable `org-reverse-note-order'."
  (interactive)
  (when (and (equal current-prefix-arg 2)
         (not (marker-buffer org-clock-marker)))
    (error "No running clock"))
  (when (org-bound-and-true-p org-jump-to-target-location)
    (let* ((end (min (point-max) (1+ (point))))
       (beg (point)))
      (if (= end beg) (setq beg (1- beg)))
      (put-text-property beg end 'org-position-cursor t)))
  (goto-char (point-min))
  (while (looking-at "^[ \t]*\n\\|^##.*\n")
    (replace-match ""))
  (goto-char (point-max))
  (beginning-of-line 1)
  (catch 'quit
    (while (looking-at "[ \t]*$\\|##.*")
      ;; Abort on empty buffer
      (if (= (point) (point-min))
          (throw 'quit nil)
        (previous-line)))
    (delete-region (point) (point-max))
    (backward-delete-char 1)
    (if org-note-abort (throw 'quit nil))
    ;; Also abort on an empty (i.e. whitespace-only) buffer
    ;; (if (not (string-match "[^[:space:]]" 
(buffer-substring-no-properties (point-min) (point-max)))) (return t))
    (let* ((visitp (org-bound-and-true-p org-jump-to-target-location))
       (previousp (and (member current-prefix-arg '((16) 0))
               org-remember-previous-location))
       (clockp (equal current-prefix-arg 2))
       (fastp (org-xor (equal current-prefix-arg 1)
               org-remember-store-without-prompt))
       (file (cond
          (fastp org-default-notes-file)
          ((and (eq org-remember-interactive-interface 'refile)
            org-refile-targets)
           org-default-notes-file)
          ((not previousp)
           (org-get-org-file))))
       (heading org-remember-default-headline)
       (visiting (and file (org-find-base-buffer-visiting file)))
       (org-startup-folded nil)
       (org-startup-align-all-tables nil)
       (org-goto-start-pos 1)
       spos exitcmd level reversed txt)
      (when (equal current-prefix-arg '(4))
    (setq visitp t))
      (when previousp
    (setq file (car org-remember-previous-location)
          visiting (and file (org-find-base-buffer-visiting file))
          heading (cdr org-remember-previous-location)
          fastp t))
      (when clockp
    (setq file (buffer-file-name (marker-buffer org-clock-marker))
          visiting (and file (org-find-base-buffer-visiting file))
          heading org-clock-heading-for-remember
          fastp t))
      (setq current-prefix-arg nil)
      ;; Modify text so that it becomes a nice subtree which can be inserted
      ;; into an org tree.
      (goto-char (point-min))
      (if (re-search-forward "[ \t\n]+\\'" nil t)
      ;; remove empty lines at end
      (replace-match ""))
      (goto-char (point-min))
      (unless (looking-at org-outline-regexp)
    ;; add a headline
    (insert (concat "* " (current-time-string)
            " (" (remember-buffer-desc) ")\n"))
    (backward-char 1)
    (when org-adapt-indentation
      (while (re-search-forward "^" nil t)
        (insert "  "))))
      (goto-char (point-min))
      (if (re-search-forward "\n[ \t]*\n[ \t\n]*\\'" nil t)
      (replace-match "\n\n")
    (if (re-search-forward "[ \t\n]*\\'")
        (replace-match "\n")))
      (goto-char (point-min))
      (setq txt (buffer-string))
      (org-save-markers-in-region (point-min) (point-max))
      (when (and (eq org-remember-interactive-interface 'refile)
         (not fastp))
    (org-refile nil (or visiting (find-file-noselect file)))
    (and visitp (run-with-idle-timer 0.01 nil 
'org-remember-visit-immediately))
    (save-excursion
      (bookmark-jump "org-refile-last-stored")
      (bookmark-set "org-remember-last-stored")
      (move-marker org-remember-last-stored-marker (point)))
    (throw 'quit t))
      ;; Find the file
      (with-current-buffer (or visiting (find-file-noselect file))
    (unless (org-mode-p)
      (error "Target files for remember notes must be in Org-mode"))
    (save-excursion
      (save-restriction
        (widen)
        (and (goto-char (point-min))
         (not (re-search-forward "^\\* " nil t))
         (insert "\n* " (or (and (stringp heading) heading)
                    "Notes") "\n"))
        (setq reversed (org-notes-order-reversed-p))

        ;; Find the default location
        (when heading
          (cond
           ((eq heading 'top)
        (goto-char (point-min))
        (or (looking-at org-outline-regexp)
            (re-search-forward org-outline-regexp nil t))
        (setq org-goto-start-pos (or (match-beginning 0) (point-min))))
           ((eq heading 'bottom)
        (goto-char (point-max))
        (or (bolp) (newline))
        (setq org-goto-start-pos (point)))
           ((and (stringp heading) (string-match "\\S-" heading))
        (goto-char (point-min))
        (if (re-search-forward
             (concat "^\\*+[ \t]+" (regexp-quote heading)
                 (org-re "\\([ \t]+:[[:alnum:]@_:]*\\)?[ \t]*$"))
             nil t)
            (setq org-goto-start-pos (match-beginning 0))
          (when fastp
            (goto-char (point-max))
            (unless (bolp) (newline))
            (insert "* " heading "\n")
            (setq org-goto-start-pos (point-at-bol 0)))))
           (t (goto-char (point-min)) (setq org-goto-start-pos (point)
                        heading 'top))))

        ;; Ask the User for a location, using the appropriate interface
        (cond
         ((and fastp (memq heading '(top bottom)))
          (setq spos org-goto-start-pos
              exitcmd (if (eq heading 'top) 'left nil)))
         (fastp (setq spos org-goto-start-pos
              exitcmd 'return))
         ((eq org-remember-interactive-interface 'outline)
          (setq spos (org-get-location (current-buffer)
                       org-remember-help)
            exitcmd (cdr spos)
            spos (car spos)))
         ((eq org-remember-interactive-interface 'outline-path-completion)
          (let ((org-refile-targets '((nil . (:maxlevel . 10))))
            (org-refile-use-outline-path t))
        (setq spos (org-refile-get-location "Heading: ")
              exitcmd 'return
              spos (nth 3 spos))))
         (t (error "This should not happen")))
        (if (not spos) (throw 'quit nil)) ; return nil to show we did
                    ; not handle this note
        (and visitp (run-with-idle-timer 0.01 nil 
'org-remember-visit-immediately))
        (goto-char spos)
        (cond ((org-on-heading-p t)
           (org-back-to-heading t)
           (setq level (funcall outline-level))
           (cond
            ((eq exitcmd 'return)
             ;; sublevel of current
             (setq org-remember-previous-location
               (cons (abbreviate-file-name file)
                 (org-get-heading 'notags)))
             (if reversed
             (outline-next-heading)
               (org-end-of-subtree t)
               (if (not (bolp))
               (if (looking-at "[ \t]*\n")
                   (beginning-of-line 2)
                 (end-of-line 1)
                 (insert "\n"))))
             (org-paste-subtree (org-get-valid-level level 1) txt)
             (and org-auto-align-tags (org-set-tags nil t))
             (bookmark-set "org-remember-last-stored")
             (move-marker org-remember-last-stored-marker (point)))
            ((eq exitcmd 'left)
             ;; before current
             (org-paste-subtree level txt)
             (and org-auto-align-tags (org-set-tags nil t))
             (bookmark-set "org-remember-last-stored")
             (move-marker org-remember-last-stored-marker (point)))
            ((eq exitcmd 'right)
             ;; after current
             (org-end-of-subtree t)
             (org-paste-subtree level txt)
             (and org-auto-align-tags (org-set-tags nil t))
             (bookmark-set "org-remember-last-stored")
             (move-marker org-remember-last-stored-marker (point)))
            (t (error "This should not happen"))))

          ((eq heading 'bottom)
           (org-paste-subtree 1 txt)
           (and org-auto-align-tags (org-set-tags nil t))
           (bookmark-set "org-remember-last-stored")
           (move-marker org-remember-last-stored-marker (point)))

          ((and (bobp) (not reversed))
           ;; Put it at the end, one level below level 1
           (save-restriction
             (widen)
             (goto-char (point-max))
             (if (not (bolp)) (newline))
             (org-paste-subtree (org-get-valid-level 1 1) txt)
             (and org-auto-align-tags (org-set-tags nil t))
             (bookmark-set "org-remember-last-stored")
             (move-marker org-remember-last-stored-marker (point))))

          ((and (bobp) reversed)
           ;; Put it at the start, as level 1
           (save-restriction
             (widen)
             (goto-char (point-min))
             (re-search-forward "^\\*+ " nil t)
             (beginning-of-line 1)
             (org-paste-subtree 1 txt)
             (and org-auto-align-tags (org-set-tags nil t))
             (bookmark-set "org-remember-last-stored")
             (move-marker org-remember-last-stored-marker (point))))
          (t
           ;; Put it right there, with automatic level determined by
           ;; org-paste-subtree or from prefix arg
           (org-paste-subtree
            (if (numberp current-prefix-arg) current-prefix-arg)
            txt)
           (and org-auto-align-tags (org-set-tags nil t))
           (bookmark-set "org-remember-last-stored")
           (move-marker org-remember-last-stored-marker (point))))

        (when remember-save-after-remembering
          (save-buffer)
          (if (and (not visiting)
               (not (equal (marker-buffer org-clock-marker)
                   (current-buffer))))
          (kill-buffer (current-buffer)))))))))

  t)    ;; return t to indicate that we took care of this note.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Org-remember-handler fix for empty remember buffer
  2009-06-04 17:45 Org-remember-handler fix for empty remember buffer Ryan C. Thompson
@ 2009-06-07 14:18 ` Carsten Dominik
  2009-06-08 17:45 ` Carsten Dominik
  1 sibling, 0 replies; 5+ messages in thread
From: Carsten Dominik @ 2009-06-07 14:18 UTC (permalink / raw)
  To: Ryan C. Thompson; +Cc: emacs-orgmode

Hi Ryan,

could you please post a patch instead, using "diff -u"  ?  Thanks.

- Carsten

On Jun 4, 2009, at 7:45 PM, Ryan C. Thompson wrote:

> Hi,
>
> I ran into a problem with org's remember functionality, and found a  
> fix for it. The problem is that if you attempt to either abort or  
> remember an empty buffer (that is, a buffer containing only  
> whitespace and comments), then org-mode hits an error and fails to  
> do either, leaving the buffer annoyingly open.
>
> The bug is in the loop that deletes trailing comments and  
> whitespace. If the buffer is empty, then this loop reaches the first  
> line, and attempts to delete a region starting at position zero,  
> which causes the error. Here is the modified function definition  
> that checks for this condition.
>
> As a bonus, the function also auto-aborts instead of saving if the  
> buffer is empty.
>
> Thank you,
>
> Ryan Thompson
>
>
>
> ;; Fix for empty remember buffer.
> (defun org-remember-handler ()
> "Store stuff from remember.el into an org file.
> When the template has specified a file and a headline, the entry is  
> filed
> there, or in the location defined by `org-default-notes-file' and
> `org-remember-default-headline'.
>
> If no defaults have been defined, or if the current prefix argument
> is 1 (so you must use `C-1 C-c C-c' to exit remember), an interactive
> process is used to select the target location.
>
> When the prefix is 0 (i.e. when remember is exited with `C-0 C-c C- 
> c'),
> the entry is filed to the same location as the previous note.
>
> When the prefix is 2 (i.e. when remember is exited with `C-2 C-c C- 
> c'),
> the entry is filed as a subentry of the entry where the clock is
> currently running.
>
> When `C-u' has been used as prefix argument, the note is stored and  
> emacs
> moves point to the new location of the note, so that editing can be
> continued there (similar to inserting \"%&\" into the template).
>
> Before storing the note, the function ensures that the text has an
> org-mode-style headline, i.e. a first line that starts with
> a \"*\".  If not, a headline is constructed from the current date and
> some additional data.
>
> If the variable `org-adapt-indentation' is non-nil, the entire text is
> also indented so that it starts in the same column as the headline
> \(i.e. after the stars).
>
> See also the variable `org-reverse-note-order'."
> (interactive)
> (when (and (equal current-prefix-arg 2)
>        (not (marker-buffer org-clock-marker)))
>   (error "No running clock"))
> (when (org-bound-and-true-p org-jump-to-target-location)
>   (let* ((end (min (point-max) (1+ (point))))
>      (beg (point)))
>     (if (= end beg) (setq beg (1- beg)))
>     (put-text-property beg end 'org-position-cursor t)))
> (goto-char (point-min))
> (while (looking-at "^[ \t]*\n\\|^##.*\n")
>   (replace-match ""))
> (goto-char (point-max))
> (beginning-of-line 1)
> (catch 'quit
>   (while (looking-at "[ \t]*$\\|##.*")
>     ;; Abort on empty buffer
>     (if (= (point) (point-min))
>         (throw 'quit nil)
>       (previous-line)))
>   (delete-region (point) (point-max))
>   (backward-delete-char 1)
>   (if org-note-abort (throw 'quit nil))
>   ;; Also abort on an empty (i.e. whitespace-only) buffer
>   ;; (if (not (string-match "[^[:space:]]" (buffer-substring-no- 
> properties (point-min) (point-max)))) (return t))
>   (let* ((visitp (org-bound-and-true-p org-jump-to-target-location))
>      (previousp (and (member current-prefix-arg '((16) 0))
>              org-remember-previous-location))
>      (clockp (equal current-prefix-arg 2))
>      (fastp (org-xor (equal current-prefix-arg 1)
>              org-remember-store-without-prompt))
>      (file (cond
>         (fastp org-default-notes-file)
>         ((and (eq org-remember-interactive-interface 'refile)
>           org-refile-targets)
>          org-default-notes-file)
>         ((not previousp)
>          (org-get-org-file))))
>      (heading org-remember-default-headline)
>      (visiting (and file (org-find-base-buffer-visiting file)))
>      (org-startup-folded nil)
>      (org-startup-align-all-tables nil)
>      (org-goto-start-pos 1)
>      spos exitcmd level reversed txt)
>     (when (equal current-prefix-arg '(4))
>   (setq visitp t))
>     (when previousp
>   (setq file (car org-remember-previous-location)
>         visiting (and file (org-find-base-buffer-visiting file))
>         heading (cdr org-remember-previous-location)
>         fastp t))
>     (when clockp
>   (setq file (buffer-file-name (marker-buffer org-clock-marker))
>         visiting (and file (org-find-base-buffer-visiting file))
>         heading org-clock-heading-for-remember
>         fastp t))
>     (setq current-prefix-arg nil)
>     ;; Modify text so that it becomes a nice subtree which can be  
> inserted
>     ;; into an org tree.
>     (goto-char (point-min))
>     (if (re-search-forward "[ \t\n]+\\'" nil t)
>     ;; remove empty lines at end
>     (replace-match ""))
>     (goto-char (point-min))
>     (unless (looking-at org-outline-regexp)
>   ;; add a headline
>   (insert (concat "* " (current-time-string)
>           " (" (remember-buffer-desc) ")\n"))
>   (backward-char 1)
>   (when org-adapt-indentation
>     (while (re-search-forward "^" nil t)
>       (insert "  "))))
>     (goto-char (point-min))
>     (if (re-search-forward "\n[ \t]*\n[ \t\n]*\\'" nil t)
>     (replace-match "\n\n")
>   (if (re-search-forward "[ \t\n]*\\'")
>       (replace-match "\n")))
>     (goto-char (point-min))
>     (setq txt (buffer-string))
>     (org-save-markers-in-region (point-min) (point-max))
>     (when (and (eq org-remember-interactive-interface 'refile)
>        (not fastp))
>   (org-refile nil (or visiting (find-file-noselect file)))
>   (and visitp (run-with-idle-timer 0.01 nil 'org-remember-visit- 
> immediately))
>   (save-excursion
>     (bookmark-jump "org-refile-last-stored")
>     (bookmark-set "org-remember-last-stored")
>     (move-marker org-remember-last-stored-marker (point)))
>   (throw 'quit t))
>     ;; Find the file
>     (with-current-buffer (or visiting (find-file-noselect file))
>   (unless (org-mode-p)
>     (error "Target files for remember notes must be in Org-mode"))
>   (save-excursion
>     (save-restriction
>       (widen)
>       (and (goto-char (point-min))
>        (not (re-search-forward "^\\* " nil t))
>        (insert "\n* " (or (and (stringp heading) heading)
>                   "Notes") "\n"))
>       (setq reversed (org-notes-order-reversed-p))
>
>       ;; Find the default location
>       (when heading
>         (cond
>          ((eq heading 'top)
>       (goto-char (point-min))
>       (or (looking-at org-outline-regexp)
>           (re-search-forward org-outline-regexp nil t))
>       (setq org-goto-start-pos (or (match-beginning 0) (point-min))))
>          ((eq heading 'bottom)
>       (goto-char (point-max))
>       (or (bolp) (newline))
>       (setq org-goto-start-pos (point)))
>          ((and (stringp heading) (string-match "\\S-" heading))
>       (goto-char (point-min))
>       (if (re-search-forward
>            (concat "^\\*+[ \t]+" (regexp-quote heading)
>                (org-re "\\([ \t]+:[[:alnum:]@_:]*\\)?[ \t]*$"))
>            nil t)
>           (setq org-goto-start-pos (match-beginning 0))
>         (when fastp
>           (goto-char (point-max))
>           (unless (bolp) (newline))
>           (insert "* " heading "\n")
>           (setq org-goto-start-pos (point-at-bol 0)))))
>          (t (goto-char (point-min)) (setq org-goto-start-pos (point)
>                       heading 'top))))
>
>       ;; Ask the User for a location, using the appropriate interface
>       (cond
>        ((and fastp (memq heading '(top bottom)))
>         (setq spos org-goto-start-pos
>             exitcmd (if (eq heading 'top) 'left nil)))
>        (fastp (setq spos org-goto-start-pos
>             exitcmd 'return))
>        ((eq org-remember-interactive-interface 'outline)
>         (setq spos (org-get-location (current-buffer)
>                      org-remember-help)
>           exitcmd (cdr spos)
>           spos (car spos)))
>        ((eq org-remember-interactive-interface 'outline-path- 
> completion)
>         (let ((org-refile-targets '((nil . (:maxlevel . 10))))
>           (org-refile-use-outline-path t))
>       (setq spos (org-refile-get-location "Heading: ")
>             exitcmd 'return
>             spos (nth 3 spos))))
>        (t (error "This should not happen")))
>       (if (not spos) (throw 'quit nil)) ; return nil to show we did
>                   ; not handle this note
>       (and visitp (run-with-idle-timer 0.01 nil 'org-remember-visit- 
> immediately))
>       (goto-char spos)
>       (cond ((org-on-heading-p t)
>          (org-back-to-heading t)
>          (setq level (funcall outline-level))
>          (cond
>           ((eq exitcmd 'return)
>            ;; sublevel of current
>            (setq org-remember-previous-location
>              (cons (abbreviate-file-name file)
>                (org-get-heading 'notags)))
>            (if reversed
>            (outline-next-heading)
>              (org-end-of-subtree t)
>              (if (not (bolp))
>              (if (looking-at "[ \t]*\n")
>                  (beginning-of-line 2)
>                (end-of-line 1)
>                (insert "\n"))))
>            (org-paste-subtree (org-get-valid-level level 1) txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point)))
>           ((eq exitcmd 'left)
>            ;; before current
>            (org-paste-subtree level txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point)))
>           ((eq exitcmd 'right)
>            ;; after current
>            (org-end-of-subtree t)
>            (org-paste-subtree level txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point)))
>           (t (error "This should not happen"))))
>
>         ((eq heading 'bottom)
>          (org-paste-subtree 1 txt)
>          (and org-auto-align-tags (org-set-tags nil t))
>          (bookmark-set "org-remember-last-stored")
>          (move-marker org-remember-last-stored-marker (point)))
>
>         ((and (bobp) (not reversed))
>          ;; Put it at the end, one level below level 1
>          (save-restriction
>            (widen)
>            (goto-char (point-max))
>            (if (not (bolp)) (newline))
>            (org-paste-subtree (org-get-valid-level 1 1) txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point))))
>
>         ((and (bobp) reversed)
>          ;; Put it at the start, as level 1
>          (save-restriction
>            (widen)
>            (goto-char (point-min))
>            (re-search-forward "^\\*+ " nil t)
>            (beginning-of-line 1)
>            (org-paste-subtree 1 txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point))))
>         (t
>          ;; Put it right there, with automatic level determined by
>          ;; org-paste-subtree or from prefix arg
>          (org-paste-subtree
>           (if (numberp current-prefix-arg) current-prefix-arg)
>           txt)
>          (and org-auto-align-tags (org-set-tags nil t))
>          (bookmark-set "org-remember-last-stored")
>          (move-marker org-remember-last-stored-marker (point))))
>
>       (when remember-save-after-remembering
>         (save-buffer)
>         (if (and (not visiting)
>              (not (equal (marker-buffer org-clock-marker)
>                  (current-buffer))))
>         (kill-buffer (current-buffer)))))))))
>
> t)    ;; return t to indicate that we took care of this note.
>
>
> _______________________________________________
> Emacs-orgmode mailing list
> Remember: use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Org-remember-handler fix for empty remember buffer
  2009-06-04 17:45 Org-remember-handler fix for empty remember buffer Ryan C. Thompson
  2009-06-07 14:18 ` Carsten Dominik
@ 2009-06-08 17:45 ` Carsten Dominik
  2009-06-08 19:45   ` Ryan C. Thompson
  1 sibling, 1 reply; 5+ messages in thread
From: Carsten Dominik @ 2009-06-08 17:45 UTC (permalink / raw)
  To: Ryan C. Thompson; +Cc: emacs-orgmode

Fixed, thanks.

- Carsten

On Jun 4, 2009, at 7:45 PM, Ryan C. Thompson wrote:

> Hi,
>
> I ran into a problem with org's remember functionality, and found a  
> fix for it. The problem is that if you attempt to either abort or  
> remember an empty buffer (that is, a buffer containing only  
> whitespace and comments), then org-mode hits an error and fails to  
> do either, leaving the buffer annoyingly open.
>
> The bug is in the loop that deletes trailing comments and  
> whitespace. If the buffer is empty, then this loop reaches the first  
> line, and attempts to delete a region starting at position zero,  
> which causes the error. Here is the modified function definition  
> that checks for this condition.
>
> As a bonus, the function also auto-aborts instead of saving if the  
> buffer is empty.
>
> Thank you,
>
> Ryan Thompson
>
>
>
> ;; Fix for empty remember buffer.
> (defun org-remember-handler ()
> "Store stuff from remember.el into an org file.
> When the template has specified a file and a headline, the entry is  
> filed
> there, or in the location defined by `org-default-notes-file' and
> `org-remember-default-headline'.
>
> If no defaults have been defined, or if the current prefix argument
> is 1 (so you must use `C-1 C-c C-c' to exit remember), an interactive
> process is used to select the target location.
>
> When the prefix is 0 (i.e. when remember is exited with `C-0 C-c C- 
> c'),
> the entry is filed to the same location as the previous note.
>
> When the prefix is 2 (i.e. when remember is exited with `C-2 C-c C- 
> c'),
> the entry is filed as a subentry of the entry where the clock is
> currently running.
>
> When `C-u' has been used as prefix argument, the note is stored and  
> emacs
> moves point to the new location of the note, so that editing can be
> continued there (similar to inserting \"%&\" into the template).
>
> Before storing the note, the function ensures that the text has an
> org-mode-style headline, i.e. a first line that starts with
> a \"*\".  If not, a headline is constructed from the current date and
> some additional data.
>
> If the variable `org-adapt-indentation' is non-nil, the entire text is
> also indented so that it starts in the same column as the headline
> \(i.e. after the stars).
>
> See also the variable `org-reverse-note-order'."
> (interactive)
> (when (and (equal current-prefix-arg 2)
>        (not (marker-buffer org-clock-marker)))
>   (error "No running clock"))
> (when (org-bound-and-true-p org-jump-to-target-location)
>   (let* ((end (min (point-max) (1+ (point))))
>      (beg (point)))
>     (if (= end beg) (setq beg (1- beg)))
>     (put-text-property beg end 'org-position-cursor t)))
> (goto-char (point-min))
> (while (looking-at "^[ \t]*\n\\|^##.*\n")
>   (replace-match ""))
> (goto-char (point-max))
> (beginning-of-line 1)
> (catch 'quit
>   (while (looking-at "[ \t]*$\\|##.*")
>     ;; Abort on empty buffer
>     (if (= (point) (point-min))
>         (throw 'quit nil)
>       (previous-line)))
>   (delete-region (point) (point-max))
>   (backward-delete-char 1)
>   (if org-note-abort (throw 'quit nil))
>   ;; Also abort on an empty (i.e. whitespace-only) buffer
>   ;; (if (not (string-match "[^[:space:]]" (buffer-substring-no- 
> properties (point-min) (point-max)))) (return t))
>   (let* ((visitp (org-bound-and-true-p org-jump-to-target-location))
>      (previousp (and (member current-prefix-arg '((16) 0))
>              org-remember-previous-location))
>      (clockp (equal current-prefix-arg 2))
>      (fastp (org-xor (equal current-prefix-arg 1)
>              org-remember-store-without-prompt))
>      (file (cond
>         (fastp org-default-notes-file)
>         ((and (eq org-remember-interactive-interface 'refile)
>           org-refile-targets)
>          org-default-notes-file)
>         ((not previousp)
>          (org-get-org-file))))
>      (heading org-remember-default-headline)
>      (visiting (and file (org-find-base-buffer-visiting file)))
>      (org-startup-folded nil)
>      (org-startup-align-all-tables nil)
>      (org-goto-start-pos 1)
>      spos exitcmd level reversed txt)
>     (when (equal current-prefix-arg '(4))
>   (setq visitp t))
>     (when previousp
>   (setq file (car org-remember-previous-location)
>         visiting (and file (org-find-base-buffer-visiting file))
>         heading (cdr org-remember-previous-location)
>         fastp t))
>     (when clockp
>   (setq file (buffer-file-name (marker-buffer org-clock-marker))
>         visiting (and file (org-find-base-buffer-visiting file))
>         heading org-clock-heading-for-remember
>         fastp t))
>     (setq current-prefix-arg nil)
>     ;; Modify text so that it becomes a nice subtree which can be  
> inserted
>     ;; into an org tree.
>     (goto-char (point-min))
>     (if (re-search-forward "[ \t\n]+\\'" nil t)
>     ;; remove empty lines at end
>     (replace-match ""))
>     (goto-char (point-min))
>     (unless (looking-at org-outline-regexp)
>   ;; add a headline
>   (insert (concat "* " (current-time-string)
>           " (" (remember-buffer-desc) ")\n"))
>   (backward-char 1)
>   (when org-adapt-indentation
>     (while (re-search-forward "^" nil t)
>       (insert "  "))))
>     (goto-char (point-min))
>     (if (re-search-forward "\n[ \t]*\n[ \t\n]*\\'" nil t)
>     (replace-match "\n\n")
>   (if (re-search-forward "[ \t\n]*\\'")
>       (replace-match "\n")))
>     (goto-char (point-min))
>     (setq txt (buffer-string))
>     (org-save-markers-in-region (point-min) (point-max))
>     (when (and (eq org-remember-interactive-interface 'refile)
>        (not fastp))
>   (org-refile nil (or visiting (find-file-noselect file)))
>   (and visitp (run-with-idle-timer 0.01 nil 'org-remember-visit- 
> immediately))
>   (save-excursion
>     (bookmark-jump "org-refile-last-stored")
>     (bookmark-set "org-remember-last-stored")
>     (move-marker org-remember-last-stored-marker (point)))
>   (throw 'quit t))
>     ;; Find the file
>     (with-current-buffer (or visiting (find-file-noselect file))
>   (unless (org-mode-p)
>     (error "Target files for remember notes must be in Org-mode"))
>   (save-excursion
>     (save-restriction
>       (widen)
>       (and (goto-char (point-min))
>        (not (re-search-forward "^\\* " nil t))
>        (insert "\n* " (or (and (stringp heading) heading)
>                   "Notes") "\n"))
>       (setq reversed (org-notes-order-reversed-p))
>
>       ;; Find the default location
>       (when heading
>         (cond
>          ((eq heading 'top)
>       (goto-char (point-min))
>       (or (looking-at org-outline-regexp)
>           (re-search-forward org-outline-regexp nil t))
>       (setq org-goto-start-pos (or (match-beginning 0) (point-min))))
>          ((eq heading 'bottom)
>       (goto-char (point-max))
>       (or (bolp) (newline))
>       (setq org-goto-start-pos (point)))
>          ((and (stringp heading) (string-match "\\S-" heading))
>       (goto-char (point-min))
>       (if (re-search-forward
>            (concat "^\\*+[ \t]+" (regexp-quote heading)
>                (org-re "\\([ \t]+:[[:alnum:]@_:]*\\)?[ \t]*$"))
>            nil t)
>           (setq org-goto-start-pos (match-beginning 0))
>         (when fastp
>           (goto-char (point-max))
>           (unless (bolp) (newline))
>           (insert "* " heading "\n")
>           (setq org-goto-start-pos (point-at-bol 0)))))
>          (t (goto-char (point-min)) (setq org-goto-start-pos (point)
>                       heading 'top))))
>
>       ;; Ask the User for a location, using the appropriate interface
>       (cond
>        ((and fastp (memq heading '(top bottom)))
>         (setq spos org-goto-start-pos
>             exitcmd (if (eq heading 'top) 'left nil)))
>        (fastp (setq spos org-goto-start-pos
>             exitcmd 'return))
>        ((eq org-remember-interactive-interface 'outline)
>         (setq spos (org-get-location (current-buffer)
>                      org-remember-help)
>           exitcmd (cdr spos)
>           spos (car spos)))
>        ((eq org-remember-interactive-interface 'outline-path- 
> completion)
>         (let ((org-refile-targets '((nil . (:maxlevel . 10))))
>           (org-refile-use-outline-path t))
>       (setq spos (org-refile-get-location "Heading: ")
>             exitcmd 'return
>             spos (nth 3 spos))))
>        (t (error "This should not happen")))
>       (if (not spos) (throw 'quit nil)) ; return nil to show we did
>                   ; not handle this note
>       (and visitp (run-with-idle-timer 0.01 nil 'org-remember-visit- 
> immediately))
>       (goto-char spos)
>       (cond ((org-on-heading-p t)
>          (org-back-to-heading t)
>          (setq level (funcall outline-level))
>          (cond
>           ((eq exitcmd 'return)
>            ;; sublevel of current
>            (setq org-remember-previous-location
>              (cons (abbreviate-file-name file)
>                (org-get-heading 'notags)))
>            (if reversed
>            (outline-next-heading)
>              (org-end-of-subtree t)
>              (if (not (bolp))
>              (if (looking-at "[ \t]*\n")
>                  (beginning-of-line 2)
>                (end-of-line 1)
>                (insert "\n"))))
>            (org-paste-subtree (org-get-valid-level level 1) txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point)))
>           ((eq exitcmd 'left)
>            ;; before current
>            (org-paste-subtree level txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point)))
>           ((eq exitcmd 'right)
>            ;; after current
>            (org-end-of-subtree t)
>            (org-paste-subtree level txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point)))
>           (t (error "This should not happen"))))
>
>         ((eq heading 'bottom)
>          (org-paste-subtree 1 txt)
>          (and org-auto-align-tags (org-set-tags nil t))
>          (bookmark-set "org-remember-last-stored")
>          (move-marker org-remember-last-stored-marker (point)))
>
>         ((and (bobp) (not reversed))
>          ;; Put it at the end, one level below level 1
>          (save-restriction
>            (widen)
>            (goto-char (point-max))
>            (if (not (bolp)) (newline))
>            (org-paste-subtree (org-get-valid-level 1 1) txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point))))
>
>         ((and (bobp) reversed)
>          ;; Put it at the start, as level 1
>          (save-restriction
>            (widen)
>            (goto-char (point-min))
>            (re-search-forward "^\\*+ " nil t)
>            (beginning-of-line 1)
>            (org-paste-subtree 1 txt)
>            (and org-auto-align-tags (org-set-tags nil t))
>            (bookmark-set "org-remember-last-stored")
>            (move-marker org-remember-last-stored-marker (point))))
>         (t
>          ;; Put it right there, with automatic level determined by
>          ;; org-paste-subtree or from prefix arg
>          (org-paste-subtree
>           (if (numberp current-prefix-arg) current-prefix-arg)
>           txt)
>          (and org-auto-align-tags (org-set-tags nil t))
>          (bookmark-set "org-remember-last-stored")
>          (move-marker org-remember-last-stored-marker (point))))
>
>       (when remember-save-after-remembering
>         (save-buffer)
>         (if (and (not visiting)
>              (not (equal (marker-buffer org-clock-marker)
>                  (current-buffer))))
>         (kill-buffer (current-buffer)))))))))
>
> t)    ;; return t to indicate that we took care of this note.
>
>
> _______________________________________________
> Emacs-orgmode mailing list
> Remember: use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Org-remember-handler fix for empty remember buffer
  2009-06-08 17:45 ` Carsten Dominik
@ 2009-06-08 19:45   ` Ryan C. Thompson
  2009-06-08 20:51     ` Carsten Dominik
  0 siblings, 1 reply; 5+ messages in thread
From: Ryan C. Thompson @ 2009-06-08 19:45 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 597 bytes --]

Carsten Dominik wrote:
> Fixed, thanks.
>
> - Carsten
>
> On Jun 4, 2009, at 7:45 PM, Ryan C. Thompson wrote:
>
>
If you used the code I sent in my previous email, I discovered a bug in 
it. It would delete the last nonblank line as well. I have fixed this in 
my code. I've fixed things by copying the function into my .emacs and 
then editing it, so generating a diff -u is nontrivial. I'll do it now 
though.

Also, I should mention that I'm not an experienced elisp hacker, so the 
solution that I came up with might not be the best. If you know a better 
way to do the same thing, go for it.

[-- Attachment #2: org-remember.el.diff --]
[-- Type: text/x-patch, Size: 806 bytes --]

--- /usr/share/emacs/site-lisp/org-mode/org-remember.el	2009-03-13 10:00:34.000000000 -0400
+++ org-remember.el	2009-06-08 15:43:04.708905961 -0400
@@ -740,10 +740,14 @@
     (replace-match ""))
   (goto-char (point-max))
   (beginning-of-line 1)
-  (while (looking-at "[ \t]*$\\|##.*")
-    (delete-region (1- (point)) (point-max))
-    (beginning-of-line 1))
   (catch 'quit
+    (while (looking-at "[ \t]*$\\|##.*")
+      ;; Abort on empty buffer
+      (if (= (point) (point-min))
+          (throw 'quit nil)
+        (previous-line)))
+    (end-of-line 1) ; end of last nonblank line
+    (delete-region (point) (point-max))
     (if org-note-abort (throw 'quit nil))
     (let* ((visitp (org-bound-and-true-p org-jump-to-target-location))
 	   (previousp (and (member current-prefix-arg '((16) 0))

[-- Attachment #3: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Org-remember-handler fix for empty remember buffer
  2009-06-08 19:45   ` Ryan C. Thompson
@ 2009-06-08 20:51     ` Carsten Dominik
  0 siblings, 0 replies; 5+ messages in thread
From: Carsten Dominik @ 2009-06-08 20:51 UTC (permalink / raw)
  To: Ryan C. Thompson; +Cc: emacs-orgmode

Hi Ryan,

On Jun 8, 2009, at 9:45 PM, Ryan C. Thompson wrote:

> Carsten Dominik wrote:
>> Fixed, thanks.
>>
>> - Carsten
>>
>> On Jun 4, 2009, at 7:45 PM, Ryan C. Thompson wrote:
>>
>>
> If you used the code I sent in my previous email, I discovered a bug  
> in it. It would delete the last nonblank line as well. I have fixed  
> this in my code. I've fixed things by copying the function into  
> my .emacs and then editing it, so generating a diff -u is  
> nontrivial. I'll do it now though.

Thanks.

>
> Also, I should mention that I'm not an experienced elisp hacker, so  
> the solution that I came up with might not be the best.

No worry, I do look at every patch beore checking it in.

- Carsten


> --- /usr/share/emacs/site-lisp/org-mode/org-remember.el	2009-03-13  
> 10:00:34.000000000 -0400
> +++ org-remember.el	2009-06-08 15:43:04.708905961 -0400
> @@ -740,10 +740,14 @@
>     (replace-match ""))
>   (goto-char (point-max))
>   (beginning-of-line 1)
> -  (while (looking-at "[ \t]*$\\|##.*")
> -    (delete-region (1- (point)) (point-max))
> -    (beginning-of-line 1))
>   (catch 'quit
> +    (while (looking-at "[ \t]*$\\|##.*")
> +      ;; Abort on empty buffer
> +      (if (= (point) (point-min))
> +          (throw 'quit nil)
> +        (previous-line)))
> +    (end-of-line 1) ; end of last nonblank line
> +    (delete-region (point) (point-max))
>     (if org-note-abort (throw 'quit nil))
>     (let* ((visitp (org-bound-and-true-p org-jump-to-target-location))
> 	   (previousp (and (member current-prefix-arg '((16) 0))

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2009-06-08 20:51 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-04 17:45 Org-remember-handler fix for empty remember buffer Ryan C. Thompson
2009-06-07 14:18 ` Carsten Dominik
2009-06-08 17:45 ` Carsten Dominik
2009-06-08 19:45   ` Ryan C. Thompson
2009-06-08 20:51     ` Carsten Dominik

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).