From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp10.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms0.migadu.com with LMTPS id AYHuNvHLPmL4HQEAgWs5BA (envelope-from ) for ; Sat, 26 Mar 2022 09:16:49 +0100 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp10.migadu.com with LMTPS id qKNYLvHLPmI4WQAAG6o9tA (envelope-from ) for ; Sat, 26 Mar 2022 09:16:49 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 1B9EB39EA5 for ; Sat, 26 Mar 2022 09:16:49 +0100 (CET) Received: from localhost ([::1]:57932 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nY1bL-0005Oe-Kd for larch@yhetil.org; Sat, 26 Mar 2022 04:16:47 -0400 Received: from eggs.gnu.org ([209.51.188.92]:43722) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nY1a0-0005OP-NH for emacs-orgmode@gnu.org; Sat, 26 Mar 2022 04:15:26 -0400 Received: from [2607:f8b0:4864:20::22e] (port=35713 helo=mail-oi1-x22e.google.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nY1Zy-0000Qo-71 for emacs-orgmode@gnu.org; Sat, 26 Mar 2022 04:15:24 -0400 Received: by mail-oi1-x22e.google.com with SMTP id e4so10631835oif.2 for ; Sat, 26 Mar 2022 01:15:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:in-reply-to:references:date:message-id :mime-version; bh=sdqYDye1oOXBYc6SzroJAHd+637wEtmeSv1soksYs/Q=; b=c+zoG9espCGqcBASFiVed4bHfCJUtqoQudej/QvAO2zEFrwWDQ55vuCt2rzI72H37y YVyU1BDU3izJG47Y26mfIxDTEbrQMbNWdwQ3Pu+O0jETbxh0hmY0ldE4WBlkGe1hVfIn UZBD0gAtQDaDOXGvFZZ61sfnA688D9fDBa7/t+Ju5ho1IuawhbZNuAr/hFKWWtnRKkhG 8tuz0Tw9ZJbe0R29qS5noB4tlB5HfB0QomL4RD2D1ZIYfOYSSttNEpWlnVKPFScvwIzu pcvMqYkB/MFHXFHBA0Ds3vsVIGTsCdrm71WM+xuVoZ2PCrfqe/qkq+G9P9AZbR3F6wZP 719Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:in-reply-to:references:date :message-id:mime-version; bh=sdqYDye1oOXBYc6SzroJAHd+637wEtmeSv1soksYs/Q=; b=leSNtWsZWLAlWzKtpwYevu0SLY/Sb7qAxIp4lIWySguGt6Lop/QLGkQ5FbplNt7v0d qRjt1U/dXgqFo0ETRiXw1opefZvda5f4S0cMNT+VoHD+ZwX/5L6GkmiNLbFy6rklMrRI jgp0SPVPUTKJImuUHZMUkdzo4zGCamyH8W0AMbd90wWc7woHgHM2L2LvuV/2JCS3Qr+t lVfwu0LV0IqOfxAIDWrHnZGbMeieR6NBWRExa+DANYfmrHehzn+1AyAUDYXZajR+35HT wm80ptrkDCZ/g7c3bl6wSRx0LKDXBBxmuHn1E1KWTEl8sooz/0EOWER+SQV/mNBWZ/XQ lunA== X-Gm-Message-State: AOAM532cLm3yPWzD6m1mvnlgH27Piegjmpbb/Hj4yfzdvtVKQ82QQ35t uT+Q9XDMczTciKnQI0ap6Sk= X-Google-Smtp-Source: ABdhPJxLMLbUNIv0jodm7nejHoEB5XatOF0BmiOXtwuVV/b3IaDmOiPkzxQt6HB7qx3DlRReUSRW4w== X-Received: by 2002:a05:6808:1a02:b0:2da:5cb7:1307 with SMTP id bk2-20020a0568081a0200b002da5cb71307mr12338944oib.238.1648282520573; Sat, 26 Mar 2022 01:15:20 -0700 (PDT) Received: from localhost ([23.227.186.130]) by smtp.gmail.com with ESMTPSA id 37-20020a9d0ea8000000b005cb439f7a8csm3855021otj.62.2022.03.26.01.15.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 26 Mar 2022 01:15:19 -0700 (PDT) From: Ihor Radchenko To: Ignacio Casso Subject: Re: [BUG] C-c C-o on headline evaluates source code blocks with links inside [9.5.2 (release_9.5.2-25-gaf6f12 @ /home/ignacio/repos/emacs/lisp/org/)] In-Reply-To: References: X-Woof-Bug: confirmed Date: Sat, 26 Mar 2022 16:15:42 +0800 Message-ID: <87ils1b041.fsf@localhost> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Host-Lookup-Failed: Reverse DNS lookup failed for 2607:f8b0:4864:20::22e (failed) Received-SPF: pass client-ip=2607:f8b0:4864:20::22e; envelope-from=yantar92@gmail.com; helo=mail-oi1-x22e.google.com X-Spam_score_int: -2 X-Spam_score: -0.3 X-Spam_bar: / X-Spam_report: (-0.3 / 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_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, GAPPY_SUBJECT=0.1, PDS_HP_HELO_NORDNS=0.659, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: emacs-orgmode@gnu.org Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Migadu-Flow: FLOW_IN X-Migadu-To: larch@yhetil.org X-Migadu-Country: US ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1648282609; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=sdqYDye1oOXBYc6SzroJAHd+637wEtmeSv1soksYs/Q=; b=jThIGMgCoYrHJv5o78pfsMO/fneM8JbivGuWsITyDoN1jQI77JARDgTwcS8fsH4a5fyYhB adSKulAcm0VJthzBcq0JE7pyS0B5IrTHGLwcsPXh7CHdjT6mJ6nc90zQhUNeaBqVLtBX1R ojarYOdP+M3T6vnu1E3dqiQC7CEgvAW/b8QoxSp/QfrbPKAA/rgIalWy8qGBiml+tllPy7 rDUKVA2tIgQ3pBs3yz5z/vjNIyyrrApXDW04STu6ztLk5e2DJzJVyQRsDpDH+WS6bZE//s gdOXuI2OAaeICEXsMm9Fu7Vcrq8/O2SBe/gZCn/xUW7Uvz4XOdd5SF3EHkZzRQ== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1648282609; a=rsa-sha256; cv=none; b=kWh7TV+UdNCH/3tC4EFfqz01plUG18o3qDDf8Gt+mRZWrTHB+M0VXWjLcm4ihzcfyoPGLP xF7pEMmdPhCuga22Q8HVJj3pt2Ne+LZjfNTm/W/yl7h8h5Vy+c/5ZbJJL4wE312KYY72EU Z/H/jrRZaI1ynxyWDtKSzsY6k7rO+mMF46bV/Gwgh6nYNjr7O5rcmm5Ce149iau6JyJgcI JFUKNrvR8xTU9/l5cIMwxxQe/veOn5aYe65ZedAwedG82SeUNBx76KXkscguuVTFZ8j3LA RyPBYxcgsSTNCf2nOhkhQJL6TuLASWkpTCvHupz41H9YMFFcBGuSayJLxBUknQ== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=c+zoG9es; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -9.08 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=c+zoG9es; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Queue-Id: 1B9EB39EA5 X-Spam-Score: -9.08 X-Migadu-Scanner: scn0.migadu.com X-TUID: KU/Q2tDigjnp --=-=-= Content-Type: text/plain Ignacio Casso writes: > 1) `org-open-at-point' with point in a source code block calls and used > to call `org-babel-open-src-block-result'. This is not documented on the > docstring, but happens at least since Emacs 27' org built-in version, > 9.4.4. Confirmed. > 3) `org-open-at-point' with point in a headline collects all org links > in the body of the entry and offers to select one and open it, or if > there was only one it opens it directly. Links are collected using a > regular expression, so they match links inside a source code block. For > the selected link, `org-open-at-point' moves the point to the link and > calls itself recursively. In old versions of org, that means that it > opened the link. But in new versions, that means it evaluates the source > code block. > > To reproduce this behavior, just copy the following entry into an org > buffer and type C-c C-o with point in the heading. It will evaluate the > source code block, instead of just messaging "No Links" as it would do > with a source code block without links. > > * Heading > #+begin_src emacs-lisp > (message "https://orgmode.org/manual/") > #+end_src Confirmed. > The following patch should fix it: > > - (push (match-string 0) links)) > + (when (eq (org-element-type (org-element-context)) 'link) > + (push (match-string 0) links))) This will skip links inside property drawers, for example. Attaching an alternative patch. Best, Ihor --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-org-open-at-point-Do-not-list-links-under-headline-t.patch >From ca6afac5d68a5e83af6d8078d09a163c34d62e2e Mon Sep 17 00:00:00 2001 Message-Id: From: Ihor Radchenko Date: Sat, 26 Mar 2022 16:08:57 +0800 Subject: [PATCH] org-open-at-point: Do not list links under headline that cannot be opened * lisp/org-element.el (org-element-context): Do not alter match-data. * lisp/org.el (org-open-at-point): Update docstring listing that `org-open-at-point' opens src-blocks and citations. (org-offer-links-in-entry): Do not display links within invalid contexts. Reported in https://list.orgmode.org/PAXPR06MB77609E8C8E769CD7D769FA4BC6199@PAXPR06MB7760.eurprd06.prod.outlook.com/ --- lisp/org-element.el | 211 ++++++++++++++++++++++---------------------- lisp/org.el | 13 ++- 2 files changed, 117 insertions(+), 107 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index 28339c1b8..c2ca9c62c 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -7770,113 +7770,114 @@ (defun org-element-context (&optional element) Providing it allows for quicker computation." (catch 'objects-forbidden (org-with-wide-buffer - (let* ((pos (point)) - (element (or element (org-element-at-point))) - (type (org-element-type element)) - (post (org-element-property :post-affiliated element))) - ;; If point is inside an element containing objects or - ;; a secondary string, narrow buffer to the container and - ;; proceed with parsing. Otherwise, return ELEMENT. - (cond - ;; At a parsed affiliated keyword, check if we're inside main - ;; or dual value. - ((and post (< pos post)) - (beginning-of-line) - (let ((case-fold-search t)) (looking-at org-element--affiliated-re)) - (cond - ((not (member-ignore-case (match-string 1) + (save-match-data + (let* ((pos (point)) + (element (or element (org-element-at-point))) + (type (org-element-type element)) + (post (org-element-property :post-affiliated element))) + ;; If point is inside an element containing objects or + ;; a secondary string, narrow buffer to the container and + ;; proceed with parsing. Otherwise, return ELEMENT. + (cond + ;; At a parsed affiliated keyword, check if we're inside main + ;; or dual value. + ((and post (< pos post)) + (beginning-of-line) + (let ((case-fold-search t)) (looking-at org-element--affiliated-re)) + (cond + ((not (member-ignore-case (match-string 1) org-element-parsed-keywords)) - (throw 'objects-forbidden element)) - ((< (match-end 0) pos) - (narrow-to-region (match-end 0) (line-end-position))) - ((and (match-beginning 2) - (>= pos (match-beginning 2)) - (< pos (match-end 2))) - (narrow-to-region (match-beginning 2) (match-end 2))) + (throw 'objects-forbidden element)) + ((< (match-end 0) pos) + (narrow-to-region (match-end 0) (line-end-position))) + ((and (match-beginning 2) + (>= pos (match-beginning 2)) + (< pos (match-end 2))) + (narrow-to-region (match-beginning 2) (match-end 2))) + (t (throw 'objects-forbidden element))) + ;; Also change type to retrieve correct restrictions. + (setq type 'keyword)) + ;; At an item, objects can only be located within tag, if any. + ((eq type 'item) + (let ((tag (org-element-property :tag element))) + (if (or (not tag) (/= (line-beginning-position) post)) + (throw 'objects-forbidden element) + (beginning-of-line) + (search-forward tag (line-end-position)) + (goto-char (match-beginning 0)) + (if (and (>= pos (point)) (< pos (match-end 0))) + (narrow-to-region (point) (match-end 0)) + (throw 'objects-forbidden element))))) + ;; At an headline or inlinetask, objects are in title. + ((memq type '(headline inlinetask)) + (let ((case-fold-search nil)) + (goto-char (org-element-property :begin element)) + (looking-at org-complex-heading-regexp) + (let ((end (match-end 4))) + (if (not end) (throw 'objects-forbidden element) + (goto-char (match-beginning 4)) + (when (looking-at org-element-comment-string) + (goto-char (match-end 0))) + (if (>= (point) end) (throw 'objects-forbidden element) + (narrow-to-region (point) end)))))) + ;; At a paragraph, a table-row or a verse block, objects are + ;; located within their contents. + ((memq type '(paragraph table-row verse-block)) + (let ((cbeg (org-element-property :contents-begin element)) + (cend (org-element-property :contents-end element))) + ;; CBEG is nil for table rules. + (if (and cbeg cend (>= pos cbeg) + (or (< pos cend) (and (= pos cend) (eobp)))) + (narrow-to-region cbeg cend) + (throw 'objects-forbidden element)))) (t (throw 'objects-forbidden element))) - ;; Also change type to retrieve correct restrictions. - (setq type 'keyword)) - ;; At an item, objects can only be located within tag, if any. - ((eq type 'item) - (let ((tag (org-element-property :tag element))) - (if (or (not tag) (/= (line-beginning-position) post)) - (throw 'objects-forbidden element) - (beginning-of-line) - (search-forward tag (line-end-position)) - (goto-char (match-beginning 0)) - (if (and (>= pos (point)) (< pos (match-end 0))) - (narrow-to-region (point) (match-end 0)) - (throw 'objects-forbidden element))))) - ;; At an headline or inlinetask, objects are in title. - ((memq type '(headline inlinetask)) - (let ((case-fold-search nil)) - (goto-char (org-element-property :begin element)) - (looking-at org-complex-heading-regexp) - (let ((end (match-end 4))) - (if (not end) (throw 'objects-forbidden element) - (goto-char (match-beginning 4)) - (when (looking-at org-element-comment-string) - (goto-char (match-end 0))) - (if (>= (point) end) (throw 'objects-forbidden element) - (narrow-to-region (point) end)))))) - ;; At a paragraph, a table-row or a verse block, objects are - ;; located within their contents. - ((memq type '(paragraph table-row verse-block)) - (let ((cbeg (org-element-property :contents-begin element)) - (cend (org-element-property :contents-end element))) - ;; CBEG is nil for table rules. - (if (and cbeg cend (>= pos cbeg) - (or (< pos cend) (and (= pos cend) (eobp)))) - (narrow-to-region cbeg cend) - (throw 'objects-forbidden element)))) - (t (throw 'objects-forbidden element))) - (goto-char (point-min)) - (let ((restriction (org-element-restriction type)) - (parent element) - last) - (catch 'exit - (while t - (let ((next (org-element--object-lex restriction))) - (when next (org-element-put-property next :parent parent)) - ;; Process NEXT, if any, in order to know if we need to - ;; skip it, return it or move into it. - (if (or (not next) (> (org-element-property :begin next) pos)) - (throw 'exit (or last parent)) - (let ((end (org-element-property :end next)) - (cbeg (org-element-property :contents-begin next)) - (cend (org-element-property :contents-end next))) - (cond - ;; Skip objects ending before point. Also skip - ;; objects ending at point unless it is also the - ;; end of buffer, since we want to return the - ;; innermost object. - ((and (<= end pos) (/= (point-max) end)) - (goto-char end) - ;; For convenience, when object ends at POS, - ;; without any space, store it in LAST, as we - ;; will return it if no object starts here. - (when (and (= end pos) - (not (memq (char-before) '(?\s ?\t)))) - (setq last next))) - ;; If POS is within a container object, move into - ;; that object. - ((and cbeg cend - (>= pos cbeg) - (or (< pos cend) - ;; At contents' end, if there is no - ;; space before point, also move into - ;; object, for consistency with - ;; convenience feature above. - (and (= pos cend) - (or (= (point-max) pos) - (not (memq (char-before pos) - '(?\s ?\t))))))) - (goto-char cbeg) - (narrow-to-region (point) cend) - (setq parent next) - (setq restriction (org-element-restriction next))) - ;; Otherwise, return NEXT. - (t (throw 'exit next))))))))))))) + (goto-char (point-min)) + (let ((restriction (org-element-restriction type)) + (parent element) + last) + (catch 'exit + (while t + (let ((next (org-element--object-lex restriction))) + (when next (org-element-put-property next :parent parent)) + ;; Process NEXT, if any, in order to know if we need to + ;; skip it, return it or move into it. + (if (or (not next) (> (org-element-property :begin next) pos)) + (throw 'exit (or last parent)) + (let ((end (org-element-property :end next)) + (cbeg (org-element-property :contents-begin next)) + (cend (org-element-property :contents-end next))) + (cond + ;; Skip objects ending before point. Also skip + ;; objects ending at point unless it is also the + ;; end of buffer, since we want to return the + ;; innermost object. + ((and (<= end pos) (/= (point-max) end)) + (goto-char end) + ;; For convenience, when object ends at POS, + ;; without any space, store it in LAST, as we + ;; will return it if no object starts here. + (when (and (= end pos) + (not (memq (char-before) '(?\s ?\t)))) + (setq last next))) + ;; If POS is within a container object, move into + ;; that object. + ((and cbeg cend + (>= pos cbeg) + (or (< pos cend) + ;; At contents' end, if there is no + ;; space before point, also move into + ;; object, for consistency with + ;; convenience feature above. + (and (= pos cend) + (or (= (point-max) pos) + (not (memq (char-before pos) + '(?\s ?\t))))))) + (goto-char cbeg) + (narrow-to-region (point) cend) + (setq parent next) + (setq restriction (org-element-restriction next))) + ;; Otherwise, return NEXT. + (t (throw 'exit next)))))))))))))) (defun org-element-lineage (datum &optional types with-self) "List all ancestors of a given element or object. diff --git a/lisp/org.el b/lisp/org.el index 5e3d0b333..56dd6cc7d 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -8980,7 +8980,9 @@ (defvar org-open-at-point-functions nil they must return nil.") (defun org-open-at-point (&optional arg) - "Open link, timestamp, footnote or tags at point. + "Open thing at point. +The thing can be a link, citation, timestamp, footnote, src-block or +tags. When point is on a link, follow it. Normally, files will be opened by an appropriate application. If the optional prefix @@ -8995,6 +8997,10 @@ (defun org-open-at-point (&optional arg) found. If it is on a reference, move to the associated definition. +When point is on a src-block of inline src-block, open its result. + +When point is on a citation, follow it. + When point is on a headline, display a list of every link in the entry, so it is possible to pick one, or all, of them. If point is on a tag, call `org-tags-view' instead. @@ -9113,7 +9119,10 @@ (defun org-offer-links-in-entry (buffer marker &optional nth zero) (org-back-to-heading t) (setq end (save-excursion (outline-next-heading) (point))) (while (re-search-forward org-link-any-re end t) - (push (match-string 0) links)) + ;; Only consider valid links or links openable via + ;; `org-open-at-point'. + (when (memq (org-element-type (org-element-context)) '(link comment comment-block node-property keyword)) + (push (match-string 0) links))) (setq links (org-uniquify (reverse links)))) (cond ((null links) -- 2.34.1 --=-=-=--