💾 Archived View for cadence.moe › bliz-documentation › 04-scripting-tips.bliz captured on 2024-08-18 at 19:17:28. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2022-08-13)
-=-=-=-=-=-=-
There is a fish function available called `gem_header`. This prints a status code, a mime type, and CRLF. The Gemini protocol needs to see this at the start of each response.
Bliz will automatically add a `20` header with an appropriate mime type when a static file is accessed, but not when a .bliz file is accessed. This means your script can return any status code or mime type it wants to. This flexibility allows .bliz scripts to act as a proxy for image files and audio files, for example.
Don't forget to call `gem_header` as the first piece of output in every .bliz file you create. (If you forget to add it, your client should warn you.)
As you may have noticed on the previous page, appending ?source=1 to any .bliz file allows you to view its source code. This is a default feature, it works on your server too, and it cannot be turned off (unless you edit the Bliz source code and remove this feature).
(a manifesto)
If other people wonder how you coded a feature in your script, it's really helpful for them to be able to look at your file in order to copy segments or draw inspiration from them.
The 1995 web, from independent hobbyists with no formal HTML education, was able to thrive due to the "view page source" feature. If you visited a site and saw a feature of its presentation that you liked, you could open the page source and find out how it is done. It was a mess, and it was a helpful beautiful inspirational mess.
With server-side scripting, the ability to learn and draw from other people's work is diminished, since you never normally get to see the code that would be executed, meaning you can't draw from it in your own work.
The hope of Bliz's ?source=1 parameter is to bring back a world of sharing techniques and learning from each other.
For example, if somebody wants to add a customised dynamic sitemap, they don't have to start from scratch - they can open the source code of my sitemap, copy it, tear it apart, learn from it, and create something new with half the effort.
Sometimes you want to use a file in your scripts that actually shouldn't be public. Something like a database, a list of passwords, whatever. I understand. I do this too.
A great place to store that file is in Bliz's `personal/` directory, which is just outside of `serve/`. Since there files are outside of `serve/`, nobody will be able to access them directly, but you'll still be able to use them in your scripts.
For example, the `bliz_hits` built-in function opens a database which is located in `personal/`.
You can open `src/script-includes.fish` to see a list of built-in functions and variables. These are available for use in any .bliz script.
In addition to those built-ins that come with Bliz, you can write your own functions and variables to always be included by simply adding them to `personal/script-includes.fish`.
These are fish functions, so you can call them in a multitude of ways.
One simple way is after % on a line:
Or you can use them any way you want in a fish script. Here is just one example:
Usage: bliz_word_count
This counts the number of words in the current .bliz script. Executable code with % or %%% is not counted. You can use this to add an automatically calculated word count to gemlog articles.
Usage: bliz_paragraph_count
This counts the number of paragraphs in the current .bliz script, excluding special lines (i.e. headers, links, and code). Paragraphs are considered to be separated by two newlines.
Usage: bliz_hits
This registers a "hit" for the current path, then returns the all-time total number of hits to that path.
Hits are stored in `personal/hits.db`.
Be sure to only include this once on each page.
Usage: gemlog_intro_meta
This generates an introduction section to a gemlog article containing metadata about that article.
You can see this in use on my personal gemlog.
This is the path to the currently executing .bliz file on disk.
This is the absolute URL that the visitor is requesting.
This is the query string of the URL after the question mark. No additional processing has been performed on it yet.
If you have a script that needs to take simple input data, you can use a URL like:
/document?hello
and $req_query will contain:
hello
If you have a script that needs to take a string with special characters, you can un-percent-encode the query string like so:
string unescape --style=url -- $req_query
If you have a script that needs to take key=value pairs, the value for key FOO is stored in variable $req_query_FOO. Only variables matching `^[a-z_]+
%%% gem_header 20 text/gemini set query_names (set -n | string replace -rf '^req_query_' '') if test -n "$query_names" echo 'Found these query parameters:' (string join ', ' -- $query_names) else echo 'No query parameters found' end %%% In particular, a = "%$req_query_a" b = "%$req_query_b"
Render this demo with ?a=1+2&b=hello%20world
However, please do note that you are now *handling potentially malicious data in a shell script, of all things.* I think this code is good, but any bugs you write could have catastrophic consequences. If you want to be really safe against malicious input, consider writing the thing in an actual programming language.
% node personal/do-the-thing.js -- "$req_query"
and then...
const params = new URLSearchParams(process.argv[2]) const whatever = params.get("some-key")
There is a little-known URL "feature" called path parameters or matrix parameters, where there's a semicolon in the URL, and it's sort of like a query string but associated with a particular path element. Like query strings, they don't contribute to the path of the file. They just convey extra information to the server.
Read more about them on StackOverflow.
You probably don't need them, but Bliz has them anyway! Note that because fish variables are just lists and can't store highly structured data, Bliz tells you the values of the path parameters but doesn't tell you which path element they're associated with.
%%% gem_header 20 text/gemini set param_names (set -n | string replace -rf '^req_path_' '') if test -n "$param_names" echo 'Found these path parameters:' (string join ', ' -- $param_names) else echo 'No path parameters found' end %%% In particular, a = "%$req_path_a" b = "%$req_path_b" req_path doesn't have path parameters: "%$req_path" but req_pathparams does have them: "%$req_pathparams"
Visit this demo at demos/path-parameters-keys-values.bliz;a=1+2&b=hello%20world
Visit this demo at demos;a=foo;b=bar/path-parameters-keys-values.bliz;b=baz
You might find these useful in Bliz for storing state in the URL without having to worry about the 10 INPUT status code overwriting that data.
%%% set required name pronouns message for key in $required if not set -q req_path_$key if test $req_query gem_header 30 "$req_pathparams;$key=$req_query" else gem_header 10 "Please enter your $key" end exit end end gem_header 20 text/gemini %%% This is a preview of your comment: > %$req_path_message > - %$req_path_name [%$req_path_pronouns]