Open ocaisa opened 4 years ago
This comes close to working, but removes the newlines rather than replace them with \n>
...and still wouldn't work in the nested case (like {: .solution}
):
> {% capture mycode %}
{% include /snippets/ep05/in.lj %}
{% endcapture %}{{ mycode | strip_newlines }}
I got it to work but it was pretty tedious:
> {% capture mycode %}
{% include /snippets/ep05/in.lj %}
{% endcapture %}{{ mycode | strip | newline_to_br | replace: '<br />', '<br />> ' | strip_html | strip }}
For a nested blockquote that would be
{% endcapture %}{{ mycode | strip | newline_to_br | replace: '<br />', '<br />> > ' | strip_html | strip }}
If it is somehow possible to create a function for this, a numerical argument would be enough to know how many >
to insert.
What you do here is pretty smart, @ocaisa. I haven't heard of Liquid functions so what you propose might be the best one can do if they want to include code from a file in a callout box. By the way, can't one replace <br />
with >
directly?, e.g.:
{% endcapture %}{{ mycode | strip | newline_to_br | replace: '<br />', '> ' }}
Not as smart as I hoped, I hadn't noticed but it is leaving behind a >
at the end of lines that aren't simply whitespace. I guess it is actually the whitespace lines that are the problem, but this is a bit too hard to figure out, I will have to find another way
Ok, the whitespace was indeed the problem. I got it to work by creating my own liquid plugin:
# Declare module of your plugin under Jekyll module
module Jekyll::CustomFilter
# Each method of the module creates a custom Jekyll filter
def append_to_newline(input, append_string = '')
input.to_s.strip.gsub(/\n/, "\n" + append_string.to_s)
end
end
Liquid::Template.register_filter(Jekyll::CustomFilter)
which is stored in an _plugins
directory relative to the root directory. You can then use this filter with
> ```
> {% capture mycode %}
{% include /snippets/ep05/in.lj %}
{% endcapture %}{{ mycode | append_to_newline: "> " }}
> ```
> {: .code}
I would have liked to simplify this to be able to create { {% include_in_callout /snippets/ep05/in.lj 1 %}}
where 1 indicates the callout depth but I couldn't figure out how to do that (this is my first look at ruby).
If input
is an array of strings, you can do this:
# num -- "depth"
input.map { |line| "> " * num + line}.join("\n")
E.g.
%w[one two three].map{ |line| "> " * 3 + line }.join("\n")
=> "> > > one\n> > > two\n> > > three"
if input
is a string, you'd have to split it first using .split("\n")
:
"one\ntwo\nthree".split("\n").map{ |line| "> " * 3 + line }.join("\n")
=> "> > > one\n> > > two\n> > > three"
I have to note that the code you provided above didn't work for me as expected for some reason. Perhaps it has to do with double empty lines in the python code snippet that I used.
Thanks, that worked for me. For completeness I'll give my final solution. I created _plugins/custom_filters.rb
with the contents
# Declare module of your plugin under Jekyll module
module Jekyll::CustomFilter
# Each method of the module creates a custom Jekyll filter
def multiline_string_in_callout(input, levels_of_indent = 0)
input.split("\n").map{ |line| "> " * levels_of_indent + line }.join("\n")
end
end
Liquid::Template.register_filter(Jekyll::CustomFilter)
Note that for the filter to be picked up, you must restart the server (with make serve
)
I can then use the filter in my lesson with
> ```
{% capture mycode %}
{% include /snippets/ep05/in.lj %}
{% endcapture %}{{ mycode | multiline_string_in_callout: 1 }}
> ```
> {: .code}
Great job! Note, you can capture
code snippets early in the episode, e.g.
{% capture mycode %}
{% include /snippets/ep05/in.lj %}
{% endcapture %}
...
...
> ```
{{ mycode | multiline_string_in_callout: 1 }}
> ```
> {: .code}
@maxim-belkin I leave it to you to decide whether to close this or not, thanks for the help.
Thanks, @ocaisa. I'd like to keep it open for now. It might be beneficial for the community to integrate this into the main template. It'll tie us more to the Shopify Liquid so we'd have to review this carefully.
This is a never-ending story! It turns out that while I could served the site locally, it didn't pick up my plugin when I served on GitHub (or when I tried to use the remote Carpentries theme), so I had to go back and try to do it using standard filters.
I managed to get it working this time but it is very very picky about the syntax:
>
> {% capture mycode %}{% include /snippets/ep05/in.lj %}{% endcapture %}
> {% assign lines_of_code = mycode | newline_to_br | strip_newlines | split: "<br />" %}
> ~~~{% for member in lines_of_code %}
> {{ member }}{% endfor %}
> ~~~
> {: .source}
This is a never-ending story! It turns out that while I could served the site locally, it didn't pick up my plugin when I served on GitHub
Yes, GitHub works in "safe" mode and does not enable plugins. It is possible to workaround this by using GitHub Actions but your solution is nothing short of brilliant, so GitHub Actions can wait!
Great stuff!
and don't forget about using ~~~ instead of ```
Not sure if this is the right place to report this, but it doesn't seem to be possible to include code snippets in a callout (or any special blockquote), for example:
will not render correctly if
in.lj
contains multiple lines.I imagine this is because the snippet is directly inserted including the line breaks. Is there a fix for this?