1

I use tabs in C/C++ but want to convert those tabs to spaces when copying code that I'm going to paste into an external program. However, I want the original code to retain tabs. Additionally (if possible), I'd like to keep the tabs when copying/pasting within Emacs.

I sort of adapted the code at this link and tried:

(advice-add 'kill-ring-save :before 'untabify)
(advice-add 'kill-ring-save :after 'tabify)

but it doesn't copy all the text and converts away from tabs when copying and pasting within Emacs.

For instance, if I use the above setup on

int main()
{
        int i = 5;
}

it only copies

int main()
{
        int i

I'm not a Lisp programmer and am relatively new to Emacs, so forgive me if I'm missing something obvious here.

2 Answers 2

0

The following might be useful for you. It doesn't know if a tab is actual code or indentation.

(defun chunyang-copy-region-replace-tab (start end)
  "Copy the region.
Tabs at the beginning of each line are replaced by the same
amount of spaces."
  (interactive "r")
  (kill-new
   (replace-regexp-in-string
    "^\t+"
    (lambda (substring)
      (make-string (length substring) ?\s))
    (buffer-substring start end))))
2
  • This only copies a single space in place of a tab for me (mine are 8 spaces). I'm just calling it on selected text. Is there a chance I'm using it wrong?
    – MattHusz
    Commented Nov 10, 2018 at 15:48
  • 1
    @MattHusz The above does replace one tab with one space. Maybe you want to change (length substring) into (* tab-width (length substring)).
    – xuchunyang
    Commented Nov 10, 2018 at 16:15
0

The problem is that tabify/untabify modify the buffer, including its length, so when you try to kill/copy the region, the copy command first gets told to copy between positions BEG and END, then modifies the buffer, then reads from BEG..END but at that moment the character that used to be at position END is now elsewhere because the untabifying.

You probably want to add an advice to gui-set-selection instead, along the lines of:

(advice-add 'gui-set-selection :around #'untabify-selection)
(defun untabify-selection (orig-fun type data &rest args)
  (when (stringp data)
    (with-temp-buffer
      (insert data)
      (untabify (point-min) (point-max))
      (setq data (buffer-string))))
  (apply orig-fun type data args))
1
  • This works, but also converts tabs for destinations within Emacs. Is there a way to turn this into a function, say "copy-untabify", that I can call specifically when I want to copy without the tabs?
    – MattHusz
    Commented Nov 10, 2018 at 15:45

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.