Is there emacs capability for visiting last edits? - emacs

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).

Related

on Emacs for OSX, how to keep kill ring and clipboard separate?

In GNU Emacs for OSX, how can I keep the kill ring and OSX clipboard separate? (Such that I essentially have two separate kill rings.)
With desired behavior, this would work:
1. ⌘C to copy text from the web to OSX clipboard.
2. controlk to kill a line in Emacs.
3. controly to yank killed text from Emacs kill ring to current Emacs buffer.
4. ⌘v to paste original web text from OSX clipboard to current Emacs buffer.
This works out of the box in Aquamacs. How to make work in GNU Emacs?
This question was discussed as it pertains to Windows here:
Emacs: How to separate the kill ring from the system clipboard?
and here:
http://lists.gnu.org/archive/html/help-emacs-windows/2010-02/msg00001.HTML
...but this solution does not work in OSX. I would like a solution for Mac OSX.
The solution in Emacs: How to separate the kill ring from the system clipboard? does work, though not complete. You may call pbcopy yourself to get clipboard pasting right. For instance, try the following in your .emacs. Note that s-v is for Cmd+V in an OS X window system. Same goes for s-c.
;;; Tested on:
;;; 1. GNU Emacs 24.3.1 (x86_64-apple-darwin13.0.0)
;;; of 2013-12-22 on tennine-slave.macports.org
;;; (MacPorts emacs#24.3_1)
;;;
;;; 2. GNU Emacs 24.3.1 (x86_64-apple-darwin, NS apple-appkit-1038.36)
;;; of 2013-03-12 on bob.porkrind.org
;;; (Emacs For Mac OS X)
(defun isolate-kill-ring()
"Isolate Emacs kill ring from OS X system pasteboard.
This function is only necessary in window system."
(interactive)
(setq interprogram-cut-function nil)
(setq interprogram-paste-function nil))
(defun pasteboard-copy()
"Copy region to OS X system pasteboard."
(interactive)
(shell-command-on-region
(region-beginning) (region-end) "pbcopy"))
(defun pasteboard-paste()
"Paste from OS X system pasteboard via `pbpaste' to point."
(interactive)
(shell-command-on-region
(point) (if mark-active (mark) (point)) "pbpaste" nil t))
(defun pasteboard-cut()
"Cut region and put on OS X system pasteboard."
(interactive)
(pasteboard-copy)
(delete-region (region-beginning) (region-end)))
(if window-system
(progn
(isolate-kill-ring)
;; bind CMD+C to pasteboard-copy
(global-set-key (kbd "s-c") 'pasteboard-copy)
;; bind CMD+V to pasteboard-paste
(global-set-key (kbd "s-v") 'pasteboard-paste)
;; bind CMD+X to pasteboard-cut
(global-set-key (kbd "s-x") 'pasteboard-cut))
;; you might also want to assign some keybindings for non-window
;; system usage (i.e., in your text terminal, where the
;; command->super does not work)
)
If you ever run into problems with UTF-8, consider the following possible solution:
;; handle emacs utf-8 input
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(setenv "LANG" "en_US.UTF-8")
After much fiddling around, I'm pretty sure that the only way to make this work is to override the x-select-text method. Check out my answer here for all the details: https://stackoverflow.com/a/23254771/71522
NOTE:  This draft solution is not meant to be an Emacs system-wide modification separating the clipboards -- instead, this is a custom solution designed to keep the clipboards separated on an interactive basis only when specifically using these custom functions. Other functions within
Emacs that use the kill-ring can be modified using a similar method -- the variables interprogram-cut-function and interprogram-paste-function can be made let-bound to a nil value for the duration of the specific functions (either through advice, or modification of the source itself, or creating new functions and/or using a defalias). However, the latter is beyond the scope of this limited example.
HISTORY
First Draft (December 23, 2014):  This is a first draft, which is based on the idea that the OSX clipboard may be accessed only when using C-u before calling either the copy or paste functions. If C-u is called first, then the OSX clipboard is utilized. As I use the functions more on a daily basis, I may have additional revisions to this code and I will update same from time to time:
EDIT (December 24, 2014):  Removed * from the interactive command statement as to lawlist-copy-selected-region -- that was a read-only check needed for pasting, but not copying. Added a statement regarding the general nature of this example.
EDIT (December 28, 2014):  Revised code to better handle when the user forgot to select a region before calling lawlist-copy-selected-region. Small revisions to make the code more concise.
(defun lawlist-copy-selected-region (&optional arg)
(interactive "P")
(let* (
(interprogram-cut-function
(when (equal arg '(4)) interprogram-cut-function))
(interprogram-paste-function
(when (equal arg '(4)) interprogram-paste-function))
(region-active-p (region-active-p))
(beg (when region-active-p (region-beginning)))
(end (when region-active-p (region-end)))
(copied-string
(when region-active-p (buffer-substring-no-properties beg end))) )
(unless region-active-p
(let ((debug-on-quit nil))
(signal 'quit `("No region has been selected!"))))
(copy-region-as-kill beg end)
(when (not (active-minibuffer-window))
(message "%s"
(concat
(if (and interprogram-cut-function interprogram-paste-function)
"OSX+Emacs: "
"Emacs: ")
(truncate-string-to-width copied-string 40)
(when (> (length copied-string) 40)
" . . .")))) ))
(defun lawlist-yank (&optional arg)
(interactive "*P")
(unless arg (setq arg 1))
(setq yank-window-start (window-start))
(setq this-command t)
(push-mark (point))
(insert-for-yank
(lawlist-current-kill
(cond
((listp arg)
arg)
((eq arg '-)
-2)
(t
(1- arg) ))))
(if (consp arg)
(goto-char (prog1 (mark t)
(set-marker (mark-marker) (point) (current-buffer)))))
(if (eq this-command t)
(setq this-command 'yank))
(when (region-active-p)
(setq mark-active nil))
nil)
(defun lawlist-current-kill (n &optional do-not-move)
(let ((interprogram-paste
(and
(equal n '(4))
interprogram-paste-function
(funcall interprogram-paste-function))))
(cond
(interprogram-paste
(let ((interprogram-cut-function nil))
(if (listp interprogram-paste)
(mapc 'kill-new (nreverse interprogram-paste))
(kill-new interprogram-paste)))
(car kill-ring))
((and (equal n '(4)) (not interprogram-paste))
(car kill-ring))
(t
(or kill-ring
(let ((debug-on-quit nil))
(signal 'quit `("The kill-ring is empty."))))
(let (
(ARGth-kill-element
(nthcdr
(mod (- n (length kill-ring-yank-pointer)) (length kill-ring))
kill-ring)))
(unless do-not-move
(setq kill-ring-yank-pointer ARGth-kill-element)
(when
(and
yank-pop-change-selection
(> n 0)
interprogram-cut-function)
(funcall interprogram-cut-function (car ARGth-kill-element))))
(car ARGth-kill-element))))))
(global-set-key (kbd "C-x M-y")
(lambda ()
(interactive)
(insert-string (ns-get-pasteboard))))
(global-set-key (kbd "C-x M-w")
(lambda ()
(interactive)
(when (region-active-p)
(ns-set-pasteboard
(buffer-substring (region-beginning)
(region-end))))))
simpleclip might be helpful -
Simplified access to the system clipboard in Emacs.
simpleclip-mode radically simplifies clipboard handling: the system
clipboard and the Emacs kill ring are made completely independent, and
never influence each other.
The super keybindings are friendly for OS X: super is generally mapped
to the "command" key ie ⌘.
Tested on OS X, X11, and MS Windows
https://github.com/rolandwalker/simpleclip
Use
(setq select-enable-clipboard nil)
This will only separate the two clipboards, and for ⌘ c and ⌘ v to work like mentioned you will have to rebind them to clipboard-kill-ring-save and clipboard-yank:
(keymap-global-set "s-c" 'clipboard-kill-ring-save)
(keymap-global-set "s-x" 'clipboard-kill-region)
(keymap-global-set "s-v" 'clipboard-yank)
I am using this Emacs: https://github.com/railwaycat/emacs-mac-port, and it also works on Emacs 28 built from source.

Emacs - set mark on edit location

I want emacs to add last edit location to the mark ring, so I can jump back to previous edit locations.
Ideally this would only mark one edit location per line. When I edit another line, the last edit location on that line would be added to the ring, and so forth.
I'm not familiar with Lisp to implement this myself. If anyone knows of a plugin or can kindly provide a solution that would be great! :)
You can install a package goto-last-change which allows you to jump sequentially to the buffer undo positions (last edit locations).
Session.el provides this functionality bound to "C-x C-/" or session-jump-to-last-change.
Session dos it per buffer. I'm unaware of anything that does it globally.
I implement a similar function, by recording 2 file's last edit locations(not per buffer), and cycle them when requested. Somewhat like how eclipse does(but less powerful, only 2 file's are recorded)
emacs-last-edit-location
the code:
;;; 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)

Close all buffers besides the current one in Emacs

How do I close all but the current buffer in Emacs? Similar to "Close other tabs" feature in modern web browsers?
For a more manual approach, you can list all buffers with C-x C-b, mark buffers in the list for deletion with d, and then use x to remove them.
I also recommend replacing list-buffers with the more advanced ibuffer: (global-set-key (kbd "C-x C-b") 'ibuffer). The above will work with ibuffer, but you could also do this:
m (mark the buffer you want to keep)
t (toggle marks)
D (kill all marked buffers)
I also use this snippet from the Emacs Wiki, which would further streamline this manual approach:
;; Ensure ibuffer opens with point at the current buffer's entry.
(defadvice ibuffer
(around ibuffer-point-to-most-recent) ()
"Open ibuffer with cursor pointed to most recent buffer name."
(let ((recent-buffer-name (buffer-name)))
ad-do-it
(ibuffer-jump-to-buffer recent-buffer-name)))
(ad-activate 'ibuffer)
From EmacsWiki: Killing Buffers:
(defun kill-other-buffers ()
"Kill all other buffers."
(interactive)
(mapc 'kill-buffer
(delq (current-buffer)
(remove-if-not 'buffer-file-name (buffer-list)))))
Edit: updated with feedback from Gilles
There isn't a way directly in emacs to do this.
You could write a function to do this. The following will close all the buffers:
(defun close-all-buffers ()
(interactive)
(mapc 'kill-buffer (buffer-list)))
There is a built in command m-x kill-some-buffers (I'm using 24.3.50) In my nextstep gui (not tried in a terminal but sure it's similar) you can then approve which buffers to kill.
(defun only-current-buffer ()
(interactive)
(let ((tobe-killed (cdr (buffer-list (current-buffer)))))
(while tobe-killed
(kill-buffer (car tobe-killed))
(setq tobe-killed (cdr tobe-killed)))))
It works as you expected.
And after reading #Starkey's answer, I think this will be better:
(defun only-current-buffer ()
(interactive)
(mapc 'kill-buffer (cdr (buffer-list (current-buffer)))))
(buffer-list (current-buffer)) will return a list that contains all the existing buffers, with the current buffer at the head of the list.
This is my first answer on StackOverflow. Hope it helps :)
I found this solution to be the simplest one. This deletes every buffer except the current one. You have to add this code to your .emacs file
(defun kill-other-buffers ()
"Kill all other buffers."
(interactive)
(mapc 'kill-buffer (delq (current-buffer) (buffer-list))))
Of course, then you use it with M-x kill-other-buffers RET or you paste the following code in the .emacs file too and then just press C-xC-b
(global-set-key (kbd "C-x C-b") 'kill-other-buffers)
You can like this one as well - kill all buffers except current one, *Messages* and *scratch* (which are handy to have, I call them "toolkit"), close redundant windows as well, living you which one window which current buffer.
(defun my/kill-all-buffers-except-toolbox ()
"Kill all buffers except current one and toolkit (*Messages*, *scratch*). Close other windows."
(interactive)
(mapc 'kill-buffer (remove-if
(lambda (x)
(or
(eq x (current-buffer))
(member (buffer-name x) '("*Messages*" "*scratch*"))))
(buffer-list)))
(delete-other-windows))
I've use crux-kill-other-buffers for some months.
But I want dired buffers get deleted too. #Euge's and #wenjun.yan's answers solve this. But it will delete special buffers (e.g *git-credential-cache--daemon*, *scratch*, helm operation, and etc). So I came up with this (current) solution.
(defun aza-kill-other-buffers ()
"Kill all buffers but current buffer and special buffers"
(interactive)
(dolist (buffer (delq (current-buffer) (buffer-list)))
(let ((name (buffer-name buffer)))
(when (and name (not (string-equal name ""))
(/= (aref name 0) ?\s)
(string-match "^[^\*]" name))
(funcall 'kill-buffer buffer)))))
Inspired from kill-matching-buffers. You can add more condition on other buffer-name to exclude, if you want to.
Hope it helps :)
I've used one of the solutions in this list for years, but now I have a new one of my own.
(defun kill-all-file-buffers ()
"Kills all buffers that are open to files. Does not kill
modified buffers or special buffers."
(interactive)
(mapc 'kill-buffer (cl-loop for buffer being the buffers
when (and (buffer-file-name buffer)
(not (buffer-modified-p buffer)))
unless (eq buffer (current-buffer))
collect buffer)))
cl-loop has buffers built in as a collection that you can iterate over. It gives you a chance to parse out anything you don't want to close. Here, I've made sure that it doesn't close anything you've modified, and it uses buffer-file-name instead of just buffer-name so it doesn't kill special buffers. I also added an 'unless' to take out the current buffer (though you could obviously add it to the 'when', I just thought this was clearer).
But for an even more generic solution, we can define this as a macro, and pass in a function that will apply to all these buffers.
(defmacro operate-on-file-buffers (func)
"Takes any function that takes a single buffer as an argument
and applies that to all open file buffers that haven't been
modified, and aren't the current one."
`(mapc ,func (cl-loop for buffer being the buffers
when (and (buffer-file-name buffer)
(not (buffer-modified-p buffer)))
unless (eq buffer (current-buffer))
collect buffer)))
Now if you want to kill all buffers that match this, you can call it like this
(operate-on-file-buffers 'kill-buffer)
This is what you want:
C-x 1
source: https://blasphemousbits.wordpress.com/2007/05/04/learning-emacs-part-4-buffers-windows-and-frames/

Emacs Lisp buffer not running font lock mode until opened by user

My problem is I am opening a buffer using (set-buffer (find-tag-noselect (current-word))) and then I try to copy some text out of that buffer. The text that I get back has only the properties (fontified nil). find-tag-noselect automatically opens the buffer found in the TAGS file but it seems it does not run the font lock mode over it. When I manually switch to this buffer after it has been opened and then run the function again when it copies the text it has all the correct text properties attached. So what do I need to do to have this buffer completely initialized so that the correct syntax highlighting will be copied in?
(defvar newline-string "
")
(defun get-initial-indent-regexp-python()
"Gets the initial amount of spaces for the function we are looking at, does not account for tabs"
(concat "^" (get-current-indent-string) (concat "[^ #" newline-string "]")))
(defun get-end-of-function-python(spaces-regex)
"Gets the point at the end of a python block"
(save-excursion
(forward-line 1)
(while (and (not (looking-at spaces-regex)) (equal (forward-line 1) 0)))
(point)))
(defun get-point-at-end-of-function ()
"This might be better served checking the major mode."
(setq extension (file-name-extension (buffer-file-name)))
(if (equal extension "py")
(get-end-of-function-python (get-initial-indent-regexp-python))))
(defun inline-function ()
"Must change to overlays, be able to toggle visibility"
(interactive)
(let (text indent-string)
; clean all overlays without attached buffer
(save-excursion
(set-buffer (find-tag-noselect (current-word)))
(setq text (buffer-substring (point) (get-point-at-end-of-function))))
(setq text (concat newline-string text))
(save-excursion
(move-end-of-line nil)
(let (overlay)
(setq overlay (make-overlay (point) (+ (point) 1) (current-buffer)))
(overlay-put overlay 'display text)
(setq inline-func-overlays (cons overlay inline-func-overlays))))))
What's happening is that font-lock is done on-the-fly, so only the displayed parts of the buffer get "fontified". If you want/need to overrule this optimization, you need different functions depending on the circumstance (depending on how font-lock happens to be configured). We should add a new font-lock-ensure-fontified function for that, but in the mean time, you can take ps-print-.el as an example:
(defun ps-print-ensure-fontified (start end)
(cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode))
(jit-lock-fontify-now start end))
((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode))
(lazy-lock-fontify-region start end))))
I'm not exactly sure what you're trying to do, but set-buffer does not display the buffer, so its effect ends when the current command terminates. It's generally useful only for temporary buffer switches inside a function and I guess this is the reason it doesn't run font-lock on the buffer. When you manually go to the buffer you're probably using a different function - switch-to-buffer.
Try explicitly calling 'font-lock-fontify-buffer'.

How to execute emacs grep-find link in the same window?

When I use grep-find it opens another window (area in the frame) with a list of results that I can select. When I select one it opens the target file in a different window than grep-find is in.
How can I get the target file to open in the same window as the grep results (replacing the grep results window with what I am actually looking for).
How can I keep grep-find from opening a separate window (have it so it opens in the current window). My goal is I look for something, I find it, I go to it, all within the same window. I would like to add this to my .emacs file.
It doesn't look like there is any way to configure the compile package to do what you're asking. And there's no easy way to use advice to tweak the behavior. I think you have to resort to editing the function which actually jumps to the error, which you can do with the following addition to your .emacs (tested in Emacs 23.1):
(eval-after-load "compile"
'(defun compilation-goto-locus (msg mk end-mk)
"Jump to an error corresponding to MSG at MK.
All arguments are markers. If END-MK is non-nil, mark is set there
and overlay is highlighted between MK and END-MK."
;; Show compilation buffer in other window, scrolled to this error.
(let* ((from-compilation-buffer (eq (window-buffer (selected-window))
(marker-buffer msg)))
;; Use an existing window if it is in a visible frame.
(pre-existing (get-buffer-window (marker-buffer msg) 0))
(w (if (and from-compilation-buffer pre-existing)
;; Calling display-buffer here may end up (partly) hiding
;; the error location if the two buffers are in two
;; different frames. So don't do it if it's not necessary.
pre-existing
(let ((display-buffer-reuse-frames t)
(pop-up-windows t))
;; Pop up a window.
(display-buffer (marker-buffer msg)))))
(highlight-regexp (with-current-buffer (marker-buffer msg)
;; also do this while we change buffer
(compilation-set-window w msg)
compilation-highlight-regexp)))
;; Ideally, the window-size should be passed to `display-buffer' (via
;; something like special-display-buffer) so it's only used when
;; creating a new window.
(unless pre-existing (compilation-set-window-height w))
(switch-to-buffer (marker-buffer mk))
;; was
;; (if from-compilation-buffer
;; ;; If the compilation buffer window was selected,
;; ;; keep the compilation buffer in this window;
;; ;; display the source in another window.
;; (let ((pop-up-windows t))
;; (pop-to-buffer (marker-buffer mk) 'other-window))
;; (if (window-dedicated-p (selected-window))
;; (pop-to-buffer (marker-buffer mk))
;; (switch-to-buffer (marker-buffer mk))))
;; If narrowing gets in the way of going to the right place, widen.
(unless (eq (goto-char mk) (point))
(widen)
(goto-char mk))
(if end-mk
(push-mark end-mk t)
(if mark-active (setq mark-active)))
;; If hideshow got in the way of
;; seeing the right place, open permanently.
(dolist (ov (overlays-at (point)))
(when (eq 'hs (overlay-get ov 'invisible))
(delete-overlay ov)
(goto-char mk)))
(when highlight-regexp
(if (timerp next-error-highlight-timer)
(cancel-timer next-error-highlight-timer))
(unless compilation-highlight-overlay
(setq compilation-highlight-overlay
(make-overlay (point-min) (point-min)))
(overlay-put compilation-highlight-overlay 'face 'next-error))
(with-current-buffer (marker-buffer mk)
(save-excursion
(if end-mk (goto-char end-mk) (end-of-line))
(let ((end (point)))
(if mk (goto-char mk) (beginning-of-line))
(if (and (stringp highlight-regexp)
(re-search-forward highlight-regexp end t))
(progn
(goto-char (match-beginning 0))
(move-overlay compilation-highlight-overlay
(match-beginning 0) (match-end 0)
(current-buffer)))
(move-overlay compilation-highlight-overlay
(point) end (current-buffer)))
(if (or (eq next-error-highlight t)
(numberp next-error-highlight))
;; We want highlighting: delete overlay on next input.
(add-hook 'pre-command-hook
'compilation-goto-locus-delete-o)
;; We don't want highlighting: delete overlay now.
(delete-overlay compilation-highlight-overlay))
;; We want highlighting for a limited time:
;; set up a timer to delete it.
(when (numberp next-error-highlight)
(setq next-error-highlight-timer
(run-at-time next-error-highlight nil
'compilation-goto-locus-delete-o)))))))
(when (and (eq next-error-highlight 'fringe-arrow))
;; We want a fringe arrow (instead of highlighting).
(setq next-error-overlay-arrow-position
(copy-marker (line-beginning-position)))))))
The eval-afer-load portion just ensures that you re-define it after Emacs defined it, so that your change takes hold.
You can add a binding (e.g. Alt-m) and do the following
(define-key grep-mode-map "\M-m" (lambda()
(interactive)
(compile-goto-error)
(delete-other-windows)
(kill-buffer "*grep*")))
I didn't find a way to replace the standard "Enter" / Mouse-click binding with a custom function
There is an another approach:
(defun eab/compile-goto-error ()
(interactive)
(let ((cwc (current-window-configuration)))
(funcall
`(lambda ()
(defun eab/compile-goto-error-internal ()
(let ((cb (current-buffer))
(p (point)))
(set-window-configuration ,cwc)
(switch-to-buffer cb)
(goto-char p ))))))
(compile-goto-error)
(run-with-timer 0.01 nil 'eab/compile-goto-error-internal))
I had the same question, and found this answer over at emacs.stackexchange https://emacs.stackexchange.com/a/33908/20000
(defun my-compile-goto-error-same-window ()
(interactive)
(let ((display-buffer-overriding-action
'((display-buffer-reuse-window
display-buffer-same-window)
(inhibit-same-window . nil))))
(call-interactively #'compile-goto-error)))
(defun my-compilation-mode-hook ()
(local-set-key (kbd "o") #'my-compile-goto-error-same-window))
(add-hook 'compilation-mode-hook #'my-compilation-mode-hook)
Pressing o in the *grep* buffer will open the location and file in the same frame.
I found this an elegant solution without deleting frames or too much lisp code and just hooking into compilation-mode-hook.