From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Arthur Miller Newsgroups: gmane.emacs.devel Subject: Path & Demo: Source View in Help Buffers Date: Wed, 22 Sep 2021 10:59:37 +0200 Message-ID: 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="10216"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Sep 22 11:02:09 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 1mSy8l-0002Mz-9r for ged-emacs-devel@m.gmane-mx.org; Wed, 22 Sep 2021 11:02:08 +0200 Original-Received: from localhost ([::1]:49292 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mSy8j-0005OG-BH for ged-emacs-devel@m.gmane-mx.org; Wed, 22 Sep 2021 05:02:05 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:58320) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mSy6T-0004B8-60 for emacs-devel@gnu.org; Wed, 22 Sep 2021 04:59:45 -0400 Original-Received: from mail-am6eur05olkn2016.outbound.protection.outlook.com ([40.92.91.16]:2118 helo=EUR05-AM6-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mSy6P-0008QJ-82 for emacs-devel@gnu.org; Wed, 22 Sep 2021 04:59:44 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=QJHsv72VbqS4+iyzEBX1nC8BDcuJZXd4pOMvXXDbOf25q+M12yhMXhdQa/qYYsad5OPcz54DpHftH4tgY7S6o82rfl161zK7s7qL0t8seS8Jjsxt1ce+zIfquQvIWcIuQ4mX4ayizeL8LK6FLmITAdI5s4w2KgHuYw/gPNcYFZeitqEeDND0jKybD/YVcalFlv5eZ+deagF1DBHdSLI+7jEc8xOkiCWeVbPRC27OGWWSdI9Mi9DagNfQyxVXIolYWwwkN4Sxj5GiMBe9Gz+JCiOFSkyTsMA4BhjEaU+4zs59/llu6Lsr4E0arLHqCY/jQH602LBSGF6KoRCQYrvvGA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=vfMpXVuyK6X/t2/Pwsi33asZRv5a9RCFgJsFYzY+AEs=; b=KXHmNfpE4ouQGcaP51gbQNoPeF/4lvWEb7vD/oC3iXQV9QedrRntgmGNz+g32zcQQjW+Rp4p1rKPNp0wlzJHfiOf+7EmbeNCveUBm7Gqgvw0PPB8jb3ozfqHaXPoHiy6l2b9FkCNH7Fl72mm2h6jDrc5anIXAhwTWvKgI04UA2Rtq09gqpw9FbOQiwPyFf6s/9sf2BdlfO/Pc+ymjvCK/nA6Ejqn7mZaWjiWMynoD3sXd6XLpPZ1WeiDboJEi14OiATLYvocw+9nmqta3PCo2oc9ssxAcOOjnI9l9AJ7UcasxCw23BRIK54IEOxdWR9I4SP0XG/cf+guUL/vFJqXdQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=live.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=vfMpXVuyK6X/t2/Pwsi33asZRv5a9RCFgJsFYzY+AEs=; b=XWqffpI78BgWnj4gPa5MpFfpm2UF/MmwNheUhEX5DoX59shQ+ksruVM3ijr/JQeXoJnnAQoiOkx05tR4mHgZhTp/ua06QNIYVmT4+e7GJ3F3sGsTB5xQTaudAq9qNLKzw3vNyAvqHIlWtDH0ETklQ6rgAdI/j6GP5AyNNh9Obl3trduiZhr8KWIjdDF/H2jX03ZtBQ3w5n+bXyiD4jwxE6Guij2L77ZEPCjiyEgn2EegBCwsU4GSZww/Bl3ENhIOOvrQSemBpPp7FBksTBramDEyFFa7skR1BiEjBIgYAKfcHhU+VdRp4tKYKtzi3BI5JdfQ0Ey0KFGTBG+PnCsHBg== Original-Received: from DB9PR09MB4986.eurprd09.prod.outlook.com (2603:10a6:10:2a9::19) by DBBPR09MB4763.eurprd09.prod.outlook.com (2603:10a6:10:204::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4544.13; Wed, 22 Sep 2021 08:59:38 +0000 Original-Received: from DB9PR09MB4986.eurprd09.prod.outlook.com ([fe80::80be:d528:d357:5d3a]) by DB9PR09MB4986.eurprd09.prod.outlook.com ([fe80::80be:d528:d357:5d3a%9]) with mapi id 15.20.4523.018; Wed, 22 Sep 2021 08:59:38 +0000 X-TMN: [6bnW56In3hnLJTcTaydez2O5nGj1mLwp] X-ClientProxiedBy: AM7PR02CA0029.eurprd02.prod.outlook.com (2603:10a6:20b:100::39) To DB9PR09MB4986.eurprd09.prod.outlook.com (2603:10a6:10:2a9::19) X-Microsoft-Original-Message-ID: <87pmt1vvd2.fsf@live.com> X-MS-Exchange-MessageSentRepresentingType: 1 Original-Received: from pascal.homepc (81.232.177.30) by AM7PR02CA0029.eurprd02.prod.outlook.com (2603:10a6:20b:100::39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4544.13 via Frontend Transport; Wed, 22 Sep 2021 08:59:37 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: eb27b77d-609a-4a35-b7a6-08d97da74e6c X-MS-TrafficTypeDiagnostic: DBBPR09MB4763: X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: VMSyM6k+LlzXHplj9rTzS2FC+3xFicWWvs+fWYZuqllp0JJirbCQMr03sWL0h2Sx5DvqibWG6Q1+CQdzVf+FHvgavtJ7zsmsViJTgH4H3pfn0BcOmbonyvST4ot29qM1tNn9WFTzRv3N4ItMXKVCNAQvJwdPfRHphAZYxI64PJeleS+rFzTJXVtwpm3RNvrW6bItWyBXWMq0BbGfQ+FcsBBnAKMhKt2kFDYqCzVwRIfKWvFyLrZlM0SPE9CekQkfT+/Tq/bcCLDzO7LCJkvIDcxJKXyv6mwr5MHtg8vLM3Tkg9bM03BP8EVWI/Knu2EE3NHTy7VKIV+Veonbam1vPH0XwlftnULj147Nj6EiesWRO74ZLQ7f7wHMSqblE90o3KRn8S+W4Hsw9dYWtxxzT/yeBy42jkGFSQ34eLod5ycmwe8CV1bT4ABEmbK4FQtfGx2saaB3hIiXWTnkQQWmJ2T4+w9hFW0ghUC+pwD174E= X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: rZ+BAJukNNODqzyoRp8pDN/ZwRNYLSfMFhfC4gLE6HNfYjHZwlwBGQqPHmRlHYcowWkJdkGWMNx5Yz9vBPQTvo+bCXyXw7QjgpBvrmxutCxSFiKy7lTU161ZDTkw6pF9v1gjc663ewS/lHNnRM0YzA== X-OriginatorOrg: sct-15-20-3174-20-msonline-outlook-72e6e.templateTenant X-MS-Exchange-CrossTenant-Network-Message-Id: eb27b77d-609a-4a35-b7a6-08d97da74e6c X-MS-Exchange-CrossTenant-AuthSource: DB9PR09MB4986.eurprd09.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Sep 2021 08:59:38.1211 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DBBPR09MB4763 Received-SPF: pass client-ip=40.92.91.16; envelope-from=arthur.miller@live.com; helo=EUR05-AM6-obe.outbound.protection.outlook.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, MSGID_FROM_MTA_HEADER=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_PASS=-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:275307 Archived-At: --=-=-= Content-Type: text/plain I had some fun and implemented somewhat different version of how code is fetched, and buttonized toggle function. Since I really didn't got much more input than what Martin gave me yesterday, I have had some fun and recorded a small demo of how it looks like: https://youtu.be/yiS1eXdgcYI Sorry, but I don't have better place to put it on, use yt-download if you prefer not to open it in a web browser. It is just a two minute of me showing how it looks when used in practice. I reason that looking at the code is one thing, seeing it is the other. I have also changed it a bit, and pasting the source after the navigation buttons. so they don't jump out of the screen when a function is very big. Don't know if it is better strategy, it is just a prototype anyway. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Display-source-code-in-help-mode-buffers.patch >From cd49759ff81466e31e4c96276dcdb2ff6d378d0f Mon Sep 17 00:00:00 2001 From: Arthur Miller Date: Wed, 22 Sep 2021 01:47:41 +0200 Subject: [PATCH] Display source code in 'help-mode' buffers * lisp/help-mode.el (help-mode-inline-source): New option. (help--fetch-c-src): New function. (help--fetch-lisp-src): New function. (help--insert-source): New function. (help--remove-source): New function. (help--toggle-source-view): New function. (help-source-view): New button. (help-make-xrefs): Check for 'help-mode-inline-source' and call 'help--insert-source' to perform insertion when possible. --- lisp/help-mode.el | 165 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 160 insertions(+), 5 deletions(-) diff --git a/lisp/help-mode.el b/lisp/help-mode.el index 551cf7e1a3..bec7d25270 100644 --- a/lisp/help-mode.el +++ b/lisp/help-mode.el @@ -149,6 +149,16 @@ help-mode-hook "Hook run by `help-mode'." :type 'hook :group 'help) + +(defcustom help-mode-inline-source nil + "Display inlined source code in `help-mode' buffers. + +When enabled the source code of a symbol currently shown in the +help-buffer will be displayed inlined in the help buffer, if the +source code for the symbol is available." + :type 'boolean + :group 'help + :version "28.1") ;; Button types used by help @@ -367,6 +377,11 @@ 'help-news (view-buffer-other-window (find-file-noselect file)) (goto-char pos)) 'help-echo (purecopy "mouse-2, RET: show corresponding NEWS announcement")) + +(define-button-type 'help-source-view + :supertype 'help-xref + 'help-function #'help-toggle-source-view + 'help-echo (purecopy "mouse-2, RET: toggle source view in help-buffer")) (defvar bookmark-make-record-function) (defvar help-mode--current-data nil) @@ -503,6 +518,115 @@ describe-symbol-backends and a frame), inserts the description of that symbol in the current buffer and returns that text as well.") +(defun help--fetch-c-src (symbol type file) + "Find C source code for a Lisp SYMBOL in a FILE. + +symbol - the symbol to find. +type - the type as obtained by 'describe-*' functions. +file - the source file to search in." + (let (src beg) + (setq file (expand-file-name file source-directory)) + (when (file-readable-p file) + (with-temp-buffer + (insert-file-contents-literally file) + (delay-mode-hooks (funcall 'c-mode)) + (goto-char (point-min)) + (unless type + (require 'find-func) + ;; Either or both an alias and its target might be advised. + (setq symbol (find-function-advised-original + (indirect-function + (find-function-advised-original symbol))))) + (when (re-search-forward + (if type + (concat "DEFVAR[A-Z_]*[ \t\n]*([ \t\n]*\"" + (regexp-quote (symbol-name symbol)) + "\"") + (concat "DEFUN[ \t\n]*([ \t\n]*\"" + (regexp-quote (subr-name (advice--cd*r symbol))) + "\"")) + nil t) + (if type ;; defvar here + (progn + (goto-char (line-beginning-position)) + (skip-chars-forward "[\s\t\n\r]") + (setq beg (point)) + (re-search-forward ");$" nil t) + (narrow-to-region beg (point))) + ;;(narrow-to-defun) + (and (re-search-backward "DEFUN" nil t) + (setq beg (point)) + (re-search-forward ")[\n\s\t\r]*{") + (re-search-forward "^}[\n\s\t\r]+") + (narrow-to-region beg (point)))) + (if (fboundp 'font-lock-ensure) + (font-lock-ensure) + (with-no-warnings (font-lock-fontify-buffer))) + (setq src (buffer-string))))) + src)) + +(defun help--fetch-lisp-src (symbol type file) + "Find emacs-lisp source code for a Lisp SYMBOL in a FILE. + +symbol - the symbol to find. +type - the type as obtained by 'describe-*' functions. +file - the source file to search in." + (let (src pos) + (when file + (setq file (or file (find-lisp-object-file-name symbol type)))) + (with-temp-buffer + (insert-file-contents file) + (delay-mode-hooks (funcall 'emacs-lisp-mode)) + (require 'find-func) + ;; Either or both an alias and its target might be advised. + ;; (setq symbol (find-function-advised-original + ;; (indirect-function + ;; (find-function-advised-original symbol))))) + (setq pos (cdr (find-function-search-for-symbol symbol type file))) + (when pos + (goto-char pos) + (forward-sexp) + (narrow-to-region pos (point)) + (if (fboundp 'font-lock-ensure) + (font-lock-ensure) + (with-no-warnings (font-lock-fontify-buffer))) + (setq src (buffer-string)))) + src)) + +(defun help--insert-source () + "Fnd and insert source for the current symbol into the help-mode +buffer." + (with-silent-modifications + (with-current-buffer (help-buffer) + (save-excursion + (let* ((file (plist-get help-mode--current-data :file)) + (type (plist-get help-mode--current-data :type)) + (sym (plist-get help-mode--current-data :symbol)) + (src "Source code not available.")) + (when (eq file 'C-source) + (setq file (help-C-file-name (indirect-function sym) 'fun))) + (setq src (if (string-suffix-p ".c" file) + (help--fetch-c-src sym type file) + (help--fetch-lisp-src sym type file))) + (goto-char (point-max)) + (let ((end (point))) + (when (search-backward "View Source Code:" nil t) + (delete-region (point) end) + (help-insert-xref-button "Hide Source Code:" 'help-source-view) + (insert (concat "\n" src "\n"))))))))) + +(defun help--remove-source () + "Remove source code from the help buffer when present." + (with-current-buffer (help-buffer) + (with-silent-modifications + (save-excursion + (goto-char (point-max)) + (let ((end (point))) + (when (search-backward "Hide Source Code:" nil t) + (delete-region (point) end) + (help-insert-xref-button + "View Source Code:" 'help-source-view))))))) + ;;;###autoload (defun help-make-xrefs (&optional buffer) "Parse and hyperlink documentation cross-references in the given BUFFER. @@ -664,7 +788,25 @@ help-make-xrefs (help-insert-xref-button help-forward-label 'help-forward (current-buffer))) (when (or help-xref-stack help-xref-forward-stack) - (insert "\n"))) + (insert "\n")) + (insert "\n") + ;; get source string if needed and available + ;; describe-symbol does not produce 'current-data' plist + (unless help-mode--current-data + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "\\.\\(el\\|c\\)" nil t) + (goto-char (- (point) 2)) + (let ((props (get-text-property (point) 'help-args))) + (when props + (setq help-mode--current-data + (list :symbol (nth 0 props) + :file (nth 1 props)))))))) + (if help-mode-inline-source + (progn + (insert "View Source Code:") ;; just a little hack + (help--insert-source)) + (help-insert-xref-button "View Source Code:" 'help-source-view))) (set-buffer-modified-p old-modified))))) ;;;###autoload @@ -819,10 +961,23 @@ help-do-xref (append args (list (generate-new-buffer-name "*info*"))) args)))) -;; The doc string is meant to explain what buttons do. -(defun help-follow-mouse () - "Follow the cross-reference that you click on." - (declare (obsolete nil "28.1")) +(defun help-toggle-source-view () + "Toggle source code display in help buffer for the current symbol." + (interactive) + (when (get-buffer-window (help-buffer)) + (with-current-buffer (help-buffer) + (unless (plist-get help-mode--current-data :file) + (error "Source file for the current help item is not defined")) + (save-excursion + (goto-char (point-min)) + (if (search-forward "Hide Source Code:" nil t) + (help--remove-source) + (help--insert-source)))))) + + ;; The doc string is meant to explain what buttons do. + (defun help-follow-mouse () + "Follow the cross-reference that you click on." + (declare (obsolete nil "28.1")) (interactive) (error "No cross-reference here")) -- 2.33.0 --=-=-=--