Skip to content

Commit

Permalink
Add options for maximum length and per-command indentation skipping
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 9aebdd3
Author: Jeff Valk <[email protected]>
Date:   Sun Jun 25 12:01:37 2023 -0400

    Generalize indentation skipping; add user-specified predicate

    This extends the ability to skip indentation based on text length and prefix
    argument to save calls as well as yank. It also gives the user full control of
    when to skip indenting via a customizable predicate function.

commit 0c50c2b
Author: Jim Myhrberg <[email protected]>
Date:   Sat Apr 29 14:02:16 2023 +0100

    feat: add option to skip indent on yank when prefix arg is given

    New option is disabled by default, ensuring no change in behavior.

commit f730e1c
Author: Jim Myhrberg <[email protected]>
Date:   Sat Apr 29 13:55:27 2023 +0100

    feat(yank): add threshold option to not indent large yank texts

    Set to nil by default, there is no change in behavior until a user
    customizes the snap-indent-yank-threshold variable.
  • Loading branch information
jeffvalk committed Jun 25, 2023
1 parent 2b8000f commit ef3bcab
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 11 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,14 @@ To configure via `use-package`, adapt the following example as desired:

### Customization

| Variable | Type | Default | Description |
| :--------------------------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- |
| `snap-indent-excluded-modes` | symbol list | `(cmake-ts-mode coffee-mode conf-mode elm-mode haml-mode haskell-mode makefile-automake-mode makefile-bsdmake-mode makefile-gmake-mode makefile-imake-mode makefile-makepp-mode makefile-mode occam-mode python-mode python-ts-mode slim-mode yaml-mode yaml-ts-mode)` | Major modes in which to ignore activation |
| `snap-indent-format` | function or list | `nil` | Additional formatting to apply when indenting |
| `snap-indent-on-save` | boolean | `nil` | Whether to indent the entire buffer on save |
| Variable | Type | Default | Description |
|:---------------------------------|:-----------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------|
| `snap-indent-excluded-modes` | symbol list | `(cmake-ts-mode coffee-mode conf-mode elm-mode haml-mode haskell-mode makefile-automake-mode makefile-bsdmake-mode makefile-gmake-mode makefile-imake-mode makefile-makepp-mode makefile-mode occam-mode python-mode python-ts-mode slim-mode yaml-mode yaml-ts-mode)` | Major modes in which to ignore activation |
| `snap-indent-format` | function or list | `nil` | Additional formatting to apply when indenting |
| `snap-indent-on-save` | boolean | `nil` | Whether to indent the entire buffer on save |
| `snap-indent-length-limit` | integer | `nil` | Maximum text length to indent |
| `snap-indent-skip-on-prefix-arg` | boolean | `nil` | Whether a prefix command argument causes indentation to be skipped |
| `snap-indent-skip-on-condition` | function | `nil` | Predicate function to cause indentation to be skipped |

### Additional formatting

Expand All @@ -71,6 +74,6 @@ Each function must accept two arguments: the beginning and end positions of the

## License

Copyright © 2022 Jeff Valk
Copyright © 2023 Jeff Valk

Distributed under the GNU General Public License, version 3
53 changes: 52 additions & 1 deletion snap-indent-tests.el
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
;;; snap-indent-tests.el --- Snap-indent tests -*- lexical-binding: t; -*-

;; Copyright (C) 2022 Jeff Valk
;; Copyright (C) 2023 Jeff Valk

;; Author: Jeff Valk <[email protected]>

Expand Down Expand Up @@ -102,6 +102,57 @@
pp-text
unindented-text)))))))

(ert-deftest snap-indent-maybe-indent-test ()
"Test conditional indentation."
;; The tests below rely on equivalence of indentation behavior between elisp
;; major mode formatting and pretty printing. If these ever break suddenly,
;; check this assumption.
(let* ((inhibit-message t) ; run tests quietly
(forms '(lorem ipsum dolor
(sit amet consectetur (adipiscing elit))
(sed () do eiusmod
(tempor incididunt) (ut (labore (et (dolore ())))))
(magna aliqua ut)
(((enim)) ad (minim) veniam)
(quis nostrud exercitation ullamco laboris nisi)))
(pp-text (pp-to-string forms))
(unindented-text (replace-regexp-in-string "^ *" "" pp-text)))
;; Skip when exceeding length limit
(with-temp-buffer
(emacs-lisp-mode)
(snap-indent-mode)
(insert unindented-text)
(let ((snap-indent-length-limit 10)) ; over limit
(snap-indent-maybe-indent (point-min) (point-max))
(should (string-equal (buffer-string) unindented-text)))
(let ((snap-indent-length-limit 10000)) ; under limit
(snap-indent-maybe-indent (point-min) (point-max))
(should (string-equal (buffer-string) pp-text))))
;; Skip when prefix arg is specified
(with-temp-buffer
(emacs-lisp-mode)
(snap-indent-mode)
(insert unindented-text)
(let ((snap-indent-skip-on-prefix-arg t)
(current-prefix-arg '(4))) ; prefixed
(snap-indent-maybe-indent (point-min) (point-max))
(should (string-equal (buffer-string) unindented-text)))
(let ((snap-indent-skip-on-prefix-arg t)
(current-prefix-arg nil)) ; not prefixed
(snap-indent-maybe-indent (point-min) (point-max))
(should (string-equal (buffer-string) pp-text))))
;; Skip according to user-defined predicate
(with-temp-buffer
(emacs-lisp-mode)
(snap-indent-mode)
(insert unindented-text)
(let ((snap-indent-skip-on-condition (lambda (_ _) t))) ; pred: t
(snap-indent-maybe-indent (point-min) (point-max))
(should (string-equal (buffer-string) unindented-text)))
(let ((snap-indent-skip-on-condition (lambda (_ _) nil))) ; pred: nil
(snap-indent-maybe-indent (point-min) (point-max))
(should (string-equal (buffer-string) pp-text))))))

(provide 'snap-indent-tests)

;;; snap-indent-tests.el ends here
43 changes: 39 additions & 4 deletions snap-indent.el
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
;;; snap-indent.el --- Simple automatic indentation -*- lexical-binding: t; -*-

;; Copyright (C) 2022 Jeff Valk
;; Copyright (C) 2023 Jeff Valk

;; Author: Jeff Valk <[email protected]>
;; URL: https://github.com/jeffvalk/snap-indent
;; Keywords: indent tools convenience
;; Version: 1.0
;; Version: 1.1
;; Package-Requires: ((emacs "24.1"))

;; This file is NOT part of GNU Emacs.
Expand Down Expand Up @@ -89,6 +89,31 @@ tab/space conversion and `delete-trailing-whitespace'."
(repeat :tag "List of functions" function))
:group 'snap-indent)

(defcustom snap-indent-length-limit nil
"Maximum text length to indent.
Set this to prevent any performance issues with large blocks of text.
When nil, no limit is applied."
:type 'integer
:group 'snap-indent)

(defcustom snap-indent-skip-on-prefix-arg nil
"Whether a prefix command argument causes indentation to be skipped.
When non-nil, this lets you skip indentation for a single operation without
disabling `snap-indent-mode'."
:type 'boolean
:group 'snap-indent)

(defcustom snap-indent-skip-on-condition nil
"Predicate function to cause indentation to be skipped.
When specified, this lets you skip indentation for a single operation without
disabling `snap-indent-mode' according to any logic you choose.
The function must accept two arguments, which specify the start and end
positions of the region on which to (potentially) operate. The function should
return non-nil to skip indentation, and nil otherwise."
:type 'function
:group 'snap-indent)

;; To make user configuration more expressive and less error-prone,
;; `snap-indent-format' may be either a function or a list of functions; if the
;; former, we'll wrap it in a list. Caveat when checking for this: lambdas are
Expand All @@ -111,15 +136,25 @@ tab/space conversion and `delete-trailing-whitespace'."
(let ((end* (+ end (- (point-max) orig-max)))) ; account for prior changes
(funcall format beg end*)))))

(defun snap-indent-maybe-indent (beg end)
"If the region between BEG and END should be indented, dispatch that action."
(unless (or (and snap-indent-length-limit
(> (- end beg) snap-indent-length-limit))
(and snap-indent-skip-on-prefix-arg
current-prefix-arg)
(and snap-indent-skip-on-condition
(funcall snap-indent-skip-on-condition beg end)))
(snap-indent-indent beg end)))

(defun snap-indent-save-handler ()
"Indent buffer text on save as specified."
(when snap-indent-on-save
(snap-indent-indent (point-min) (point-max))))
(snap-indent-maybe-indent (point-min) (point-max))))

(defun snap-indent-command-handler ()
"Indent region text on yank."
(when (memq this-command '(yank yank-pop))
(snap-indent-indent (region-beginning) (region-end))))
(snap-indent-maybe-indent (region-beginning) (region-end))))

;;;###Autoload
(define-minor-mode snap-indent-mode
Expand Down

0 comments on commit ef3bcab

Please sign in to comment.