25

There's lots of documentation about inserting or storing org-mode-links, but apparently none about copying them to buffers in other formats.

How do you copy the URL of an org-mode-link from an org file into the clipboard/kill ring with as few keystrokes as possible? I tried org-store-link and org-insert-link, but it dumps the whole org-mode syntax into whatever other buffer you have open.

Example: buffer 1 org-mode, buffer 2 Markdown.

  1. Visit buffer 1, C-s search for link.
  2. Magic happens, URL is in clipboard
  3. Visit buffer 2. C-y to yank URL into buffer.

9 Answers 9

13

Here is one way of achieving what you want, using text properties.

You can go to the link in the org file you want to copy and execute the command my-org-retrieve-url-from-point this will copy the org link at current point to the clipboard. Before adding the link to clipboard a yank-handler (my-yank-org-link) is registered which is called while pasting the link. The yank-handler checks if the current buffer is in org-mode or a mode derived from org-mode, if so it inserts the link as it is (a org-link), otherwise it extracts the URL from the link and inserts it

(defun my-yank-org-link (text)
  (if (derived-mode-p 'org-mode)
      (insert text)
    (string-match org-bracket-link-regexp text)
    (insert (substring text (match-beginning 1) (match-end 1)))))

(defun my-org-retrieve-url-from-point ()
  (interactive)
  (let* ((link-info (assoc :link (org-context)))
         (text (when link-info
                 ;; org-context seems to return nil if the current element
                 ;; starts at buffer-start or ends at buffer-end
                 (buffer-substring-no-properties (or (cadr link-info) (point-min))
                                                 (or (caddr link-info) (point-max))))))
    (if (not text)
        (error "Not in org link")
      (add-text-properties 0 (length text) '(yank-handler (my-yank-org-link)) text)
      (kill-new text))))

Here is a DWIM version of kill-ring-save, which uses kill-ring-save if region is active or copies the org-link at point

(defun my-smarter-kill-ring-save ()
  (interactive)
  (if (region-active-p)
      (call-interactively #'kill-ring-save)
    (when (eq major-mode 'org-mode)
      (call-interactively #'my-org-retrieve-url-from-point))))

Note: This does not currently distinguish between a URL link and internal links.

1
  • 1
    I removed the if, because when using the GUI Emacs it always copied the entire link ([[a]][b]]) instead of the URL part (a)
    – Nitz
    Feb 1, 2015 at 8:06
16

People tend to over complicate that, try this instead:

(defun farynaio/org-link-copy (&optional arg)
  "Extract URL from org-mode link and add it to kill ring."
  (interactive "P")
  (let* ((link (org-element-lineage (org-element-context) '(link) t))
          (type (org-element-property :type link))
          (url (org-element-property :path link))
          (url (concat type ":" url)))
    (kill-new url)
    (message (concat "Copied URL: " url))))

(define-key org-mode-map (kbd "C-x C-l") 'farynaio/org-link-copy)
1
  • 1
    This is an excellent solution. Simple and clear.
    – theherk
    Feb 24, 2021 at 14:50
7

Another possibility: With the cursor on the link, execute org-insert-link. This is normally C-c C-l. With evil mode (or maybe just with Spacemacs) , i l also works. This enters the link insert flow with the link value pre-populated. You can then do M-x evil-yank-line while the minibuffer has the contents of the link address.

2
  • This method is basically what I use, specifically I go C-c C-l M-S-<backspace> C-g.
    – Omar
    Jun 6, 2019 at 3:02
  • It works but not so efficient. Sep 8, 2019 at 21:02
7

Late to the party (and my first post here, by the way), but I think this might be useful to others too. The accepted answer works perfectly when yanking inside emacs again, but the actual text copied to the system clipboard is still the full org-mode syntax. I wanted something that could copy a link out of both org-mode and emacs. Use cases: I've been doing a lot of web dev lately, and I often use multiple browsers. Only one of them can be the default for the C-c c-o shortcut, and sometimes I want to open a link in a non-default one. Also, pasting links to coworkers on Slack, et cetera.

Long story short, I've come up with this solution by mixing and matching the accepted answer:

(defun my-org-export-url ()
  (interactive)
  (let* ((link-info (assoc :link (org-context)))
         (text (when link-info
                 (buffer-substring-no-properties (or (cadr link-info) (point-min))
                                                 (or (caddr link-info) (point-max))))))
    (if (not text)
        (error "Not in org link")
      (string-match org-bracket-link-regexp text)
      (kill-new (substring text (match-beginning 1) (match-end 1))))))

This will copy to the clipboard the link only part of an org-mode link.

In fact, I have integrated both the previous answer's solution and this new function inside my .emacs, each with its own keybinding. Full code here:

(defun my-yank-org-link (text)
  (if (derived-mode-p 'org-mode)
      (insert text)
    (string-match org-bracket-link-regexp text)
    (insert (substring text (match-beginning 1) (match-end 1)))))

(defun my-org-copy-smart-url ()
  (interactive)
  (let* ((link-info (assoc :link (org-context)))
         (text (when link-info
                 (buffer-substring-no-properties (or (cadr link-info) (point-min))
                                                 (or (caddr link-info) (point-max))))))
    (if (not text)
        (error "Not in org link")
      (add-text-properties 0 (length text) '(yank-handler (my-yank-org-link)) text)
      (kill-new text))))
(global-set-key (kbd "C-c c") 'my-org-copy-smart-url)

(defun my-org-export-url ()
  (interactive)
  (let* ((link-info (assoc :link (org-context)))
         (text (when link-info
                 (buffer-substring-no-properties (or (cadr link-info) (point-min))
                                                 (or (caddr link-info) (point-max))))))
    (if (not text)
        (error "Not in org link")
      (string-match org-bracket-link-regexp text)
      (kill-new (substring text (match-beginning 1) (match-end 1))))))
(global-set-key (kbd "C-c e") 'my-org-export-url)

I've chosen the C-c e and C-c c keybindings because they are good mnemonics for export and copy and they are unused in org-mode. They also somehow fit with the already existing keybinding C-c C-o for opening links.

2

With no customization required, I would suggest:

  • C-c C-l to enter org-insert-link. You must be familiar with this command, because you have to use it whenever you need to change the link or its description.

  • M-w to copy the link.

  • C-g to leave org-insert-link.

That is, for copying only the URL. If you need the URL plus the org-mode syntax, just copy the link until the following word or the end of the line.

6
  • You can also do ESC 3 times instead of C-g
    – crocefisso
    Jul 16, 2021 at 9:53
  • This also copies the "Link: " text displayed in the minibuffer, which adds to the awkwardness. Otherwise it would be acceptable, for me.
    – petre
    Oct 21, 2023 at 10:36
  • @petre No it doesn’t. Did you try it?
    – kotchwane
    Oct 22, 2023 at 13:50
  • @kotchwane of course I tried it! Version 29.1 (9). Probably some quirk, because I can move the cursor (with the arrow keys, not with e.g. C-a) over the "Link" text.
    – petre
    Oct 24, 2023 at 5:17
  • Maybe what I didn’t say in my answer is that your cursor must be over a link when you do C-c C-l (org-insert-link). When you do that, you enter the edition of the link in the minibuffer with the cursor at the end of the link, and typing M-w copies only the link, not the "Link:" prefix. It is normal to be able to move over this "Link:" prefix with the arrow keys.
    – kotchwane
    Oct 25, 2023 at 13:29
2

I am not sure if this solves all use cases, but this is how I would do it (this only saves to the kill ring, but for me, maybe because I am using Spacemacs, I can also access/retrieve it from clipboard):

  • plain url, I would just select and copy the text (with evil y i W), but alternatively you could create a function using (thing-at-point 'url)
  • url part of org mode link
(defun org-copy-link-url ()
  (interactive)
  (kill-new (org-element-property :raw-link (org-element-context))))

or use link-hint-copy-link, which uses

(kill-new (plist-get (get-text-property (point) 'htmlize-link) :uri))
  • full link (including format text), which is often handy within org-mode
(defun org-copy-link ()
  (interactive)
  (let ((begin (org-element-property :begin (org-element-context)))
          (end (org-element-property :end (org-element-context))))
    (kill-ring-save begin end)))

I did not study all other answers, but on first sight these solutions look the simplest and most straightforward to me.

1

A super naive solution is to remove a character from the link, breaking it, allowing you to copy it using yi[ in evil-mode for example. Afterwards, just undo the change.

It's pretty silly but it takes 0s of effort.

1
  • You can toggle the visibility of the link with org-toggle-link-display - no need to delete characters (although I have done the latter too :-) )
    – NickD
    Apr 6, 2022 at 21:37
0

Here is my crap solution. I don't like it because things get unfolded and the method will not work in read-only-mode. But it works :P

;;#+begin_src emacs-lisp  [2020-06-20 18:49]
(defun myhyp ()
  "Extract html hyperlink from org link nearest to point. 
     At least that is the goal eventually."
  (interactive)
  (save-excursion
    (setq hcurr (point))
    (org-next-link)
    (setq hnext (point))
    (org-previous-link)
    (setq hprev (point)))
  (save-excursion
    (goto-char hnext)
    (org-toggle-link-display)
    (re-search-forward "]")
    (backward-char 1)
    (kill-ring-save (+ hnext 2) (point))
    (org-toggle-link-display)))
;;#+end_src

Perhaps a better solution would copy the whole link string and parse it via regex.

2
  • I am going to use @Adam Farnya's solution instead, and try to read it
    – redhouse
    Sep 27, 2020 at 6:07
  • Now I just need to figure out which link is closer to point.
    – redhouse
    Sep 27, 2020 at 6:48
0

For me, the following keyboard shortcuts sequence works (I use Doom Emacs, but all the shortcuts are default ones):

  1. Put cursor on the org link
  2. Press C-c C-l to enter link editing mode. The minibuffer shows the link with the cursor at the end of the link.
  3. Press C-space to start selecting a region.
  4. Press C-a to extend the region to the beginning of the link. Now the whole link is selected.
  5. Press M-w to copy the region into buffer.
  6. Press C-g to cancel link-editing mode.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.