├── .github
├── DISCUSSION_TEMPLATE
│ ├── ideas.yml
│ └── q-a.yml
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug.yml
│ └── config.yml
├── dependabot.yml
└── workflows
│ └── release.yml
├── .gitignore
├── CITATION.cff
├── LICENSE
├── README.md
├── _extensions
└── highlight-text
│ ├── LICENSE
│ ├── _extension.yml
│ └── highlight-text.lua
└── example.qmd
/.github/DISCUSSION_TEMPLATE/ideas.yml:
--------------------------------------------------------------------------------
1 | title: "The (missing) feature you want to discuss"
2 | labels:
3 | - "Type: Enhancement :bulb:"
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | First, please check if your feature request has already been discussed.
9 | If it has, please consider adding a comment to the existing discussion instead of creating a new one.
10 |
11 | If you want to ask for help, please consider using the Q&A GitHub Discussions, as it is better suited for answering your question.
12 |
13 | Finally, try to describe the best you can what you want to achieve and why you think it is important.
14 | This will help us to understand your request and prioritise it.
15 |
16 | _Thank you for opening this feature request!_
17 | - type: textarea
18 | attributes:
19 | label: Description
20 | description: Start your discussion!
21 | validations:
22 | required: true
23 | - type: markdown
24 | attributes:
25 | value: |
26 | _Thank you for opening this feature request!_
27 |
--------------------------------------------------------------------------------
/.github/DISCUSSION_TEMPLATE/q-a.yml:
--------------------------------------------------------------------------------
1 | title: "Your question in one sentence"
2 | body:
3 | - type: markdown
4 | attributes:
5 | value: |
6 | First, please check if your question has already been asked.
7 | If it has, please consider adding a comment to the existing discussion instead of creating a new one.
8 |
9 | Finally, try to describe the best you can what you want to achieve or what is your issue, especially by providing a complete self-contained reproducible example.
10 | This will help us to understand your question and answer it.
11 |
12 | `````md
13 | ````qmd
14 | ---
15 | title: "Reproducible Quarto Document"
16 | format: html
17 | engine: jupyter
18 | ---
19 |
20 | This is a reproducible Quarto document using `format: html`.
21 | It is written in Markdown and contains embedded Python code.
22 | When you run the code, it will produce a message.
23 |
24 | ```{python}
25 | print("Hello, world!")
26 | ```
27 |
28 | {#fig-placeholder}
29 |
30 | {{< lipsum 1 >}}
31 |
32 | A reference to @fig-placeholder.
33 |
34 | The end.
35 | ````
36 | `````
37 |
38 | You can add some additional information that can help us to help you:
39 |
40 | - What Quarto version are you using?
41 | You can find the version of Quarto you used by running `quarto --version` in your terminal.
42 | - What version of the Quarto extension are you using?
43 | You can find the version of the Quarto extension you used by running `quarto list extensions` in your terminal.
44 | - What operating system are you using?
45 | Linux Ubuntu 20.04, macOS 11.2.3, Windows 10, _etc._
46 |
47 | _Thank you for opening this discussion either to ask for help or to report a possible bug!_
48 | - type: textarea
49 | attributes:
50 | label: Description
51 | description: Start your question/report!
52 | placeholder: |
53 | You can include Quarto document code which includes code blocks like this:
54 |
55 | `````md
56 | ````qmd
57 | ---
58 | title: "Reproducible Quarto Document"
59 | format: html
60 | engine: jupyter
61 | ---
62 |
63 | This is a reproducible Quarto document using `format: html`.
64 | It is written in Markdown and contains embedded Python code.
65 | When you run the code, it will produce a message.
66 |
67 | ```{python}
68 | print("Hello, world!")
69 | ```
70 |
71 | {#fig-placeholder}
72 |
73 | {{< lipsum 1 >}}
74 |
75 | A reference to @fig-placeholder.
76 |
77 | The end.
78 | ````
79 | `````
80 |
81 | ---
82 |
83 | ### Additional information that can help us to help you
84 |
85 | - What Quarto version are you using?
86 | You can find the version of Quarto you used by running `quarto --version` in your terminal.
87 | - What version of the Quarto extension are you using?
88 | You can find the version of the Quarto extension you used by running `quarto list extensions` in your terminal.
89 | - What operating system are you using?
90 | Linux Ubuntu 20.04, macOS 11.2.3, Windows 10, _etc._
91 | validations:
92 | required: true
93 | - type: markdown
94 | attributes:
95 | value: |
96 | _Thank you for opening this discussion either to ask for help or to report a possible bug!_
97 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: mcanouil
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.yml:
--------------------------------------------------------------------------------
1 | name: Bug report
2 | description: Report an error or unexpected behaviour
3 | labels:
4 | - "Type: Bug :bug:"
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Welcome!
11 |
12 | - type: checkboxes
13 | attributes:
14 | label: "I Have checked the following"
15 | options:
16 | - label: I have searched the issue tracker for similar issues
17 | required: true
18 | - label: I have the latest version of [Quarto CLI](https://github.com/quarto-dev/quarto-cli/releases/latest)
19 | required: true
20 | - label: I have the latest version of the Quarto extension
21 | required: true
22 |
23 | - type: textarea
24 | attributes:
25 | label: Bug description
26 | description: Description of the bug.
27 | placeholder: Please describe the bug here.
28 |
29 | - type: textarea
30 | attributes:
31 | label: Steps to reproduce
32 | description: |
33 | Tell us how to reproduce this bug.
34 |
35 | - type: textarea
36 | attributes:
37 | label: Actual behaviour
38 | description: Tell us what happens instead.
39 |
40 | - type: textarea
41 | attributes:
42 | label: Expected behaviour
43 | description: Tell us what should happen.
44 |
45 | - type: textarea
46 | attributes:
47 | label: Your environment
48 | description: |
49 | Please document the IDE (_e.g._ RStudio, Positron, VSCode, NVim), its version, and the operating system you're running (_e.g., MacOS Ventura 13.4, Windows 11, Linux Debian 11, _etc._).
50 | placeholder: |
51 | - IDE: RStudio 2023.03.1+446 | VSCode | Positron
52 | - OS: MacOS Ventura 13.4 | Windows | Ubuntu
53 |
54 | - type: markdown
55 | attributes:
56 | value: "_Thanks for submitting this bug report!_"
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: Support
4 | url: https://github.com/mcanouil/quarto-highlight-text/discussions
5 | about: Please ask and answer questions here.
6 | - name: Issue with Quarto CLI
7 | url: https://github.com/quarto-dev/quarto-cli
8 | about: Please report issues with the Quarto CLI here
9 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | labels:
8 | - "Type: Dependencies :arrow_up:"
9 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release Quarto Extension
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | type: choice
8 | description: "Version"
9 | required: false
10 | default: "patch"
11 | options:
12 | - "patch"
13 | - "minor"
14 | - "major"
15 | quarto:
16 | type: choice
17 | description: "Quarto version"
18 | required: false
19 | default: "release"
20 | options:
21 | - "release"
22 | - "pre-release"
23 |
24 | permissions:
25 | contents: write
26 | pull-requests: write
27 | id-token: write
28 | pages: write
29 |
30 | jobs:
31 | release:
32 | uses: mcanouil/quarto-workflows/.github/workflows/release-extension.yml@main
33 | secrets: inherit
34 | with:
35 | version: "${{ github.event.inputs.version }}"
36 | formats: "html typst pdf-xelatex pdf-lualatex pdf-pdflatex docx revealjs beamer pptx"
37 | tinytex: true
38 | quarto: "${{ github.event.inputs.quarto }}"
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.luarc.json
2 | /.quarto/
3 | _quarto.yml
4 | *.html
5 | *.pdf
6 | *.docx
7 | *.pptx
8 | *_files/
9 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | title: "Highlight-text Extension For Quarto"
3 | message: "If you use this project, please cite it as below."
4 | type: software
5 | authors:
6 | - family-names: "Canouil"
7 | given-names: "Mickaël"
8 | orcid: "https://orcid.org/0000-0002-3396-4549"
9 | repository-code: "https://github.com/mcanouil/quarto-highlight-text"
10 | url: "http://m.canouil.dev/quarto-highlight-text/"
11 | license: "MIT"
12 | date-released: "2025-05-05"
13 | version: 1.3.3
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Mickaël Canouil
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Highlight-text Extension For Quarto
2 |
3 | This is a Quarto extension that allows to highlight text in a document for various format: HTML, LaTeX, Typst, and Docx.
4 |
5 | ## Installing
6 |
7 | ```bash
8 | quarto add mcanouil/quarto-highlight-text
9 | ```
10 |
11 | This will install the extension under the `_extensions` subdirectory.
12 | If you're using version control, you will want to check in this directory.
13 |
14 | ## Using
15 |
16 | To use the extension, add the following to your document's front matter:
17 |
18 | ```yaml
19 | filters:
20 | - highlight-text
21 | ```
22 |
23 | Then you can use the span syntax markup to highlight text in your document, *e.g.*:
24 |
25 | ```markdown
26 | [Red]{colour="#b22222" bg-colour="#abc123"} # UK
27 | [Blue]{color="#0000FF" bg-color="#ABC123"} # US
28 | ```
29 |
30 | You can also use the shorter syntax ([v1.1.1](../../releases/tag/1.1.1)):
31 |
32 | ```markdown
33 | [Red]{fg="red" bg="primary"}
34 | ```
35 |
36 | Using colours from `_brand.yml` ([v1.1.0](../../releases/tag/1.1.0)):
37 |
38 | ```yaml
39 | color:
40 | palette:
41 | red: "#b22222"
42 | primary: "#abc123"
43 | ```
44 |
45 | ```markdown
46 | [Red]{colour="brand-color.red" bg-colour="brand-color.primary"}
47 | ```
48 |
49 | Using colours from light/dark themes with Quarto CLI >=1.7.28 ([v1.2.0](../../releases/tag/1.2.0)):
50 |
51 | - From document front matter:
52 |
53 | ```yaml
54 | brand:
55 | light:
56 | color:
57 | palette:
58 | fg: "#ffffff"
59 | bg: "#b22222"
60 | dark:
61 | color:
62 | palette:
63 | fg: "#b22222"
64 | bg: "#ffffff"
65 | ```
66 |
67 | - From `_quarto.yml` and `_brand.yml` file
68 |
69 | ```yaml
70 | brand:
71 | dark: _brand.yml
72 | ```
73 |
74 | ```markdown
75 | [Light: White/Red | Dark: Red/White]{colour="brand-color.fg" bg-colour="brand-color.bg"}
76 | ```
77 |
78 | > [!NOTE]
79 | > Only the `html` support light/dark mode switching.
80 | > The other formats will use the light mode colours if available or the dark mode colours otherwise.
81 |
82 | ## Limitations
83 |
84 | LaTeX `\colorbox` command does not support wrapping/line breaks in the text to be highlighted.
85 | This means that the above example will not work well in LaTeX output.
86 | In order to get a slightly better result, you can use the `par=true` attribute to add `\parbox{\linewidth}`:
87 |
88 | ```markdown
89 | [Red]{colour="#b22222" bg-colour="#abc123" par=true}
90 | ```
91 |
92 | Use `pdf-engine: lualatex` in your YAML front matter to use the `luatex` engine and fully alleviate the above issue.
93 |
94 | ## Examples
95 |
96 | Here is the source code for a minimal example: [`example.qmd`](example.qmd).
97 |
98 | Outputs of `example.qmd`:
99 |
100 | - [HTML](https://m.canouil.dev/quarto-highlight-text/)
101 | - [Typst/PDF](https://m.canouil.dev/quarto-highlight-text/highlight-typst.pdf)
102 | - [LaTeX/PDF (XeLaTeX)](https://m.canouil.dev/quarto-highlight-text/highlight-xelatex.pdf)
103 | - [LaTeX/PDF (LuaLaTeX)](https://m.canouil.dev/quarto-highlight-text/highlight-lualatex.pdf)
104 | - [LaTeX/PDF (PDFLaTeX)](https://m.canouil.dev/quarto-highlight-text/highlight-pdflatex.pdf)
105 | - [Word/Docx](https://m.canouil.dev/quarto-highlight-text/highlight-openxml.docx) (**only supports plain text, *i.e.*, no URLs**)
106 | - [Reveal.js](https://m.canouil.dev/quarto-highlight-text/highlight-revealjs.html)
107 | - [Beamer/PDF](https://m.canouil.dev/quarto-highlight-text/highlight-beamer.pdf)
108 | - [PowerPoint/Pptx](https://m.canouil.dev/quarto-highlight-text/highlight-pptx.pptx) (**only supports plain text, *i.e.*, no URLs**)
109 |
--------------------------------------------------------------------------------
/_extensions/highlight-text/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Mickaël Canouil
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/_extensions/highlight-text/_extension.yml:
--------------------------------------------------------------------------------
1 | title: Highlight Text
2 | author: Mickaël Canouil
3 | version: 1.3.3
4 | quarto-required: ">=1.7.29"
5 | contributes:
6 | filters:
7 | - highlight-text.lua
8 |
--------------------------------------------------------------------------------
/_extensions/highlight-text/highlight-text.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | # MIT License
3 | #
4 | # Copyright (c) 2025 Mickaël Canouil
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | ]]
24 |
25 | --- Gets a colour value from brand theme or formats it for later use
26 | --- @param theme string The brand theme to use (light/dark)
27 | --- @param colour string The colour value or brand colour reference
28 | --- @return string The processed colour value
29 | local function get_brand_colour(theme, colour)
30 | local brand = require('modules/brand/brand')
31 | if colour and colour:match('^brand%-color.') then
32 | colour = brand.get_color(theme, colour:gsub('^brand%-color%.', ''))
33 | else
34 | if FORMAT:match 'typst' and colour ~= nil then
35 | colour = 'rgb("' .. colour .. '")'
36 | end
37 | end
38 | return colour
39 | end
40 |
41 | --- Applies text and background colour styling for HTML-based outputs
42 | --- @param span table The span element to modify
43 | --- @param settings table The highlight settings containing colour and background colour
44 | --- @return table The modified span with HTML styling
45 | local function highlight_html(span, settings)
46 | local result = {}
47 | local theme_keys = {}
48 |
49 | for key, _ in pairs(settings) do
50 | table.insert(theme_keys, key)
51 | end
52 |
53 | for _, theme in ipairs(theme_keys) do
54 | local theme_span = pandoc.Span(span.content)
55 | local colour = settings[theme].colour
56 | local bg_colour = settings[theme].bg_colour
57 |
58 | for k, v in pairs(span.attributes) do
59 | theme_span.attributes[k] = v
60 | end
61 |
62 | if theme_span.attributes['style'] == nil then
63 | theme_span.attributes['style'] = ''
64 | elseif theme_span.attributes['style']:sub(-1) ~= ';' then
65 | theme_span.attributes['style'] = theme_span.attributes['style'] .. ';'
66 | end
67 |
68 | theme_span.classes = theme_span.classes or {}
69 | table.insert(theme_span.classes, theme .. '-content')
70 |
71 | if colour ~= nil then
72 | theme_span.attributes['colour'] = nil
73 | theme_span.attributes['color'] = nil
74 | theme_span.attributes['style'] = theme_span.attributes['style'] .. 'color: ' .. colour .. ';'
75 | end
76 |
77 | if bg_colour ~= nil then
78 | theme_span.attributes['bg-colour'] = nil
79 | theme_span.attributes['bg-color'] = nil
80 | theme_span.attributes['style'] = theme_span.attributes['style'] ..
81 | 'border-radius: 0.2rem; padding: 0 0.2rem 0 0.2rem;' .. 'background-color: ' .. bg_colour .. ';'
82 | end
83 |
84 | table.insert(result, theme_span)
85 | end
86 |
87 | if #result == 1 then
88 | return result[1]
89 | else
90 | return result
91 | end
92 | end
93 |
94 | --- Applies text and background colour styling for LaTeX-based outputs
95 | --- @param span table The span element to modify
96 | --- @param colour string The text colour to apply
97 | --- @param bg_colour string The background colour to apply
98 | --- @param par boolean Whether to wrap in a paragraph box
99 | --- @return table The span content with LaTeX markup
100 | local function highlight_latex(span, colour, bg_colour, par)
101 | local is_lualatex = quarto.doc.pdf_engine() == 'lualatex'
102 |
103 | if is_lualatex and bg_colour ~= nil then
104 | quarto.doc.use_latex_package('luacolor, lua-ul')
105 | end
106 |
107 | if colour == nil then
108 | colour_open = ''
109 | colour_close = ''
110 | else
111 | colour_open = '\\textcolor[HTML]{' .. colour:gsub('^#', '') .. '}{'
112 | colour_close = '}'
113 | end
114 |
115 | if bg_colour == nil then
116 | bg_colour_open = ''
117 | bg_colour_close = ''
118 | else
119 | if is_lualatex then
120 | bg_colour_open = '\\highLight[{[HTML]{' .. bg_colour:gsub('^#', '') .. '}}]{'
121 | bg_colour_close = '}'
122 | else
123 | bg_colour_open = '\\colorbox[HTML]{' .. bg_colour:gsub('^#', '') .. '}{'
124 | bg_colour_close = '}'
125 | end
126 | end
127 |
128 | if par and not is_lualatex then
129 | bg_colour_open = bg_colour_open .. '\\parbox{\\linewidth}{'
130 | bg_colour_close = '}' .. bg_colour_close
131 | end
132 |
133 | table.insert(
134 | span.content, 1,
135 | pandoc.RawInline('latex', colour_open .. bg_colour_open)
136 | )
137 | table.insert(span.content, pandoc.RawInline('latex', bg_colour_close .. colour_close))
138 |
139 | return span.content
140 | end
141 |
142 | --- Applies text and background colour styling for Word documents
143 | --- @param span table The span element to modify
144 | --- @param colour string The text colour to apply
145 | --- @param bg_colour string The background colour to apply
146 | --- @return table The span content with OpenXML markup for Word
147 | local function highlight_openxml_docx(span, colour, bg_colour)
148 | local spec = ''
149 | if bg_colour ~= nil then
150 | spec = spec .. ''
151 | end
152 | if colour ~= nil then
153 | spec = spec .. ''
154 | end
155 | spec = spec .. ''
156 |
157 | table.insert(span.content, 1, pandoc.RawInline('openxml', spec))
158 | table.insert(span.content, pandoc.RawInline('openxml', ''))
159 |
160 | return span.content
161 | end
162 |
163 | --- Applies text and background colour styling for PowerPoint presentations
164 | --- @param span table The span element to modify
165 | --- @param colour string The text colour to apply
166 | --- @param bg_colour string The background colour to apply
167 | --- @return table Raw inline containing OpenXML markup for PowerPoint
168 | local function highlight_openxml_pptx(span, colour, bg_colour)
169 | local spec = ''
170 | if colour ~= nil then
171 | spec = spec .. ''
172 | end
173 | if bg_colour ~= nil then
174 | spec = spec .. ''
175 | end
176 | spec = spec .. ''
177 |
178 | -- table.insert(span.content, 1, pandoc.RawInline('openxml', spec))
179 | -- table.insert(span.content, pandoc.RawInline('openxml', ''))
180 |
181 | local span_content_string = ''
182 | for i, inline in ipairs(span.content) do
183 | span_content_string = span_content_string .. pandoc.utils.stringify(inline)
184 | end
185 |
186 | return pandoc.RawInline('openxml', spec .. span_content_string .. '')
187 | end
188 |
189 | --- Applies text and background colour styling for Typst output
190 | --- @param span table The span element to modify
191 | --- @param colour string The text colour to apply
192 | --- @param bg_colour string The background colour to apply
193 | --- @return table The span content with Typst markup
194 | local function highlight_typst(span, colour, bg_colour)
195 | if colour == nil then
196 | colour_open = ''
197 | colour_close = ''
198 | else
199 | colour_open = '#text(' .. colour .. ')['
200 | colour_close = ']'
201 | end
202 |
203 | if bg_colour == nil then
204 | bg_colour_open = ''
205 | bg_colour_close = ''
206 | else
207 | bg_colour_open = '#highlight(fill: ' .. bg_colour .. ')['
208 | bg_colour_close = ']'
209 | end
210 |
211 | table.insert(
212 | span.content, 1,
213 | pandoc.RawInline('typst', colour_open .. bg_colour_open)
214 | )
215 | table.insert(
216 | span.content,
217 | pandoc.RawInline('typst', bg_colour_close .. colour_close)
218 | )
219 |
220 | return span.content
221 | end
222 |
223 | --- Main filter function that processes span elements and applies highlighting
224 | --- based on the output format and specified attributes
225 | --- @param span table The span element from the document
226 | --- @return table The modified span or span content with appropriate styling
227 | local function highlight(span)
228 | local colour = span.attributes['fg']
229 | if colour == nil then
230 | colour = span.attributes['colour']
231 | end
232 | if colour == nil then
233 | colour = span.attributes['color']
234 | end
235 |
236 | local bg_colour = span.attributes['bg']
237 | if bg_colour == nil then
238 | bg_colour = span.attributes['bg-colour']
239 | end
240 | if bg_colour == nil then
241 | bg_colour = span.attributes['bg-color']
242 | end
243 |
244 | local highlight_settings = {}
245 | if quarto.brand.has_mode('light') or quarto.brand.has_mode('dark') then
246 | local modes = {'light', 'dark'}
247 |
248 | for _, mode in ipairs(modes) do
249 | if quarto.brand.has_mode(mode) then
250 | highlight_settings[mode] = {
251 | colour = get_brand_colour(mode, colour),
252 | bg_colour = get_brand_colour(mode, bg_colour)
253 | }
254 | end
255 | end
256 | else
257 | highlight_settings.light = {
258 | colour = get_brand_colour('light', colour),
259 | bg_colour = get_brand_colour('light', bg_colour)
260 | }
261 | end
262 |
263 | if highlight_settings.light == nil and highlight_settings.dark == nil then
264 | return span
265 | end
266 |
267 | if highlight_settings.light == nil then
268 | highlight_settings.light = highlight_settings.dark
269 | end
270 |
271 | colour = highlight_settings.light.colour
272 | bg_colour = highlight_settings.light.bg_colour
273 |
274 | if colour == nil and bg_colour == nil then return span end
275 |
276 | if span.attributes['par'] == nil then
277 | par = false
278 | else
279 | par = true
280 | span.attributes['par'] = nil
281 | end
282 |
283 | if quarto.doc.is_format('html') or quarto.doc.is_format('revealjs') then
284 | return highlight_html(span, highlight_settings)
285 | elseif quarto.doc.is_format('latex') or quarto.doc.is_format('beamer') then
286 | return highlight_latex(span, colour, bg_colour, par)
287 | elseif quarto.doc.is_format('docx') then
288 | return highlight_openxml_docx(span, colour, bg_colour)
289 | elseif quarto.doc.is_format('pptx') then
290 | return highlight_openxml_pptx(span, colour, bg_colour)
291 | elseif quarto.doc.is_format('typst') then
292 | return highlight_typst(span, colour, bg_colour)
293 | else
294 | return span
295 | end
296 | end
297 |
298 | return {
299 | { Span = highlight },
300 | }
301 |
--------------------------------------------------------------------------------
/example.qmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Highlight-text Quarto Extension"
3 | format:
4 | html:
5 | output-file: index
6 | typst:
7 | output-file: highlight-typst
8 | papersize: a4
9 | margin:
10 | x: 2.5cm
11 | y: 2.5cm
12 | pdf-xelatex:
13 | output-file: highlight-xelatex
14 | papersize: a4
15 | margin:
16 | x: 2.5cm
17 | y: 2.5cm
18 | pdf-lualatex:
19 | output-file: highlight-lualatex
20 | pdf-engine: lualatex
21 | papersize: a4
22 | margin:
23 | x: 2.5cm
24 | y: 2.5cm
25 | pdf-pdflatex:
26 | output-file: highlight-pdflatex
27 | pdf-engine: lualatex
28 | papersize: a4
29 | margin:
30 | x: 2.5cm
31 | y: 2.5cm
32 | docx:
33 | output-file: highlight-docx
34 | revealjs:
35 | output-file: highlight-revealjs
36 | beamer:
37 | output-file: highlight-beamer
38 | aspectratio: 169
39 | pptx:
40 | output-file: highlight-pptx
41 | format-links:
42 | - html
43 | - typst
44 | - format: pdf-xelatex
45 | text: "PDF (XeLaTeX)"
46 | - format: pdf-lualatex
47 | text: "PDF (LuaLaTeX)"
48 | - format: pdf-pdflatex
49 | text: "PDF (PDFLaTeX)"
50 | - docx
51 | - revealjs
52 | - beamer
53 | - pptx
54 | embed-resources: true
55 | execute:
56 | echo: true
57 | filters:
58 | - highlight-text
59 | brand:
60 | light:
61 | color:
62 | palette:
63 | fg: "#ffffff"
64 | bg: "#b22222"
65 | foreground: "#333333"
66 | background: "#fafafa"
67 | dark:
68 | color:
69 | palette:
70 | fg: "#b22222"
71 | bg: "#ffffff"
72 | foreground: "#fafafa"
73 | background: "#333333"
74 | ---
75 |
76 | This is a Quarto extension that allows to highlight text in a document for various format: HTML, LaTeX, Typst, and Docx.
77 |
78 | ## Installing
79 |
80 | ```bash
81 | quarto add mcanouil/quarto-highlight-text
82 | ```
83 |
84 | This will install the extension under the `_extensions` subdirectory.
85 | If you're using version control, you will want to check in this directory.
86 |
87 | ## Using
88 |
89 | To use the extension, add the following to your document's front matter:
90 |
91 | ```yaml
92 | filters:
93 | - highlight-text
94 | ```
95 |
96 | Then you can use the span syntax markup to highlight text in your document.
97 |
98 | ```markdown
99 | [Red]{colour="#b22222" bg-colour="#abc123"} # UK
100 | [Red]{fg="#b22222" bg="#abc123"}
101 | [Blue]{color="#0000FF" bg-color="#ABC123"} # US
102 | ```
103 |
104 | ## Font Colour
105 |
106 | ```markdown
107 | [Red text]{colour="#b22222"}
108 | ```
109 |
110 | [Red text]{colour="#b22222"}
111 |
112 | ```markdown
113 | [Blue text]{color="#0000FF"}
114 | ```
115 |
116 | [Blue text]{color="#0000FF"}
117 |
118 | ## Background Colour
119 |
120 | ```markdown
121 | [Red background]{bg-colour="#b22222"}
122 | ```
123 |
124 | [Red background]{bg-colour="#b22222"}
125 |
126 | ```markdown
127 | [Blue background]{bg-color="#0000FF"}
128 | ```
129 |
130 | [Blue background]{bg-color="#0000FF"}
131 |
132 | ## Font and Background Colour
133 |
134 | ```markdown
135 | [White text, Red background]{
136 | fg="#FFFFFF" bg="#b22222"
137 | }
138 | ```
139 |
140 | [White text, Red background]{fg="#FFFFFF" bg="#b22222"}
141 |
142 | ```markdown
143 | [White text, Blue background]{
144 | colour="#FFFFFF" bg-colour="#0000FF"
145 | }
146 | ```
147 |
148 | [White text, Blue background]{colour="#FFFFFF" bg-colour="#0000FF"}
149 |
150 | ## More Examples
151 |
152 | ```markdown
153 | [text [with a link](https://quarto.org/)]{
154 | color="#FFFFFF" bg-color="#00FFFF"
155 | }
156 | ```
157 |
158 | [text [with a link](https://quarto.org/)]{
159 | color="#FFFFFF" bg-color="#00FFFF"
160 | }
161 |
162 | ## `_brand.yml`
163 |
164 | ```markdown
165 | [Light: White/Red | Dark: Red/White]{
166 | colour="brand-color.fg"
167 | bg-colour="brand-color.bg"
168 | }
169 | ```
170 |
171 | [Light: White/Red | Dark: Red/White]{colour="brand-color.fg" bg-colour="brand-color.bg"}
172 |
173 | ## Limitations `xelatex` and `pdflatex`
174 |
175 | LaTeX `\colorbox` command does not support wrapping/line breaks in the text to be highlighted.
176 | This means that the above example will not work well in LaTeX output.
177 |
178 | ```markdown
179 | [Your long text]{colour="#b22222" bg-colour="#abc123"}
180 | ```
181 | [
182 | LaTeX `\colorbox` command does not support wrapping/line breaks in the text to be highlighted.
183 | This means that the above example will not work well in LaTeX output.
184 | ]{colour="#b22222" bg-colour="#abc123"}
185 |
186 | In order to get a slightly better result, you can use the `par=true` attribute to add `\parbox{\linewidth}`:
187 |
188 | ```markdown
189 | [Your long text]{colour="#b22222" bg-colour="#abc123" par=true}
190 | ```
191 |
192 | [
193 | LaTeX `\colorbox` command does not support wrapping/line breaks in the text to be highlighted.
194 | This means that the above example will not work well in LaTeX output.
195 | ]{colour="#b22222" bg-colour="#abc123" par=true}
196 |
197 | Use `pdf-engine: lualatex` in the YAML front matter to get the best result.
198 |
--------------------------------------------------------------------------------