emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/coterm 2358124 48/80: Try to enter and leave char-mode


From: ELPA Syncer
Subject: [elpa] externals/coterm 2358124 48/80: Try to enter and leave char-mode automatically
Date: Wed, 13 Oct 2021 18:57:34 -0400 (EDT)

branch: externals/coterm
commit 23581244de3f74ac1d8ed4f1236fcd1e218e8408
Author: m <>
Commit: m <>

    Try to enter and leave char-mode automatically
---
 coterm.el | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 195 insertions(+), 38 deletions(-)

diff --git a/coterm.el b/coterm.el
index b6c46cf..1754728 100644
--- a/coterm.el
+++ b/coterm.el
@@ -1,6 +1,8 @@
 ;;; coterm.el --- Terminal emulation for comint -*- lexical-binding: t; -*-
 
 (require 'term)
+(eval-when-compile
+  (require 'cl-lib))
 
 ;;; Mode functions and configuration
 
@@ -85,13 +87,13 @@ if [ $1 = .. ]; then shift; fi; exec \"$@\"" null-device)
     (setq coterm-term-environment-function #'comint-term-environment)
     (setq coterm-start-process-function #'start-file-process)))
 
-;;; Raw mode
+;;; Char mode
 
 (defvar coterm-char-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map term-raw-map)
-    (define-key map [remap term-char-mode] #'coterm-char-mode)
-    (define-key map [remap term-line-mode] #'coterm-char-mode)
+    (define-key map [remap term-char-mode] #'coterm-char-mode-cycle)
+    (define-key map [remap term-line-mode] #'coterm-char-mode-cycle)
     map))
 
 (define-minor-mode coterm-char-mode
@@ -107,8 +109,7 @@ customize it."
 
 (define-minor-mode coterm-scroll-snap-mode
   "Keep scroll synchronized.
-Usually enabled for full-screen terminal programs to keep them on
-screen."
+Useful for full-screen terminal programs to keep them on screen."
   :keymap nil
   (if coterm-scroll-snap-mode
       (progn
@@ -117,7 +118,8 @@ screen."
                 (cons scroll-margin
                       (local-variable-p 'scroll-margin)))
           (setq-local scroll-margin 0))
-        (add-hook 'coterm-t-after-insert-hook #'coterm--scroll-snap nil t))
+        (add-hook 'coterm-t-after-insert-hook #'coterm--scroll-snap 'append t)
+        (coterm--scroll-snap))
     (when-let ((margin coterm--char-old-scroll-margin))
       (setq coterm--char-old-scroll-margin nil)
       (if (cdr margin)
@@ -126,30 +128,193 @@ screen."
     (remove-hook 'coterm-t-after-insert-hook #'coterm--scroll-snap t)))
 
 (defun coterm--scroll-snap ()
-  (let* ((buf (current-buffer))
-         (pmark (process-mark (get-buffer-process buf)))
-         (sel-win (selected-window))
-         (w sel-win))
-    ;; Avoid infinite loop in strange case where minibuffer window
-    ;; is selected but not active.
-    (while (window-minibuffer-p w)
-      (setq w (next-window w nil t)))
-    (while
-        (progn
-          (when (and (eq buf (window-buffer w))
-                     ;; Only snap if point is on pmark
-                     (= (window-point w) pmark))
-            (if (eq sel-win w)
-                (progn
+  ;; We need to check for `coterm-scroll-snap-mode' because a function in
+  ;; `coterm-t-after-insert-hook' might have changed it
+  (when coterm-scroll-snap-mode
+    (let* ((buf (current-buffer))
+           (pmark (process-mark (get-buffer-process buf)))
+           (sel-win (selected-window))
+           (w sel-win))
+      ;; Avoid infinite loop in strange case where minibuffer window
+      ;; is selected but not active.
+      (while (window-minibuffer-p w)
+        (setq w (next-window w nil t)))
+      (while
+          (progn
+            (when (and (eq buf (window-buffer w))
+                       ;; Only snap if point is on pmark
+                       (= (window-point w) pmark))
+              (if (eq sel-win w)
+                  (progn
+                    (coterm--t-goto 0 0)
+                    (recenter 0)
+                    (goto-char pmark))
+                (with-selected-window w
                   (coterm--t-goto 0 0)
                   (recenter 0)
-                  (goto-char pmark))
-              (with-selected-window w
-                (coterm--t-goto 0 0)
-                (recenter 0)
-                (goto-char pmark))))
-          (setq w (next-window w nil t))
-          (not (eq w sel-win))))))
+                  (goto-char pmark))))
+            (setq w (next-window w nil t))
+            (not (eq w sel-win)))))))
+
+(defvar coterm-auto-char-mode)
+
+(defun coterm-char-mode-cycle ()
+  "Cycle between char mode on, off and auto.
+
+If `coterm-auto-char-mode' is enabled, disable it and enable
+both `coterm-char-mode' and `coterm-scroll-snap-mode'.
+
+If `coterm-char-mode' is enabled, disable it along with
+`coterm-scroll-snap-mode'.
+
+If it is disabled, enable `coterm-auto-char-mode'."
+  (interactive)
+  (cond
+   (coterm-auto-char-mode
+    ;; Interactively to show the message.
+    (funcall-interactively #'coterm-auto-char-mode -1)
+    (coterm-char-mode 1)
+    (coterm-scroll-snap-mode 1))
+   (coterm-char-mode
+    (coterm-char-mode -1)
+    (coterm-scroll-snap-mode -1))
+   (t (funcall-interactively #'coterm-auto-char-mode 1))))
+
+;;;; Automatic entry to char mode
+
+(define-minor-mode coterm-auto-char-mode
+  "Whether we should enter or leave char mode automatically.
+If enabled, `coterm-auto-char-functions' are consulted to set
+`coterm-char-mode' and `coterm-scroll-snap-mode' automatically."
+  :global nil
+  (if coterm-auto-char-mode
+      (progn
+        (add-hook 'coterm-t-after-insert-hook #'coterm--auto-char nil t)
+        (add-hook 'post-command-hook #'coterm--auto-char nil t)
+        (coterm--auto-char))
+    (remove-hook 'coterm-t-after-insert-hook #'coterm--auto-char t)
+    (remove-hook 'post-command-hook #'coterm--auto-char t)))
+
+(defvar coterm-auto-char-functions
+  (list #'coterm--auto-char-less-prompt
+        #'coterm--auto-char-mpv-prompt
+        #'coterm--auto-char-not-eob
+        #'coterm--auto-char-leave-both)
+  "Abnormal hook to enter or leave `coterm-char-mode'.
+This hook is run after every command and process output, if
+`coterm-auto-char-mode' enabled.  It is only called if point is
+on process's mark.
+
+Each function is called with zero argumets and with `point-max'
+on the end of process output until one returns non-nil.")
+
+(defun coterm--auto-char ()
+  "Automatically enter or leave `coterm-char-mode'.
+If point is not on process mark, leave `coterm-char-mode' and
+`coterm-scroll-snap-mode'.  Otherwise, call functions from
+`coterm-auto-char-functions' until one returns non-nil."
+  (let* ((proc (get-buffer-process (current-buffer)))
+         (pmark (and proc (process-mark proc)))
+         (opoint))
+    (if (and pmark (= (setq opoint (point)) pmark))
+        (save-restriction
+          (coterm--narrow-to-process-output pmark)
+          (goto-char opoint)
+          (run-hook-with-args-until-success 'coterm-auto-char-functions))
+      (when coterm-char-mode (coterm-char-mode -1))
+      (when coterm-scroll-snap-mode (coterm-scroll-snap-mode -1)))))
+
+(defun coterm--auto-char-less-prompt ()
+  (when (eobp)
+    (let ((opoint (point)))
+      (forward-line 0)
+      (prog1
+          (and
+           (looking-at
+            (concat
+             ":\\|"
+             "(END)\\|"
+             "byte [0-9]+\\|"
+             "100%\\|"
+             "\\(?:[^\n]* \\)?" "[0-9]?[0-9]%\\|"
+             "[^\n]*(press h for help or q to quit)"))
+           (when (= opoint (match-end 0))
+             (unless coterm-char-mode (coterm-char-mode 1))
+             (unless coterm-scroll-snap-mode (coterm-scroll-snap-mode 1))
+             t))
+        (goto-char opoint)))))
+
+(defun coterm--auto-char-mpv-prompt ()
+  (when (coterm--auto-char-mpv-prompt-1)
+    ;; (unless coterm-char-mode (coterm-char-mode 1))
+    ;; (when coterm-scroll-snap-mode (coterm-scroll-snap-mode -1))
+    (coterm-char-mode 1)
+    (cl-labels
+        ((hook ()
+           (or (coterm--auto-char-mpv-prompt-1)
+               (and (eobp) (bolp))
+               (ignore (rem-hook))))
+         (rem-hook ()
+           (remove-hook 'coterm-auto-char-functions #'hook t)
+           (remove-hook 'coterm-auto-char-mode-hook #'rem-hook t)))
+      (add-hook 'coterm-auto-char-functions #'hook nil t)
+      (add-hook 'coterm-auto-char-mode-hook #'rem-hook nil t)
+      (add-hook 'coterm-char-mode-hook #'rem-hook nil t)
+      (add-hook 'coterm-scroll-snap-mode-hook #'rem-hook nil t))
+    t))
+
+(defun coterm--auto-char-mpv-prompt-1 ()
+  "Return t if mpv is likely running."
+  (when (bolp)
+    (let ((opoint (point)))
+      (forward-line -1)
+      (prog1 (looking-at
+              (concat "\\(?:[^\n]*\n\\)?"
+                      "AV?: "
+                      "[0-9][0-9]:[0-9][0-9]:[0-9][0-9] / "
+                      "[0-9][0-9]:[0-9][0-9]:[0-9][0-9] "
+                      "([0-9]?[0-9]%)"
+                      "\\(?:"
+                      "\n\\[-*\\+-*\\]"
+                      "\\)?"
+                      "\\'"))
+        (goto-char opoint)))))
+
+(defun coterm--auto-char-not-eob ()
+  (when (looking-at "\\(?:.*\n\\)\\{9,\\}")
+    ;; (unless coterm-char-mode (coterm-char-mode 1))
+    ;; (unless coterm-scroll-snap-mode (coterm-scroll-snap-mode 1))
+    (coterm-char-mode 1)
+    (coterm-scroll-snap-mode 1)
+    (cl-labels
+        ((hook ()
+           (or (looking-at ".*\n.")
+               (ignore (rem-hook))))
+         (rem-hook ()
+           (remove-hook 'coterm-auto-char-functions #'hook t)
+           (remove-hook 'coterm-auto-char-mode-hook #'rem-hook t)))
+      (add-hook 'coterm-auto-char-functions #'hook nil t)
+      (add-hook 'coterm-auto-char-mode-hook #'rem-hook nil t)
+      (add-hook 'coterm-char-mode-hook #'rem-hook nil t)
+      (add-hook 'coterm-scroll-snap-mode-hook #'rem-hook nil t))
+    t))
+
+(defun coterm--auto-char-leave-both ()
+  (when coterm-char-mode (coterm-char-mode -1))
+  (when coterm-scroll-snap-mode (coterm-scroll-snap-mode -1))
+  t)
+
+(defun coterm--narrow-to-process-output (pmark)
+  "Narrow to process output and move point to the end of it.
+If there is no user input at end of buffer, simply widen.  PMARK
+is the process mark."
+  (widen)
+  (unless (eq (get-char-property (max 1 (1- (point-max))) 'field)
+              'output)
+    (goto-char (point-max))
+    (text-property-search-backward 'field 'output)
+    (when (<= pmark (point))
+      (narrow-to-region (point-min) (point)))))
 
 ;;; Terminal emulation
 
@@ -230,6 +395,7 @@ In sync with variables `coterm--t-home-marker',
 
     (setq-local comint-inhibit-carriage-motion t)
     (add-hook 'comint-output-filter-functions #'coterm--comint-strip-CR nil t)
+    (coterm-auto-char-mode)
 
     (add-function :filter-return
                   (local 'window-adjust-process-window-size-function)
@@ -499,16 +665,7 @@ buffer and the scrolling region must cover the whole 
screen."
           (setq old-pmark (copy-marker pmark window-point-insertion-type))
           (coterm--t-adjust-from-pmark pmark)
           (save-restriction
-            (widen)
-            (goto-char (point-max))
-            ;; Use narrowing to prevent modification of user input at end of
-            ;; buffer
-            (unless (eq (get-char-property (max 1 (1- (point-max))) 'field)
-                        'output)
-              (goto-char (point-max))
-              (text-property-search-backward 'field 'output)
-              (when (<= pmark (point))
-                (narrow-to-region (point-min) (point))))
+            (coterm--narrow-to-process-output pmark)
 
             (while (setq match (string-match coterm--t-control-seq-regexp
                                              string ctl-end))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]