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.
bright-star
  • 839
  • 9
  • 17

8 Answers8

14

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)
Navidot
  • 732
  • 5
  • 12
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.

Iqbal Ansari
  • 7,468
  • 1
  • 28
  • 31
  • 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 01 '15 at 08:06
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.

mowwwalker
  • 211
  • 2
  • 6
6

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.

ggrocca
  • 61
  • 1
  • 3
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.

dalanicolai
  • 6,108
  • 7
  • 23
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.

kotchwane
  • 481
  • 2
  • 12
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.

sp3ctum
  • 111
  • 2
  • 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 06 '22 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.

redhouse
  • 11
  • 3