Final implementation of <include> tag.
This commit is contained in:
10
.zed/debug.json
Normal file
10
.zed/debug.json
Normal file
@@ -0,0 +1,10 @@
|
||||
// Project-local debug tasks
|
||||
//
|
||||
// For more documentation on how to configure debug tasks,
|
||||
// see: https://zed.dev/docs/debugger
|
||||
[{
|
||||
"label": "Python Active File",
|
||||
"adapter": "Debugpy",
|
||||
"program": "$ZED_FILE",
|
||||
"request": "launch"
|
||||
}]
|
||||
50
.zed/tasks.json
Normal file
50
.zed/tasks.json
Normal file
@@ -0,0 +1,50 @@
|
||||
// Project tasks configuration. See https://zed.dev/docs/tasks for documentation.
|
||||
//
|
||||
// Example:
|
||||
[
|
||||
{
|
||||
"label": "Example task",
|
||||
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
|
||||
//"args": [],
|
||||
// Env overrides for the command, will be appended to the terminal's environment from the settings.
|
||||
"env": { "foo": "bar" },
|
||||
// Current working directory to spawn the command into, defaults to current project root.
|
||||
//"cwd": "/path/to/working/directory",
|
||||
// Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
|
||||
"use_new_terminal": false,
|
||||
// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
|
||||
"allow_concurrent_runs": false,
|
||||
// What to do with the terminal pane and tab, after the command was started:
|
||||
// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
|
||||
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
|
||||
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
|
||||
"reveal": "always",
|
||||
// Where to place the task's terminal item after starting the task:
|
||||
// * `dock` — in the terminal dock, "regular" terminal items' place (default)
|
||||
// * `center` — in the central pane group, "main" editor area
|
||||
"reveal_target": "dock",
|
||||
// What to do with the terminal pane and tab, after the command had finished:
|
||||
// * `never` — Do nothing when the command finishes (default)
|
||||
// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
|
||||
// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
|
||||
"hide": "never",
|
||||
// Which shell to use when running a task inside the terminal.
|
||||
// May take 3 values:
|
||||
// 1. (default) Use the system's default terminal configuration in /etc/passwd
|
||||
// "shell": "system"
|
||||
// 2. A program:
|
||||
// "shell": {
|
||||
// "program": "sh"
|
||||
// }
|
||||
// 3. A program with arguments:
|
||||
// "shell": {
|
||||
// "with_arguments": {
|
||||
// "program": "/bin/bash",
|
||||
// "args": ["--login"]
|
||||
// }
|
||||
// }
|
||||
"shell": "system",
|
||||
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
|
||||
"tags": []
|
||||
}
|
||||
]
|
||||
40
README.md
40
README.md
@@ -2,6 +2,44 @@
|
||||
|
||||
Reuse chunks of HTML in other HTML files via preprocessing.
|
||||
|
||||
Reused the chunk in `global_nav.html` via `<include src="global_nav.html" />`.
|
||||
Reuse the chunk in `global_nav.html` via `<include src="global_nav.html" />`.
|
||||
|
||||
Balloon will inflate the chunk in place of the `<include>` tag in the source file, dumping a released target file which can be pushed to the web server.
|
||||
|
||||
--
|
||||
|
||||
I do plan to migrate this project to rust once I'm finished tinkering around with the concept. I am considering adding the ability to add includes which wrap other includes.
|
||||
|
||||
This could be useful for templates, so that the base html template could look like this:
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{Inserted Var}</title>
|
||||
<meta />
|
||||
<link />
|
||||
</head>
|
||||
<body>
|
||||
{Inserted Nav Chunk}
|
||||
{Inserted Page Chunk}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
With the actual composing file, say `index.html` looking like this:
|
||||
|
||||
<!-- Without the DOCTYPE line -->
|
||||
<!DOCTYPE html>
|
||||
|
||||
<include src="templates/template.html">
|
||||
<insert id="title">Home | MySite.tld</insert>
|
||||
<insert id="chunk_nav">
|
||||
<include src="nav.html"></include>
|
||||
<h1>Welcome</h1>
|
||||
<p>lorem ipsum...</p>
|
||||
</insert>
|
||||
</include>
|
||||
|
||||
Perhaps I could do this with a custom `<insert>` tag with maybe an `id` parameter. How you would declare a variable, I'm not sure. At the very least, I'll likely have to make a proper parser to make this happen. The script is kinda hacky as it is.
|
||||
|
||||
The idea being that `<include>` in effect pulls in stuff from another file, and `<insert>` places in within something. Perhaps think of it as sewing; you stitch both sides together by pushing the pin through, and pulling it back.
|
||||
|
||||
BIN
src/__pycache__/main.cpython-313.pyc
Normal file
BIN
src/__pycache__/main.cpython-313.pyc
Normal file
Binary file not shown.
101
src/main.py
Normal file
101
src/main.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from os import setregid
|
||||
from types import NoneType
|
||||
from typing import Optional
|
||||
from result import Result, Ok, Err
|
||||
from icecream import ic
|
||||
|
||||
@dataclass
|
||||
class Tag:
|
||||
value: str
|
||||
trail: Optional[str]
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.trail = self.trail if (self.trail is not None) and (self.trail.strip() != '') else None
|
||||
|
||||
# Returns the type of tag.
|
||||
def type(self) -> str:
|
||||
type = str()
|
||||
|
||||
for c in self.value:
|
||||
if c.isspace():
|
||||
break
|
||||
|
||||
type += c
|
||||
|
||||
|
||||
return type
|
||||
|
||||
def get_param(self, param: str) -> Optional[str]:
|
||||
pos = self.value.find(param) + param.__len__() + len('="')
|
||||
|
||||
if pos == -1:
|
||||
return None
|
||||
|
||||
param_value = str()
|
||||
|
||||
for idx in range(pos, (self.value.__len__() - param.__len__())):
|
||||
param_value += self.value[idx]
|
||||
|
||||
return param_value
|
||||
|
||||
def write(self) -> str:
|
||||
return f'<{self.value}>{self.trail if self.trail != None else ''}'
|
||||
|
||||
@dataclass
|
||||
class HTML:
|
||||
value: str
|
||||
|
||||
# Returns all tags in order in the html file.
|
||||
def tags(self) -> list[Tag]:
|
||||
tag = str()
|
||||
trail: Optional[str] = str()
|
||||
tags = list()
|
||||
record = False
|
||||
|
||||
for c in self.value:
|
||||
if c == '<' and tag != '':
|
||||
tags.append(Tag(tag, trail))
|
||||
tag = str()
|
||||
trail = str()
|
||||
|
||||
if c == '<' or c == '>':
|
||||
record = not record # why can't I have ! operator...
|
||||
elif record == True:
|
||||
tag += c
|
||||
else:
|
||||
trail += c
|
||||
|
||||
tags.append(Tag(tag, trail))
|
||||
return tags
|
||||
|
||||
def inflate(self) -> Result[str, str]:
|
||||
file = str()
|
||||
|
||||
for tag in self.tags():
|
||||
if tag.type() == 'include':
|
||||
chunk = tag.get_param('src')
|
||||
if isinstance(chunk, NoneType):
|
||||
return Err('FileNotFoundError')
|
||||
|
||||
html = HTML(open(chunk, 'rt').read())
|
||||
file += html.inflate().expect('FileNotFoundError')
|
||||
else:
|
||||
file += tag.write()
|
||||
|
||||
return Ok(file)
|
||||
|
||||
# Convert the HTML obj into a str to write to file.
|
||||
def write(self) -> str:
|
||||
return self.value
|
||||
|
||||
def run() -> None:
|
||||
with open('/home/cutieguwu/Workspace/balloon/tests/src/index.html', 'rt') as f:
|
||||
html_src = HTML(f.read())
|
||||
with open('/home/cutieguwu/Workspace/balloon/target/index.html', 'w') as f:
|
||||
f.write(html_src.write())
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
@@ -2,12 +2,9 @@
|
||||
<html lang="en-ca">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Home | Cutieguwu</title>
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="img/test-favicon.jpg" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
|
||||
<meta name="description" content="Cutieguwu's Official website" />
|
||||
<meta
|
||||
name="viewport"
|
||||
@@ -16,6 +13,7 @@
|
||||
<meta name="keywords" content="cutieguwu" />
|
||||
</head>
|
||||
<body class="viewport">
|
||||
<include src="/home/cutieguwu/Workspace/balloon/tests/src/nav.html" />
|
||||
<div class="main_pane">
|
||||
<p>lorem ipsum etc idk what else there is in this latin phrase</p>
|
||||
</div>
|
||||
|
||||
@@ -1,69 +1,52 @@
|
||||
<!doctype html>
|
||||
<nav class="nav_pane">
|
||||
<h2 class="nav_logo">Cutieguwu</h2>
|
||||
|
||||
<html lang="en-ca">
|
||||
<head>
|
||||
<link rel="icon" type="image/x-icon" href="img/test-favicon.jpg" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="">
|
||||
<h2 class="nav_logo">Cutieguwu</h2>
|
||||
|
||||
<ul class="nav_menu">
|
||||
<li class="nav_body"><a class="nav_title" href="">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<p class="nav_title">Public Services</p>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="https://webcheck.cutieguwu.ca">Web Check</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<p class="nav_title">Links</p>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="https://gitea.cutieguwu.ca">Gitea</a>
|
||||
<a class="nav_title" href="https://jellyfin.cutieguwu.ca">Jellyfin</a>
|
||||
<a class="nav_title" href="https://nextcloud.cutieguwu.ca">Nextcloud</a>
|
||||
<a class="nav_title" href="https://play.cutieguwu.ca">Rebirth</a>
|
||||
<a class="nav_title" href="https://zotero.cutieguwu.ca">Zotero</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<p class="nav_title" href="#">Minecraft</p>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="#">Bearock SMP</a>
|
||||
<a class="nav_title" href="#">Rebirth SMP</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<a class="nav_title" href="https://pronouns.page/@Cutieguwu"
|
||||
>Pronoun Pages</a
|
||||
>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="https://en.pronouns.page/@Cutieguwu">English</a>
|
||||
<a class="nav_title" href="https://pronoms.fr/@Cutieguwu">French</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav_body">
|
||||
<a class="nav_title" href="#">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<script
|
||||
type="module"
|
||||
src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"
|
||||
></script>
|
||||
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
<ul class="nav_menu">
|
||||
<li class="nav_body"><a class="nav_title" href="">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<p class="nav_title">Public Services</p>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="https://webcheck.cutieguwu.ca">Web Check</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<p class="nav_title">Links</p>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="https://gitea.cutieguwu.ca">Gitea</a>
|
||||
<a class="nav_title" href="https://jellyfin.cutieguwu.ca">Jellyfin</a>
|
||||
<a class="nav_title" href="https://nextcloud.cutieguwu.ca">Nextcloud</a>
|
||||
<a class="nav_title" href="https://play.cutieguwu.ca">Rebirth</a>
|
||||
<a class="nav_title" href="https://zotero.cutieguwu.ca">Zotero</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<p class="nav_title" href="#">Minecraft</p>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="#">Bearock SMP</a>
|
||||
<a class="nav_title" href="#">Rebirth SMP</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<div class="dropdown_header nav_body">
|
||||
<a class="nav_title" href="https://pronouns.page/@Cutieguwu">Pronoun Pages</a>
|
||||
<ion-icon name="chevron-forward-outline"></ion-icon>
|
||||
</div>
|
||||
<div class="dropdown_body">
|
||||
<a class="nav_title" href="https://en.pronouns.page/@Cutieguwu">English</a>
|
||||
<a class="nav_title" href="https://pronoms.fr/@Cutieguwu">French</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav_body">
|
||||
<a class="nav_title" href="#">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
Reference in New Issue
Block a user