2

I have stored in my clipboard a path to an image, which I want to paste inside emacs.

I would like to modify the path to change/postpone/prepone some stuff before yanking.

Following my previous question here, I tried

  (defun replace-in-string (what with in)
   (replace-regexp-in-string (regexp-quote what) with in nil 'literal)) 
  (defun paste-image-link ()
     (interactive)
     (let ((tmp  (car kill-ring))))
     (setq tmp (replace-in-string  "E:\\Dropbox\\JULIEN\\01.Emacs"
                             "../.."
                             tmp))
     (setq tmp (concat "[[file:" tmp "]]"))
     (setq kill-ring  (cons tmp (cdr kill-ring)))
     (yank)                               
     )
   (global-set-key (kbd "M-i")  'paste-image-link)

My goal is to change the absolute path to a relative path and add [[file: before.

For example, this :

E:\Dropbox\JULIEN\01.Emacs\02.Emacs screenshots\2021-04-04_02-23-12_vivaldi.png

should become :

[[file:../..\02.Emacs screenshots\2021-04-04_02-23-12_vivaldi.png]]

I am obviously making trivial mistakes about let and setqstatements because I get instead :

[[file:[[file:[[file:[[file:[[file:[[file:[[file:(car kill-ring)]]]]]]]]]]]]]]

and the number of [[file:before is growing each time i try

what should I do ?

Addendum : besides i would like to add a line before to finally get

#+ATTR_ORG: :width 300px
[[file:../..\02.Emacs screenshots\2021-04-04_02-23-12_vivaldi.png]]

1 Answer 1

2

Mostly your problem was misplaces parens: too many ) here:

(let ((tmp  (car kill-ring))))

Use paren-mode to see which parens balances which parens.


Standard function kill-new replaces the head of the kill-ring if you give it a second arg of non-nil. So (kill-new "xxx" t) replaces the head of the kill-ring with xxx.

So try this:

(defun foo ()
  (interactive)
  (let ((new  (format "[[file:%s]]" (replace-in-string
                                     "E:\\Dropbox\\JULIEN\\01.Emacs" "../.."
                                     (car kill-ring)))))
    (kill-new new t)))

You can add the yank or whatever to do that and add whatever other lines you want.


But a guess is that maybe you don't really need to change the kill-ring, you just want to be able to grab its head and from that produce a different string to then insert. That you can do directly, using insert after getting the head of the ring and from that getting the string you want to insert.


Also, it's pretty unusual to modify kill-ring entries. Usually it's enough, if you need something on the ring, just to put it there, not caring about what other elements are already on the ring. Use kill-new (without second arg) to add a to the front of the ring.


Finally, if you're using file names ("paths"), just use / always, in Emacs, as the directory separator char, not \\, even on MS Windows. Emacs just does the right thing - there's pretty much never any need to use \\ for that.

2
  • 1
    thank you very much. I will try it. Apr 6, 2021 at 19:25
  • 1
    Upvoted Drew's superbly comprehensive answer, which I think you should accept. I would just add this: I think you need to use replace-regexp-in-string, not your replace-in-string, using a regex that intelligently strips out a leading [[file: if it's already present, so that repeated invocations don't keep prefixing more and more copies of [[file:. Apr 7, 2021 at 10:03

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.