In Emacs org-mode, is there a way to get inline footnote definitions to appear as collapsed?
So that for instance, a line like this:
This effect is due to the strength of weak ties[fn:: Newman, Mark, Albert-László Barabási, and Duncan J. Watts. 2006. The Structure and Dynamics of Networks. Princeton, NJ: Princeton University Press].
might simply appear like this:
This effect is due to the strength of weak ties[✭].
I would also need a command to show the footnotes when necessary. So maybe what is needed are two commands: org-hide-footnotes and org-show-footnotes.
I don't believe this is possible at the moment. Also using TAB as the expansion key within for it would likely cause even more overloading of the key.
On the other hand, is there any particular reason not to use a footnote section for the footnotes?
C-c C-x f will create/interact with any footnotes you have.
(org-footnote-action &optional SPECIAL)
Do the right thing for footnotes.
When at a footnote reference, jump to the definition.
When at a definition, jump to the references if they exist, offer to
create them otherwise.
When neither at definition or reference, create a new footnote,
interactively.
With prefix arg SPECIAL, offer additional commands in a menu.
The additional commands being:
s Sort the footnote definitions by reference sequence. During editing,
Org makes no effort to sort footnote definitions into a particular
sequence. If you want them sorted, use this command, which will
also move entries according to org-footnote-section. Automatic
sorting after each insertion/deletion can be configured using the
variable org-footnote-auto-adjust.
r Renumber the simple fn:N footnotes. Automatic renumbering
after each insertion/deletion can be configured using the variable
org-footnote-auto-adjust.
S Short for first r, then s action.
n Normalize the footnotes by collecting all definitions (including
inline definitions) into a special section, and then numbering them
in sequence. The references will then also be numbers. This is
meant to be the final step before finishing a document (e.g., sending
off an email). The exporters do this automatically, and so could
something like message-send-hook.
d Delete the footnote at point, and all definitions of and references
to it.
INITIAL (February 6, 2014): First working draft.
EDIT February 18, 2014: Revised the function lawlist-toggle-block-visibility so that it contains a proper if/then/else statement -- i.e., if the line contains the requisite beginning region regexp, then the block visibility will be toggled, else a message saying sorry . . . . Added a citation to a related thread for code folding. Revised the error message to refer to a point rather than a line.
The source code for the answer below is also stored on Github: https://github.com/lawlist/lawlist-org-block-toggle/blob/master/lawlist-org-block-toggle.el
On a related issue (i.e., to completely hide the properties drawer including the word :PROPERTIES:), please refer to the following thread: Completely hide the :PROPERTIES: drawer in org-mode
On a semi-related issue (i.e., to create a custom block to be code-folded), see also: https://tex.stackexchange.com/a/161196/26911
This solution was tested with a fairly recent version of Emacs Trunk (built on January 19, 2014), which contains org-mode version 8.2.5c. Inasmuch as the :PROPERTIES: drawer through its :END: gets folded separately from the footnotes and the html blocks, this solution contemplates that the footnote and/or html code blocks will not be anywhere inside that properties drawer. The footnote can appear anywhere in the text paragraph, but cannot have another pair of square brackets inside the footnote -- since this code looks for the first ending square bracket in order to mark the end of the folded region. This code contemplates that #+BEGIN_HTML and #+END_HTML will both be flush-left with the left-hand margin. The startup views still work the same way -- e.g., the variables org-startup-folded and org-hide-block-startup.
The modification of org-cycle-internal-local enables tab cycling for all forms of folding in org-mode. All we did was fix the pagination of the function to make it more readable, and added the following condition: ((eq org-cycle-subtree-status 'subtree) (org-show-subtree) (message "ALL") (setq org-cycle-subtree-status 'all)). The interactive function org-cycle is still used to tab cycle between all of the various folded / unfolded views. The function lawlist-block-org-cycle-internal-local is a non-interactive supporting function that is used by org-cycle. The two defalias portions of the code in this solution are needed for everything to work properly. Rather than using tab cycling, the user can also call the interactive function directly at the beginning of the headings or subheadings with: M-x org-cycle RET
To toggle visibility of the footnote or html block directly, we use the interactive function lawlist-toggle-block-visibility. Place the cursor anywhere on the line containing the beginning of the footnote or, the beginning of the html block, and type: M-x lawlist-toggle-block-visibility RET
(require 'org)
(defalias 'org-cycle-hide-drawers 'lawlist-block-org-cycle-hide-drawers)
(defun lawlist-block-org-cycle-hide-drawers (state)
"Re-hide all drawers, footnotes or html blocks after a visibility state change."
(when
(and
(derived-mode-p 'org-mode)
(not (memq state '(overview folded contents))))
(save-excursion
(let* (
(globalp (memq state '(contents all)))
(beg (if globalp (point-min) (point)))
(end
(cond
(globalp
(point-max))
((eq state 'children)
(save-excursion (outline-next-heading) (point)))
(t (org-end-of-subtree t)) )))
(goto-char beg)
(while
(re-search-forward
".*\\[fn\\|^\\#\\+BEGIN_HTML.*$\\|^[ \t]*:PROPERTIES:[ \t]*$" end t)
(lawlist-org-flag t))))))
(defalias 'org-cycle-internal-local 'lawlist-block-org-cycle-internal-local)
(defun lawlist-block-org-cycle-internal-local ()
"Do the local cycling action."
(let ((goal-column 0) eoh eol eos has-children children-skipped struct)
(save-excursion
(if (org-at-item-p)
(progn
(beginning-of-line)
(setq struct (org-list-struct))
(setq eoh (point-at-eol))
(setq eos (org-list-get-item-end-before-blank (point) struct))
(setq has-children (org-list-has-child-p (point) struct)))
(org-back-to-heading)
(setq eoh (save-excursion (outline-end-of-heading) (point)))
(setq eos (save-excursion (1- (org-end-of-subtree t t))))
(setq has-children
(or
(save-excursion
(let ((level (funcall outline-level)))
(outline-next-heading)
(and
(org-at-heading-p t)
(> (funcall outline-level) level))))
(save-excursion
(org-list-search-forward (org-item-beginning-re) eos t)))))
(beginning-of-line 2)
(if (featurep 'xemacs)
(while
(and
(not (eobp))
(get-char-property (1- (point)) 'invisible))
(beginning-of-line 2))
(while
(and
(not (eobp))
(get-char-property (1- (point)) 'invisible))
(goto-char (next-single-char-property-change (point) 'invisible))
(and
(eolp)
(beginning-of-line 2))))
(setq eol (point)))
(cond
((= eos eoh)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-pre-cycle-hook 'empty))
(org-unlogged-message "EMPTY ENTRY")
(setq org-cycle-subtree-status nil)
(save-excursion
(goto-char eos)
(outline-next-heading)
(if (outline-invisible-p)
(org-flag-heading nil))))
((and
(or
(>= eol eos)
(not (string-match "\\S-" (buffer-substring eol eos))))
(or
has-children
(not (setq children-skipped
org-cycle-skip-children-state-if-no-children))))
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-pre-cycle-hook 'children))
(if (org-at-item-p)
;; then
(org-list-set-item-visibility (point-at-bol) struct 'children)
;; else
(org-show-entry)
(org-with-limited-levels (show-children))
(when (eq org-cycle-include-plain-lists 'integrate)
(save-excursion
(org-back-to-heading)
(while (org-list-search-forward (org-item-beginning-re) eos t)
(beginning-of-line 1)
(let* (
(struct (org-list-struct))
(prevs (org-list-prevs-alist struct))
(end (org-list-get-bottom-point struct)))
(mapc (lambda (e) (org-list-set-item-visibility e struct 'folded))
(org-list-get-all-items (point) struct prevs))
(goto-char (if (< end eos) end eos)))))))
(org-unlogged-message "CHILDREN")
(save-excursion
(goto-char eos)
(outline-next-heading)
(if (outline-invisible-p)
(org-flag-heading nil)))
(setq org-cycle-subtree-status 'children)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-cycle-hook 'children)))
((or
children-skipped
(and
(eq last-command this-command)
(eq org-cycle-subtree-status 'children)))
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-pre-cycle-hook 'subtree))
(outline-flag-region eoh eos nil)
(org-unlogged-message
(if children-skipped
"SUBTREE (NO CHILDREN)"
"SUBTREE"))
(setq org-cycle-subtree-status 'subtree)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-cycle-hook 'subtree)))
((eq org-cycle-subtree-status 'subtree)
(org-show-subtree)
(message "ALL")
(setq org-cycle-subtree-status 'all))
(t
(run-hook-with-args 'org-pre-cycle-hook 'folded)
(outline-flag-region eoh eos t)
(org-unlogged-message "FOLDED")
(setq org-cycle-subtree-status 'folded)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-cycle-hook 'folded))))))
(defun lawlist-org-flag (flag)
"When FLAG is non-nil, hide any of the following: html code block;
footnote; or, the properties drawer. Otherwise make it visible."
(save-excursion
(beginning-of-line 1)
(cond
((looking-at ".*\\[fn")
(let* (
(begin (match-end 0))
end-footnote)
(if (re-search-forward "\\]"
(save-excursion (outline-next-heading) (point)) t)
(progn
(setq end-footnote (point))
(outline-flag-region begin end-footnote flag))
(user-error "Error beginning at point %s." begin))))
((looking-at "^\\#\\+BEGIN_HTML.*$\\|^[ \t]*:PROPERTIES:[ \t]*$")
(let* ((begin (match-end 0)))
(if (re-search-forward "^\\#\\+END_HTML.*$\\|^[ \t]*:END:"
(save-excursion (outline-next-heading) (point)) t)
(outline-flag-region begin (point-at-eol) flag)
(user-error "Error beginning at point %s." begin)))))))
(defun lawlist-toggle-block-visibility ()
"For this function to work, the cursor must be on the same line as the regexp."
(interactive)
(if
(save-excursion
(beginning-of-line 1)
(looking-at
".*\\[fn\\|^\\#\\+BEGIN_HTML.*$\\|^[ \t]*:PROPERTIES:[ \t]*$"))
(lawlist-org-flag (not (get-char-property (match-end 0) 'invisible)))
(message "Sorry, you are not on a line containing the beginning regexp.")))
Related
[[search for me]]
doesn't end up finding the text 'search for me' in the same org file (internal link), instead, it always says 'no match' and asks if I'd like to create a new headline. If the text 'search for me' is instead enclosed in double brackets, e.g.,
<<search for me>>
then the link above works. It shouldn't need double brackets to work. Perhaps I have something configured to interfere with the normal behavior? Not sure how to debug this. Any ideas what is happening? Does it work for you?
I created a few versions that work for me. Hopefully it will help someone else:
(defun my-org-search-link-regexp ()
"Search an org link by text in the same file."
(interactive)
(if (org-in-regexp org-bracket-link-regexp 1)
(let ((link-text (if (match-end 1)
(org-match-string-no-properties 1)
nil)))
(goto-char (point-min))
(re-search-forward link-text nil t))))
or
(defun my-org-search-link-regexp ()
(interactive)
(when (equal major-mode 'org-mode)
(let ((object (org-element-context)))
(when (eq (car object) 'link)
(let ((link (org-element-property :raw-link object)))
(goto-char (point-min))
(re-search-forward link nil t))))))
or
(defun my-org-search-link-regexp ()
"If link under point is org link and of link type `regexp:',
e.g., regexp:search for this text, then search for the regexp supplied,
otherwise invoke org-open-at-point."
(interactive)
(when (equal major-mode 'org-mode)
(let ((link-type "regexp:")
(command-prefix-value)
(object (org-element-context)))
(when (eq (car object) 'link)
(let ((link (org-element-property :raw-link object)))
(when (>= (length link) (length link-type))
(setf command-prefix-value (substring link 0 (length link-type))))
(if (and command-prefix-value
(equal link-type command-prefix-value))
(let ((link-regexp (substring link (1+ (length link-type)) nil)))
(org-mark-ring-push)
(goto-char (point-min))
(re-search-forward link-regexp nil t))
(call-interactively 'org-open-at-point)))))))
(bind-key "C-c C-o" #'my-org-search-link-regexp org-mode-map)
My preference is the third one as it, combined with the keybinding, allows me to use my regular keybinding for org-open-at-point. There is probably a better way of doing this using an actual org link type datatype of something, but it works nicely for me. I don't want double brackets all over the place in my org files. I call org-mark-ring-push so that I can later call org-mark-ring-goto which I have mapped to evil-leader m B. This way I can reliably jump back to the originating link.
Would it be possible to add a comment-end character to emacs?
I'll take the first code I have and apply what I would like as example:
(defun smart-tab ()
(interactive)
\1\ (if (minibufferp)
\1a\ (minibuffer-complete)
\2\ (if (eq major-mode 'emacs-lisp-mode)
(progn
(save-excursion
(search-backward "(def")
(while (not (looking-at "\\s-*)"))
(beginning-of-line 1)
(indent-for-tab-command)
(beginning-of-line 1)
(next-line)
(when (looking-at (concat ".*" comment-start))
(next-line))))
(indent-for-tab-command))
(yas-expand)))
)
I would like to add some information in the indentation area before the functions, indicating where the logical parts start.
Would this be possible for emacs-lisp, would there be an easy way to use some little trick to consider the evaluater to skip certain text?
Emacs Lisp doesn't have reader macros (or any other way of modifying the reader). But you can do something close to what you want by writing your own macro and using it instead of defun. For example, with this macro definition:
(defmacro mydefun (name args &rest body)
"Define NAME as a function.
Like normal `defun', except BODY may contain |comments|."
(labels ((uncomment (form)
(cond ((not (consp form)) form)
((and (symbolp (car form))
(string-match "|.*|$" (symbol-name (car form))))
(uncomment (cdr form)))
(t (cons (uncomment (car form))
(uncomment (cdr form)))))))
`(defun ,name ,args ,#(uncomment body))))
you can write:
(mydefun smart-tab ()
(interactive)
|1| (if (minibufferp)
|1a| (minibuffer-complete)
|2| (if (eq major-mode 'emacs-lisp-mode)
(progn
(indent-for-tab-command)))))
(It's not possible to use \ for this because that character already has a meaning for the Emacs Lisp reader.)
I have to say, though, that this doesn't seem like a particularly good idea to me. It would be much better to put your section headings in comments to the right of the source:
(defun smart-tab ()
(interactive)
(if (minibufferp) ; 1
(minibuffer-complete) ; 1a
(if (eq major-mode 'emacs-lisp-mode) ; 2
(progn
(indent-for-tab-command)))))
This seems just as clear as your proposal, and much easier for other Emacs Lisp programmers to understand.
I wrote a snippet to copy previous line to point,if I repeat the command,it copy more previous line. It's here:
(defun my-copy-line (num)
"copy lines"
(interactive "p")
(save-excursion
(move-end-of-line 1)
(push-mark)
(move-beginning-of-line num)
(kill-ring-save (point) (mark))))
(defvar copy-line-num 1)
(defun my-copy-line-here (num)
"copy line ahead here"
(interactive "p")
(if (eq this-command last-command)
(setq copy-line-num (+ copy-line-num num)) ;count num lines up
(setq copy-line-default 1))
(save-excursion
(save-excursion ;make current line blank
(move-beginning-of-line 1)
(push-mark)
(move-end-of-line 1)
(kill-region (point) (mark))) ;不用kill-line,以免删除空白行
(push-mark)
(previous-line copy-line-num)
(my-copy-line 1)
(exchange-point-and-mark)
(yank))
(setq this-command 'my-copy-line-here))
I intended to yank previous line to override current line.If I repeat my-copy-line-here,I'll yank the 2th previous line,this is accomplished by the test (if (eq this-command last-command).But it failed ,Because every time after executing my-copy-line-here,it sets the last-command to yank,instead my-copy-line-here.I just can't figure out what's going on.I need your help.
`M-y (yank-pop) works similarly, pasting previous copied lines on repeated calls. Checking its sources, I see two differences with yours:
; explicit check for yank
(if (not (eq last-command 'yank))
; setting this command
(setq this-command 'yank)
Perhaps one or both of these together can be useful. Set this-command after calling yank maybe?
I use M-q for fill-paragraph, can I do the un-fill-paragraph in auto-fill-mode?
With org mode, I sometimes enter [[Very long HTML][Name with spaces]], and for the 'Name with spaces' the auto-fill mode break the whole line based on the inserted space, which makes it very ugly.
Is there a command something like un-fill-paragraph? Or, is there a way disable auto-fill-mode temporarily/locally?
Emacs does not record what was your line before calling fill-paragraph. So the only thing you can do is C-_ which runs the command undo. It can undo your fill-paragraph command but only if it is the preceding command call.
If you want to put a multi-line paragraph on one line you could do like this :
Select the region
C-M-% C-q C-j RET SPACE RET !
Xah Lee has updated his code since monotux's answer, and I refactored it somewhat for readability:
(defun my-toggle-fill-paragraph ()
;; Based on http://xahlee.org/emacs/modernization_fill-paragraph.html
"Fill or unfill the current paragraph, depending upon the current line length.
When there is a text selection, act on the region.
See `fill-paragraph' and `fill-region'."
(interactive)
;; We set a property 'currently-filled-p on this command's symbol
;; (i.e. on 'my-toggle-fill-paragraph), thus avoiding the need to
;; create a variable for remembering the current fill state.
(save-excursion
(let* ((deactivate-mark nil)
(line-length (- (line-end-position) (line-beginning-position)))
(currently-filled (if (eq last-command this-command)
(get this-command 'currently-filled-p)
(< line-length fill-column)))
(fill-column (if currently-filled
most-positive-fixnum
fill-column)))
(if (region-active-p)
(fill-region (region-beginning) (region-end))
(fill-paragraph))
(put this-command 'currently-filled-p (not currently-filled)))))
To remake a long line out of a paragraph in Org mode, I gave myself a new command. Here is the associated Emacs Lisp code:
(defun fp-unfill-paragraph (&optional justify region)
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(interactive)
(let ((fill-column 100000))
(fill-paragraph justify region)))
(global-set-key "\C-ceu" 'fp-unfill-paragraph)
Of course, you adjust the command keybinding as you see fit!
I use the following snippet to fill and un-fill paragraphs (using only M-q), it is really, really handy. I borrowed it from Xah Lee, but removed some comments and whitespace in order to make it fit in here. The link in the first comment goes to his original code.
;; http://xahlee.org/emacs/modernization_fill-paragraph.html
(defun compact-uncompact-block ()
"Remove or add line endings on the current block of text.
This is similar to a toggle for fill-paragraph and unfill-paragraph
When there is a text selection, act on the region.
When in text mode, a paragraph is considered a block. When in programing
language mode, the block defined by between empty lines.
Todo: The programing language behavior is currently not done.
Right now, the code uses fill* functions, so does not work or work well
in programing lang modes. A proper implementation to compact is replacing
newline chars by space when the newline char is not inside string.
"
(interactive)
(let (bds currentLineCharCount currentStateIsCompact
(bigFillColumnVal 4333999) (deactivate-mark nil))
(save-excursion
(setq currentLineCharCount
(progn
(setq bds (bounds-of-thing-at-point 'line))
(length (buffer-substring-no-properties (car bds) (cdr bds)))))
(setq currentStateIsCompact
(if (eq last-command this-command)
(get this-command 'stateIsCompact-p)
(if (> currentLineCharCount fill-column) t nil)))
(if (and transient-mark-mode mark-active)
(if currentStateIsCompact
(fill-region (region-beginning) (region-end))
(let ((fill-column bigFillColumnVal))
(fill-region (region-beginning) (region-end)))
)
(if currentStateIsCompact
(fill-paragraph nil)
(let ((fill-column bigFillColumnVal))
(fill-paragraph nil))))
(put this-command 'stateIsCompact-p
(if currentStateIsCompact
nil t)))))
(global-set-key (kbd "M-q") 'compact-uncompact-block)
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.