From cfa2293b71af972432969f784b33a29ec0ac7b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miha=20Rihtar=C5=A1i=C4=8D?= Date: Mon, 15 Nov 2021 23:37:36 +0100 Subject: [PATCH 5/5] 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 the 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 sh-mode. --- lisp/comint.el | 95 +++++++++++++++++++++++++++++++++++++++++++++----- lisp/shell.el | 4 +++ 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/lisp/comint.el b/lisp/comint.el index 54f5bcd7f7..cc3cf2a7fa 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -4043,22 +4043,22 @@ comint-osc-hyperlink-handler (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 buffer. This function is called by `comint-indirect-buffer' with zero arguments after making a comint 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 -`after-change-major-mode-hook' are bound to nil.") +set to 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 "Hook run after setting up the indirect fontification buffer. @@ -4216,6 +4216,83 @@ comint--intersect-regions (when return-beg (cons (car return-beg) (car return-end))))) +(defun comint-indent-input-line (fun) + "Indent current input or process output line. +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 the region 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 input or output line. +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 the region 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 buffer. If an indirect buffer for the current buffer already exists, diff --git a/lisp/shell.el b/lisp/shell.el index 3c008ec508..3629171fbe 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -639,6 +639,10 @@ shell-mode (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)) -- 2.34.0