0

I have the following configuration for tabs:

(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)

This works inside code and text files, where hitting tab indeed gives me 4 spaces.

However, when I hit tab inside a Markdown (.md) file, it is 3 spaces and I can't figure out why. This is messing up the Markdown parser which expects 4-space indents.

I don't think I am in any special mode in the Markdown file. When I use M-x describe-mode I get the following:

Enabled minor modes: Auto-Composition Auto-Compression Auto-Encryption
Blink-Cursor Electric-Indent File-Name-Shadow Font-Lock Global-Eldoc
Global-Font-Lock Line-Number Menu-Bar Mouse-Wheel Nyan Tool-Bar
Tooltip Transient-Mark

(Information about these minor modes follows the major mode info.)

Fundamental mode defined in ‘simple.el’:
Major mode not specialized for anything in particular.
Other major modes are defined by comparison with this one.

As far as I can tell, I get the same list if I use describe-mode from the .txt file.

I also double-checked that tab-width is indeed 4 by using describe-variable, and it is.

What could be going on?

1 Answer 1

1

Your buffer is in fundamental mode, which means that there is no major mode. This means that only Emacs’ default behavior matters (You do have a few minor modes enabled but none of them are relevant here.)

The default behavior is to mimic the indentation of the prior line when you press tab. This includes lining things up with the next character after a whitespace character on the previous line. Probably the first line you indented started with a two–letter word, and every line after that was indented by the same amount.

You can figure this out from within Emacs, btw. If you use C-h k, it will prompt you to press a key or key sequence. It then shows you the help for whatever that key or key sequence does inside Emacs. Pressing TAB here will show you the help for the command called indent-for-tab-command. The documentation for this function starts out by saying:

Indent the current line or region, or insert a tab, as appropriate.

This function either inserts a tab, or indents the current line,
or performs symbol completion, depending on tab-always-indent.
The function called to actually indent the line or insert a tab
is given by the variable indent-line-function.

Well, it didn’t do symbol completion, so to figure out how it indented the line we should look at the value of indent-line-function. If you use C-h v, it will prompt you for the name of a variable. Enter indent-line-function there (and note that if you place the cursor over the name first then you won’t actually have to actually type anything), it will tell you the value of the variable:

indent-line-function is a variable defined in indent.el.gz.

Value
indent-relative

Documentation
Function to indent the current line.

So indent-relative is the name of the function we are really interested in. Using C-h f will give us help about a function, just as C-h v gave us help about a variable. The documentation for indent-relative explains all:

indent-relative is an interactive and byte-compiled function defined
in indent.el.gz.

Signature
(indent-relative &optional FIRST-ONLY UNINDENTED-OK)

Documentation
Space out to under next indent point in previous nonblank line.

An indent point is a non-whitespace character following whitespace.
The following line shows the indentation points in this line.
    ^         ^    ^     ^   ^           ^      ^  ^    ^
If FIRST-ONLY is non-nil, then only the first indent point is
considered.

If the previous nonblank line has no indent points beyond the
column point starts at, then tab-to-tab-stop is done, if both
FIRST-ONLY and UNINDENTED-OK are nil, otherwise nothing is done.
If there isn't a previous nonblank line and UNINDENTED-OK is nil,
call tab-to-tab-stop.

See also indent-relative-first-indent-point.

If this isn’t the behavior that you want, you can of course customize the indent-line-function variable so that it names some other function. The docstring for indent-line-function states that it falls back to calling tab-to-tab-stop when there is no previous line to go by, so you can just set indent-line-function to tab-for-tab-stop to get that behavior all of the time if you prefer it.

1

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.