From: Miha Rihtaršič Date: Fri, 9 Sep 2022 18:13:13 +0000 (+0200) Subject: Input indentation for M-x shell X-Git-Tag: emacs-29.0.90~1856^2~631 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=3b105e978c42973fb5810a74681f263889fc23c0;p=emacs.git Input indentation for M-x shell * lisp/comint.el (comint-indent-input-line): (comint-indent-input-line-default): (comint-indent-input-region): (comint-indent-input-region-default): New functions that implement a general mechanism for input indentation through an indirect buffer in comint derived major modes. * lisp/shell.el (shell-mode): Set up input indentation according to sh-mode (bug#51940). --- diff --git a/lisp/comint.el b/lisp/comint.el index 4fcfb500e18..751e561d3e3 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -4012,21 +4012,21 @@ This function is intended to be included as an entry of (cons (point-marker) (match-string-no-properties 1 text))))) -;;; Input fontification through an indirect buffer +;;; Input fontification and indentation through an indirect buffer ;;============================================================================ ;; -;; Modes derived from `comint-mode' can set up fontification input -;; text with the help of an indirect buffer whose major mode and -;; font-lock settings are set accordingly. +;; Modes derived from `comint-mode' can set up fontification and +;; indentation of input text with the help of an indirect buffer whose +;; major mode and font-lock settings are set accordingly. (defvar-local comint-indirect-setup-function nil "Function to set up an indirect comint fontification buffer. This function is called by `comint-indirect-buffer' with zero arguments after making an indirect buffer. It is usually set to -a major-mode command whose font-locking is desired for input -text. In order to prevent possible mode hooks from running, the -variable `delay-mode-hooks' is set to t prior to calling this -function and `change-major-mode-hook' along with +a major-mode command whose font-locking and indentation are +desired for input text. In order to prevent possible mode hooks +from running, the variable `delay-mode-hooks' is set to t prior +to calling this function and `change-major-mode-hook' along with `after-change-major-mode-hook' are bound to nil.") (defcustom comint-indirect-setup-hook nil @@ -4191,6 +4191,83 @@ function called, or nil, if no function was called (if BEG = END)." (when return-beg (cons (car return-beg) (car return-end))))) +(defun comint-indent-input-line (fun) + "Indent current line from comint process output or input. +If point is on output, call FUN, otherwise indent the current +line in the indirect buffer created by `comint-indirect-buffer', +which see." + (if (or comint-use-prompt-regexp + (eq (get-text-property (point) 'field) 'output)) + (funcall fun) + (let ((point (point)) + (min (point-min)) + (max (point-max))) + (unwind-protect + (with-current-buffer (comint-indirect-buffer) + (narrow-to-region min max) + (goto-char point) + (narrow-to-region (field-beginning) (field-end)) + (unwind-protect (funcall indent-line-function) + (setq point (point)))) + (goto-char point))))) + +(defun comint-indent-input-region (fun start end) + "Indent comint process output and input between START and END. +Output text between START and END is indented with FUN and input +text is indented in the indirect buffer created by +`comint-indirect-buffer', which see." + (if comint-use-prompt-regexp + (funcall fun start end) + (let ((opoint (copy-marker (point))) + final-point) + (unwind-protect + (comint--intersect-regions + (lambda (start end) + (goto-char opoint) + (if (= opoint (point)) + (unwind-protect (funcall fun start end) + (setq final-point (copy-marker (point)))) + (funcall fun start end))) + (lambda (start end) + (let ((min (point-min)) + (max (point-max)) + (final-point1 nil)) + (unwind-protect + (with-current-buffer (comint-indirect-buffer) + (narrow-to-region min max) + (goto-char opoint) + (if (= opoint (point)) + (unwind-protect + (funcall indent-region-function start end) + (setq final-point1 (point))) + (funcall indent-region-function start end))) + (when final-point1 + (setq final-point (copy-marker final-point1)))))) + start end) + (if final-point + (progn + (goto-char final-point) + (set-marker final-point nil)) + (goto-char opoint)) + (set-marker opoint nil))))) + +(defun comint-indent-input-line-default () + "Indent current line from comint process output or input. +If point is on output, indent the current line according to the +default value of `indent-line-function', otherwise indent the +current line in the indirect buffer created by +`comint-indirect-buffer', which see." + (comint-indent-input-line (default-value 'indent-line-function))) + +(defun comint-indent-input-region-default (start end) + "Indent comint process output and input between START and END. +Output text between START and END is indented according to the +default value of `indent-region-function' and input text is +indented in the indirect buffer created by +`comint-indirect-buffer', which see." + (comint-indent-input-region (default-value 'indent-line-function) + start end)) + (defun comint-indirect-buffer (&optional no-create) "Return an indirect comint fontification buffer. If an indirect buffer for the current buffer already exists, diff --git a/lisp/shell.el b/lisp/shell.el index e8ae1c9738f..b65792e10a9 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -653,6 +653,10 @@ command." (message-log-max nil)) (sh-mode))))) + (setq-local indent-line-function #'comint-indent-input-line-default) + (setq-local indent-region-function + #'comint-indent-input-region-default) + ;; This is not really correct, since the shell buffer does not really ;; edit this directory. But it is useful in the buffer list and menus. (setq list-buffers-directory (expand-file-name default-directory))