0

In C and C++ files, I want to configure the mode so that any time I request indentation, that it will always expand all of the embedded TAB characters in indentation (at the start of the line, and no where else) into space characters. How do I do that using vanilla emacs execution (emacs -Q) plus some calls to setq of whatever variables, and not writing special Emacs Lisp or rebinding keys etc.?

Detail:

Version of emacs I am using is:

GNU Emacs 25.2.2 (x86_64-pc-linux-gnu, GTK+ Version 3.22.21) of 2017-09-22, modified by Debian

Execute emacs -Q (so as to get the default c-style-alist value which for this should imply using the gnu style) and then open a .C file and insert in exactly this code:

// A C++ file

void function_using_tabs_inside_indentation () {
  printf("A message\n");
  if (bad) {
    printf("A bad message\n");
    if (bad) {
      printf("A bad message\n");
      if (bad) {
    printf("A bad message\n"); // TAB!!
      }
    }
  }
}

Note the comment above about the indented tab.

Then type M-x whitespace-mode. You should see something like this that clearly shows that there is a TAB code embedded in the indentation:

whitespace-mode view of cxx file

Now set indent-tabs-mode to nil by typing M-: (setq indent-tabs-mode nil).

Move your point to the "v" in "void" and type C-M-q, which should execute the command c-indent-exp.

But notice that nothing changed: The embedded tab does not get expanded properly into spaces, as the TAB code is still there.

Then, move point directly on the TAB code in that file. Type the TAB key. Notice nothing changes, but I want it to be expanded into the required number of spaces.

Yes, I know I can resort to using expand -2 on the file, but that takes me out of Emacs and I want it to happen automatically when I indent the line.

I also don't want to have to manually backspace over the TAB code and then type the TAB key to insert the required number of spaces, either. If I do that to fix it manually, then this is what I expect to see (well mostly):

expected view mostly

Notice how when I "fixed" it, the whitespace-mode highlights it in brighter yellow (brighter than the other space "glyphs" it uses for space characters)? Why? Perhaps it it telling me something is incorrect there?

Update #1:

I know about M-x untabify and that does what I want, but I want it to happen globally across all C and C++ files I open, and without having to type it. Yes, I can write some Emacs Lisp code to rewire the TAB key binding and the C-M-q bindings, but I hope to avoid that complexity, as I need this to be something I can request my fellow Emacs-using developers to use in our projects development.

2
  • Try a little bit different: highlight your initial function and check M-x whitespace-report-region and see the report. On my mac, clang style, (two more spaces than gnu style) the report was >= 'tab-width' SPACEs at the beginning of the line and M-x fixup-whitespace moved the offending line to start at the first column, so try to increase the tab-width variable.
    – Ian
    Commented Aug 26, 2018 at 14:07
  • Thanks, I am aware of the white space functions now. However they don't directly address the basic question of how to remove all tabs from the current indentation of the current line even if there are tabs there to begin with. And automatically when you use the Tab Key and any other types of indentation functions.
    – bgoodr
    Commented Aug 27, 2018 at 14:38

2 Answers 2

1

I usually do my untabify and line-endings check on save with a before save hook. Put something like this in your init file:

(add-hook 'before-save-hook
 (lambda ()
  (when (eq major-mode 'c-mode)  
   ;; or for multiple modes: (when (memq major-mode '(c-mode cc-mode etc)))
   (untabify (point-min) (point-max)))))
4
  • That is helpful for ensuring the entire buffer is untabified when it is saved on disk. My question is specifically to ensure that, effectively, untabify is done on the current line each time I use the TAB key. I mean, that is what (setq indent-tabs-mode nil) should have been doing all along, instead of just not changing the pre-existing TAB characters into space characters in the indentation on that line.
    – bgoodr
    Commented Aug 30, 2018 at 14:30
  • It seems as if something is trying its best to avoid changing anything on the line if the indentation lines up with the current tab-width, when in fact that is exactly what I want it to do: change it always to convert the TAB characters into the required number of spaces.
    – bgoodr
    Commented Aug 30, 2018 at 14:32
  • Sigh. I'm starting to conclude that the only way that I'm going to be able to get that behavior is to override the binding for the TAB key to instead call some function that calls untabify on the region of that line, followed by calling the original function that TAB was bound to, and only in the specific modes derived from the C mode.
    – bgoodr
    Commented Aug 30, 2018 at 14:34
  • Sigh #2: and if I'm going to have to go through all that trouble, then I might as well buckle and just go with your before-save-hook approach in this answer and fogetaboutit. :)
    – bgoodr
    Commented Aug 30, 2018 at 14:35
0

Ok how about adding advice around c-indent-exp for C-M-q and around c-indent-line-or-region for <TAB>.

(defun untabify-line-or-region (&optional arg region)
  "Convert all tabs in region to multiple spaces, preserving columns."
  (if (region-active-p)
      (untabify (region-beginning) (region-end))
    (untabify (line-beginning-position) (line-end-position))))

(advice-add 'c-indent-line-or-region :after 'untabify-line-or-region)
(advice-add 'c-indent-exp :after 'untabify-line-or-region)

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.