diff --git a/modules/init-look-and-feel.el b/modules/init-look-and-feel.el index 185f13f9..0a05127f 100644 --- a/modules/init-look-and-feel.el +++ b/modules/init-look-and-feel.el @@ -281,6 +281,68 @@ Set FONT and SIZE if they are passed as arguments." :ensure vlf :defer t) +(require 'rx) + +(defun exordium--alist-get-derived-mode (alist) + "Return value from ALIST where key matches `derived-mode-p' of current buffer." + (alist-get nil alist nil nil + (lambda (elt _) + (apply #'derived-mode-p + (if (listp elt) elt (list elt)))))) + +(defun exordium--delete-trailing-whitespace-data-start-and-cleanup () + "Find beginning of data section start. +Also cleanup trailing lines when `delete-trailing-lines' is +non-nil and insert new line when `require-final-newline' is +non-nil." + (save-excursion + (when-let* + ((exordium-delete-trailing-whitespace-skip-data) + (data-keywords (exordium--alist-get-derived-mode + exordium-delete-trailing-whitespace-data-keywords))) + (when (re-search-forward + (rx-to-string + `(seq line-start + (or ,@data-keywords) + (zero-or-more whitespace) + line-end) + t) + nil t) + (let ((point (point))) + ;; When this is not a perlpod, clean it too - return nil + (unless (when-let* + ((perlpod-keywords + (exordium--alist-get-derived-mode + exordium-delete-trailing-whitespace-data-perlpod-keywords))) + (re-search-forward + (rx-to-string + `(seq "\n" (zero-or-more whitespace) + "\n=" (or ,@perlpod-keywords)) + t) + nil t)) + ;; Otherwise do a minimal cleanup: + ;; Delete trailing lines, as `delete-trailing-whitespace' won't + ;; handle it + (when-let* + ((delete-trailing-lines) + ((re-search-forward + (rx line-start + (group (one-or-more (or whitespace "\n"))) + string-end) + nil t)) + (b (match-beginning 1)) + (e (match-end 1)) + ((region-modifiable-p b e))) + (delete-region b e)) + ;; Ensure trailing new line is present, as + ;; `delete-trailing-whitespace' won't handle it + (when (and require-final-newline + (not (re-search-forward (rx "\n" string-end) nil t))) + (goto-char (point-max)) + (insert "\n")) + ;; trim whitespace only up to data section + point)))))) + (defun exordium-delete-trailing-whitespace-in-buffer (&optional start end) "Delete trailing whitespace in current buffer. Like `delete-trailing-whitespace', but any restrictions are @@ -297,11 +359,11 @@ non-nil END it will delete trailing whitespace up to END. If called interactively, START and END are the start/end of the region if the mark is active, or the whole buffer, up to data secion (when `exordium-delete-trailing-whitespace-skip-data' is -non-nil), if the mark is inactive. +non-nil) if the mark is inactive. The function doesn't delete trailing whitespaces when buffer is -in `diff-mode', `exordium-delete-trailing-whitespace-skip-data' -is non-nil, and the function has been called without a prefix argument. +in any of `exordium-delete-trailing-whitespace-inhibit-modes', +and the function has been called without a prefix argument. Depending on mode a data section starts after a line with a one of keywords __END__ or __DATA__ or a one of control @@ -319,7 +381,7 @@ https://docs.ruby-lang.org/en/3.3/Object.html for more details." (list nil nil)))) (if (and (not current-prefix-arg) (apply #'derived-mode-p - '(diff-mode special-mode view-mode comint-mode cider-repl-mode haskell-interactive-mode))) + exordium-delete-trailing-whitespace-inhibit-modes)) (when (called-interactively-p 'any) (user-error "Not deleting trailing whitespaces in '%s', call with prefix to override" major-mode)) @@ -327,58 +389,19 @@ https://docs.ruby-lang.org/en/3.3/Object.html for more details." (save-mark-and-excursion (save-match-data (goto-char (point-min)) - (when-let* (((looking-at - (rx string-start (group (zero-or-more (or whitespace "\n")) (or "\n" line-end))))) - (b (match-beginning 1)) - (e (match-end 1)) - ((region-modifiable-p b e))) + (when-let* + (((looking-at + (rx string-start + (group (zero-or-more (or whitespace "\n")) + (or "\n" line-end))))) + (b (match-beginning 1)) + (e (match-end 1)) + ((region-modifiable-p b e))) (delete-region b e)) (let ((end (or end - (when-let* ((exordium-delete-trailing-whitespace-skip-data) - (data-keywords (cond - ((derived-mode-p 'ruby-mode - 'ruby-ts-mode - 'enh-ruby-mode) - '("__END__")) - ((derived-mode-p 'perl-mode - 'perl-ts-mode - 'cperl-mode) - '("__END__" "__DATA__" "" "")))) - (perlpod-keywords '("pod" "head1" "head2" "head3" - "head4" "head5" "head6" "over" - "item" "back" "begin" "end" - "for" "encoding" "cut"))) - (when (re-search-forward - (rx-to-string - `(seq line-start (or ,@data-keywords) (zero-or-more whitespace) line-end) - t) - nil t) - (let ((point (point))) - (unless (and (derived-mode-p 'perl-mode - 'perl-ts-mode - 'cperl-mode) - (re-search-forward - (rx-to-string - `(seq "\n" (zero-or-more whitespace) "\n" "=" (or ,@perlpod-keywords)) t) - nil t)) - ;; delete trailing lines, as `delete-trailing-whitespace' won't handle it - (when-let* ((delete-trailing-lines) - ((re-search-forward - (rx line-start (group (one-or-more (or whitespace "\n"))) string-end) - nil t)) - (b (match-beginning 1)) - (e (match-end 1)) - ((region-modifiable-p b e))) - (delete-region b e)) - ;; ensure trailing new line is present, as `delete-trailing-whitespace' won't handle it - (when (and require-final-newline - (not (re-search-forward (rx "\n" string-end) nil t))) - (goto-char (point-max)) - (insert "\n"))) - ;; trim whitespace only up to data section - point)))))) + (exordium--delete-trailing-whitespace-data-start-and-cleanup)))) (delete-trailing-whitespace start end))))))) ;; Remove trailing blanks on save @@ -387,8 +410,10 @@ https://docs.ruby-lang.org/en/3.3/Object.html for more details." See `exordium-delete-trailing-whitespace-in-buffer' for more details." :lighter nil (if delete-trailing-whitespace-mode - (add-hook 'before-save-hook #'exordium-delete-trailing-whitespace-in-buffer nil t) - (remove-hook 'before-save-hook #'exordium-delete-trailing-whitespace-in-buffer t))) + (add-hook 'before-save-hook + #'exordium-delete-trailing-whitespace-in-buffer nil t) + (remove-hook 'before-save-hook + #'exordium-delete-trailing-whitespace-in-buffer t))) (define-globalized-minor-mode global-delete-trailing-whitespace-mode delete-trailing-whitespace-mode diff --git a/modules/init-prefs.el b/modules/init-prefs.el index 244b2735..92bd422a 100644 --- a/modules/init-prefs.el +++ b/modules/init-prefs.el @@ -94,13 +94,56 @@ a lot of trailing whitespaces." (defcustom exordium-delete-trailing-whitespace-skip-data t "When t preserve whitespaces in Data section in Perl and Ruby modes. This variable is used by -`exordium-delete-trailing-whitespace-in-buffer' (see docstring -for details) and in consequence in -`delete-trailing-whitespace-mode' and -`global-delete-trailing-whitespace-mode'." +`exordium-delete-trailing-whitespace-in-buffer' (which see) and +in consequence in `delete-trailing-whitespace-mode' and +`global-delete-trailing-whitespace-mode'. + +See also `exordium-delete-trailing-whitespace-data-keywords'." :group 'exordium :type 'boolean) +(defcustom exordium-delete-trailing-whitespace-inhibit-modes + '(diff-mode special-mode view-mode comint-mode cider-repl-mode + haskell-interactive-mode) + "List of modes where deletion of trailing whitespaces is inhibited. +See also docstring for +`exordium-delete-trailing-whitespace-in-buffer' and +`delete-trailing-whitespace-mode'." + :type '(repeat (symbol :tag "Mode")) + :group 'exordium) + +(defcustom exordium-delete-trailing-whitespace-data-keywords + '(((ruby-mode ruby-ts-mode enh-ruby-mode) . ("__END__")) + ((perl-mode perl-ts-mode cperl-mode) . ("__END__" "__DATA__" "" ""))) + "Mapping between modes and keywords that indicate data section for that mode. +Data section will not have its trailing whitespace +deleted, barred for trailing new lines when +`delete-trailing-lines' is non nil and for ensuring ending +newline when `require-final-newline' is non nil. + +See also `exordium-delete-trailing-whitespace-data-perlpod-keywords'." + :type '(alist :key-type (choice + (symbol :tag "Mode") + (repeat (symbol :tag "Mode"))) + :value-type (repeat (string :tag "Keyword"))) + :group 'exordium) + +(defcustom exordium-delete-trailing-whitespace-data-perlpod-keywords + '((perl-mode perl-ts-mode cperl-mode) . ("pod" "head1" "head2" "head3" + "head4" "head5" "head6" "over" + "item" "back" "begin" "end" + "for" "encoding" "cut")) + "Mapping between Perl mode and perlpod keywords. +When a data section happens to contain a perlpod as sensed by +existence of a perlpod keyword it will have its trailing +whitespaces deleted, even when +`exordium-delete-trailing-whitespace-skip-data' is non-nil." + :type '(alist :key-type (choice + (symbol :tag "Mode") + (repeat (symbol :tag "Mode"))) + :value-type (repeat (string :tag "Keyword"))) + :group 'exordium) + (defcustom exordium-enable-electric-pair-mode t "Whether to enable `electric-pair-mode'." :group 'exordium