emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Links & images with different attributes in the same paragraph
@ 2023-11-11 15:54 Max Nikulin
  2023-12-05 13:46 ` Ihor Radchenko
  0 siblings, 1 reply; 10+ messages in thread
From: Max Nikulin @ 2023-11-11 15:54 UTC (permalink / raw)
  To: emacs-orgmode

Hi,

I raised this topic earlier. It seems, there is a rather generic 
workaround that may help.

Sometimes it is necessary to assign specific export attributes to some 
links in a paragraph while others should get another set of them. Inline 
images should have different alt text.

--- 8< ---
Text with <<anchor>> in a paragraph.

Any link types are supported including
[[wrap::href "anchor"][internal]] ones.
Attributes may be added selectively:
<wrap::href "https://microsoft.com/" :attr_html ":class external \
:title Link that does not increase target page rank \
:noreferrer 1" :attr_html ":nofollow 1 :noopener 1">

Images in the same paragraph may have different =alt= attribute:
raster
[[wrap::attr_html ":alt PNG Unicorn"
:href 
"https://orgmode.org/worg/images/orgmode/org-mode-unicorn-original-logo.png"]]
and vector
[[wrap::attr_html ":alt SVG Unicorn"
:href "https://orgmode.org/resources/img/org-mode-unicorn.svg"]]
images.
--- >8 ---

is exported as

--- 8< ---
<p>
Text with <a id="org0424ec3"></a> in a paragraph.
</p>

<p>
Any link types are supported including
<a href="#org0424ec3">internal</a> ones.
Attributes may be added selectively:
<a href="https://microsoft.com/" class="external" title="Link that does 
not increase target page rank" noreferrer="1" nofollow="1" 
noopener="1">https://microsoft.com/</a>
</p>

<p>
Images in the same paragraph may have different <code>alt</code> attribute:
raster
<img 
src="https://orgmode.org/worg/images/orgmode/org-mode-unicorn-original-logo.png" 
alt="PNG Unicorn" />
and vector
<img src="https://orgmode.org/resources/img/org-mode-unicorn.svg" 
alt="SVG Unicorn" class="org-svg" />
images.
</p>
--- >8 ---

and it requires not so much code:

# #+header: :eval never-export
#+begin_src elisp :exports results :results silent
   (defun nm/org-link-wrap-path-to-props (path)
     (read (concat "(" path ")")))

   (defun nm/org-link-wrap-copy-props (props link)
     (while props
       (let ((name (pop props))
   	  (value (pop props))
   	  (case-fold-search t))
         (org-element-put-property
          link
          name
          ;; `org-element--collect-affiliated-keywords'
          (if (string-match-p "\\`:attr_" (symbol-name name))
   	   (append (org-element-property name link) (list value))
   	 value)))))

   (defun nm/org-link-wrap-export
       (path description backend info)
     (let* ((props-all (nm/org-link-wrap-path-to-props path))
   	 (href (plist-get props-all :href))
   	 ;; `org-plist-delete' removes other duplicated keys as well.
   	 (props (map-delete props-all :href))
   	 ;; Taken from `org-link-open-from-string'.
   	 (link (with-temp-buffer
   		 (let ((org-inhibit-startup nil))
   		   (insert "[[" (org-link-escape href) "]]")
   		   (org-mode)
   		   (goto-char (point-min))
   		   (org-element-link-parser)))))
       (nm/org-link-wrap-copy-props props link)
       (when description
         (org-element-set-contents link description))
       (org-no-properties
        (org-export-data-with-backend link backend info))))

   (defun nm/org-link-wrap-follow (path arg)
     (let* ((props (nm/org-link-wrap-path-to-props path))
   	 (href (plist-get props :href)))
       (org-link-open-from-string
        (concat "[[" (org-link-escape href) "]]")
        arg)))

   (org-link-set-parameters
    "wrap"
    :follow #'nm/org-link-wrap-follow
    :export #'nm/org-link-wrap-export)
#+end_src

An example of earlier discussion:
https://list.orgmode.org/t8q71r$mgv$1@ciao.gmane.io/
Max Nikulin. [BUG] manual: confusing example of adding attributes to a 
link (affiliated keywords). Mon, 20 Jun 2022 23:25:29 +0700



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-11-11 15:54 Links & images with different attributes in the same paragraph Max Nikulin
@ 2023-12-05 13:46 ` Ihor Radchenko
  2023-12-12 11:08   ` Max Nikulin
  0 siblings, 1 reply; 10+ messages in thread
From: Ihor Radchenko @ 2023-12-05 13:46 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode

Max Nikulin <manikulin@gmail.com> writes:

> I raised this topic earlier. It seems, there is a rather generic 
> workaround that may help.
>
> Sometimes it is necessary to assign specific export attributes to some 
> links in a paragraph while others should get another set of them. Inline 
> images should have different alt text.
>
> --- 8< ---
> Text with <<anchor>> in a paragraph.
>
> Any link types are supported including
> [[wrap::href "anchor"][internal]] ones.
> Attributes may be added selectively:
> <wrap::href "https://microsoft.com/" :attr_html ":class external \
> :title Link that does not increase target page rank \
> :noreferrer 1" :attr_html ":nofollow 1 :noopener 1">
> ...
> An example of earlier discussion:
> https://list.orgmode.org/t8q71r$mgv$1@ciao.gmane.io/
> Max Nikulin. [BUG] manual: confusing example of adding attributes to a 
> link (affiliated keywords). Mon, 20 Jun 2022 23:25:29 +0700

We definitely need something to fine-tune export properties inline.
However, I am skeptical about using links for this purpose in Org
proper, not individual user configs.

This is because link description cannot contain arbitrary objects. In
particular, one cannot put other links, radio-targets, line-breaks,
citations, etc.
I believe that the right way to go here is what we previously discussed
as inline special block equivalent. That way, we will not need to create
workarounds with special link type.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-05 13:46 ` Ihor Radchenko
@ 2023-12-12 11:08   ` Max Nikulin
  2023-12-12 13:18     ` Ihor Radchenko
  0 siblings, 1 reply; 10+ messages in thread
From: Max Nikulin @ 2023-12-12 11:08 UTC (permalink / raw)
  To: emacs-orgmode

On 05/12/2023 20:46, Ihor Radchenko wrote:
> 
> We definitely need something to fine-tune export properties inline.
> However, I am skeptical about using links for this purpose in Org
> proper, not individual user configs.

Sometimes links are really links, however some links require some 
tuning. Global style or custom export backend that modifies all links is 
not always suitable.

Perhaps special :href values may be added to allow just decorations 
without hyperlinks.

> I believe that the right way to go here is what we previously discussed
> as inline special block equivalent. That way, we will not need to create
> workarounds with special link type.

It is limitation of top-down parser that object of the same time can not 
be nested, so I am unsure if special blocks would be solution in all cases.

I have added a hack to allow definitions of links or their attributes 
outside of paragraphs. Noweb and source code blocks allow it. Perhaps is 
should be implemented as a filter to avoid tricks to get noexport source 
blocks

---- 8< ----
A link defined in a source block
[[wrap:<<org-mode>> :attr_html ":class org"][Org mode]]

#+name: org-mode
#+begin_src elisp :exports none
:href "https://orgmode.org"
:attr_html ":title Org Mode — Your life in plain text"
#+end_src
---- >8 ----

(defun nm/org-link-wrap-path-to-props (path &optional info)
   (let* ((with-broken-links (plist-get info :with-broken-links))
	 (org-babel-noweb-error-all-langs
	  (if (not with-broken-links)
	      t
	    ;; TODO Handle `mark', currently errors are ignored.
	    org-babel-noweb-error-all-langs))
	 (expanded
	  (org-babel-expand-noweb-references
	   (list "elisp" path '(:noweb-prefix "no"))
	   ;; Allow noweb references to code blocks
	   ;; having ":exports none".
	   (plist-get info :input-buffer))))
     (read(concat "(" expanded ")"))))

(defun nm/org-link-wrap-assert-href (props path)
   (let ((href (plist-get props :href)))
     (pcase href
       ((pred null) (signal
		    'org-link-broken
		    (list (format "no :href property in `%s'" path))))
       ((pred stringp) href)
       ((pred symbolp) (symbol-name href))
       (_ (signal
	  'org-link-broken
	  (list (format "Invalid :href type in `%s'" path)))))))

(defun nm/org-link-wrap-copy-props (props link)
   (while props
     (let ((name (pop props))
	  (value (pop props))
	  (case-fold-search t))
       (org-element-put-property
        link
        name
        ;; `org-element--collect-affiliated-keywords'
        (if (string-match-p "\\`:attr_" (symbol-name name))
	   (append (org-element-property name link) (list value))
	 value)))))

(defun nm/org-link-wrap-export
     (path description backend info)
   (let* ((props-all (nm/org-link-wrap-path-to-props path info))
	 (href (nm/org-link-wrap-assert-href props-all path))
	 ;; `org-plist-delete' removes other duplicated keys as well.
	 (props (map-delete props-all :href))
	 ;; Taken from `org-link-open-from-string'.
	 (link (with-temp-buffer
		 (let ((org-inhibit-startup nil))
		   (insert "[[" (org-link-escape href) "]]")
		   (org-mode)
		   (goto-char (point-min))
		   (org-element-link-parser)))))
     (nm/org-link-wrap-copy-props props link)
     (when description
       (org-element-set-contents link description))
     (org-no-properties
      (org-export-data-with-backend link backend info))))

(defun nm/org-link-wrap-follow (path arg)
   (let* ((props (nm/org-link-wrap-path-to-props path))
	 (href (nm/org-link-wrap-assert-href props path)))
     (org-link-open-from-string
      (concat "[[" (org-link-escape href) "]]")
      arg)))

(org-link-set-parameters
  "wrap"
  :follow #'nm/org-link-wrap-follow
  :export #'nm/org-link-wrap-export)




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-12 11:08   ` Max Nikulin
@ 2023-12-12 13:18     ` Ihor Radchenko
  2023-12-13 11:50       ` Max Nikulin
  0 siblings, 1 reply; 10+ messages in thread
From: Ihor Radchenko @ 2023-12-12 13:18 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode

Max Nikulin <manikulin@gmail.com> writes:

>> I believe that the right way to go here is what we previously discussed
>> as inline special block equivalent. That way, we will not need to create
>> workarounds with special link type.
>
> It is limitation of top-down parser that object of the same time can not 
> be nested, so I am unsure if special blocks would be solution in all cases.

Nested objects of the same type are not really a limitation of top-down
parser. It is the syntax of objects that might but does not have to be.
We might come up with a syntax that allow nesting.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-12 13:18     ` Ihor Radchenko
@ 2023-12-13 11:50       ` Max Nikulin
  2023-12-14 15:23         ` Ihor Radchenko
  0 siblings, 1 reply; 10+ messages in thread
From: Max Nikulin @ 2023-12-13 11:50 UTC (permalink / raw)
  To: emacs-orgmode

On 12/12/2023 20:18, Ihor Radchenko wrote:
> Max Nikulin writes:
> 
>> It is limitation of top-down parser that object of the same time can not
>> be nested, so I am unsure if special blocks would be solution in all cases.
> 
> Nested objects of the same type are not really a limitation of top-down
> parser. It is the syntax of objects that might but does not have to be.
> We might come up with a syntax that allow nesting.

I would be glad to learn that I am wrong. The current parser picks first 
terminating token ignoring other opening tokens in between. The only way 
I see is unique identifiers for opening and closing tokens to allow 
match them in pairs. It would be tedious to type and to copy fragments 
from similar text.

A similar problem is importing and exporting fragments of mail messages 
having multilevel quotes. #+begin_quote is not enough, it is necessary 
to use something else for inner citations, e.g. #+begin_quote1.

Moreover I would prefer to have links as links even when they need some 
special treatment.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-13 11:50       ` Max Nikulin
@ 2023-12-14 15:23         ` Ihor Radchenko
  2023-12-16  8:06           ` Max Nikulin
  0 siblings, 1 reply; 10+ messages in thread
From: Ihor Radchenko @ 2023-12-14 15:23 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode

Max Nikulin <manikulin@gmail.com> writes:

>> Nested objects of the same type are not really a limitation of top-down
>> parser. It is the syntax of objects that might but does not have to be.
>> We might come up with a syntax that allow nesting.
>
> I would be glad to learn that I am wrong. The current parser picks first 
> terminating token ignoring other opening tokens in between. The only way 
> I see is unique identifiers for opening and closing tokens to allow 
> match them in pairs. It would be tedious to type and to copy fragments 
> from similar text.

Not necessarily. The current parser also allows balanced brackets inside
an object. Search for "balanced" in
https://orgmode.org/worg/org-syntax.html and you will see many examples.

In addition, we can allow multiple forms of tokens. For example,
@wrap{simple wrap}; @wrap{{we can have } inside}};
@wrap{outer wrap; @wrap{inner wrap}; back}.
@wrap{{outer wrap; @wrap{{inner wrap allowing } as well}}; back}}.

> A similar problem is importing and exporting fragments of mail messages 
> having multilevel quotes. #+begin_quote is not enough, it is necessary 
> to use something else for inner citations, e.g. #+begin_quote1.

As you see, my solution is conceptually similar to #+begin_quote1 idea.

> Moreover I would prefer to have links as links even when they need some 
> special treatment.

What about @wrap[#+attr_html: :alt "Text"]{[[/path/to/image]]}?

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-14 15:23         ` Ihor Radchenko
@ 2023-12-16  8:06           ` Max Nikulin
  2023-12-16 14:44             ` Ihor Radchenko
  0 siblings, 1 reply; 10+ messages in thread
From: Max Nikulin @ 2023-12-16  8:06 UTC (permalink / raw)
  To: emacs-orgmode

On 14/12/2023 22:23, Ihor Radchenko wrote:
> 
> Not necessarily. The current parser also allows balanced brackets inside
> an object.

Thanks, I forgot about it. Balancing of brackets alleviates the issue 
with nested objects. I am unsure if it is still pure top-down parser, 
but it does not matter.

> @wrap{{outer wrap; @wrap{{inner wrap allowing } as well}}; back}}.

Are you assuming invisible zero-width space as a way to escape literal 
{{ or }}? I would prefer some visible characters.

> As you see, my solution is conceptually similar to #+begin_quote1 idea.

It is better since balanced delimiters make adding unique suffix to 
#+begin_... and #+end... unnecessary.

> What about @wrap[#+attr_html: :alt "Text"]{[[/path/to/image]]}?

Leaving aside precise syntax (that perhaps should be discussed in 
another thread), it solves the issue.

Do you have any idea how to address the following complain?

https://list.orgmode.org/orgmode/875ykwvmz7.fsf@posteo.net
Juan Manuel Macías. Re: About 'inline special blocks' Sun, 19 Jun 2022 
12:47:40 +0000
> Bringing that into the paragraph is
> unnecessarily overloading the paragraph and breaking the social contract
> of lightweight markup, where paragraphs should still look like
> paragraphs.

I consider it as a valid point, so I tried to take advantage of noweb 
features. I am in doubts concerning *evaluation* of expressions in 
addition to just substitutions. It allows to implement another kind of 
#+link: macro, but it gives too much power to my taste.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-16  8:06           ` Max Nikulin
@ 2023-12-16 14:44             ` Ihor Radchenko
  2023-12-19 14:39               ` Max Nikulin
  0 siblings, 1 reply; 10+ messages in thread
From: Ihor Radchenko @ 2023-12-16 14:44 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode

Max Nikulin <manikulin@gmail.com> writes:

>> @wrap{{outer wrap; @wrap{{inner wrap allowing } as well}}; back}}.
>
> Are you assuming invisible zero-width space as a way to escape literal 
> {{ or }}? I would prefer some visible characters.

No, not zero-width space. Literally, {{...}}. The idea is to define
delimiters as "[{]+" the matching number of "}". This way, we do not
need to worry about escaping "}" inside and can get nested markup for
free. It is more or less how Org parser works for special block:
the opening delimiter is #+begin_whatever is matched against
#+end_<same as opening delimiter>.

Also, see https://list.orgmode.org/orgmode/87mtaez8do.fsf@localhost/
with my original proposal and some discussion that followed up.

>> What about @wrap[#+attr_html: :alt "Text"]{[[/path/to/image]]}?
>
> Leaving aside precise syntax (that perhaps should be discussed in 
> another thread), it solves the issue.
>
> Do you have any idea how to address the following complain?
>
> https://list.orgmode.org/orgmode/875ykwvmz7.fsf@posteo.net
> Juan Manuel Macías. Re: About 'inline special blocks' Sun, 19 Jun 2022 
> 12:47:40 +0000
>> Bringing that into the paragraph is
>> unnecessarily overloading the paragraph and breaking the social contract
>> of lightweight markup, where paragraphs should still look like
>> paragraphs.
>
> I consider it as a valid point, so I tried to take advantage of noweb 
> features. I am in doubts concerning *evaluation* of expressions in 
> addition to just substitutions. It allows to implement another kind of 
> #+link: macro, but it gives too much power to my taste.

I am pretty sure that I replied to that concern raised in a parallel
thread. My idea was to allow macro replacement inside attributes:

#+macro: alt #+attr_html :alt $1
What about @wrap[<<<alt(Text)>>>]{[[/path/to/image]]}

Or even inline definition like

#+@macro: alt @wrap[@+attr_html :alt $1]
What about @alt[Text]{[[/path/to/image]]}

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-16 14:44             ` Ihor Radchenko
@ 2023-12-19 14:39               ` Max Nikulin
  2023-12-21 14:03                 ` Ihor Radchenko
  0 siblings, 1 reply; 10+ messages in thread
From: Max Nikulin @ 2023-12-19 14:39 UTC (permalink / raw)
  To: emacs-orgmode

On 16/12/2023 21:44, Ihor Radchenko wrote:
> Max Nikulin writes:
> 
>>> @wrap{{outer wrap; @wrap{{inner wrap allowing } as well}}; back}}.
>>
>> Are you assuming invisible zero-width space as a way to escape literal
>> {{ or }}? I would prefer some visible characters.
> 
> No, not zero-width space. Literally, {{...}}. The idea is to define
> delimiters as "[{]+" the matching number of "}". This way, we do not
> need to worry about escaping "}" inside and can get nested markup for
> free. It is more or less how Org parser works for special block:
> the opening delimiter is #+begin_whatever is matched against
> #+end_<same as opening delimiter>.

I am afraid, there is an issue if wrapped content is surrounded by 
braces. An ambiguity arises for

     @wrap{{{content}}}

it may be @wrap{{{ content }}}, @wrap{{ {content} }},
or @wrap{ {{content}} }. It seems, some escape character is unavoidable.

> Also, see https://list.orgmode.org/orgmode/87mtaez8do.fsf@localhost/
> with my original proposal and some discussion that followed up.

I completely forgot that you wrote about balanced parenthesis earlier.

>> Juan Manuel Macías. Re: About 'inline special blocks'
>>> Bringing that into the paragraph is
>>> unnecessarily overloading the paragraph and breaking the social contract
>>> of lightweight markup, where paragraphs should still look like
>>> paragraphs.

> I am pretty sure that I replied to that concern raised in a parallel
> thread. My idea was to allow macro replacement inside attributes:
> 
> #+macro: alt #+attr_html :alt $1
> What about @wrap[<<<alt(Text)>>>]{[[/path/to/image]]}

Certainly it allows to shorten in-text arguments. Just as noweb 
references, it has some disadvantages. I consider comma as macro 
argument separator as a kind of a pitfall. Macro definitions, unlike 
code blocks definitions for noweb references, can not be multiline
(unless defined in elisp code).

Unless something better will be proposed, I consider macro expansion 
inside arguments as a viable approach. (I can not recall if it was 
discussed earlier.)



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Links & images with different attributes in the same paragraph
  2023-12-19 14:39               ` Max Nikulin
@ 2023-12-21 14:03                 ` Ihor Radchenko
  0 siblings, 0 replies; 10+ messages in thread
From: Ihor Radchenko @ 2023-12-21 14:03 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode

Max Nikulin <manikulin@gmail.com> writes:

>> No, not zero-width space. Literally, {{...}}. The idea is to define
>> delimiters as "[{]+" the matching number of "}". This way, we do not
>> need to worry about escaping "}" inside and can get nested markup for
>> free. It is more or less how Org parser works for special block:
>> the opening delimiter is #+begin_whatever is matched against
>> #+end_<same as opening delimiter>.
>
> I am afraid, there is an issue if wrapped content is surrounded by 
> braces. An ambiguity arises for
>
>      @wrap{{{content}}}
>
> it may be @wrap{{{ content }}}, @wrap{{ {content} }},
> or @wrap{ {{content}} }. It seems, some escape character is unavoidable.

For such tricky cases, yes. Either escape character or another suggested
approach with "empty" joiner entity like \--

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-12-21 14:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-11 15:54 Links & images with different attributes in the same paragraph Max Nikulin
2023-12-05 13:46 ` Ihor Radchenko
2023-12-12 11:08   ` Max Nikulin
2023-12-12 13:18     ` Ihor Radchenko
2023-12-13 11:50       ` Max Nikulin
2023-12-14 15:23         ` Ihor Radchenko
2023-12-16  8:06           ` Max Nikulin
2023-12-16 14:44             ` Ihor Radchenko
2023-12-19 14:39               ` Max Nikulin
2023-12-21 14:03                 ` Ihor Radchenko

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).