Emacs persistent folding mode - emacs

There are plenty of ways to fold code in Emacs and I've settled in on using the outline minor mode... it works great!
However, I really want my folding to be persisted when I close and re-open files. It is quite frustrating to have folding set up in a file the way I like it, only to have that lost when I restart Emacs.
Has anyone found a way to keep the folding state of a file persistent?

Edit: Now that I understand the question...
How about something like the following nippet of code. It seems to work for me, though I haven't figured out how to avoid being prompted for the file local variable every time.
(defvar omm-state nil
"file local variable storing outline overlays")
(defun omm-state-mode (&optional arg)
"poor man's minor mode to re-apply the outline overlays "
(interactive)
(omm-re-enable-outline-state)
(add-hook 'before-save-hook 'omm-state-save))
(defun omm-get-all-overlays ()
"return a list of outline information for all the current buffer"
(save-excursion
(let ((all-overlays (overlays-in (point-min) (point-max))))
(mapcar (lambda (o)
(list (overlay-start o) (overlay-end o) (overlay-get o 'invisible)))
(reverse all-overlays)))))
(defun omm-re-enable-outline-state (&optional arg)
"turn on outline-minor-mode and re-apply the outline information"
(outline-minor-mode 1)
(when (listp omm-state)
(mapcar (lambda (p)
(apply 'outline-flag-region p))
omm-state)))
(defun omm-state-save ()
"save the outline state in a file local variable
Note: this just replaces the existing value, you need to start
it off by adding something like this to your file:
# Local Variables:
# omm-state:()
# mode:omm-state
# End:
"
(ignore-errors
(save-excursion
(goto-char (point-max))
(when (search-backward "omm-state:" nil t)
(goto-char (match-end 0))
(kill-sexp)
(princ (omm-get-all-overlays) (current-buffer)))))
nil)
This solution requires you "seeding" your file with something like:
# Local Variables:
# omm-state:()
# mode:omm-state
# End:

I realize this is an old post but FWIW I created a minor mode that complements hs-minor-mode, outline-mode etc. I also "really want my folding to be persisted when I close and re-open files". :)
The package is in MELPA as of today and called persistent-overlays.
It is also available directly on github: https://github.com/mneilly/Emacs-Persistent-Overlays

Related

Is there emacs capability for visiting last edits?

In the JetBrains products, there's a very handy key binding that lets you visit all the spots you made an edit. Hit the key once to go to the last edit (file and location), and keep hitting the key to go back to earlier edits. It's typically when editing that you want to be editing the same places over and over again, and if one has many buffers open, many of which are not edited, this is even more useful.
Emacs has a mark ring, but that's not quite the same thing.
On a related note, is there functionality in magit, the emacs git add-on, to jump to edits?
There is GotoLastChange which allows you to travel along the chain of undo locations. You can assign it to a key:
(global-set-key "\C-x\C-\\" 'goto-last-change)
There is GotoChg which allows you to travel back and forth the chain of undo locations. Sample init code snippet:
(require 'goto-chg)
(global-set-key [(control ?.)] 'goto-last-change)
(global-set-key [(control ?,)] 'goto-last-change-reverse)
(Just like the other alternatives, GotoLastChange and session.el, it can not jump between buffers)
Global, multi-buffer goto-last-change:
;;; record two different file's last change. cycle them
(defvar feng-last-change-pos1 nil)
(defvar feng-last-change-pos2 nil)
(defun feng-swap-last-changes ()
(when feng-last-change-pos2
(let ((tmp feng-last-change-pos2))
(setf feng-last-change-pos2 feng-last-change-pos1
feng-last-change-pos1 tmp))))
(defun feng-goto-last-change ()
(interactive)
(when feng-last-change-pos1
(let* ((buffer (find-file-noselect (car feng-last-change-pos1)))
(win (get-buffer-window buffer)))
(if win
(select-window win)
(switch-to-buffer-other-window buffer))
(goto-char (cdr feng-last-change-pos1))
(feng-swap-last-changes))))
(defun feng-buffer-change-hook (beg end len)
(let ((bfn (buffer-file-name))
(file (car feng-last-change-pos1)))
(when bfn
(if (or (not file) (equal bfn file)) ;; change the same file
(setq feng-last-change-pos1 (cons bfn end))
(progn (setq feng-last-change-pos2 (cons bfn end))
(feng-swap-last-changes))))))
(add-hook 'after-change-functions 'feng-buffer-change-hook)
;;; just quick to reach
(global-set-key (kbd "M-`") 'feng-goto-last-change)
from http://shenfeng.me/emacs-last-edit-location.html
This implementation works for the last two changes in any buffers. I imagine extending the length of its change-list beyond two wouldn't be too hard.
There is the command session-jump-to-last-change in session.el which allows you to travel along the chain of undo locations. Init code snippet:
(require 'session)
(setq session-jump-undo-threshold 80) ; default was 240
(global-set-key [(control ?.)] 'session-jump-to-last-change)
(Just like the other alternatives, GotoLastChange and GotoChg, it can not jump between buffers)
Single buffer
Tracking edits and go back to where they occurred depends on the type of them.
If your edit added something, you can go back to it with a rather simple:
(goto-char (car(cadr buffer-undo-list)))
If you deleted, something you can go back to it with:
(goto-char (abs (cdr(cadr buffer-undo-list))))
and you might like displaying what you deleted in the minibuffer:
(progn
(goto-char (abs (cdr(cadr buffer-undo-list))))
(message "DEL->: %s" (substring-no-properties (car(cadr buffer-undo-list)))))
Summing up:
(defun last-edit ()
"Go back to last add/delete edit"
(interactive)
(let* ((ubuf (cadr buffer-undo-list))
(beg (car ubuf))
(end (cdr ubuf)))
(cond
((integerp beg) (goto-char beg))
((stringp beg) (goto-char (abs end))
(message "DEL-> %s" (substring-no-properties beg)))
(t (message "No add/delete edit occurred")))))
Read C-h v buffer-undo-list and you might integrate this for less subtle edits, such as setting text properties (assuming you really need it).
Multi-buffer
I used the buffer-undo-list variable to carry out the tasks. There is a distinct list for each buffer and, as far as I know, there is no global undo-list. Most likely you know in which buffer you typed something and you want Emacs to bring to the edited spot. There is in this case a single global-mark-ring variable recording the sequence of buffers that you have been.
Successive uses of the command Meta-Xpop-global-mark,
or simply
Ctrl-X Ctrl-Space,
will bring you to earlier visited buffers (and mark positions). Once you get to the target buffer, you can trigger Meta-Xlast-edit (or the bound keys).

How to automatically do org-mobile-push org-mobile pull in emacs

Since I am using org-mode to track my todo list in emacs, I like the iPhone app: MobileOrg, with it, I can access my todo list all day.
But here's the problem:
I have to manually org-mobile-push my changes from local file to mobile phone through dropbox, and org-mobile-pull the changes made by phone back.
How to make that automatically? Like adding some recipes in dotemacs file.
Add these two lines to dot emacs file:
(add-hook 'after-init-hook 'org-mobile-pull)
(add-hook 'kill-emacs-hook 'org-mobile-push)
With them, it automatically pulls the changes on emacs startup, and pushes the changes before emacs exits.
-- Update
If you never exit your Emacs, this solution might not work for you. So, another solution using idle timer
;; moble sync
(defvar org-mobile-sync-timer nil)
(defvar org-mobile-sync-idle-secs (* 60 10))
(defun org-mobile-sync ()
(interactive)
(org-mobile-pull)
(org-mobile-push))
(defun org-mobile-sync-enable ()
"enable mobile org idle sync"
(interactive)
(setq org-mobile-sync-timer
(run-with-idle-timer org-mobile-sync-idle-secs t
'org-mobile-sync)));
(defun org-mobile-sync-disable ()
"disable mobile org idle sync"
(interactive)
(cancel-timer org-mobile-sync-timer))
(org-mobile-sync-enable)
I just found out it is same as below answer, so, if you prefer the idle timer solution, please upvote tkf's answer.
I have something like this in my Emacs setting to do push and pull when I am away from computer.
(defvar my-org-mobile-sync-timer nil)
(defvar my-org-mobile-sync-secs (* 60 20))
(defun my-org-mobile-sync-pull-and-push ()
(org-mobile-pull)
(org-mobile-push)
(when (fboundp 'sauron-add-event)
(sauron-add-event 'my 3 "Called org-mobile-pull and org-mobile-push")))
(defun my-org-mobile-sync-start ()
"Start automated `org-mobile-push'"
(interactive)
(setq my-org-mobile-sync-timer
(run-with-idle-timer my-org-mobile-sync-secs t
'my-org-mobile-sync-pull-and-push)))
(defun my-org-mobile-sync-stop ()
"Stop automated `org-mobile-push'"
(interactive)
(cancel-timer my-org-mobile-sync-timer))
(my-org-mobile-sync-start)
Alternative is to put the following in cron job
(I found this here https://github.com/matburt/mobileorg-android/wiki/Scripting/):
emacs --batch --load ~/.emacs --eval "(org-mobile-pull)" --eval "(org-mobile-push)"
This code is taken from http://kenmankoff.com/2012/08/17/emacs-org-mode-and-mobileorg-auto-sync/, with a couple of details changed. You need to configure the variables in the beginning. This code will
Check every 30s whether MobileOrg has synced, and if so
Pull from MobileOrg.
Push to MobileOrg.
This is necessary to update the agenda views in MobileOrg.
With this behavior, you can be away from your computer, update some things in MobileOrg, sync, wait 30 seconds, sync again, and your mobile agenda view will be updated.
Whenever an org file is saved
Check whether the saved org file is supposed to be synced with MobileOrg, and if so
Wait for the user to become idle
Push to MobileOrg
Code for your .emacs file:
(require 'org-mobile)
;; Configure these two variables
(setq org-mobile-inbox-for-pull "~/Dropbox/org/mobile.org"
org-mobile-directory "~/Dropbox/MobileOrg")
(require 'gnus-async)
;; Define a timer variable
(defvar org-mobile-push-timer nil
"Timer that `org-mobile-push-timer' used to reschedule itself, or nil.")
;; Push to mobile when the idle timer runs out
(defun org-mobile-push-with-delay (secs)
(when org-mobile-push-timer
(cancel-timer org-mobile-push-timer))
(setq org-mobile-push-timer
(run-with-idle-timer
(* 1 secs) nil 'org-mobile-push)))
;; After saving files, start an idle timer after which we are going to push
(add-hook 'after-save-hook
(lambda ()
(if (or (eq major-mode 'org-mode) (eq major-mode 'org-agenda-mode))
(dolist (file (org-mobile-files-alist))
(if (string= (expand-file-name (car file)) (buffer-file-name))
(org-mobile-push-with-delay 10))))))
;; watch mobileorg.org for changes, and then call org-mobile-pull
(defun org-mobile-install-monitor (file secs)
(run-with-timer
0 secs
(lambda (f p)
(unless (< p (second (time-since (elt (file-attributes f) 5))))
(org-mobile-pull)
(org-mobile-push)))
file secs))
(defvar monitor-timer (org-mobile-install-monitor (concat org-mobile-directory "/mobileorg.org") 30)
"Check if file changed every 30 s.")
you can also push right after saving a note, like this:
(add-hook
'after-save-hook
(lambda ()
(if (string= buffer-file-name "<path to my notes.org>")
(org-mobile-push)
)
))
I use this elisp code from gist on my init.el and it works pretty well, except it doesn't have org-mobile-pull built in.
As a side solution, similar to Sandeep C's
;; for Emacs 24.3.1 insert next line
(require 'cl)
;; automatically org-mobile-push on save of a file
(add-hook
'after-save-hook
(lambda ()
(let (
(org-filenames (mapcar 'file-name-nondirectory (directory-files org-directory))) ; list of org file names (not paths)
(filename (file-name-nondirectory buffer-file-name)) ; list of the buffers filename (not path)
)
(if (find filename org-filenames :test #'string=)
(org-mobile-push)
)
)
)
)
I opted to simply push when saving, so I added this to my emacs init file:
(defun org-mobile-push-on-save ()
"Used in `after-save-hook'."
(when (memq this-command '(save-buffer save-some-buffers))
(org-mobile-push)))
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'after-save-hook 'org-mobile-push-on-save nil 'make-local)))
In a nutshell, it adds an after-save-hook to org-mode buffers.
More info on the code:
https://emacs.stackexchange.com/a/14476/12694
https://stackoverflow.com/a/6141681/45881
For auto-pull, a timer as in other answers is probably a good way.

Persistent Undos in Emacs [duplicate]

Is there any way to have EMACS save your undo history between sessions?
I'm aware of the savehist lib, the saveplace lib, the desktop lib, and the windows lib, these all provide some session control but none seem to save the undo history.
From version 0.4 onwards, undo-tree supports persistent storage of undo-tree data between sessions "out of the box". (Note that there are significant bug-fixes related to this feature in more recent versions; the latest version at the time of writing is 0.6.3.)
Simply enable the undo-tree-auto-save-history customization option to automatically save and load undo history in undo-tree buffers. Or use the undo-tree-save/load-history commands to save and load undo history manually.
You need at least Emacs version 24.3 for this to work reliably, but with a recent enough Emacs it works very well.
Add the following to your .emacs file :
(global-undo-tree-mode)
(setq undo-tree-auto-save-history t)
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))
Explanation
(global-undo-tree-mode) enables undo tree.
(setq undo-tree-auto-save-history t) enables auto save of undo history.
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))) so that your project does not get littered with undo-history savefiles.
Here's some code I wrote which seems to do the trick. It isn't bullet-proof, as in, it doesn't handle all the file handling intricacies that Emacs does (e.g. overriding where auto-save files are put, symlink handling, etc.). But, it seemed to do the trick for some simple text files I manipulated.
(defun save-undo-filename (orig-name)
"given a filename return the file name in which to save the undo list"
(concat (file-name-directory orig-name)
"."
(file-name-nondirectory orig-name)
".undo"))
(defun save-undo-list ()
"Save the undo list to a file"
(save-excursion
(ignore-errors
(let ((undo-to-save `(setq buffer-undo-list ',buffer-undo-list))
(undo-file-name (save-undo-filename (buffer-file-name))))
(find-file undo-file-name)
(erase-buffer)
(let (print-level
print-length)
(print undo-to-save (current-buffer)))
(let ((write-file-hooks (remove 'save-undo-list write-file-hooks)))
(save-buffer))
(kill-buffer))))
nil)
(defvar handling-undo-saving nil)
(defun load-undo-list ()
"load the undo list if appropriate"
(ignore-errors
(when (and
(not handling-undo-saving)
(null buffer-undo-list)
(file-exists-p (save-undo-filename (buffer-file-name))))
(let* ((handling-undo-saving t)
(undo-buffer-to-eval (find-file-noselect (save-undo-filename (buffer-file-name)))))
(eval (read undo-buffer-to-eval))))))
(add-hook 'write-file-hooks 'save-undo-list)
(add-hook 'find-file-hook 'load-undo-list)
desktop-save-mode does not save buffer-undo-list by default. You just have to tell him!
(add-to-list 'desktop-locals-to-save 'buffer-undo-list)
Emacs Session appears to support this:
(add-to-list 'session-locals-include 'buffer-undo-list)
I have managed to get the undo history working by using the information provided here: http://emacs.stackexchange.com/q/3725/2287
Instead of patching the original file desktop.el.gz I created an advice that temporarily overrides (buffer-local-variables) then I use it together with the function that gathers information about the buffer.
(defun +append-buffer-undo-list-to-buffer-local-variables-advice (orig-fn &rest args)
"Override `buffer-local-variables' and call ORIG-FN with ARGS.
There is a bug in Emacs where the `buffer-undo-list' data is
missing from the output of `buffer-local-variables'. This
advice temporarily overrides the function and appends the
missing data."
(let ((orig-buffer-local-variables-fn (symbol-function 'buffer-local-variables)))
(cl-letf (((symbol-function 'buffer-local-variables)
#'(lambda () (append (funcall orig-buffer-local-variables-fn)
`(,(cons 'buffer-undo-list buffer-undo-list))))))
(apply orig-fn args))))
(advice-add #'desktop-buffer-info :around #'+append-buffer-undo-list-to-buffer-local-variables-advice)
(push 'buffer-undo-list desktop-locals-to-save)
(desktop-save-mode 1)
I hope this helps someone else.

Is there any way to have Emacs save your undo history between sessions?

Is there any way to have EMACS save your undo history between sessions?
I'm aware of the savehist lib, the saveplace lib, the desktop lib, and the windows lib, these all provide some session control but none seem to save the undo history.
From version 0.4 onwards, undo-tree supports persistent storage of undo-tree data between sessions "out of the box". (Note that there are significant bug-fixes related to this feature in more recent versions; the latest version at the time of writing is 0.6.3.)
Simply enable the undo-tree-auto-save-history customization option to automatically save and load undo history in undo-tree buffers. Or use the undo-tree-save/load-history commands to save and load undo history manually.
You need at least Emacs version 24.3 for this to work reliably, but with a recent enough Emacs it works very well.
Add the following to your .emacs file :
(global-undo-tree-mode)
(setq undo-tree-auto-save-history t)
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))
Explanation
(global-undo-tree-mode) enables undo tree.
(setq undo-tree-auto-save-history t) enables auto save of undo history.
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))) so that your project does not get littered with undo-history savefiles.
Here's some code I wrote which seems to do the trick. It isn't bullet-proof, as in, it doesn't handle all the file handling intricacies that Emacs does (e.g. overriding where auto-save files are put, symlink handling, etc.). But, it seemed to do the trick for some simple text files I manipulated.
(defun save-undo-filename (orig-name)
"given a filename return the file name in which to save the undo list"
(concat (file-name-directory orig-name)
"."
(file-name-nondirectory orig-name)
".undo"))
(defun save-undo-list ()
"Save the undo list to a file"
(save-excursion
(ignore-errors
(let ((undo-to-save `(setq buffer-undo-list ',buffer-undo-list))
(undo-file-name (save-undo-filename (buffer-file-name))))
(find-file undo-file-name)
(erase-buffer)
(let (print-level
print-length)
(print undo-to-save (current-buffer)))
(let ((write-file-hooks (remove 'save-undo-list write-file-hooks)))
(save-buffer))
(kill-buffer))))
nil)
(defvar handling-undo-saving nil)
(defun load-undo-list ()
"load the undo list if appropriate"
(ignore-errors
(when (and
(not handling-undo-saving)
(null buffer-undo-list)
(file-exists-p (save-undo-filename (buffer-file-name))))
(let* ((handling-undo-saving t)
(undo-buffer-to-eval (find-file-noselect (save-undo-filename (buffer-file-name)))))
(eval (read undo-buffer-to-eval))))))
(add-hook 'write-file-hooks 'save-undo-list)
(add-hook 'find-file-hook 'load-undo-list)
desktop-save-mode does not save buffer-undo-list by default. You just have to tell him!
(add-to-list 'desktop-locals-to-save 'buffer-undo-list)
Emacs Session appears to support this:
(add-to-list 'session-locals-include 'buffer-undo-list)
I have managed to get the undo history working by using the information provided here: http://emacs.stackexchange.com/q/3725/2287
Instead of patching the original file desktop.el.gz I created an advice that temporarily overrides (buffer-local-variables) then I use it together with the function that gathers information about the buffer.
(defun +append-buffer-undo-list-to-buffer-local-variables-advice (orig-fn &rest args)
"Override `buffer-local-variables' and call ORIG-FN with ARGS.
There is a bug in Emacs where the `buffer-undo-list' data is
missing from the output of `buffer-local-variables'. This
advice temporarily overrides the function and appends the
missing data."
(let ((orig-buffer-local-variables-fn (symbol-function 'buffer-local-variables)))
(cl-letf (((symbol-function 'buffer-local-variables)
#'(lambda () (append (funcall orig-buffer-local-variables-fn)
`(,(cons 'buffer-undo-list buffer-undo-list))))))
(apply orig-fn args))))
(advice-add #'desktop-buffer-info :around #'+append-buffer-undo-list-to-buffer-local-variables-advice)
(push 'buffer-undo-list desktop-locals-to-save)
(desktop-save-mode 1)
I hope this helps someone else.

Suppress emacs auto-fill in a selected region

I use emacs to edit everything. On some of my LateX documents I would like to automatically disable auto-fill mode when I am editing tables and code. Basically, I'd like to have two tags, like:
%%% BEGIN NO FILL
%%% END NO FILL
and nothing between them will be autofilled.
Can anybody think of a way to do this? I would need to figure out whether or not the cursor is inside the region and then have to toggle the mode, and would need to do that every time the cursor moved. Or is there a better way to do it?
If you are using AUCTeX (you should be) then you may want to check out LaTeX-indent-environment-list. Adding an environment to this variable will make it so that (among other things) M-q doesn't refill the paragraph. Unfortunately it doesn't seem work for auto-fill-mode. The following largely untested code added to LaTeX-mode-hook might do what you want.
(setq auto-fill-function
(lambda ()
(unless (> (save-excursion (or (search-backward "%%% BEGIN NO FILL" (point-min) t) 0))
(save-excursion (or (search-backward "%%% END NO FILL" (point-min) t) 0)))
(do-auto-fill))))
It's very stupid and inefficient, but seems to be fast enough on my machine. It doesn't allow nesting, and requires that you manually mark up all sections that you don't want filled. What I am thinking of adding to my .emacs (until I read your question I didn't realize how much this bugged me) is below which keys off of the current environment so there is no need for special markup (though it only looks at the innermost environment (I'm not sure how much of a problem that will cause in practice)). Combining the two is left as an exercise to the interested reader.
;; You can use the following to unset the variables and play around with them
;; (makunbound 'auto-fill-ignore-environments)
;; (makunbound 'auto-fill-ignore-environments-regexp)
(defcustom auto-fill-ignore-environments
(mapcar 'car LaTeX-indent-environment-list)
"List of environments for which `auto-fill-mode' should be
disabled. Used to generate `auto-fill-ignore-environments-regexp'."
:type '(sexp)
)
(defcustom auto-fill-ignore-environments-regexp
(regexp-opt auto-fill-ignore-environments)
"Regexp matching LaTeX environments for which `auto-fill-mode'
should be disabled. If not set, automatically generated from
`auto-fill-ignore-environments'"
:type '(string)
:set-after '(auto-fill-ignore-environments)
)
(add-hook 'LaTeX-mode-hook
(lambda ()
(setq auto-fill-function
(lambda ()
(unless (string-match auto-fill-ignore-environments-regexp
(LaTeX-current-environment))
(do-auto-fill))))))
I have never used defcustom before so I'm sure that part could be improved quite a bit.
Got it. Check this out:
(defun in-no-auto-fill-region ()
(> (save-excursion (or (search-backward "%%% BEGIN NO FILL" (point-min) t) 0))
(save-excursion (or (search-backward "%%% END NO FILL" (point-min) t) 0))
))
(defun previous-line-checking-auto-fill (arg)
(interactive "P")
(previous-line arg)
(if (in-no-auto-fill-region)
(turn-off-auto-fill)
(turn-on-auto-fill)))
(defun next-line-checking-auto-fill (arg)
(interactive "P")
(next-line arg)
(if (in-no-auto-fill-region)
(turn-off-auto-fill)
(turn-on-auto-fill)))
(add-hook 'LaTeX-mode-hook
'(lambda nil
(local-set-key "C-p" 'previous-line-checking-auto-fill)
(local-set-key "C-n" 'next-line-checking-auto-fill)
(auto-fill-mode 1)
))
Alternately, you can turn off auto-fill-mode and use M-q to format paragraphs. I don't love auto-fill's jumpiness so I use this in every mode.
If you want to go the route of advising/redefining all the movement functions, this should help:
(defmacro movement-advice (func)
`(defadvice ,func (after ; run this after the original function is done (and point has moved)
;; Give it a unique name
,(intern (concat (symbol-name func) "-auto-fill-auto-off"))
;; Hopefully this satisfies the arguments of any function we can throw at it
(&rest args)
;; turn it on
activate
)
"Turn auto-fill-mode on or off automatically."
(auto-fill-mode (not (in-no-auto-fill-region)))))
(dolist (func '(next-line
previous-line
forward-paragraph
backward-paragraph
mouse-drag-region
;; Whatever you use
))
(eval `(movement-advice ,func)))