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
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
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))))
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))))))