4

Working on .py files, I know how to get emacs to use 4 spaces as an indent by default. I also know how to get it to use the tab character by default. I'd like to leave it at using spaces by default, but recognize when tab characters are used and use that instead (for my older python files). I know I can just untabify everything, but this might not be an option when working on someone else's code and they'd like to use tabs instead (for whatever reason).

I created 2 simple files consisting of:

a = 1
if a == 1:
    b = 1

In one file, that indent is using 4 spaces while the other file uses a tab character. I can't get Emacs to recognize the difference. I am using Elpy, but I've tried this with Elpy disabled. I've also tried this with a blank init file and having only the modifications to tab. Anyone know the solution to this?

I've been messing around with the following:

(add-hook 'python-mode-hook
    (lambda ()
       (setq indent-tabs-mode t)
       (setq tab-width 4)))

Setting indent-tabs-mode to t makes it always use a tab character. Setting it to nil makes it always use spaces. I've also tried the following:

(add-hook 'python-mode-hook 'guess-style-guess-tabs-mode)
(add-hook 'python-mode-hook (lambda ()
                            (guess-style-guess-tab-width)))

This will only use spaces in Python files... What do?

4
  • I would argue to simply untabify in accordance with: python.org/dev/peps/pep-0008 Python 3 disallows mixing the use of tabs and spaces for indentation Commented Apr 13, 2017 at 16:41
  • 1
    I'm not looking to mix the use of tabs & spaces (in a single file). They're always consistent. But I want it to recognize when a specific file is using tabs & when it's using spaces. Official documentation says that the default Python mode does this. But I don't see it doing that. Commented Apr 13, 2017 at 16:57
  • What documentation is that? Looking at guess-style.el I guess (add-hook 'python-mode-hook (lambda () (setq indent-tabs-mode (guess-style-guess-tabs-mode)))) would work.
    – npostavs
    Commented Apr 13, 2017 at 18:06
  • I found that here: emacswiki.org/emacs/IndentingPython And that line didn't work. Tabs are always spaces. And I tried a config file with JUST that line in it. Same result. Commented Apr 13, 2017 at 18:19

1 Answer 1

5

I feel kind of ridiculous for not having seen this before, but I found the answer on the EmacsWiki: No Tabs page under the "Smart inference of indentation style" section. Putting that code in my init.el file (and those last 2 lines in my python-mode-hook) got Emacs to know whether tabs or spaces were being used.

From: https://www.emacswiki.org/emacs/NoTabs I put the following code in my init.el (.emacs) file:

(defun how-many-region (begin end regexp &optional interactive)
  "Print number of non-trivial matches for REGEXP in region.                    
   Non-interactive arguments are Begin End Regexp"
  (interactive "r\nsHow many matches for (regexp): \np")
  (let ((count 0) opoint)
    (save-excursion
      (setq end (or end (point-max)))
      (goto-char (or begin (point)))
      (while (and (< (setq opoint (point)) end)
                  (re-search-forward regexp end t))
        (if (= opoint (point))
            (forward-char 1)
          (setq count (1+ count))))
      (if interactive (message "%d occurrences" count))
      count)))

(defun infer-indentation-style ()
  ;; if our source file uses tabs, we use tabs, if spaces spaces, and if        
  ;; neither, we use the current indent-tabs-mode                               
  (let ((space-count (how-many-region (point-min) (point-max) "^  "))
        (tab-count (how-many-region (point-min) (point-max) "^\t")))
    (if (> space-count tab-count) (setq indent-tabs-mode nil))
    (if (> tab-count space-count) (setq indent-tabs-mode t))))

And in the same file, I put the following 2 lines

(setq indent-tabs-mode nil)
(infer-indentation-style)

under my python-mode hook. For example:

(add-hook 'python-mode-hook
    (lambda ()
        (setq indent-tabs-mode nil)
        (infer-indentation-style)))
0

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.