From 68c23c6e154e9386cb95e1e4737dc4ea980663c4 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 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. --- lisp/comint.el | 93 +++++++++++++++++++++++++++++++++++++++++++++----- lisp/shell.el | 4 +++ 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/lisp/comint.el b/lisp/comint.el index dbbd687e18..23ec9cbabb 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -4043,21 +4043,21 @@ 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 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 @@ -4222,6 +4222,83 @@ comint--intersect-regions (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 71a37c37ca..3b1244fa8d 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