From 755612ee3d7e3e25be98bea457de26288bdd9a51 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 25 Apr 2022 23:52:20 +0200 Subject: [PATCH 1/3] colorize-compilation-buffer: Use inhibit-read-only This is the idiomatic way to modify a read-only buffer. --- zig-mode.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zig-mode.el b/zig-mode.el index 4064605..5e2f46d 100644 --- a/zig-mode.el +++ b/zig-mode.el @@ -551,9 +551,8 @@ This is written mainly to be used as `end-of-defun-function' for Zig." (zig-format-buffer))) (defun colorize-compilation-buffer () - (read-only-mode 0) - (ansi-color-apply-on-region compilation-filter-start (point)) - (read-only-mode 1)) + (let ((inhibit-read-only t)) + (ansi-color-apply-on-region compilation-filter-start (point)))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode)) From 68382ab7dd503ed9525bd06f543c747e75875a1d Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 25 Apr 2022 23:52:21 +0200 Subject: [PATCH 2/3] Use builtin `ansi-color-compilation-filter` on Emacs >= 28 --- zig-mode.el | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/zig-mode.el b/zig-mode.el index 5e2f46d..ef43ad7 100644 --- a/zig-mode.el +++ b/zig-mode.el @@ -550,13 +550,15 @@ This is written mainly to be used as `end-of-defun-function' for Zig." (when zig-format-on-save (zig-format-buffer))) -(defun colorize-compilation-buffer () - (let ((inhibit-read-only t)) - (ansi-color-apply-on-region compilation-filter-start (point)))) - ;;;###autoload (add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode)) -(add-hook 'compilation-filter-hook 'colorize-compilation-buffer) +(if (>= emacs-major-version 28) + (add-hook 'compilation-filter-hook 'ansi-color-compilation-filter) + (progn + (defun colorize-compilation-buffer () + (let ((inhibit-read-only t)) + (ansi-color-apply-on-region compilation-filter-start (point)))) + (add-hook 'compilation-filter-hook 'colorize-compilation-buffer))) (provide 'zig-mode) ;;; zig-mode.el ends here From c0652b4253b0c00d688f12bf7cdbfc91c681fa88 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 26 Apr 2022 01:12:13 +0200 Subject: [PATCH 3/3] [DRAFT] enable std.Progress output --- README.md | 7 +++++ zig-mode.el | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b7a1237..f40cd3b 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,13 @@ Alternatively, you can `git clone` the `zig-mode` repository somewhere (add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode))) ``` +To enable parsing of Zig `std.Progress` output (which is shown during `zig build`) in compilation or shell +buffers, add the following to your emacs config: +``` +(zig-enable-progress-parsing) +``` +This overrides function `ansi-color-apply-on-region` with a patched version. + ## Testing [![Build status](https://ci.appveyor.com/api/projects/status/u78j130vv4l6v21t?svg=true)](https://ci.appveyor.com/project/mdsteele/zig-mode) diff --git a/zig-mode.el b/zig-mode.el index ef43ad7..8d00c62 100644 --- a/zig-mode.el +++ b/zig-mode.el @@ -76,7 +76,12 @@ If given a SOURCE, execute the CMD on it." (let ((cmd-args (if source (mapconcat 'shell-quote-argument (cons source args) " ") - args))) + args)) + (compilation-environment + (append (when (advice-member-p 'zig--ansi-color-apply-on-region 'ansi-color-apply-on-region) + ;; Enable std.Progress output for zig commands + '("TERM=ansi")) + compilation-environment))) (compile (concat zig-zig-bin " " cmd " " cmd-args)))) ;;;###autoload @@ -550,6 +555,80 @@ This is written mainly to be used as `end-of-defun-function' for Zig." (when zig-format-on-save (zig-format-buffer))) +(when (= emacs-major-version 28) + (defun zig-enable-progress-parsing () + "Enable std.Progress output parsing for compilation and shell buffers." + (advice-add 'ansi-color-apply-on-region :override 'zig--ansi-color-apply-on-region)) + + ;; A patched version of `ansi-color-apply-on-region` that supports + ;; cursor back (CUB) ANSI sequences that are required to parse Zig's std.Progress output. + ;; Based on the Emacs 28.1 version of this function. + (defun zig--ansi-color-apply-on-region (begin end &optional preserve-sequences) + (let ((codes (car ansi-color-context-region)) + (start-marker (or (cadr ansi-color-context-region) + (copy-marker begin))) + (end-marker (copy-marker end))) + (save-excursion + (goto-char start-marker) + ;; Find the next escape sequence. + (while (re-search-forward ansi-color-control-seq-regexp end-marker t) + ;; Extract escape sequence. + (let ((esc-seq (buffer-substring + (match-beginning 0) (point)))) + (if preserve-sequences + ;; Make the escape sequence transparent. + (overlay-put (make-overlay (match-beginning 0) (point)) + 'invisible t) + ;; Otherwise, strip. + (delete-region (match-beginning 0) (point))) + + ;; Colorize the old block from start to end using old face. + (funcall ansi-color-apply-face-function + (prog1 (marker-position start-marker) + ;; Store new start position. + (set-marker start-marker (point))) + (match-beginning 0) (ansi-color--find-face codes)) + (let ((last-char (aref esc-seq (1- (length esc-seq))))) + (pcase last-char + ;; A color sequence + (`?m + ;; update the list of ansi codes. + (setq codes (ansi-color-apply-sequence esc-seq codes))) + ;; A cursor back (CUB) sequence + (`?D + (let ((n (string-to-number (substring esc-seq 2 -1))) + (line-start (let ((inhibit-field-text-motion t)) + (line-beginning-position)))) + (delete-region (max line-start (- (point) n)) (point)))))))) + ;; search for the possible start of a new escape sequence + (if (re-search-forward "\033" end-marker t) + (progn + ;; if the rest of the region should have a face, put it there + (funcall ansi-color-apply-face-function + start-marker (point) (ansi-color--find-face codes)) + ;; save codes and point + (setq ansi-color-context-region + (list codes (copy-marker (match-beginning 0))))) + ;; if the rest of the region should have a face, put it there + (funcall ansi-color-apply-face-function + start-marker end-marker (ansi-color--find-face codes)) + ;; Save a restart position when there are codes active. It's + ;; convenient for man.el's process filter to pass `begin' + ;; positions that overlap regions previously colored; these + ;; `codes' should not be applied to that overlap, so we need + ;; to know where they should really start. + (setq ansi-color-context-region + (if codes (list codes (copy-marker (point))))))) + ;; Clean up our temporary markers. + (unless (eq start-marker (cadr ansi-color-context-region)) + (set-marker start-marker nil)) + (unless (eq end-marker (cadr ansi-color-context-region)) + (set-marker end-marker nil))))) + +;;;###autoload +(when (= emacs-major-version 28) + (autoload 'zig-mode "zig-enable-progress-parsing")) + ;;;###autoload (add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode)) (if (>= emacs-major-version 28)