Return link type property from org-follow-link-hook - emacs

I would like org-mode to automatically narrow to subtree, when I follow an internal link. So, following this thread I added this code to my init.el file:
(add-hook 'org-follow-link-hook (lambda () (org-narrow-to-subtree)))
This works great. But... it also narrows to the current subtree when I follow an external link (like a URL of a web page).
Is there some way to return the link type property (internal v. external) so that I can limit this behavior?
Something like this...
Org-follow-link hook
If link type==internal
Narrow
End if
Thanks!

You could wrap the function and check whether you're in a different
location before narrowing.
(defun my-org-open-at-point ()
(interactive)
(let ((starting-loc (point)))
(call-interactively #'org-open-at-point)
(when (not (equal starting-loc (point)))
(org-narrow-to-subtree))))
(define-key org-mode-map [remap org-open-at-point] 'my-org-open-at-point)
This works for internal links, but I thought it'd fail for links to
other files within Emacs (which could be fixed using markers). This
doesn't happen though because the current buffer stays the same.
(defun test-org-open-at-point-which-buffer ()
(interactive)
(message "before call: %s" (current-buffer))
(call-interactively #'org-open-at-point)
(message "after call: %s" (current-buffer)))
I haven't looked at the source of org-open-at-point to figure out why
that is.
By the way, to get the link type, you can use
(org-element-property :type (org-element-context))
when the point is on a link.

Related

How to use the function option of org-capture correctly?

I want to dynamically open the correct file in an orgmode capture template using the function option:
("a" "foo" plain
(function my-visit-timestamped-file)
"<some content>")
Function my-visit-timestamped-file is defined as
(defun my-visit-timestamped-file ()
(interactive)
(let
((theDate (format-time-string "%Y%m%d-%H%M.org")))
(find-file (concat "<some_path>" theDate))))
If I run the capture template a, emacs opens the file <some_path>theDate in a buffer and opens the capture buffer with the file.
Thus my window is split into 2 buffers showing the same content.
Can function my-visit-timestamped-file be changed somehow such that the buffer is not opened but org capture still gets the correct file pointer/file handle?
The answer by #jpkotta pointed me in the right direction.
The bug was gone, but instead the content of the capture buffer was always pasted into the buffer I was currently editing.
In an old thread on the org-mode mailing list I found the answer to my question. The function should be:
(defun my-visit-timestamped-file ()
"Visit a new file named by the current timestamp"
(interactive)
(let* (
(curr-date-stamp (format-time-string "%Y%m%d-%H%M.org"))
(file-name (expand-file-name curr-date-stamp "/some/path/")))
(set-buffer (org-capture-target-buffer file-name))
(goto-char (point-max))))
Link to mailing list thread: https://lists.gnu.org/archive/html/emacs-orgmode/2013-11/msg00676.html
You probably want find-file-noselect instead of find-file. Note that the docs of org-capture-templates say this:
(function function-finding-location)
Most general way: write your own function which both visits
the file and moves point to the right location
so you might want to add some code to go to the correct location (I'm guessing either (point-min) or (point-max)) in the file. That might look like this:
(defun my-visit-timestamped-file ()
(interactive)
(let* ((the-date (format-time-string "%Y%m%d-%H%M.org"))
(the-buffer (find-file-noselect (expand-file-name the-date "/some/path/"))))
(with-current-buffer the-buffer
(goto-char (point-min)))
the-buffer))

Emacs org-mode: textual reference to a file:line

I am using org-mode in Emacs to document my development activities. One of the tasks which I must continuously do by hand is to describe areas of code. Emacs has a very nice Bookmark List: create a bookmark with CTRL-x r m, list them with CTRL-x r l. This is very useful, but is not quite what I need.
Org-mode has the concept of link, and the command org-store-link will record a link to the current position in any file, which can be pasted to the org-file. The problem with this is two-fold:
It is stored as an org-link, and the linked position is not directly visible (just the description).
It is stored in the format file/search, which is not what I want.
I need to have the bookmark in textual form, so that I can copy paste it into org-mode, end edit it if needed, with a simple format like this:
absolute-file-path:line
And this must be obtained from the current point position. The workflow would be as simple as:
Go to the position which I want to record
Call a function: position-to-kill-ring (I would bind this to a keyboard shortcut)
Go to the org-mode buffer.
Yank the position.
Edit if needed (sometimes I need to change absolute paths by relative paths, since my code is in a different location in different machines)
Unfortunately my lisp is non-existent, so I do not know how to do this. Is there a simple solution to my problem?
(defun position-to-kill-ring ()
"Copy to the kill ring a string in the format \"file-name:line-number\"
for the current buffer's file name, and the line number at point."
(interactive)
(kill-new
(format "%s:%d" (buffer-file-name) (save-restriction
(widen) (line-number-at-pos)))))
You want to use the org-create-file-search-functions and org-execute-file-search-functions hooks.
For example, if you need the search you describe for text-mode files, use this:
(add-hook 'org-create-file-search-functions
'(lambda ()
(when (eq major-mode 'text-mode)
(number-to-string (line-number-at-pos)))))
(add-hook 'org-execute-file-search-functions
'(lambda (search-string)
(when (eq major-mode 'text-mode)
(goto-line (string-to-number search-string)))))
Then M-x org-store-link RET will do the right thing (store a line number as the search string) and C-c C-o (i.e. M-x org-open-at-point RET) will open the file and go to this line number.
You can of course check for other modes and/or conditions.
An elisp beginner myself I though of it as a good exercise et voila:
Edit: Rewrote it using the format methode, but I still think not storing it to the kill-ring is less intrusive in my workflow (don't know about you). Also I have added the capability to add column position.
(defvar current-file-reference "" "Global variable to store the current file reference")
(defun store-file-line-and-col ()
"Stores the current file, line and column point is at in a string in format \"file-name:line-number-column-number\". Insert the string using \"insert-file-reference\"."
(interactive)
(setq current-file-reference (format "%s:%d:%d" (buffer-file-name) (line-number-at-pos) (current-column))))
(defun store-file-and-line ()
"Stores the current file and line oint is at in a string in format \"file-name:line-number\". Insert the string using \"insert-file-reference\"."
(interactive)
(setq current-file-reference (format "%s:%d" (buffer-file-name) (line-number-at-pos))))
(defun insert-file-reference ()
"Inserts the value stored for current-file-reference at point."
(interactive)
(if (string= "" current-file-reference)
(message "No current file/line/column set!")
(insert current-file-reference)))
Not tested extensively but working for me. Just hit store-file-and-line or store-file-line-and-col to store current location and insert-file-reference to insert the stored value at point.
BTW, if you want something better than FILE:LINE, you can try to use add-log-current-defun (in add-log.el) which should return the name of the current function.
;; Insert a org link to the function in the next window
(defun insert-org-link-to-func ()
(interactive)
(insert (with-current-buffer (window-buffer (next-window))
(org-make-link-string
(concat "file:" (buffer-file-name)
"::" (number-to-string (line-number-at-pos)))
(which-function)
))))
This func generates link with the function name as the description.
Open two windows, one is the org file and the other is src code.
Then M-x insert-org-link-to-func RET

How to run hook depending on file location

I am involved in python project where tabs are used, however i am not using them in every other code i write, it is vital to use them in that particular project. Projects are located in one directory under specific directories. I.E:
\main_folder
\project1
\project2
\project3
...etc
I have couple functions/hooks on file open and save that untabify and tabify whole buffer i work on.
;; My Functions
(defun untabify-buffer ()
"Untabify current buffer"
(interactive)
(untabify (point-min) (point-max)))
(defun tabify-buffer ()
"Tabify current buffer"
(interactive)
(tabify (point-min) (point-max)))
;; HOOKS
; untabify buffer on open
(add-hook 'find-file-hook 'untabify-buffer)
; tabify on save
(add-hook 'before-save-hook 'tabify-buffer)
If i put it in .emacs file it is run on every .py file i open which is not what i want. What i`d like to have is to have these hooks used only in one particular folder with respective subfolders. Tried .dir_locals but it works only for properties not hooks. I can not use hooks in specific modes (i.e. python-mode) as almost all projects are written in python. To be honest i tried writing elisp conditional save but failed.
A very easy solution is to just add a configuration variable that can be used to disable the hooks. For example:
(defvar tweak-tabs t)
(add-hook 'find-file-hook
(lambda () (when tweak-tabs (untabify (point-min) (point-max)))))
(add-hook 'before-save-hook
(lambda () (when tweak-tabs (tabify (point-min) (point-max)))))
Now you can add a .dir-locals.el file in the relevant directories, setting tweak-tabs to nil, disabling this feature there.
(But another problem is that this is a pretty bad way to deal with tabs. For example, after you save a file you do see the tabs in it.)
Just for the record, to answer the literal question in the title (as I reached this question via a web search): one way to add a hook that depends on file location is to make it a function that checks for buffer-file-name. (Idea from this answer.)
For example, for the exact same problem (turn on tabs only in a particular directory, and leave tabs turned off elsewhere), I'm currently doing something like (after having installed the package smart-tabs-mode with M-x package-install):
(smart-tabs-insinuate 'python) ; This screws up all Python files (inserts tabs)
(add-hook 'python-mode-hook ; So we need to un-screw most of them
(lambda ()
(unless (and (stringp buffer-file-name)
(string-match "specialproject" buffer-file-name))
(setq smart-tabs-mode nil)))
t) ; Add this hook to end of the list
(This is a bit inverted, as smart-tabs-insinuate itself modifies python-mode-hook and then we're modifying it back, but it should do as an example.)

Emacs persistent folding mode

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

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