19

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

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.

| improve this answer | |
  • 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 '15 at 8:06
5

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.

| improve this answer | |
  • This method is basically what I use, specifically I go C-c C-l M-S-<backspace> C-g. – Omar Jun 6 '19 at 3:02
  • It works but not so efficient. – itirazimvar Sep 8 '19 at 21:02
5

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.

| improve this answer | |
2

People tend to over complicate that, try this instead:

(defun jarfar/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") 'jarfar/org-link-copy)
| improve this answer | |
0

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.

| improve this answer | |
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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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