From 44a459cefe76d9dbef1822142fc85e4e06244aa6 Mon Sep 17 00:00:00 2001 From: Pierre Neidhardt Date: Mon, 23 Oct 2017 20:06:08 +0100 Subject: [PATCH] Eshell: Backport ANSI color patch --- .emacs.d/lisp/init-eshell.el | 18 +++++-- .emacs.d/lisp/patch-eshell.el | 95 +++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 .emacs.d/lisp/patch-eshell.el diff --git a/.emacs.d/lisp/init-eshell.el b/.emacs.d/lisp/init-eshell.el index d4fe8ffc..956e81c6 100644 --- a/.emacs.d/lisp/init-eshell.el +++ b/.emacs.d/lisp/init-eshell.el @@ -6,6 +6,12 @@ ;;; modules, runs their hooks and concludes with `eshell-first-time-mode-hook' ;;; (for the first session only) and `eshell-mode-hook'. +;;; REVIEW: ANSI coloring goes wrong sometimes. Quite often with emerge/eix. +;;; Fixed in #27407. +(require 'patch-eshell) + +;;; TODO: Sometimes transmission-daemon does not start from Eshell. + ;;; TODO: Redirecting big output to file (e.g. /dev/null) is extremely slow. ;; > cat /usr/share/dict/british-english | wc -l ;;; The above line yields rancom results. Plus it's much slower than @@ -24,9 +30,6 @@ ;;; See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=27411 ;;; and #28323. -;;; REVIEW: Eshell/TRAMP's sudo does not work with aliases. -;;; See #28320. - ;;; REVIEW: Eshell/Shell completion fails when PATH has a non-readable element. ;;; See https://github.com/emacs-helm/helm/issues/1785 ;;; and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27300. @@ -123,11 +126,16 @@ '(("l" "ls -1 $*") ("la" "ls -lAh $*") ("ll" "ls -lh $*") + ;; TODO: Aliasing eshell/{cp,mv,ln} does not work. + ;; TODO: "sudo" does not work on aliases. + ;; See bug #27168. + ;; REVIEW: Eshell/TRAMP's sudo does not work with aliases. + ;; See #28320. ;; ("ls" "ls -F $*") ; not supported ;; ("emacs" "find-file $1") - ;; ("cp" "eshell/cp -iv $*") ; TODO: Aliasing eshell/{cp,mv,ln} does not work. + ;; ("cp" "eshell/cp -iv $*") ;; ("mv" "eshell/mv -iv $*") - ("cpv" "cp -iv $*") ; TODO: "sudo" does not work on aliases. + ("cpv" "cp -iv $*") ("mvv" "mv -iv $*") ("rmv" "rm -v $*") ("md" "eshell/mkdir -p $*") diff --git a/.emacs.d/lisp/patch-eshell.el b/.emacs.d/lisp/patch-eshell.el new file mode 100644 index 00000000..dca30dab --- /dev/null +++ b/.emacs.d/lisp/patch-eshell.el @@ -0,0 +1,95 @@ +;;; Eshell patches. + +;;; Fix 27407, expected in Emacs 26.1. +;;; http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=4ebdcc46ab345849332332d580bd1e3c2c9adb1e +;;; http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=37cdfec7c73205668498da9b27387f5f3ccfebee +;;; Test: +;;; +;; (insert "echo \"\e[33mhello\e[0m\"") +;; (insert "echo \"\e[33mhello\"") + +(with-eval-after-load 'ansi-color + (defun ansi-color-make-extent (from to &optional object) + "Make an extent for the range [FROM, TO) in OBJECT. + +OBJECT defaults to the current buffer. XEmacs uses `make-extent', Emacs +uses `make-overlay'. XEmacs can use a buffer or a string for OBJECT, +Emacs requires OBJECT to be a buffer." + (if (fboundp 'make-extent) + (make-extent from to object) + ;; In Emacs, the overlay might end at the process-mark in comint + ;; buffers. In that case, new text will be inserted before the + ;; process-mark, ie. inside the overlay (using insert-before-marks). + ;; In order to avoid this, we use the `insert-behind-hooks' overlay + ;; property to make sure it works. + (let ((overlay (make-overlay from to object))) + (overlay-put overlay 'modification-hooks '(ansi-color-freeze-overlay)) + (overlay-put overlay 'insert-behind-hooks '(ansi-color-freeze-overlay)) + overlay)))) + +(with-eval-after-load "esh-mode" + (defun eshell-output-filter (process string) + "Send the output from PROCESS (STRING) to the interactive display. +This is done after all necessary filtering has been done." + (let ((oprocbuf (if process (process-buffer process) + (current-buffer))) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t)) + (let ((functions eshell-preoutput-filter-functions)) + (while (and functions string) + (setq string (funcall (car functions) string)) + (setq functions (cdr functions)))) + (if (and string oprocbuf (buffer-name oprocbuf)) + (let (opoint obeg oend) + (with-current-buffer oprocbuf + (setq opoint (point)) + (setq obeg (point-min)) + (setq oend (point-max)) + (let ((buffer-read-only nil) + (nchars (length string)) + (ostart nil)) + (widen) + (goto-char eshell-last-output-end) + (setq ostart (point)) + (if (<= (point) opoint) + (setq opoint (+ opoint nchars))) + (if (< (point) obeg) + (setq obeg (+ obeg nchars))) + (if (<= (point) oend) + (setq oend (+ oend nchars))) + ;; Let the ansi-color overlay hooks run. + (let ((inhibit-modification-hooks nil)) + (insert-before-markers string)) + (if (= (window-start) (point)) + (set-window-start (selected-window) + (- (point) nchars))) + (if (= (point) eshell-last-input-end) + (set-marker eshell-last-input-end + (- eshell-last-input-end nchars))) + (set-marker eshell-last-output-start ostart) + (set-marker eshell-last-output-end (point)) + (force-mode-line-update)) + (narrow-to-region obeg oend) + (goto-char opoint) + (eshell-run-output-filters))))))) + +(with-eval-after-load 'em-prompt + (defun eshell-emit-prompt () + "Emit a prompt if eshell is being used interactively." + (when (boundp 'ansi-color-context-region) + (setq ansi-color-context-region nil)) + (run-hooks 'eshell-before-prompt-hook) + (if (not eshell-prompt-function) + (set-marker eshell-last-output-end (point)) + (let ((prompt (funcall eshell-prompt-function))) + (and eshell-highlight-prompt + (add-text-properties 0 (length prompt) + '(read-only t + font-lock-face eshell-prompt + front-sticky (font-lock-face read-only) + rear-nonsticky (font-lock-face read-only)) + prompt)) + (eshell-interactive-print prompt))) + (run-hooks 'eshell-after-prompt-hook))) + +(provide 'patch-eshell)