reddit / emacs

Please help with custom paste (yank) function.

rtwyyn · 2022-10-01 20:41
Hello everyone! I copy text (outside of emacs) that can be one of these lines: 57,655 45,049 45,363 (57,655) (45,049) (45,363) 57,655) (45,049) (45,363 57,655 45,049 45,363 $ 57,655 $ 45,049 $ 45,363 (amount of spaces/tabs can very, and number of elements is 3 most of the time, sometimes two) And need to paste it either as 57,655|45,049|45,363 Or as (57,655)|(45,049)|(45,363) (basically ignore everything except digits and "," and separate elements with "|") As i understand i need to create 2 custom paste functions (one regular, one with "()"s) taking original paste function as basis. I found the pasting function (via c-h k): (defun cua-paste (arg) "Paste last cut or copied region or rectangle. An active region is deleted before executing the command. With numeric prefix arg, paste from register 0-9 instead. If global mark is active, copy from register or one character." (interactive "P") (setq arg (cua--prefix-arg arg)) (let ((regtxt (and cua--register (get-register cua--register))) (count (prefix-numeric-value arg))) (cond ((and cua--register (not regtxt)) (message "Nothing in register %c" cua--register)) (cua--global-mark-active (if regtxt (cua--insert-at-global-mark regtxt) (when (not (eobp)) (cua--insert-at-global-mark (filter-buffer-substring (point) (+ (point) count))) (forward-char count)))) (buffer-read-only (error "Cannot paste into a read-only buffer")) (t (cond (regtxt (cond ;; This being a cons implies cua-rect is loaded? ((consp regtxt) (cua--insert-rectangle regtxt)) ((stringp regtxt) (insert-for-yank regtxt)) (t (message "Unknown data in register %c" cua--register)))) ((memq this-original-command '(clipboard-yank x-clipboard-yank)) (funcall this-original-command)) (t (yank arg))))))) and as i understand i need to modify "arg" before doing "yank arg", but i have not idea how this "modification" should look like :) Could someone please help?
Careful_Assignment · 2022-10-01 22:09
Here's some code to convert one line of your text into the new format. It assumes the region is active and has point and mark at the beginning and end of a line that needs to be converted. It needs cl-macs and subr-x to be loaded. Try it by selecting a line and running M-x my-paste (require 'subr-x) (require 'cl-macs) (defun my-paste (b e) (interactive "r") (let* ((str (buffer-substring b e)) (istrs (split-string str "[[:space:]$]+" "[[:space:]$]+")) (istrs (cl-loop for s in istrs collect (cond ((and (string-prefix-p "(" s) (not (string-suffix-p ")" s))) (concat s ")")) ((and (not (string-prefix-p "(" s)) (string-suffix-p ")" s)) (concat "(" s)) (t s))))) (delete-region b e) (goto-char b) (insert (string-join istrs "|"))))
rtwyyn · 2022-10-01 23:39
Hi there! Thank you for your help! "It assumes the region is active and has point and mark at the beginning and end of a line that needs to be converted" -, text is in clipboard (i copy in browser), and then have say "57,655 45,049 45,363" in clipboard which i want to past in emacs as "57,655|45,049|45,363" (if i call say my-paste1) or "(57,655)|(45,049)|(45,363)" (if i call say my-paste2) As i understand with above code i need to firstly paste it in emacs as it is, and then select, and then run command, correct? Is it possible to do it in one step (from clipboard)?
Careful_Assignment · 2022-10-02 05:39
Yeah, my thought was you'd copy the line or lines into Emacs first and then run the function against each line. Here's a variation that modifies whatever is in the current cut buffer. This assumes that what's there is a line that follows your pattern. I'm not sure what it will do if it doesn't: (defun my-paste2 () (interactive) (let* ((str (current-kill 0)) (istrs (split-string str "[[:space:]$]+" "[[:space:]$]+")) (istrs (cl-loop for s in istrs collect (cond ((and (string-prefix-p "(" s) (not (string-suffix-p ")" s))) (concat s ")")) ((and (not (string-prefix-p "(" s)) (string-suffix-p ")" s)) (concat "(" s)) (t s))))) (insert (string-join istrs "|"))))
rtwyyn · 2022-10-02 09:14
thank you again! i tried, and it works, the only thing it seems to be "smart" version :), it auto detects if there is "(" or ")" and then assumes we need "()" around; is there a way to do 2 "dumb" versions? one "regular", one "reversed" ? Cause from source i am copying often "()" inserted reversly (have them for elements where they should not be, and lack them where they needed). Basically if i copied "57,655 45,049 45,363" i need to be able to insert it both as "57,655|45,049|45,363" (if i call my-paste) or "(57,655)|(45,049)|(45,363)" (if i call my-paste-reverse) Also mixed is possible, say i have "57,655 45,049 (45,363)" and i need to be able to insert it both as "57,655|45,049|(45,363)" (if i call my-paste) or "(57,655)|(45,049)|45,363" (if i call my-paste-reverse) --- and i think we can ingore "57,655) (45,049) (45,363", "57,655) 45,049 (45,363", etc - situations with not complete "()" items... otherwise it makes logic too difficult. Or maybe we can precheck if there are "()" items lacking "(" or ")" one either side and complete them before processing with main logic?
Careful_Assignment · 2022-10-02 16:48
I'm not exactly sure what you're asking. I would play with the cond section of the code. The cl-loop loops through every number as a string with maybe a paren on one or both sides. The cond then decides what to do with that number. If you want them all to not have parens, you might change it so that instead of adding a paren with concat, you remove the paren. If you want them all to have parens, then you change the "(t s)" part of the cond to use concat to add the parens.
rtwyyn · 2022-10-02 21:14
Thank you for the explanation, i managed to tweak cond to my needs. Thanks for all the help!!!