4

I want to force Emacs to do (quasi-)dumb indentation à la Eclipse. By this I mean the following:

  1. If the point is at the beginning of a line and I press tab, force shift the line 2 spaces to the right.
  2. If a region is selected and I press tab, force shift each new line 2 spaces to the right.

At least in LaTeX-mode (which is the one I mainly use), the current behavior is that pressing tab does not shift at all my lines.

Is there any way I could make Emacs obey my dumb indenting?

  • 2
    You can insert plain character by adding C-q prefix to it. i.e. C-q TAB inserts a TAB and runs nothing else. – Tu Do Nov 4 '14 at 5:28
6

The indent-rigidly command can be used to indent the region by some fixed amount.

By default C-x TAB is bound to indent-rigidly and puts you in an interactive mode where you can indent the region left or right with additional keys. With a prefix argument you can directly indent by some number of columns. For example, to indent by 5:

 C-5 C-x TAB

If you don't need this flexibility, you could rebind the key to a function that always indents by the same amount. Here's an example that will indent the active region or the current line by 2 spaces. If there is no region and point is not at the beginning of the line, it does nothing.

(defun simple-indent (start end)
  (interactive "r")
  (let ((size 2))
    (if (region-active-p)
        (indent-rigidly start end size)   
      (if  (bolp)
          (indent-rigidly (line-beginning-position) (line-end-position) size)))))

(global-set-key (kbd "C-x <tab>") #'simple-indent)
  • I had no idea about that keybinding! Very useful :) – Sean Allred Nov 4 '14 at 22:34
  • Thanks. The indent-rigidly function itself proves adequate. – NVaughan Nov 5 '14 at 2:31
  • 1
    @NVaughan Great! I've reworked the answer to describe the built-in behavior in a bit more detail before providing an example custom function. – glucas Nov 5 '14 at 14:50
0

I just checked the behaviour for an example text.

{
Hello
world
!

When marking the region and pressing tab, they were indented automatically according to the indentation rules, i.e.

{
  Hello
  world
  !

Can you verify whether this happens for you?

If you want to force a specific behaviour of Tab, I came up with this solution:

(defcustom dumb-indent-string "  "
  "What string should be used for indenting?"
  :group 'dumb-indent
  :type 'string 
  :safe #'booleanp) ;; <- Considered safe as a buffer local variable.

(defun dumb-indent-line ()
  (interactive)
  (save-excursion 
    (goto-char (line-beginning-position))
    (search-forward-regexp "[[:blank:]]*") 
    (insert dumb-indent-string)
    (setq deactivate-mark nil)))

(defun dumb-indent-region (start end)
  (interactive (list (region-beginning) (region-end)))
  (save-excursion
    (goto-char start)
    (while (< (point) end)
      (dumb-indent-line)
      (forward-line))
    (setq deactivate-mark nil))) ;; Works only when calling function directly.

(defun dumb-indent-activate ()
  "A hook function for activating dumb indenting. Can also be used as 
`M-x dumb-indent-activate'."
  (interactive)
  (setq-local indent-line-function #'dumb-indent-line)
  (setq-local indent-region-function #'dumb-indent-region))

(add-hook 'latex-mode-hook #'dumb-indent-activate) ;; preinstalled latex-mode
(add-hook 'LaTeX-mode-hook #'dumb-indent-activate) ;; AucTeX LaTeX-mode

There is a little flaw though. Pressing tab will remove highlighting, because indent-region explicitly calls (deactivate-mark) without querying the deactivate-mark variable. I could have written a function, that is bound to TAB instead of indent-for-tab-command, but I hope for someone having a better idea.

  • Thanks! Works fine except for the fact that I cannot keep indenting to the right (i.e. it only works once). – NVaughan Nov 4 '14 at 16:06
0

You're probably better off figuring out how to get the smart indentation facilities to work to your advantage, but if you really want to do dumb indentation, this no-frills function will do it:

(defun dumb-indent ()
  "Indent two spaces when at the beginning of a line, or to each
line of a region."
  (interactive)
  (let ((prefix "  "))
    (cond ((region-active-p)
           (string-insert-rectangle (region-beginning) (region-end) prefix))
          ((bolp)
           (insert prefix))
          (t
           (message "Can't dumb-indent here!")))))

I'd suggest that, rather than binding such a function to tab, you consider something like shift-tab or C-tab so that you don't clobber bindings you might want to keep. That way, you can still use dumb indentation if you really want it, but it doesn't get in the way when you don't.

  • Thanks. However, for some reason it gives me an 8-space indent! – NVaughan Nov 4 '14 at 16:06
  • It shouldn't: try M-x dumb-indent at the very beginning of a line, or with a region selected. FWIW: the default value of tab-width is 8. – Dan Nov 4 '14 at 16:09
  • The 8-space step may happen if you use this function on a region/line, where the leading whitespace contains a tab character, since a string " \t" is displayed as 8 spaces, while " \t" will look like 16 spaces. – kdb Nov 6 '14 at 13:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.