0

Is there a Elisp function that deletes "redundant" leading whitespace of the region while maintaining relative indentation.

This behavior is like textwrap.dedent in python. https://docs.python.org/2/library/textwrap.html#textwrap.dedent

  • Not real sure what you mean, but if this is about outdenting (removing the same amount of indentation from) all lines (or all lines in the region) then you can use C-x TAB with a numeric prefix arg (for the number of columns to outdent). – Drew Nov 13 '17 at 15:19
  • I'm also not clear on what you mean. But if you want a more programatic solution, check whitespace-mode. – xmonk Nov 13 '17 at 23:26
  • Based on the Python link, my understanding is that OP is looking for a function which deletes the greatest common whitespace prefix of some region of text. – Basil Nov 14 '17 at 0:06
  • @Basil yes. a simple elisp function. I might come up with my own. – FunkyBaby Nov 14 '17 at 0:56
  • 2
    Possible duplicate of copy region without leading indentation – phils Nov 14 '17 at 0:59
1

This is a variant of my answer to copy region without leading indentation which acts directly in the original buffer.

(defun my-unindent-region (pad beginning end)
  "Un-indent the region by the length of its minimum indent.

If numeric prefix argument PAD is supplied, indent the resulting
text by that amount."
  (interactive "P\nr")
  (save-excursion
    ;; Establish the minimum level of indentation.
    (let ((indent nil))
      (goto-char beginning)
      (while (and (re-search-forward "^[[:space:]\n]*" nil :noerror)
                  (< (point) end))
        (let ((length (current-column)))
          (when (or (not indent) (< length indent))
            (setq indent length)))
        (forward-line 1))
      (if (not indent)
          (error "Region is entirely whitespace")
        ;; Un-indent the buffer contents by the length of the minimum
        ;; indent level.
        (when pad
          (setq indent (- indent (prefix-numeric-value pad))))
        (indent-rigidly beginning end (- indent))))))
2

N.B. See the answer by phils and its linked inspiration for a similar but more general solution.

The command indent-rigidly comes quite close to the desired functionality:

indent-rigidly is an interactive compiled Lisp function in
‘indent.el’.

It is bound to C-x TAB.

(indent-rigidly START END ARG &optional INTERACTIVE)

Indent all lines starting in the region.
If called interactively with no prefix argument, activate a
transient mode in which the indentation can be adjusted interactively
by typing <left>, <right>, <S-left>, or <S-right>.
Typing any other key deactivates the transient mode.

If called from a program, or interactively with prefix ARG,
indent all lines starting in the region forward by ARG columns.
If called from a program, START and END specify the beginning and
end of the text to act on, in place of the region.

Negative values of ARG indent backward, so you can remove all
indentation by specifying a large negative ARG.

but unfortunately a large enough ARG will change the relative indentation of lines. A workaround is to dedent by (i.e. pass a negative ARG of absolute value equal to) the smallest indentation level in the region:

(defun my-dedent (&optional start end)
  "Delete all common indentation between START and END.
If called interactively, START and END are the start/end of the
region if the mark is active, or of the buffer's accessible
portion if the mark is inactive.

Blank lines are ignored."
  (interactive (and (use-region-p)
                    (list (region-beginning)
                          (region-end))))
  (setq start (or start (point-min)))
  (setq end   (or end   (point-max)))
  (undo-boundary)
  (indent-rigidly start end
                  (- (indent-rigidly--current-indentation start end))))
  • 1
    I hadn't noticed indent-rigidly--current-indentation. That seems like a function which shouldn't really be marked as internal. – phils Nov 14 '17 at 1:14
  • @phils Sorry, I wouldn't have posted a separate answer if I had seen your comment and answer in time, as our basic ideas are the same and your answer is more general. I agree that indent-rigidly--current-indentation seems too useful to be marked as internal, but the fact of the matter is it is, so one should use it with caution. If there are no objections, I'll leave my answer open purely as an example of an alternative approach. – Basil Nov 14 '17 at 1:27
  • 1
    No need to apologise! (Especially as you actually posted yours first :) but even if you hadn't I'd still be glad of your answer. – phils Nov 14 '17 at 2:13
  • I notice that indent-rigidly--current-indentation calls current-indentation, whereas I was using current-column in my answer. I haven't tested, but my gut tells me that the former is going to be more correct, given that we're both calling indent-rigidly. – phils Nov 14 '17 at 4:18
  • @phils Indeed, without being too familiar with the subtleties of their implementations and purpose, it looks like current-column would not DTRT in certain edge cases, as it handles more scenarios. You could probably use current-indentation as a drop-in replacement for current-column in your answer, though, no? – Basil Nov 14 '17 at 12:05

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.