💾 Archived View for cadence.moe › bliz-documentation › 03-dot-bliz-scripting.bliz captured on 2023-06-14 at 14:05:28. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-08-13)

-=-=-=-=-=-=-

Bliz documentation: .bliz scripting

So far so good. You can write static files and serve them to your heart's content. What about dynamic content?

.bliz files are the killer feature of Bliz server.

They're basically gemtext

The most basic idea of a .bliz file is that you write a gemtext document, and insert a bit of dynamic content somewhere in the middle of it, without it getting in your way. In more advanced cases, you can use .bliz files to call other services, serve dynamically generated images, or anything else you can think of.

Writing a static .bliz file

% gem_header 20 text/gemini
# Demo bliz file

Hello world!

Run this demo on my server

Download source code

Don't just look at it on my server - please also copy this file into your own `serve/` so that you can play around with it yourself!

When you access this file, you should see the gemtext document rendered (without the % line displaying visually). So far so good.

Making it do something

That document is the same every time. Let's make it do something.

Starting a line with `%` in the document will execute a line of code in fish shell, inserting the output into the document at that point.

% gem_header 20 text/gemini
# Current time

The current time is...
% date

Isn't that something?

Run this demo on my server

Download source code

In this case, it runs the `date` command in the shell and adds its output into the document.

Multiple lines

Gemini lets you fence code blocks with triple backticks ``` in the document.

Bliz lets you fence executable code with triple percents %%% in the same way.

%%%
gem_header 20 text/gemini
echo '# Fenced code demo'\n
# This is a shell comment, so it won't display.
set wordle_guess (grep -E '^[a-z]{5}


 /usr/share/dict/words | shuf -n 1)
echo "You should totally use \"$wordle_guess\" as your starting guess on today's Wordle."
%%%

Don't blame me if it goes horribly, though!

Run this demo on my server

Download source code

Inline variables

Whilst not in a code block, you can interpolate a shell variable in the middle of a line.

For example, the current page you are accessing is /bliz-documentation/03-dot-bliz-scripting.bliz (that was just generated dynamically).

You can do this by writing %$variable_name. For example, in the above paragraph, I wrote %$req_path. To type %$ without activating that functionality, escape it with a backslash like \%$req_path.

Calling other programs

Fish is *awesome* for joining a couple of things together. However, if you wanted to write a huge program that, for example, proxies an HTTP service to Gemini, you might find it easier to use another programming language.

But fear not, because the shell wins again. You can natually use the shell to call whatever program you want. If you insert lines like this into your .bliz file...

% python3 personal/really_complex_program.py
% personal/some-compiled-binary # because the rust programming language has scuttled into your heart and will never let you go

...then the shell will straight away call Python to run that .py file, or will call that compiled binary directly. Isn't that lovely?

Using other shells inline

An alternative way to call other programs is to specify their input inline.

When you use a fenced %%% block, the code will be run in fish by default, but you can also use any other program. You can specify a program name after the opening %%%.

Example with Bash:

% gem_header 20 text/gemini
%%% bash
echo 'This is now running in bash.'
echo 'To prove it, the `<< END` is a "heredoc", which is bash syntax, and not valid fish syntax.'

grep -F bash << END
aaaaaaaaaaaaaa
See, this is definitely bash!
bbbbbbbbbbbbbb
END
%%%

Run this demo on my server

Download source code

Example with Python:

% gem_header 20 text/gemini
%%% python3
import sys
print("Hello from {}!".format(sys.executable))
%%%

Run this demo on my server

Download source code

Security concerns

Shell scripts have the power to do great harm. You are the one writing the shell scripts.

The only data that a user can input in the Gemini protocol is a single URL - the URL of the page they want to load.

.bliz script execution is not sandboxed, but it is unlikely that a user will be able to exploit unexpected flaws in your script using weird inputs, because they only have one input. If you do not touch the variable `$req_query`, then the script has no inputs.

For this reason, I believe that .bliz scripts that you write are exactly as safe as shell scripts that you write that take no input. I suggest that, when writing .bliz scripts, you should take the same amount of caution that you take while writing personal shell scripts, since they are exactly as capable as each other.

If you plan to do a lot of parsing on `$req_query`, there are fewer opportunities for a security mistake if you write the program in another programming language. See the next page for more information about this.

Next page: Scripting tips

Back to documentation index