From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Augusto Stoffel Newsgroups: gmane.emacs.devel Subject: Re: OSC control sequences in comint Date: Mon, 23 Aug 2021 18:46:58 +0200 Message-ID: <87o89oqfb1.fsf@gmail.com> References: <87bl5pgzdo.fsf@gmail.com> <87tujhumuk.fsf@gnus.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="28467"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cc: emacs-devel@gnu.org To: Lars Ingebrigtsen Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Aug 23 18:57:24 2021 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mIDGF-00079h-Kr for ged-emacs-devel@m.gmane-mx.org; Mon, 23 Aug 2021 18:57:23 +0200 Original-Received: from localhost ([::1]:42642 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mIDGE-0005US-K0 for ged-emacs-devel@m.gmane-mx.org; Mon, 23 Aug 2021 12:57:22 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:50074) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mID6I-0000eD-0R for emacs-devel@gnu.org; Mon, 23 Aug 2021 12:47:06 -0400 Original-Received: from mail-wr1-x42d.google.com ([2a00:1450:4864:20::42d]:37418) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mID6E-0001us-Fv for emacs-devel@gnu.org; Mon, 23 Aug 2021 12:47:05 -0400 Original-Received: by mail-wr1-x42d.google.com with SMTP id v10so15945261wrd.4 for ; Mon, 23 Aug 2021 09:47:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=xV8RQoEodr489De5lVPLqeXwxaDwJAD9a/aNMa0C/ck=; b=HhfTM0BAfLaGbxge8hOhiUv0Dj2BdWNxdZ5LiBh6f8YKRg2aLkm6xvkqxQ7cQOjSVH SWv5FT9F4dmUyuSsZ6pXWhqbaXPt9H6+ifst9g812cfZPt5/JQvKW5/gHb+iWLNbp34V kypjMYEDinFLrtJmnes5yPWhUh4Twzx+ie2vGoOy0AE1Or7vzUkMNhqjH3jkaCDw6XQu llxtLtp0DVwFp+8h/n22uSgudMRIGmdliRqstILkfLI37uM2t0nEV9DFDS6K7ApzKrGN nmA8EvBz4LRxlNEPznOj0JvxTJg3bqj+E3wwxvI1sGdi0NlRYvSyjUBrlmthcdbn1Gd0 DFIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=xV8RQoEodr489De5lVPLqeXwxaDwJAD9a/aNMa0C/ck=; b=qbPhC52Q+ykv53TGMv7l114XsEHPWsD/Udq3cYr9reEn10o8D7RZWn1hsLlLEWiPPk 3ISbdtU9b4CzDhlB8SNu3Rk5dwEW5YivkYGDq075WCRcBMwAvLV0SIfBoz0LgbaeM6En R71sltIJOaUEf83JpyJ2PXW/Lidp6mwPQwO13TWoMeh6ueDsJ8/LTeR399slSyIkwCiR jjDmt3NamW4z9gOv8Q8QIu/ESbBa93Z6Gt8gpUMZ7qnnu9AnQ48BoMIp6rwqSFWnBa7h lQwBA3j8sFAN6LMwUTgbWkuqz1TllKJ6uOjYKM4tWHdZ82ZhQyVEwBrR61L+Qi7TGfXr xlog== X-Gm-Message-State: AOAM532rK3sGkPmV0VyfHxE8HTom3xH0dsrF1iFuUaDJY5cOjVcpzRSH HFvd/7w2L1ndBzdyvNtetiimU96HR34= X-Google-Smtp-Source: ABdhPJy9PfmK8ZF/8QnKsBHUq1fwfcvtU6QyIDdB74tEnYZ1QP7RdqR4xv2ITeoh316eAZbk4M9kHw== X-Received: by 2002:a5d:5107:: with SMTP id s7mr14187155wrt.283.1629737220798; Mon, 23 Aug 2021 09:47:00 -0700 (PDT) Original-Received: from ars3 ([2a02:8109:8ac0:56d0::ae3f]) by smtp.gmail.com with ESMTPSA id f17sm13565907wmq.17.2021.08.23.09.46.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 09:47:00 -0700 (PDT) In-Reply-To: <87tujhumuk.fsf@gnus.org> (Lars Ingebrigtsen's message of "Mon, 23 Aug 2021 00:38:11 +0200") Received-SPF: pass client-ip=2a00:1450:4864:20::42d; envelope-from=arstoffel@gmail.com; helo=mail-wr1-x42d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:272878 Archived-At: --=-=-= Content-Type: text/plain On Mon, 23 Aug 2021 at 00:38, Lars Ingebrigtsen wrote: > I think it sounds like a good idea. Could you format it up as a patch? All right, I have attached a patch. Since a comint buffer is editable, I chose an unobtrusive but less convenient keymap to the hyperlink buttons, based on bug-reference.el: 'C-c RET' opens the links. Note that there's a call to (autoload 'browse-url-button-open "browse-url.el") in the patch, which is probably not the best procedure. Should that function be autoloaded in browse-url.el? Finally, in case anyone wants to test or play around, a handler for the OSC 1337 escape (for inline images) could look like this: (defun comint-osc-1337-handler (_ text) (when (string-match ":" text) (insert-image (create-image (base64-decode-string (substring text (match-end 0))) nil t)))) Then one can say (add-hook 'comint-output-filter-functions 'comint-osc-process-output nil t) (push '("1337" . comint-osc-1337-handler) comint-osc-handlers) and use https://iterm2.com/utilities/imgcat to show (small...) images in the shell. However, I don't think it makes sense to provide this handler in Emacs itself, since it is rather nonstandard. Best, Augusto --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Add-support-for-OSC-escape-sequences-in-comint.patch >From 290107a10b638e41a73509d346336566791e6525 Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Mon, 23 Aug 2021 18:03:39 +0200 Subject: [PATCH] Add support for OSC escape sequences in comint * lisp/comint.el (comint-osc-handlers, comint-osc--marker, comint-osc-process-output): New general infrastructure to handle OSC escape sequences. (comint-osc-hyperlink-map, comint-osc-hyperlink--state, comint-osc-hyperlink-handler): New functions and variables to handle OSC 8 (hyperlinks). --- etc/NEWS | 10 ++++++ lisp/comint.el | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index b008c46291..ac8bec244d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3019,6 +3019,16 @@ default are unaffected.) states to be maintained if 'so-long-mode' replaces the original major mode. By default, these new options support 'view-mode'. +** Comint + +*** Support for OSC escape sequences +Adding the new 'comint-osc-process-output' to +'comint-output-filter-functions' enables the interpretation of OSC +escape sequences in comint buffers. By default, only OSC 8, for +hyperlinks, is acted upon. Adding more entries to +`comint-osc-handlers' allows a customized treatment of further escape +sequences. + * New Modes and Packages in Emacs 28.1 diff --git a/lisp/comint.el b/lisp/comint.el index 7af8e8fd2a..b924029a3b 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -3887,6 +3887,93 @@ comint-redirect-results-list-from-process ;; don't advance, so ensure forward progress. (forward-line 1))) (nreverse results)))) + + +;;; OSC escape sequences (operating system commands) +;;============================================================================ +;; Adding `comint-osc-process-output' to `comint-output-filter-functions' +;; enables the interpretation of OSC escape sequences. By default, only +;; OSC 8, for hyperlinks, is acted upon. Adding more entries to +;; `comint-osc-handlers' allows a customized treatment of further sequences. + +(defvar-local comint-osc-handlers '(("8" . comint-osc-hyperlink-handler)) + "Alist of handlers for OSC escape sequences. +See `comint-osc-process-output' for details.") + +(defvar-local comint-osc--marker nil) + +(defun comint-osc-process-output (_) + "Interpret OSC escape sequences in comint output. + +This function is intended to be added to +`comint-output-filter-functions' in order to interpret escape +sequences of the forms + + ESC ] command ; text BEL + ESC ] command ; text ESC \\ + +Specifically, every occurrence of such escape sequences is +removed from the buffer. Then, if `command' is a key of the +`comint-osc-handlers' alist, the corresponding value, which +should be a function, is called with `command' and `text' as +arguments, with point where the escape sequence was located." + (let ((bound (process-mark (get-buffer-process (current-buffer))))) + (save-excursion + (goto-char (or comint-osc--marker + (and (markerp comint-last-output-start) + (eq (marker-buffer comint-last-output-start) + (current-buffer)) + comint-last-output-start) + (point-min))) + (when (eq (char-before) ?\e) (backward-char)) + (while (re-search-forward "\e]" bound t) + (let ((pos0 (match-beginning 0)) + (code (and (re-search-forward "\\=\\([0-9A-Za-z]*\\);" bound t) + (match-string 1))) + (pos1 (point))) + (if (re-search-forward "\a\\|\e\\\\" bound t) + (let ((text (buffer-substring-no-properties pos1 (match-beginning 0)))) + (setq comint-osc--marker nil) + (delete-region pos0 (point)) + (when-let ((fun (cdr (assoc-string code comint-osc-handlers)))) + (funcall fun code text))) + (put-text-property pos0 bound 'invisible t) + (setq comint-osc--marker (copy-marker pos0)))))))) + +;; Hyperlink handling (OSC 8) + +(autoload 'browse-url-button-open "browse-url.el") + +(defvar comint-osc-hyperlink-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\r" 'browse-url-button-open) + (define-key map [mouse-2] 'browse-url-button-open) + (define-key map [follow-link] 'mouse-face) + map) + "Keymap used by OSC 8 hyperlink buttons.") + +(define-button-type 'comint-osc-hyperlink + 'keymap comint-osc-hyperlink-map + 'help-echo (lambda (_ buffer pos) + (when-let ((url (get-text-property pos 'browse-url-data buffer))) + (format "mouse-2, C-c RET: Open %s" url)))) + +(defvar-local comint-osc-hyperlink--state nil) + +(defun comint-osc-hyperlink-handler (_ text) + "Create a hyperlink from an OSC 8 escape sequence. +This function is intended to be included as an entry of +`comint-osc-handlers'." + (when comint-osc-hyperlink--state + (let ((start (car comint-osc-hyperlink--state)) + (url (cdr comint-osc-hyperlink--state))) + (make-text-button start (point) + 'type 'comint-osc-hyperlink + 'browse-url-data url))) + (setq comint-osc-hyperlink--state + (and (string-match ";\\(.+\\)" text) + (cons (point-marker) (match-string-no-properties 1 text))))) + ;;; Converting process modes to use comint mode ;;============================================================================ -- 2.31.1 --=-=-=--