Create Two Versions of a Document - tex

I am using quarto to create a lesson with lots of mixed in tex. I want two version of this lesson -- one with answers and one without the answers -- in the same document to avoid trying to keep the two files consistent. What is the easiest way to do this?
I tried
::: {.content-visible XXX}
Will only appear in HTML.
:::
but that only seems to be working if I want to change the document output format. I want it to toggle with just a TRUE or FALSE value. I also tried
```{r, eval = showText, echo = TRUE, output = "asis"}
The probability that $n^2$ items happy is `dpois(n, 1)`.
```
However, this gives me the error
Error: unexpected symbol in "The probability"
Furthermore, it doesn't render the latex $n^2$
UPDATE: I tried the Lua filter approach without success.
---
title: "Conditional Content"
format: pdf
editor: visual
hide-answer: false
filters:
- hide-answer.lua
---
## Answer Test
- This is a list
- This $n^2$ works
- This is another element
- **Question:** What is my name?
::: answer
- Why is this $n^2$ failing?
:::
- Continuation

You can use Lua filter to create an option which if true, will remove all the contents within answer divs.
---
title: Conditional content
format: pdf
hide-answer: true
filters:
- hide-answer.lua
---
## Part 01
**Question 01: What is the probability that .... ?**
::: answer
The probability that $n^2$ items happy is `dpois(n, 1)`.
:::
hide-answer.lua
function answer()
return {
Div = function(el)
if el.classes:includes('answer') then
return pandoc.Null()
else
return el
end
end
}
end
function Pandoc(doc)
local meta = doc.meta
local hide = meta['hide-answer']
if hide then
return doc:walk(answer())
end
end
output when hide-answer: true,
output when hide-answer: false,

I’m trying to do the same at the moment and am exploring the use of profiles. https://quarto.org/docs/projects/profiles.html
I’d love to give a more complete answer, but just wanted to share that. I’m creating a profile for student (without answers) and TA (with answers).
If any experts have further advice, please feel free!
Best wishes!

Related

Nesting extra Span in Pandoc filter disappears the image

I am currently working on massaging the HTML output of a Pandoc filter due to some annoying restrictions in the CMS that is the eventual beneficiary of my hard work.
My working filter (now with the obvious declarations) is as follows:
local List = require 'pandoc.List'
local Emph = pandoc.Emph
local Quoted = pandoc.Quoted
local Span = pandoc.Span
local Str = pandoc.Str
local Strong = pandoc.Strong
local image_base = "http://my.website.example/images/"
local image_author = "Someone Not Stigma"
function process_images(el)
el.src = el.src:gsub("^file:images/", image_base)
el.caption = {
Strong( Quoted( "DoubleQuote", el.caption ) ),
Str(" by "),
Emph(image_author)
}
return el
end
return {{Image = process_images}}
In the eventual HTML, this gives me a nice figure with img and figcaption element inside of it. Wonderful. Unfortunately, my CMS destroys the figcaption (like it tends to destroy other stuff), and as such I figured I'd wrap everything in an extra span so I can style that one instead.
function process_images(el)
el.src = el.src:gsub("^file:images/", image_base)
el.caption = {
Span(
{
Strong( Quoted( "DoubleQuote", el.caption ) ),
Str(" by "),
Emph(image_author)
},
{ class="img-caption" }
)
}
return el
end
And yet somehow, this causes Pandoc to completely delete the image from the resulting HTML.
I have tried replacing the table syntaxes with List({}) syntaxes, but that just gives me upvalue complaints. I looked at the manual, but for as far I can tell I am doing everything right.
What am I missing here?
I call pandoc as follows:
pandoc --from=markdown-tex_math_dollars "Content.pure.txt" --lua-filter=".\pandoc-filter.lua" --to=html5 --template=".\pandoc-template.txt" -o "Content.txt"
Extensions are .txt (because these files are not browser ready). The template being used is rather lengthy (there's a fair bit of YAML variables and related markup), but be assured: $body$ can be found in there.
I am not a wise man. Always update to the latest version before posting questions, folks.
I was running an older version of Pandoc (v2.6), and upgrading to v2.9.1.1 suddenly made the output appear again. That's a lot of versions released in the span of about a year!
(In my defense, my Pandoc-filter-fu is not particularly strong, so it makes sense to assume user error rather than program bug. Why is it that every time you assume bug, it is user error, and every time you assume user error, it is an outright bug?)

Highlight one specific author when generating references in Pandoc

I am using Pandoc to generate a list of publications for my website. I'm using it solely to generate the html with the publications so that I can then paste the raw html in jekyll. This part works fine.
The complications arise when I tty to generate the html so that my name appears boldfaced in all entries. I'm trying to use this solution for that, which works when I apply it to a pure Latex document I am generating. However when I try to apply the same Pandoc, the html is generated without any boldface.
Here's my Pandoc file:
---
bibliography: /home/tomas/Dropbox/cv/makerefen4/selectedpubs.bib
nocite: '#'
linestretch: 1.5
fontsize: 12pt
header-includes: |
\usepackage[
backend=biber,
dashed=false,
style=authoryear-icomp,
natbib=true,
url=false,
doi=true,
eprint=false,
sorting=ydnt, %Year (Descending) Name Title
maxbibnames=99
]{biblatex}
\renewcommand{\mkbibnamegiven}[1]{%
\ifitemannotation{highlight}
{\textbf{#1}}
{#1}}
\renewcommand*{\mkbibnamefamily}[1]{%
\ifitemannotation{highlight}
{\textbf{#1}}
{#1}}
...
And here's the relevant part of my Makefile:
PANDOC_OPTIONS=--columns=80
PANDOC_HTML_OPTIONS=--filter=pandoc-citeproc --csl=els-modified.csl --biblatex
Again: this code generates the references fine. It just doesn't boldface anything as it is supposed to.
Any ideas?
EDIT
Bib entries look like this
#MISC{test,
AUTHOR = {Last1, First1 and Last2, First2 and Last3, First3},
AUTHOR+an = {2=highlight},
}
And versions are
- Biblatex 3.12
- Biber 2.12
You can use a lua filter to modify the AST. The following works for me to get the surname and initials (Smith, J.) highlighted in the references (see here). You can replace pandoc.Strong with pandoc.Underline or pandoc.Emph. Replace Smith and J. with your name/initials, save it as myname.lua and use something like:
pandoc --citeproc --bibliography=mybib.bib --csl.mycsl.csl --lua-filter=myname.lua -o refs.html refs.md
i.e. put the filter last.
local highlight_author_filter = {
Para = function(el)
if el.t == "Para" then
for k,_ in ipairs(el.content) do
if el.content[k].t == "Str" and el.content[k].text == "Smith,"
and el.content[k+1].t == "Space"
and el.content[k+2].t == "Str" and el.content[k+2].text:find("^J.") then
local _,e = el.content[k+2].text:find("^J.")
local rest = el.content[k+2].text:sub(e+1)
el.content[k] = pandoc.Strong { pandoc.Str("Smith, J.") }
el.content[k+1] = pandoc.Str(rest)
table.remove(el.content, k+2)
end
end
end
return el
end
}
function Div (div)
if 'refs' == div.identifier then
return pandoc.walk_block(div, highlight_author_filter)
end
return nil
end
Notes:
The above works if you use an author-date format csl. If you want to use a numeric format csl (e.g. ieee.csl or nature.csl) you will need to substitute Span for Para in the filter, i.e.:
Span = function(el)
if el.t == "Span" then
If you also want to use the multiple-bibliographies lua filter, it should go before the author highlight filter. And 'refs' should be 'refs_biblio1' or 'refs_biblio2' etc, depending on how you have defined them:
function Div (div)
if 'refs' or 'refs_biblio1’ or 'refs_biblio2’ == div.identifier then
For pdf output, you will also need to add -V csl-refs in the pandoc command if you use a numeric format csl.
The filter highlights Smith, J. if formated in this order by the csl. Some csl will use this format for the first author and then switch to J. Smith for the rest, so you will have to adjust the filter accordingly adding an extra if el.content[k].t == "Str”…etc. Converting to .json first will help to check the correct formatting in the AST.

How to use LaTeX section numbers in Pandoc cross-reference

The Pandoc documentation says that cross references can be made to section headers in a number of ways. For example, you can create your own ID and reference that ID. For example:
# This is my header {#header}
Will create an ID with value '#header' that can be refenced in the text, as such:
[Link to header](#header)
Which will display the text 'Link to header' with a link to the header.
I couldn't find anywhere how to make the text of the link be the section number when compiled as a LaTeX document.
For example, if my header is compiled to '1.2.3 Section Header', I want my cross-reference to text to display as '1.2.3'.
This can be achieved by defining the ID as done previously. eg:
# This is my header {#header}
Then in the text, the cross reference can be written as:
\ref{header}
When this compiles to LaTeX, the cross-reference text will be the section number of the referenced heading.
You can use the pandoc-secnos filter, which is part of the pandoc-xnos filter suite.
The header
# This is my header {#sec:header}
is referenced using #sec:header. Alternatively, you can reference
# This is my header
using #sec:this-is-my-header.
Markdown documents coded in this way can be processed by adding --filter pandoc-secnos to the pandoc call. The --number-sections option should be used as well. The output uses LaTeX's native commands (i.e., \label and \ref or \cref).
The benefit to this approach is that output in other formats (html, epub, docx, ...) is also possible.
A general solution which works with all supported output formats can be build by leveraging pandoc Lua filters: The function pandoc.utils.hierarchicalize can be used to get the document hierarchy. We can use this to associate section IDs with section numbers, which can later be used to add these numbers to links with no link description (e.g., [](#myheader)).
local hierarchicalize = (require 'pandoc.utils').hierarchicalize
local section_numbers = {}
function populate_section_numbers (doc)
function populate (elements)
for _, el in pairs(elements) do
if el.t == 'Sec' then
section_numbers['#' .. el.attr.identifier] = table.concat(el.numbering, '.')
populate(el.contents)
end
end
end
populate(hierarchicalize(doc.blocks))
end
function resolve_section_ref (link)
if #link.content > 0 or link.target:sub(1, 1) ~= '#' then
return nil
end
local section_number = pandoc.Str(section_numbers[link.target])
return pandoc.Link({section_number}, link.target, link.title, link.attr)
end
return {
{Pandoc = populate_section_numbers},
{Link = resolve_section_ref}
}
The above should be saved to a file and then passed to pandoc via the --lua-filter option.
Example
Using the example from the question
# This is my header {#header}
## Some subsection
See section [](#header), especially [](#some-subsection)
Using the above filter, the last line will render as "See section 1, especially 1.1".
Don't forget to call pandoc with option --number-sections, or headers will not be numbered.
Since pandoc version 2.8 the function pandoc.utils.hierarchicalize has been replaced with make_sections. Here is an updated version of the #tarleb's answer which works with newer ´pandoc´ versions.
local make_sections = (require 'pandoc.utils').make_sections
local section_numbers = {}
function populate_section_numbers (doc)
function populate (elements)
for _, el in pairs(elements) do
if el.t == 'Div' and el.attributes.number then
section_numbers['#' .. el.attr.identifier] = el.attributes.number
populate(el.content)
end
end
end
populate(make_sections(true, nil, doc.blocks))
end
function resolve_section_ref (link)
if #link.content > 0 or link.target:sub(1, 1) ~= '#' then
return nil
end
local section_number = pandoc.Str(section_numbers[link.target])
return pandoc.Link({section_number}, link.target, link.title, link.attr)
end
return {
{Pandoc = populate_section_numbers},
{Link = resolve_section_ref}
}

Nokogiri/Ruby array question

I have a quick question. I am currently writing a Nokogiri/Ruby script and have the following code:
fullId = doc.xpath("/success/data/annotatorResultBean/annotations/annotationBean/concept/fullId")
fullId.each do |e|
e = e.to_s()
g.write(e + "\n")
end
This spits out the following text:
<fullId>D001792</fullId>
<fullId>D001792</fullId>
<fullId>D001792</fullId>
<fullId>D008715</fullId>
I wanted the just the numbers text in between the "< fullid>" saved, without the < fullId>,< /fullId> markup. What am I missing?
Bobby
I think you want to use the text() accessor (which returns the child text values), rather than to_s() (which serializes the entire node, as you see here).
I'm not sure what the g object you're calling write on is, but the following code should give you an array containing all of the text in the fullId nodes:
doc.xpath(your_xpath).map {|e| e.text}

Truncate Markdown?

I have a Rails site, where the content is written in markdown. I wish to display a snippet of each, with a "Read more.." link.
How do I go about this? Simple truncating the raw text will not work, for example..
>> "This is an [example](http://example.com)"[0..25]
=> "This is an [example](http:"
Ideally I want to allow the author to (optionally) insert a marker to specify what to use as the "snippet", if not it would take 250 words, and append "..." - for example..
This article is an example of something or other.
This segment will be used as the snippet on the index page.
^^^^^^^^^^^^^^^
This text will be visible once clicking the "Read more.." link
The marker could be thought of like an EOF marker (which can be ignored when displaying the full document)
I am using maruku for the Markdown processing (RedCloth is very biased towards Textile, BlueCloth is extremely buggy, and I wanted a native-Ruby parser which ruled out peg-markdown and RDiscount)
Alternatively (since the Markdown is translated to HTML anyway) truncating the HTML correctly would be an option - although it would be preferable to not markdown() the entire document, just to get the first few lines.
So, the options I can think of are (in order of preference)..
Add a "truncate" option to the maruku parser, which will only parse the first x words, or till the "excerpt" marker.
Write/find a parser-agnostic Markdown truncate'r
Write/find an intelligent HTML truncating function
Write/find an intelligent HTML truncating function
The following from http://mikeburnscoder.wordpress.com/2006/11/11/truncating-html-in-ruby/, with some modifications will correctly truncate HTML, and easily allow appending a string before the closing tags.
>> puts "<p><b>Something</p>".truncate_html(5, at_end = "...")
=> <p><b>Someth...</b></p>
The modified code:
require 'rexml/parsers/pullparser'
class String
def truncate_html(len = 30, at_end = nil)
p = REXML::Parsers::PullParser.new(self)
tags = []
new_len = len
results = ''
while p.has_next? && new_len > 0
p_e = p.pull
case p_e.event_type
when :start_element
tags.push p_e[0]
results << "<#{tags.last}#{attrs_to_s(p_e[1])}>"
when :end_element
results << "</#{tags.pop}>"
when :text
results << p_e[0][0..new_len]
new_len -= p_e[0].length
else
results << "<!-- #{p_e.inspect} -->"
end
end
if at_end
results << "..."
end
tags.reverse.each do |tag|
results << "</#{tag}>"
end
results
end
private
def attrs_to_s(attrs)
if attrs.empty?
''
else
' ' + attrs.to_a.map { |attr| %{#{attr[0]}="#{attr[1]}"} }.join(' ')
end
end
end
Here's a solution that works for me with Textile.
Convert it to HTML
Truncate it.
Remove any HTML tags that got cut in half with
html_string.gsub(/<[^>]*$/, "")
Then, uses Hpricot to clean it up and close unclosed tags
html_string = Hpricot( html_string ).to_s
I do this in a helper, and with caching there's no performance issue.
You could use a regular expression to find a line consisting of nothing but "^" characters:
markdown_string = <<-eos
This article is an example of something or other.
This segment will be used as the snippet on the index page.
^^^^^^^^^^^^^^^
This text will be visible once clicking the "Read more.." link
eos
preview = markdown_string[0...(markdown_string =~ /^\^+$/)]
puts preview
Rather than trying to truncate the text, why not have 2 input boxes, one for the "opening blurb" and one for the main "guts". That way your authors will know exactly what is being show when without having to rely on some sort of funkly EOF marker.
I will have to agree with the "two inputs" approach, and the content writer would need not to worry, since you can modify the background logic to mix the two inputs in one when showing the full content.
full_content = input1 + input2 // perhaps with some complementary html, for a better formatting
Not sure if it applies to this case, but adding the solution below for the sake of completeness. You can use strip_tags method if you are truncating Markdown-rendered contents:
truncate(strip_tags(markdown(article.contents)), length: 50)
Sourced from:
http://devblog.boonecommunitynetwork.com/rails-and-markdown/
A simpler option that just works:
truncate(markdown(item.description), length: 100, escape: false)

Resources