internal link searching via org-open-at-point not working for me - org-mode

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

Related

How to change the behaviour of org-agenda-goto to open org-file in a new frame?

When pressing TAB (org-agenda-goto) in org-agenda I want to open the related org-file in a new frame instead of splitting the existing frame.
I could create a modified function of org-agenda-goto replacing switch-to-buffer-other-window with switch-to-buffer-other-frame and rebinding the TAB-key but I assume there is a more elegant way to do so?
The quick solution would be as below modifying line 8:
(defun sk/org-agenda-goto (&optional highlight)
"Go to the entry at point in the corresponding Org file."
(interactive)
(let* ((marker (or (org-get-at-bol 'org-marker)
(org-agenda-error)))
(buffer (marker-buffer marker))
(pos (marker-position marker)))
(switch-to-buffer-other-frame buffer)
(widen)
(push-mark)
(goto-char pos)
(when (derived-mode-p 'org-mode)
(org-show-context 'agenda)
(recenter (/ (window-height) 2))
(org-back-to-heading t)
(let ((case-fold-search nil))
(when (re-search-forward org-complex-heading-regexp nil t)
(goto-char (match-beginning 4)))))
(run-hooks 'org-agenda-after-show-hook)
(and highlight (org-highlight (point-at-bol) (point-at-eol)))))
I assume it may be done more elegantly with advice but I'm not so experienced in emacs-lisp and would not know how exactly this could be achived or if using advice would be the right approach.
I found out in override prefered method are hints for using advice-add like this in order to replace the original function with my own:
(advice-add 'org-agenda-goto :override #'sk/org-agenda-goto)
You can use advice to temporarily redefine switch-to-buffer-other-window using cl-letf. Assuming your on at least emacs 25.1 you can use define-advice, eg.
(define-advice org-agenda-goto (:around (orig-fn &rest args) "new-frame")
(cl-letf (((symbol-function 'switch-to-buffer-other-window)
(symbol-function 'switch-to-buffer-other-frame)))
(apply orig-fn args)))
In the advice orig-fn is a placeholder to org-agenda-goto. Alternatively, you could temporarily override display-buffer's function (there are a number of options you could use here -- see help for display-buffer), eg.
(define-advice org-agenda-goto (:around (orig-fn &rest args) "new-frame")
(let ((display-buffer-overriding-action '(display-buffer-pop-up-frame)))
(apply orig-fn args)))

A Simple 'copy-form Command

I want a command that copies a form to the kill ring. In emacs-live, the closest thing I could find was this command / key-binding
(global-set-key (kbd "M-]") 'kill-ring-save)
However kill-ring-save has some wonky behaviour. Ii copies more than 1 form, past the cursor. Ultimately, I want a simple function along the lines of what's below (this doesn't quite work).
(defun copy-form ()
(kill-ring-save (line-beginning-position) (live-paredit-forward)))
(global-set-key (kbd "M-]") 'copy-form)
I've searched high and low ( SO question and Google search), but can't seem to find a simple, working command to copy a balanced expression. Has someone already done this?
Thanks
Tim
Function sexp-at-point gives you the sexp ("form") at the cursor. Just copy that to the kill-ring, using kill-ring-save. E.g.:
(defun copy-sexp-at-point ()
(interactive)
(let ((bnds (bounds-of-thing-at-point 'sexp)))
(kill-ring-save (car bnds) (cdr bnds))))
Alternatively, just use kill-new:
(defun copy-sexp-at-point ()
(interactive)
(kill-new (thing-at-point 'sexp)))
The reason your copy-form cannot be bound to a key is that it is a function, not a command - it is missing an interactive form.
However, in your case you don't even need to write a new function.
Try a combination of
mark-sexp is an interactive compiled Lisp function in `lisp.el'.
It is bound to C-M-#, C-M-SPC.
and
M-w runs the command kill-ring-save, which is an interactive compiled
Lisp function in `simple.el'.
It is bound to <C-insertchar>, M-w, <menu-bar> <edit> <copy>.
I'm not sure I understand the question, but when I need to do what I consider as "copy a balanced form", I do: M-C-SPC M-w. If I want to cut it instead, I do M-C-SPC C-w.
Here's what I generally use. Somehow it's more useful for me
to kill the balanced expression instead of copying. If I want a
copy instead, I first kill, then undo.
This function kills a string, if the point is inside string,
otherwise the balanced expression, i.e. (),[],{},<>
or whatever is defined by the syntax.
(defun kill-at-point ()
"Kill the quoted string or the list that includes the point"
(interactive)
(let ((p (nth 8 (syntax-ppss))))
(cond
;; string
((eq (char-after p) ?\")
(goto-char p)
(kill-sexp))
;; list
((ignore-errors (when (eq (char-after) ?\()
(forward-char))
(up-list)
t)
(let ((beg (point)))
(backward-list)
(kill-region beg (point)))))))
I've also tried to add a special case for when the point is
inside the comment, but I couldn't find a generic
way to determine bounds of comment at point. If anyone knows,
please tell me.
This other function can be relevant as well. It marks instead
of killing, like the previous one. The nice thing that it
extends the region each time it's called.
I bind the first one to C-, and the second to
C-M-,.
(defun mark-at-point ()
"Mark the quoted string or the list that includes the point"
(interactive)
(let ((p (nth 8 (syntax-ppss))))
(if (eq (char-after p) ?\")
(progn
(goto-char p)
(set-mark (point))
(forward-sexp))
(progn
(when (eq (char-after) 40)
(forward-char))
(condition-case nil
(progn
(up-list)
(set-mark (point))
(let ((beg (point)))
(backward-list)
(exchange-point-and-mark)))
(error
(when (looking-back "}")
(exchange-point-and-mark)
;; assumes functions are separated by one empty line
(re-search-backward "^[^A-Z-a-z]" nil t)
(forward-char))))))))

Could Emacs fontify elisp string constants?

The Dilemma: readability or maintainability?
Let's look at the following function.
It doesn't really matter what it does, the important part is that
it's using twice the string "(let\\*?[ \t]*":
(defun setq-expression-or-sexp ()
"Return the smallest list that contains point.
If inside VARLIST part of `let' form,
return the corresponding `setq' expression."
(interactive)
(ignore-errors
(save-excursion
(up-list)
(let ((sexp (preceding-sexp)))
(backward-list 1)
(cond
((looking-back "(let\\*?[ \t]*")
(cons 'setq
(if (= (length sexp) 1)
(car sexp)
(cl-mapcan
(lambda (x) (unless (listp x) (list x nil)))
sexp))))
((progn
(up-list)
(backward-list 1)
(looking-back "(let\\*?[ \t]*"))
(cons 'setq sexp))
(t
sexp))))))
Since it's a headache having to update the string in two (or more) locations,
I'd have to defconst it like so:
(defconst regex-let-form "(let\\*?[ \t]*")
Although the code became more maintainable, it became less readable as well,
because it's hard to see at a glance what regex-let-form really is:
(defun setq-expression-or-sexp ()
"Return the smallest list that contains point.
If inside VARLIST part of `let' form,
return the corresponding `setq' expression."
(interactive)
(ignore-errors
(save-excursion
(up-list)
(let ((sexp (preceding-sexp)))
(backward-list 1)
(cond
((looking-back regex-let-form)
(cons 'setq
(if (= (length sexp) 1)
(car sexp)
(cl-mapcan
(lambda (x) (unless (listp x) (list x nil)))
sexp))))
((progn
(up-list)
(backward-list 1)
(looking-back regex-let-form))
(cons 'setq sexp))
(t
sexp))))))
The idea: why not both?
Since it's a constant anyway, why not font-lock it
and make regex-let-form appear as if it's "(let\\*?[ \t]*"?
It's a feasable job, since:
It's possible to font-lock identifiers like so: http://www.emacswiki.org/emacs/PrettyLambda,
or even so: rainbow-mode.
And it's possible to font-lock constants. It's already done for c++-mode,
but not yet for emacs-lisp-mode, as far as I know.
Then it remains only to connect the two. Unfortunately, I don't know
enough of font-lock innards to do it, but maybe someone else does?
Or is there already a package that does this?
Tweaking the code from this answer,
I've solved the problem:
(font-lock-add-keywords
'emacs-lisp-mode
'((fl-string-constant . 'font-lock-constant-face)) 'append)
(defun fl-string-constant (_limit)
(while (not
(ignore-errors
(save-excursion
(skip-chars-forward "'")
(let ((opoint (point))
(obj (read (current-buffer)))
obj-val)
(and (symbolp obj)
(risky-local-variable-p obj)
(special-variable-p obj)
(stringp (setq obj-val (eval obj)))
(progn
(put-text-property
(1- (point)) (point) 'display
(format "%c\"%s\"" (char-before) obj-val))
(set-match-data (list opoint (point)))
t))))))
(if (looking-at "\\(\\sw\\|\\s_\\)")
(forward-sexp 1)
(forward-char 1)))
t)
This displays the value of a string constant right after the constant name.
It works quite nicely with fontified string constants as well.
Speed is a bit of an issue - suggestions to improve are welcome.
Also, I couldn't find anything better than risky-local-variable-p to determine
that it's a constant. The doc says that defconst marks the variable
as special and risky, but nothing else.
hl-defined.el (updated today, 2013-10-20) can highlight constant Emacs-Lisp symbols as such, that is, variables whose current value is the symbol itself. If your defconst has been evaluated then this will do what you are requesting.
This seems to work (source: http://www.emacswiki.org/emacs/PrettyLambda):
(font-lock-add-keywords 'emacs-lisp-mode
`(("\\<\\(regex-let-form\\)\\>" (0 (prog1 nil
(compose-region (match-beginning 1)
(match-end 1)
"\"(let\\\\*?[ \\t]*\""))))))
Although I think adding regex-let-form into the existing let block would be a cleaner solution:
(let ((sexp (preceding-sexp))
(regex-let-form "(let\\*?[ \t]*"))
...
Perhaps your example is not indicative of the real problem, and you really do want to do some display replacement or font-locking, as you say.
But I will answer wrt your example and the problem as posed, regarding maintainability vs readability: Just let-bind your regexp. The binding, unlike a defconst will be nearby and clearly related to the occurrences of the bound variable.
This is typically what people do. Again, you might have had another use case in mind --- I am responding only to the problem as posed narrowly.

in org-mode, how to fold/hide footnotes?

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

Adding comment-end character to Emacs-Lisp

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.