t-doc-common 0.4.dev1__tar.gz → 0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.gitignore +1 -3
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.hgignore +1 -3
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.hgtags +2 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/PKG-INFO +1 -1
- t_doc_common-0.5/docs/demo/index.md +11 -0
- t_doc_common-0.5/docs/demo/people.sql +11 -0
- t_doc_common-0.5/docs/demo/sql.md +113 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/docs/development.md +48 -0
- t_doc_common-0.5/docs/edit.md +106 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/docs/index.md +2 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/docs/install.md +70 -4
- t_doc_common-0.5/serve.bat +2 -0
- t_doc_common-0.5/serve.desktop +10 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/tdoc/common/__init__.py +63 -7
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/tdoc/common/cli.py +1 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/tdoc/common/defaults.py +7 -0
- t_doc_common-0.5/tdoc/common/static/styles/t-doc.css +100 -0
- t_doc_common-0.5/tdoc/common/static/tdoc-sql.js +173 -0
- t_doc_common-0.4.dev1/tdoc/common/common.mk +0 -52
- t_doc_common-0.4.dev1/tdoc/common/static/styles/t-doc.css +0 -22
- t_doc_common-0.4.dev1/tdoc/common/static/tdoc-sql.js +0 -141
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.github/workflows/deploy-github-pages.yml +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.github/workflows/publish.yml +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.gitmodules +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.hgsub +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/.hgsubstate +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/LICENSE.txt +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/README.md +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/docs/conf.py +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/.gitignore +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/.prettierrc +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/README.md +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/bin/index.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/index.html +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/main-thread.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/module-workers-polyfill.min.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/script.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/worker.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/wrapped-worker.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/index.d.ts +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/index.mjs +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/package-lock.json +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/package.json +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-bundler-friendly.mjs +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-node.mjs +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-opfs-async-proxy.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-worker1-bundler-friendly.mjs +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-worker1-promiser.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-worker1-promiser.mjs +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-worker1.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.js +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.mjs +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.wasm +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/pyproject.toml +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/tdoc/common/components/copyright.html +0 -0
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/tdoc/common/theme.toml +1 -1
- {t_doc_common-0.4.dev1 → t_doc_common-0.5}/tdoc/common/util.py +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
create table people (
|
|
2
|
+
first_name text not null,
|
|
3
|
+
last_name text not null,
|
|
4
|
+
height real,
|
|
5
|
+
favorite_food text
|
|
6
|
+
);
|
|
7
|
+
insert into people values
|
|
8
|
+
('Joe', 'Bar', 1.83, null),
|
|
9
|
+
('Jack', 'Smith', 1.55, 'burgers'),
|
|
10
|
+
('Jim', 'Davis', null, 'pizza'),
|
|
11
|
+
('Anthony', 'Miller', 1.78, null);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!-- Copyright 2024 Caroline Blank <caro@c-space.org> -->
|
|
2
|
+
<!-- Copyright 2024 Remy Blank <remy@c-space.org> -->
|
|
3
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
4
|
+
|
|
5
|
+
# SQL
|
|
6
|
+
|
|
7
|
+
The `{exec} sql` block allows executing SQL directly in the browser. Each block
|
|
8
|
+
is executed in a new, empty database.
|
|
9
|
+
|
|
10
|
+
## Directive
|
|
11
|
+
|
|
12
|
+
````{rst:directive} .. {exec}:: language (sql)
|
|
13
|
+
This directive is a `{code-block}` that allows executing the code directly in
|
|
14
|
+
the browser. It supports all the options of `{code-block}`, and a few more
|
|
15
|
+
described below.
|
|
16
|
+
|
|
17
|
+
{.rubric}
|
|
18
|
+
Options
|
|
19
|
+
```{rst:directive:option} after: name
|
|
20
|
+
:type: text
|
|
21
|
+
References an `{exec}` block to be executed before this block, in the same
|
|
22
|
+
environment. The referenced block can itself have an `:after:` option, forming
|
|
23
|
+
a chain of blocks to execute in the environment.
|
|
24
|
+
```
|
|
25
|
+
```{rst:directive:option} when: value
|
|
26
|
+
:type: click | load | never
|
|
27
|
+
Determines when the block's code is executed: on a click by the user (`click`),
|
|
28
|
+
when the page loads (`load`) or not at all (`never`).
|
|
29
|
+
```
|
|
30
|
+
````
|
|
31
|
+
|
|
32
|
+
## Database definition
|
|
33
|
+
|
|
34
|
+
A database can be defined as a named `{exec} sql` block, to be referenced in the
|
|
35
|
+
`:after:` option of other blocks.
|
|
36
|
+
|
|
37
|
+
```{exec} sql
|
|
38
|
+
:name: sql-countries
|
|
39
|
+
:when: never
|
|
40
|
+
create table countries (
|
|
41
|
+
country text not null,
|
|
42
|
+
country_code text not null,
|
|
43
|
+
dial_code text not null,
|
|
44
|
+
capital text not null,
|
|
45
|
+
population int not null,
|
|
46
|
+
food text
|
|
47
|
+
);
|
|
48
|
+
insert into countries values
|
|
49
|
+
('Switzerland', 'CH', '+41', 'Bern', 8776000, 'fondue!'),
|
|
50
|
+
('France', 'FR', '+33', 'Paris', 67970000, null),
|
|
51
|
+
('Germany', 'DE', '+49', 'Berlin', 83800000, null),
|
|
52
|
+
('Italy', 'IT', '+39', 'Rome', 58940000, null),
|
|
53
|
+
('Austria', 'AT', '+43', 'Vienna', 9042000, 'Kaiserschmarrn'),
|
|
54
|
+
('Lichtenstein', 'LI', '+423', 'Vaduz', 39327, null);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Queries
|
|
58
|
+
|
|
59
|
+
The results of the first `select` statement in an `{exec} sql` block are
|
|
60
|
+
displayed as a table.
|
|
61
|
+
|
|
62
|
+
```{exec} sql
|
|
63
|
+
:after: sql-countries
|
|
64
|
+
:when: load
|
|
65
|
+
select * from countries;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The SQL code can be hidden by adding `:class: hidden`.
|
|
69
|
+
|
|
70
|
+
```{exec} sql
|
|
71
|
+
:after: sql-countries
|
|
72
|
+
:when: load
|
|
73
|
+
:class: hidden
|
|
74
|
+
select * from countries where country_code = 'CH';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Empty results
|
|
78
|
+
|
|
79
|
+
```{exec} sql
|
|
80
|
+
:after: sql-countries
|
|
81
|
+
:when: load
|
|
82
|
+
select * from countries where false;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Mutations
|
|
86
|
+
|
|
87
|
+
```{exec} sql
|
|
88
|
+
:after: sql-countries
|
|
89
|
+
:when: load
|
|
90
|
+
update countries set food = 'baguette' where country_code = 'FR';
|
|
91
|
+
select * from countries where country_code = 'FR';
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## SQL errors
|
|
95
|
+
|
|
96
|
+
```{exec} sql
|
|
97
|
+
:when: load
|
|
98
|
+
select * from unknown_table;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Execution trigger
|
|
102
|
+
|
|
103
|
+
By default, `{exec} sql` blocks are executed on click (`:when: click`), with
|
|
104
|
+
controls displayed next to the block.
|
|
105
|
+
|
|
106
|
+
```{exec} sql
|
|
107
|
+
:after: sql-countries
|
|
108
|
+
select * from countries where country_code = 'LI';
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
They can also be executed immediately on load (`:when: load`) or not at all
|
|
112
|
+
(`:when: never`, useful for database definitions that are referenced by other
|
|
113
|
+
blocks). In these cases, no controls aren displayed.
|
|
@@ -4,45 +4,93 @@
|
|
|
4
4
|
|
|
5
5
|
# Development
|
|
6
6
|
|
|
7
|
+
This page describes how to set up t-doc for development. It isn't necessary for
|
|
8
|
+
creating and editing documents.
|
|
9
|
+
|
|
7
10
|
## Install
|
|
8
11
|
|
|
9
12
|
- Install the [required packages](install.md#requirements) for your system.
|
|
10
13
|
|
|
11
14
|
- Clone the `t-doc/common` repository (substitute `USER` with your username).
|
|
15
|
+
|
|
12
16
|
```{code-block} shell-session
|
|
13
17
|
hg clone https://USER@c-space.net/rc/hg/t-doc/common
|
|
14
18
|
cd common
|
|
15
19
|
```
|
|
16
20
|
|
|
17
21
|
- Enable git subrepositories.
|
|
22
|
+
|
|
18
23
|
```{code-block} shell-session
|
|
19
24
|
echo -e '[subrepos]\ngit:allowed = true\n' >> .hg/hgrc
|
|
20
25
|
```
|
|
21
26
|
|
|
22
27
|
- Checkout the subrepositories and activate the `main` bookmark.
|
|
28
|
+
|
|
23
29
|
```{code-block} shell-session
|
|
24
30
|
hg checkout main
|
|
25
31
|
```
|
|
26
32
|
|
|
27
33
|
- Install the `t-doc-common` package from editable sources.
|
|
34
|
+
|
|
35
|
+
`````{tab-set}
|
|
36
|
+
:sync-group: platform
|
|
37
|
+
````{tab-item} Windows
|
|
38
|
+
:sync: windows
|
|
39
|
+
```{code-block} shell-session
|
|
40
|
+
python -m pip install --editable .
|
|
41
|
+
```
|
|
42
|
+
````
|
|
43
|
+
````{tab-item} macOS
|
|
44
|
+
:sync: macos
|
|
45
|
+
```{code-block} shell-session
|
|
46
|
+
python -m pip install --user --editable .
|
|
47
|
+
```
|
|
48
|
+
You may have to add `$HOME/.local/bin` to your `PATH`.
|
|
49
|
+
````
|
|
50
|
+
````{tab-item} Linux
|
|
51
|
+
:sync: linux
|
|
28
52
|
```{code-block} shell-session
|
|
29
53
|
python -m pip install --user --editable .
|
|
30
54
|
```
|
|
55
|
+
You may have to add `$HOME/.local/bin` to your `PATH`.
|
|
56
|
+
````
|
|
57
|
+
`````
|
|
31
58
|
|
|
32
59
|
## Upgrade
|
|
33
60
|
|
|
34
61
|
- Pull missing changesets from the `t-doc/common` repository.
|
|
62
|
+
|
|
35
63
|
```{code-block} shell-session
|
|
36
64
|
cd common
|
|
37
65
|
hg pull
|
|
38
66
|
```
|
|
39
67
|
|
|
40
68
|
- Update to the branch head.
|
|
69
|
+
|
|
41
70
|
```{code-block} shell-session
|
|
42
71
|
hg update --check
|
|
43
72
|
```
|
|
44
73
|
|
|
45
74
|
- Upgrade the `t-doc-common` package metadata and any out-of-date dependencies.
|
|
75
|
+
|
|
76
|
+
`````{tab-set}
|
|
77
|
+
:sync-group: platform
|
|
78
|
+
````{tab-item} Windows
|
|
79
|
+
:sync: windows
|
|
80
|
+
```{code-block} shell-session
|
|
81
|
+
python -m pip install --upgrade --editable .
|
|
82
|
+
```
|
|
83
|
+
````
|
|
84
|
+
````{tab-item} macOS
|
|
85
|
+
:sync: macos
|
|
86
|
+
```{code-block} shell-session
|
|
87
|
+
python -m pip install --user --upgrade --editable .
|
|
88
|
+
```
|
|
89
|
+
````
|
|
90
|
+
````{tab-item} Linux
|
|
91
|
+
:sync: linux
|
|
46
92
|
```{code-block} shell-session
|
|
47
93
|
python -m pip install --user --upgrade --editable .
|
|
48
94
|
```
|
|
95
|
+
````
|
|
96
|
+
`````
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!-- Copyright 2024 Caroline Blank <caro@c-space.org> -->
|
|
2
|
+
<!-- Copyright 2024 Remy Blank <remy@c-space.org> -->
|
|
3
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
4
|
+
|
|
5
|
+
# Create & edit documents
|
|
6
|
+
|
|
7
|
+
## Check out a repository
|
|
8
|
+
|
|
9
|
+
Documents are grouped into **repositories**, which represent the unit of
|
|
10
|
+
deployment. Each document repository is tracked as a Mercurial repository. A
|
|
11
|
+
repository can be checked out with (substitute `USER` with your username, and
|
|
12
|
+
`REPO` with the name of the repository):
|
|
13
|
+
|
|
14
|
+
```{code-block} shell-session
|
|
15
|
+
hg checkout https://USER@c-space.net/rc/hg/t-doc/REPO
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The typical structure of a document repository is shown below. The source files
|
|
19
|
+
are located below the `docs` directory.
|
|
20
|
+
|
|
21
|
+
```{code-block}
|
|
22
|
+
:class: line-height-normal
|
|
23
|
+
├── .github
|
|
24
|
+
│ └── workflows
|
|
25
|
+
│ └── publish.yml A workflow to publish the repository
|
|
26
|
+
├── docs
|
|
27
|
+
│ ├── conf.py The Sphinx configuration
|
|
28
|
+
│ ├── index.md The main index page
|
|
29
|
+
│ └── ... The source documents
|
|
30
|
+
├── .gitignore
|
|
31
|
+
├── .hgignore
|
|
32
|
+
├── LICENSE.txt
|
|
33
|
+
├── README.md
|
|
34
|
+
├── serve.bat A script to run the local server on Windows
|
|
35
|
+
└── serve.desktop A desktop entry to run the local server on Linux
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Edit documents
|
|
39
|
+
|
|
40
|
+
- **Run the local server.**
|
|
41
|
+
|
|
42
|
+
`````{tab-set}
|
|
43
|
+
:sync-group: platform
|
|
44
|
+
````{tab-item} Windows
|
|
45
|
+
:sync: windows
|
|
46
|
+
Double-click the file `serve.bat` in the repository directory.
|
|
47
|
+
````
|
|
48
|
+
````{tab-item} macOS
|
|
49
|
+
:sync: macos
|
|
50
|
+
Open a terminal, change to the repository directory, and run:
|
|
51
|
+
```{code-block} shell-session
|
|
52
|
+
tdoc serve
|
|
53
|
+
```
|
|
54
|
+
````
|
|
55
|
+
````{tab-item} Linux
|
|
56
|
+
:sync: linux
|
|
57
|
+
Double-click the file `serve.desktop` in the repository directory.
|
|
58
|
+
|
|
59
|
+
Alternatively, open a terminal, change to the repository directory, and run:
|
|
60
|
+
```{code-block} shell-session
|
|
61
|
+
tdoc serve
|
|
62
|
+
```
|
|
63
|
+
````
|
|
64
|
+
`````
|
|
65
|
+
|
|
66
|
+
The server renders the source files into HTML, and serves the result over
|
|
67
|
+
HTTP.
|
|
68
|
+
|
|
69
|
+
```{code-block} text
|
|
70
|
+
Running Sphinx v8.0.2
|
|
71
|
+
loading translations [fr]... done
|
|
72
|
+
making output directory... done
|
|
73
|
+
(...)
|
|
74
|
+
build succeeded.
|
|
75
|
+
|
|
76
|
+
The HTML pages are in _build\serve-1724331687766143000\html.
|
|
77
|
+
Serving at <http://[::1]:8000/>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- **Navigate** to [http://localhost:8000/](http://localhost:8000/) to view the
|
|
81
|
+
generated pages.
|
|
82
|
+
|
|
83
|
+
- **Create and edit documents** in the `docs` directory. This can be done with
|
|
84
|
+
any plain text editor. The local server watches the source files and
|
|
85
|
+
**automatically rebulids the HTML when a file changes**. Reload the page in
|
|
86
|
+
the browser to view the updated output. If a build fails, the errors can be
|
|
87
|
+
found in the terminal.
|
|
88
|
+
|
|
89
|
+
- **Stop the local server** with {kbd}`Ctrl+C` in the terminal, or by closing
|
|
90
|
+
the terminal window.
|
|
91
|
+
|
|
92
|
+
- Don't forget to **commit changes frequently**.
|
|
93
|
+
|
|
94
|
+
## Deploy documents
|
|
95
|
+
|
|
96
|
+
To deploy the repository to `tdoc.org`, make sure that all changes have been
|
|
97
|
+
committed (and that new files have been added with Mercurial), then push the
|
|
98
|
+
changes to the server.
|
|
99
|
+
|
|
100
|
+
```{code-block} shell-session
|
|
101
|
+
hg push
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The changes should be live at `https://t-doc.org/REPO` within a few minutes. If
|
|
105
|
+
the build fails, GitHub will send you an email notification. It contains a link
|
|
106
|
+
to the build log, which should allow figuring out what went wrong.
|
|
@@ -15,34 +15,60 @@ t-doc requires the following software to be installed:
|
|
|
15
15
|
### Windows
|
|
16
16
|
|
|
17
17
|
- Install [Python](https://www.python.org/).
|
|
18
|
+
|
|
18
19
|
```{code-block} shell-session
|
|
19
20
|
winget install --id Python.Python.3.12
|
|
20
21
|
```
|
|
21
22
|
|
|
23
|
+
- Check that Python can be launched from the command-line, by running:
|
|
24
|
+
|
|
25
|
+
```{code-block} shell-session
|
|
26
|
+
python
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If this opens the Microsoft Store, open Windows settings, search for "App
|
|
30
|
+
execution aliases", and disable the "App Installer" entries for `python.exe`
|
|
31
|
+
and `python3.exe`.
|
|
32
|
+
|
|
22
33
|
- Install [Graphviz](https://graphviz.org/). The installer must be run
|
|
23
34
|
interactively and the **"Add Graphviz to the system PATH for all users"**
|
|
24
35
|
option must be enabled.
|
|
36
|
+
|
|
25
37
|
```{code-block} shell-session
|
|
26
38
|
winget install --id Graphviz.Graphviz --interactive
|
|
27
39
|
```
|
|
28
40
|
|
|
29
41
|
- Install [TortoiseHg](https://tortoisehg.bitbucket.io/).
|
|
42
|
+
|
|
30
43
|
```{code-block} shell-session
|
|
31
44
|
winget install --id TortoiseHg.TortoiseHg
|
|
32
45
|
```
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
- Open the TortoiseHg settings, go to your user's global settings, then click
|
|
48
|
+
"Edit file" and add the following to the configuration (substitute `FIRST`
|
|
49
|
+
and `LAST` with your first and last name, and `EMAIL` with your email
|
|
50
|
+
address, e.g. `Joe Smith <joe@example.com>`):
|
|
51
|
+
|
|
52
|
+
```ini
|
|
53
|
+
[ui]
|
|
54
|
+
username = FIRST LAST <EMAIL>
|
|
55
|
+
```
|
|
37
56
|
|
|
38
57
|
- (Optional, Windows 10) Install
|
|
39
58
|
[Windows Terminal](https://github.com/microsoft/terminal) (it's already
|
|
40
59
|
installed on Windows 11 and later).
|
|
60
|
+
|
|
41
61
|
```{code-block} shell-session
|
|
42
62
|
winget install --id Microsoft.WindowsTerminal
|
|
43
63
|
```
|
|
44
64
|
|
|
45
|
-
###
|
|
65
|
+
### macOS
|
|
66
|
+
|
|
67
|
+
- Install [Python](https://www.python.org/), [Graphviz](https://graphviz.org/)
|
|
68
|
+
and [Mercurial](https://www.mercurial-scm.org/) either by hand or through a
|
|
69
|
+
package manager like [Homebrew](https://brew.sh/).
|
|
70
|
+
|
|
71
|
+
### Linux
|
|
46
72
|
|
|
47
73
|
- Install [Python](https://www.python.org/), [Graphviz](https://graphviz.org/)
|
|
48
74
|
and [Mercurial](https://www.mercurial-scm.org/) through your system's package
|
|
@@ -53,13 +79,53 @@ t-doc requires the following software to be installed:
|
|
|
53
79
|
- Install the [required packages](#requirements).
|
|
54
80
|
|
|
55
81
|
- Install the `t-doc-common` package.
|
|
82
|
+
|
|
83
|
+
`````{tab-set}
|
|
84
|
+
:sync-group: platform
|
|
85
|
+
````{tab-item} Windows
|
|
86
|
+
:sync: windows
|
|
87
|
+
```{code-block} shell-session
|
|
88
|
+
python -m pip install t-doc-common
|
|
89
|
+
```
|
|
90
|
+
````
|
|
91
|
+
````{tab-item} macOS
|
|
92
|
+
:sync: macos
|
|
93
|
+
```{code-block} shell-session
|
|
94
|
+
python -m pip install --user t-doc-common
|
|
95
|
+
```
|
|
96
|
+
You may have to add `$HOME/.local/bin` to your `PATH`.
|
|
97
|
+
````
|
|
98
|
+
````{tab-item} Linux
|
|
99
|
+
:sync: linux
|
|
56
100
|
```{code-block} shell-session
|
|
57
101
|
python -m pip install --user t-doc-common
|
|
58
102
|
```
|
|
103
|
+
You may have to add `$HOME/.local/bin` to your `PATH`.
|
|
104
|
+
````
|
|
105
|
+
`````
|
|
59
106
|
|
|
60
107
|
## Upgrade
|
|
61
108
|
|
|
62
109
|
- Upgrade the `t-doc-common` package and any out-of-date dependencies.
|
|
110
|
+
|
|
111
|
+
`````{tab-set}
|
|
112
|
+
:sync-group: platform
|
|
113
|
+
````{tab-item} Windows
|
|
114
|
+
:sync: windows
|
|
115
|
+
```{code-block} shell-session
|
|
116
|
+
python -m pip install --upgrade t-doc-common
|
|
117
|
+
```
|
|
118
|
+
````
|
|
119
|
+
````{tab-item} macOS
|
|
120
|
+
:sync: macos
|
|
121
|
+
```{code-block} shell-session
|
|
122
|
+
python -m pip install --user --upgrade t-doc-common
|
|
123
|
+
```
|
|
124
|
+
````
|
|
125
|
+
````{tab-item} Linux
|
|
126
|
+
:sync: linux
|
|
63
127
|
```{code-block} shell-session
|
|
64
128
|
python -m pip install --user --upgrade t-doc-common
|
|
65
129
|
```
|
|
130
|
+
````
|
|
131
|
+
`````
|
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
# SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
5
5
|
import pathlib
|
|
6
|
+
import re
|
|
6
7
|
|
|
7
8
|
from docutils import nodes
|
|
9
|
+
from docutils.parsers.rst import directives
|
|
8
10
|
from sphinx.directives.code import CodeBlock
|
|
9
11
|
from sphinx.util import logging
|
|
10
12
|
|
|
11
13
|
__project__ = 't-doc-common'
|
|
12
|
-
__version__ = '0.
|
|
14
|
+
__version__ = '0.5'
|
|
13
15
|
|
|
14
16
|
_common = pathlib.Path(__file__).absolute().parent
|
|
15
17
|
_root = _common.parent.parent
|
|
16
|
-
makefile = str(_common / 'common.mk')
|
|
17
18
|
|
|
18
19
|
_log = logging.getLogger(__name__)
|
|
19
20
|
|
|
@@ -34,9 +35,11 @@ def setup(app):
|
|
|
34
35
|
|
|
35
36
|
app.add_html_theme('t-doc', str(_common))
|
|
36
37
|
app.add_directive('exec', Exec)
|
|
38
|
+
app.add_node(ExecBlock, html=(visit_ExecBlock, depart_ExecBlock))
|
|
37
39
|
|
|
38
40
|
app.connect("config-inited", on_config_inited)
|
|
39
41
|
app.connect('builder-inited', on_builder_inited)
|
|
42
|
+
app.connect('doctree-resolved', check_after_references)
|
|
40
43
|
app.connect('html-page-context', on_html_page_context)
|
|
41
44
|
|
|
42
45
|
return {
|
|
@@ -61,6 +64,7 @@ def on_config_inited(app, config):
|
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
def on_builder_inited(app):
|
|
67
|
+
# Add our own static paths.
|
|
64
68
|
app.config.html_static_path.append(str(_common / 'static'))
|
|
65
69
|
sw = _root / 'ext' / 'sqlite-wasm' / 'sqlite-wasm'
|
|
66
70
|
if (sw / 'jswasm').is_dir():
|
|
@@ -79,13 +83,25 @@ def on_html_page_context(app, page, template, context, doctree):
|
|
|
79
83
|
# TODO: Work around inability to specify headers on GitHub Pages
|
|
80
84
|
|
|
81
85
|
|
|
86
|
+
def format_data_attrs(translator, /, **kwargs):
|
|
87
|
+
return ' '.join(f'data-tdoc-{k}="{translator.attval(v)}"'
|
|
88
|
+
for k, v in sorted(kwargs.items()) if v is not None)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class ExecBlock(nodes.literal_block): pass
|
|
92
|
+
|
|
93
|
+
|
|
82
94
|
class Exec(CodeBlock):
|
|
83
|
-
# TODO: :
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
# TODO: :include:
|
|
96
|
+
|
|
97
|
+
option_spec = CodeBlock.option_spec | {
|
|
98
|
+
'after': directives.unchanged,
|
|
99
|
+
'when': lambda c: directives.choice(c, ('click', 'load', 'never')),
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
@staticmethod
|
|
87
103
|
def match_node(lang=None):
|
|
88
|
-
return lambda n: isinstance(n,
|
|
104
|
+
return lambda n: isinstance(n, ExecBlock) \
|
|
89
105
|
and 'tdoc-exec' in n['classes'] \
|
|
90
106
|
and (lang is None or n.get('language') == lang)
|
|
91
107
|
|
|
@@ -93,6 +109,46 @@ class Exec(CodeBlock):
|
|
|
93
109
|
res = super().run()
|
|
94
110
|
for node in res:
|
|
95
111
|
for n in node.findall(nodes.literal_block):
|
|
96
|
-
|
|
112
|
+
self._update_node(node)
|
|
97
113
|
# _log.info("res: %s", res, color='yellow')
|
|
98
114
|
return res
|
|
115
|
+
|
|
116
|
+
def _update_node(self, node):
|
|
117
|
+
node.__class__ = ExecBlock
|
|
118
|
+
node.tagname = node.__class__.__name__
|
|
119
|
+
node['classes'] += ['tdoc-exec']
|
|
120
|
+
if after := self.options.get('after'):
|
|
121
|
+
node['after'] = after
|
|
122
|
+
node['when'] = self.options.get('when', 'click')
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def check_after_references(app, doctree, docname):
|
|
126
|
+
nodes = list(doctree.findall(Exec.match_node('sql')))
|
|
127
|
+
names = set()
|
|
128
|
+
for n in nodes:
|
|
129
|
+
names.update(n['names'])
|
|
130
|
+
for n in nodes:
|
|
131
|
+
after = n.get('after')
|
|
132
|
+
if after and after not in names:
|
|
133
|
+
doctree.reporter.error(
|
|
134
|
+
f"'exec': Unknown :after: reference: {after}", base_node=n)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
div_attrs_re = re.compile(r'(?s)^(<div[^>]*)(>.*)$')
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def visit_ExecBlock(self, node):
|
|
141
|
+
try:
|
|
142
|
+
return self.visit_literal_block(node)
|
|
143
|
+
except nodes.SkipNode:
|
|
144
|
+
attrs = format_data_attrs(self, after=node.get('after'),
|
|
145
|
+
when=node.get('when'))
|
|
146
|
+
if attrs:
|
|
147
|
+
def subst(m):
|
|
148
|
+
return f'{m.group(1)} {attrs}{m.group(2)}'
|
|
149
|
+
self.body[-1] = div_attrs_re.sub(subst, self.body[-1], 1)
|
|
150
|
+
raise
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def depart_ExecBlock(self, node):
|
|
154
|
+
return self.depart_literal_block(node)
|
|
@@ -208,6 +208,7 @@ class ServerBase(server.ThreadingHTTPServer):
|
|
|
208
208
|
self.cfg.stderr.write(f"Scan: {e}\n")
|
|
209
209
|
mtime = 0
|
|
210
210
|
for path in itertools.chain([self.cfg.source], self.cfg.watch):
|
|
211
|
+
# TODO: Exclude files in __pycache__
|
|
211
212
|
for base, dirs, files in path.walk(on_error=on_error):
|
|
212
213
|
for file in files:
|
|
213
214
|
try:
|
|
@@ -9,6 +9,7 @@ smartquotes = False
|
|
|
9
9
|
primary_domain = None
|
|
10
10
|
nitpicky = True
|
|
11
11
|
exclude_patterns = ['_build', '.DS_Store', 'Thumbs.db']
|
|
12
|
+
highlight_language = 'text'
|
|
12
13
|
|
|
13
14
|
extensions = [
|
|
14
15
|
'myst_parser',
|
|
@@ -34,6 +35,10 @@ extensions = [
|
|
|
34
35
|
'tdoc.common',
|
|
35
36
|
]
|
|
36
37
|
|
|
38
|
+
suppress_warnings = [
|
|
39
|
+
'myst.strikethrough', # Only supported for HTML, but that's all we want
|
|
40
|
+
]
|
|
41
|
+
|
|
37
42
|
# Extension options.
|
|
38
43
|
graphviz_output_format = 'svg'
|
|
39
44
|
todo_include_todos = True
|
|
@@ -41,6 +46,8 @@ todo_include_todos = True
|
|
|
41
46
|
# MyST options.
|
|
42
47
|
myst_enable_extensions = {
|
|
43
48
|
'amsmath',
|
|
49
|
+
'attrs_block',
|
|
50
|
+
'attrs_inline',
|
|
44
51
|
'colon_fence',
|
|
45
52
|
'deflist',
|
|
46
53
|
'dollarmath',
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Copyright 2024 Caroline Blank <caro@c-space.org> */
|
|
2
|
+
/* Copyright 2024 Remy Blank <remy@c-space.org> */
|
|
3
|
+
/* SPDX-License-Identifier: MIT */
|
|
4
|
+
|
|
5
|
+
:not(#_).hidden {
|
|
6
|
+
display: none;
|
|
7
|
+
}
|
|
8
|
+
:not(#_).line-height-normal .highlight pre {
|
|
9
|
+
line-height: normal;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* Set the maximum width of sidebars instead of a fixed width. */
|
|
13
|
+
div.sidebar, aside.sidebar {
|
|
14
|
+
max-width: 40%;
|
|
15
|
+
width: inherit;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Invert the even and odd row colors in tables, so that the first row below the
|
|
19
|
+
header has a different color than the header. */
|
|
20
|
+
.table tbody tr:nth-child(even) {
|
|
21
|
+
background-color: var(--pst-color-table-row-zebra-low-bg);
|
|
22
|
+
}
|
|
23
|
+
.table tbody tr:nth-child(odd) {
|
|
24
|
+
background-color: var(--pst-color-table-row-zebra-high-bg);
|
|
25
|
+
}
|
|
26
|
+
.table tbody tr:hover {
|
|
27
|
+
background-color: var(--pst-color-table-row-hover-bg);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Execution controls */
|
|
31
|
+
div[class*=highlight-].tdoc-exec {
|
|
32
|
+
flex-direction: row;
|
|
33
|
+
}
|
|
34
|
+
div.tdoc-exec div.highlight {
|
|
35
|
+
flex-basis: 100%;
|
|
36
|
+
}
|
|
37
|
+
div.tdoc-exec-controls {
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
margin-left: 0.3rem;
|
|
41
|
+
}
|
|
42
|
+
div.tdoc-exec-controls button {
|
|
43
|
+
aspect-ratio: 1;
|
|
44
|
+
border-radius: 0.25rem;
|
|
45
|
+
padding: 0.3rem;
|
|
46
|
+
border: 1px solid var(--pst-color-border);
|
|
47
|
+
background-color: var(--pst-color-surface);
|
|
48
|
+
font: var(--fa-font-solid);
|
|
49
|
+
transition: background-color .3s;
|
|
50
|
+
}
|
|
51
|
+
div.tdoc-exec-controls button:hover {
|
|
52
|
+
background-color: var(--pst-color-shadow);
|
|
53
|
+
}
|
|
54
|
+
div.tdoc-exec-controls * {
|
|
55
|
+
margin-top: 0.3rem;
|
|
56
|
+
}
|
|
57
|
+
div.tdoc-exec-controls *:first-child {
|
|
58
|
+
margin-top: 0;
|
|
59
|
+
}
|
|
60
|
+
div.tdoc-exec-controls button.tdoc-exec-run::before {
|
|
61
|
+
content: '\f04b';
|
|
62
|
+
}
|
|
63
|
+
div.tdoc-exec-controls button.tdoc-exec-reset::before {
|
|
64
|
+
content: '\f2ea';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* SQL execution results */
|
|
68
|
+
.table tbody tr:nth-child(odd).tdoc-no-results {
|
|
69
|
+
background: repeating-linear-gradient(-45deg,
|
|
70
|
+
var(--pst-color-table-row-zebra-low-bg) 0px 2px,
|
|
71
|
+
var(--pst-color-table-row-zebra-high-bg) 2px 20px);
|
|
72
|
+
}
|
|
73
|
+
.tdoc-error {
|
|
74
|
+
margin-bottom: 1rem;
|
|
75
|
+
border: 1px solid var(--pst-color-danger);
|
|
76
|
+
padding: 0.5rem;
|
|
77
|
+
background: repeating-linear-gradient(-45deg,
|
|
78
|
+
var(--pst-color-table-row-zebra-low-bg) 0px 2px,
|
|
79
|
+
var(--pst-color-table-row-zebra-high-bg) 2px 20px);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Prevent the wrapper background from being visible if the wrapper is larger
|
|
83
|
+
than its content. */
|
|
84
|
+
.highlight.highlight.highlight {
|
|
85
|
+
background: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Fix the gap left by pydata_sphinx_theme between the table and the
|
|
89
|
+
scrollbar. */
|
|
90
|
+
div.pst-scrollable-table-container {
|
|
91
|
+
margin-bottom: 1rem;
|
|
92
|
+
}
|
|
93
|
+
.table {
|
|
94
|
+
margin-bottom: 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Reduce the bottom margin of directive definition list options. */
|
|
98
|
+
dl[class]:not(.option-list,.field-list,.footnote,.glossary,.simple):not(._) {
|
|
99
|
+
margin-bottom: 1rem;
|
|
100
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Copyright 2024 Caroline Blank <caro@c-space.org>
|
|
2
|
+
// Copyright 2024 Remy Blank <remy@c-space.org>
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
import {default as sqlite3_init} from './jswasm/sqlite3-worker1-promiser.mjs';
|
|
6
|
+
|
|
7
|
+
function waitLoaded() {
|
|
8
|
+
return new Promise(resolve => {
|
|
9
|
+
if (document.readyState !== 'loading') {
|
|
10
|
+
resolve();
|
|
11
|
+
} else if (document.addEventListener) {
|
|
12
|
+
document.addEventListener('DOMContentLoaded', resolve);
|
|
13
|
+
} else {
|
|
14
|
+
document.attachEvent('onreadystatechange', () => {
|
|
15
|
+
if (document.readyState === 'interactive') resolve();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function text(value) {
|
|
22
|
+
return document.createTextNode(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function element(html) {
|
|
26
|
+
const t = document.createElement('template');
|
|
27
|
+
t.innerHTML = html.trim();
|
|
28
|
+
return t.content.firstChild;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const promiser = await sqlite3_init({
|
|
32
|
+
// debug: console.debug,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
class Database {
|
|
36
|
+
static async config() {
|
|
37
|
+
return (await promiser('config-get', {})).result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static async open(filename) {
|
|
41
|
+
let {dbId} = await promiser('open', {filename});
|
|
42
|
+
return new Database(dbId);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
constructor(dbId) {
|
|
46
|
+
this.dbId = dbId;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async close() {
|
|
50
|
+
if (this.dbId) {
|
|
51
|
+
// TODO: Check if "unlink" makes any difference
|
|
52
|
+
await promiser('close', {dbId: this.dbId, unlink: true});
|
|
53
|
+
delete this.dbId;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async exec(sql, on_result) {
|
|
58
|
+
// TODO: Check if other args could be useful, e.g. for splitting a
|
|
59
|
+
// script into multiple statements
|
|
60
|
+
await promiser('exec', {dbId: this.dbId, sql, callback: on_result});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let db_num = 0;
|
|
65
|
+
|
|
66
|
+
async function execute(exec) {
|
|
67
|
+
// Compute the chain of nodes to execute.
|
|
68
|
+
const nodes = [];
|
|
69
|
+
for (let node = exec; node;) {
|
|
70
|
+
if (node.classList.contains('tdoc-exec')) {
|
|
71
|
+
nodes.push(node);
|
|
72
|
+
node = document.getElementById(node.dataset.tdocAfter)
|
|
73
|
+
} else { // Secondary name as a nested <span>
|
|
74
|
+
node = node.parentNode;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
nodes.reverse();
|
|
78
|
+
|
|
79
|
+
removeResults(exec);
|
|
80
|
+
let results, tbody;
|
|
81
|
+
const db = await Database.open(`file:db-${db_num++}?vfs=memdb`);
|
|
82
|
+
try {
|
|
83
|
+
for (const [i, node] of nodes.entries()) {
|
|
84
|
+
const pre = node.querySelector('pre');
|
|
85
|
+
if (!pre) {
|
|
86
|
+
console.error("<pre> element not found in node ", node);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
await db.exec(pre.innerText, res => {
|
|
90
|
+
if (res.columnNames.length === 0) return;
|
|
91
|
+
if (i < nodes.length - 1) return;
|
|
92
|
+
if (!results) {
|
|
93
|
+
results = element(`\
|
|
94
|
+
<div class="pst-scrollable-table-container tdoc-exec-output">\
|
|
95
|
+
<table class="table"><thead><tr></tr></thead><tbody></tbody></table>\
|
|
96
|
+
</div>`);
|
|
97
|
+
const tr = results.querySelector('tr');
|
|
98
|
+
for (const col of res.columnNames) {
|
|
99
|
+
const th = tr.appendChild(element(
|
|
100
|
+
`<th class="text-center"></th>`));
|
|
101
|
+
th.appendChild(text(col));
|
|
102
|
+
}
|
|
103
|
+
tbody = results.querySelector('tbody');
|
|
104
|
+
}
|
|
105
|
+
if (res.row) {
|
|
106
|
+
const tr = tbody.appendChild(element(`<tr></tr>`));
|
|
107
|
+
for (const val of res.row) {
|
|
108
|
+
tr.appendChild(element(`<td class="text-center"></td>`))
|
|
109
|
+
.appendChild(val === null ?
|
|
110
|
+
element(`<code>NULL</code>`) :
|
|
111
|
+
text(val));
|
|
112
|
+
}
|
|
113
|
+
} else if (tbody.children.length === 0) {
|
|
114
|
+
tbody.appendChild(element(`\
|
|
115
|
+
<tr class="tdoc-no-results">\
|
|
116
|
+
<td colspan="${res.columnNames.length}">No results</td>\
|
|
117
|
+
</tr>`))
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (results) exec.after(results);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
let msg;
|
|
124
|
+
if (e.dbId === db.dbId) {
|
|
125
|
+
msg = /^(SQLITE_ERROR: sqlite3 result code \d+: )?(.*)$/
|
|
126
|
+
.exec(e.result.message)[2]
|
|
127
|
+
} else {
|
|
128
|
+
msg = e.toString();
|
|
129
|
+
}
|
|
130
|
+
results = element(`\
|
|
131
|
+
<div class="tdoc-exec-output tdoc-error"><strong>Error:</strong></div>`);
|
|
132
|
+
results.appendChild(text(` ${msg}`));
|
|
133
|
+
exec.after(results);
|
|
134
|
+
} finally {
|
|
135
|
+
await db.close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function tryExecute(exec) {
|
|
140
|
+
try {
|
|
141
|
+
await execute(exec);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.error(e);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function removeResults(exec) {
|
|
148
|
+
for (;;) {
|
|
149
|
+
const next = exec.nextElementSibling;
|
|
150
|
+
if (!next || !next.classList.contains('tdoc-exec-output')) break;
|
|
151
|
+
next.parentNode.removeChild(next);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await waitLoaded();
|
|
156
|
+
console.info("SQLite version:", (await Database.config()).version.libVersion);
|
|
157
|
+
|
|
158
|
+
for (const exec of document.querySelectorAll('div.tdoc-exec.highlight-sql')) {
|
|
159
|
+
const when = exec.dataset.tdocWhen;
|
|
160
|
+
if (when === 'load') {
|
|
161
|
+
tryExecute(exec); // Intentionally don't await
|
|
162
|
+
} else if (when === 'click') {
|
|
163
|
+
const controls = exec.appendChild(element(`\
|
|
164
|
+
<div class="tdoc-exec-controls">\
|
|
165
|
+
<button class="tdoc-exec-run" title="Run"></button>\
|
|
166
|
+
<button class="tdoc-exec-reset" title="Reset"></button>\
|
|
167
|
+
</div>`));
|
|
168
|
+
controls.querySelector('.tdoc-exec-run').addEventListener(
|
|
169
|
+
'click', async () => { await tryExecute(exec); });
|
|
170
|
+
controls.querySelector('.tdoc-exec-reset').addEventListener(
|
|
171
|
+
'click', () => { removeResults(exec); });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Copyright 2024 Caroline Blank <caro@c-space.org>
|
|
2
|
-
# Copyright 2024 Remy Blank <remy@c-space.org>
|
|
3
|
-
# SPDX-License-Identifier: MIT
|
|
4
|
-
|
|
5
|
-
# Configuration.
|
|
6
|
-
COLOR ?= 1
|
|
7
|
-
SPHINX_OPTS ?= --jobs=auto --fail-on-warning
|
|
8
|
-
SPHINX_BUILD ?= sphinx-build
|
|
9
|
-
SOURCE ?= docs
|
|
10
|
-
BUILD ?= docs/_build
|
|
11
|
-
|
|
12
|
-
# ANSI escape codes.
|
|
13
|
-
_V := $(if $(VERBOSE:0=),,@)
|
|
14
|
-
_ANSI = $(if $(COLOR:0=),\e[$(1)m)
|
|
15
|
-
_NORM := $(call _ANSI,39)
|
|
16
|
-
_BLACK := $(call _ANSI,30)
|
|
17
|
-
_RED := $(call _ANSI,31)
|
|
18
|
-
_GREEN := $(call _ANSI,32)
|
|
19
|
-
_YELLOW := $(call _ANSI,33)
|
|
20
|
-
_BLUE := $(call _ANSI,34)
|
|
21
|
-
_MAGENTA := $(call _ANSI,35)
|
|
22
|
-
_CYAN := $(call _ANSI,36)
|
|
23
|
-
_GREY := $(call _ANSI,37)
|
|
24
|
-
_DGREY := $(call _ANSI,90)
|
|
25
|
-
_LRED := $(call _ANSI,91)
|
|
26
|
-
_LGREEN := $(call _ANSI,92)
|
|
27
|
-
_LYELLOW := $(call _ANSI,93)
|
|
28
|
-
_LBLUE := $(call _ANSI,94)
|
|
29
|
-
_LMAGENTA := $(call _ANSI,95)
|
|
30
|
-
_LCYAN := $(call _ANSI,96)
|
|
31
|
-
_WHITE := $(call _ANSI,97)
|
|
32
|
-
|
|
33
|
-
.PHONY: default
|
|
34
|
-
default: help
|
|
35
|
-
|
|
36
|
-
.PHONY: help
|
|
37
|
-
help:
|
|
38
|
-
$(_V)echo -e "$(_WHITE)Make targets:$(_NORM)"
|
|
39
|
-
$(_V)echo -e " $(_LBLUE)serve$(_NORM): Build the $(_LBLUE)html$(_NORM) target, then serve the result on http://localhost:8000"
|
|
40
|
-
$(_V)echo -e
|
|
41
|
-
$(_V)PYTHONPATH="$(PYTHONPATH)" $(SPHINX_BUILD) -M help \
|
|
42
|
-
"$(SOURCE)" "$(BUILD)" $(SPHINX_OPTS) $(O)
|
|
43
|
-
|
|
44
|
-
.PHONY: serve
|
|
45
|
-
serve: html
|
|
46
|
-
$(_V)echo -e "$(_WHITE)Serving:$(_NORM) $(_LBLUE)http://localhost:8000$(_NORM)"
|
|
47
|
-
$(_V)PYTHONPATH="$(PYTHONPATH)" $(PYTHON) -m http.server \
|
|
48
|
-
--bind=localhost --directory="$(BUILD)/html"
|
|
49
|
-
|
|
50
|
-
%:
|
|
51
|
-
$(_V)PYTHONPATH="$(PYTHONPATH)" $(SPHINX_BUILD) -M $@ \
|
|
52
|
-
"$(SOURCE)" "$(BUILD)" $(SPHINX_OPTS) $(O)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/* Copyright 2024 Caroline Blank <caro@c-space.org> */
|
|
2
|
-
/* Copyright 2024 Remy Blank <remy@c-space.org> */
|
|
3
|
-
/* SPDX-License-Identifier: MIT */
|
|
4
|
-
|
|
5
|
-
.hidden {
|
|
6
|
-
display: none !important;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/* Set the maximum width of sidebars instead of a fixed width. */
|
|
10
|
-
div.sidebar, aside.sidebar {
|
|
11
|
-
max-width: 40%;
|
|
12
|
-
width: inherit;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/* Fix the gap left by pydata_sphinx_theme between the table and the
|
|
16
|
-
scrollbar. */
|
|
17
|
-
div.pst-scrollable-table-container {
|
|
18
|
-
margin-bottom: 1rem;
|
|
19
|
-
}
|
|
20
|
-
.table {
|
|
21
|
-
margin-bottom: 0;
|
|
22
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
// Copyright 2024 Caroline Blank <caro@c-space.org>
|
|
2
|
-
// Copyright 2024 Remy Blank <remy@c-space.org>
|
|
3
|
-
// SPDX-License-Identifier: MIT
|
|
4
|
-
|
|
5
|
-
import {default as sqlite3_init} from './jswasm/sqlite3-worker1-promiser.mjs';
|
|
6
|
-
|
|
7
|
-
function waitLoaded() {
|
|
8
|
-
return new Promise(resolve => {
|
|
9
|
-
if (document.readyState !== 'loading') {
|
|
10
|
-
resolve();
|
|
11
|
-
} else if (document.addEventListener) {
|
|
12
|
-
document.addEventListener('DOMContentLoaded', resolve);
|
|
13
|
-
} else {
|
|
14
|
-
document.attachEvent('onreadystatechange', () => {
|
|
15
|
-
if (document.readyState === 'interactive') resolve();
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function text(value) {
|
|
22
|
-
return document.createTextNode(value);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function addChild(parent, tag) {
|
|
26
|
-
const el = document.createElement(tag);
|
|
27
|
-
parent.appendChild(el);
|
|
28
|
-
return el;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const promiser = await sqlite3_init({
|
|
32
|
-
// debug: console.debug,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
class Database {
|
|
36
|
-
static async config() {
|
|
37
|
-
return (await promiser('config-get', {})).result;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
static async open(filename) {
|
|
41
|
-
// TODO: Pass name and vfs separately
|
|
42
|
-
let {dbId} = await promiser('open', {filename});
|
|
43
|
-
return new Database(dbId);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
constructor(dbId) {
|
|
47
|
-
this.dbId = dbId;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async close() {
|
|
51
|
-
if (this.dbId) {
|
|
52
|
-
// TODO: Check if "unlink" makes any difference
|
|
53
|
-
await promiser('close', {dbId: this.dbId, unlink: true});
|
|
54
|
-
delete this.dbId;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async exec(sql, on_result) {
|
|
59
|
-
// TODO: Check if final result has anything useful
|
|
60
|
-
// TODO: Check if other args could be useful, e.g. for splitting a
|
|
61
|
-
// script into multiple statements
|
|
62
|
-
await promiser('exec', {dbId: this.dbId, sql, callback: on_result});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async *query(sql) {
|
|
66
|
-
let notify, queue;
|
|
67
|
-
let promise = new Promise(resolve => { notify = resolve; });
|
|
68
|
-
const exec = this.exec(sql, res => {
|
|
69
|
-
if (queue) {
|
|
70
|
-
queue.push(res);
|
|
71
|
-
} else {
|
|
72
|
-
queue = [res]
|
|
73
|
-
notify(queue);
|
|
74
|
-
promise = new Promise(resolve => { notify = resolve; });
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
let done = false;
|
|
78
|
-
while (!done) {
|
|
79
|
-
const q = await promise;
|
|
80
|
-
queue = undefined;
|
|
81
|
-
for (const res of q) {
|
|
82
|
-
done = !res.row;
|
|
83
|
-
if (done) break;
|
|
84
|
-
yield res;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
await exec;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function execute(exec) {
|
|
92
|
-
const pre = exec.querySelector('pre');
|
|
93
|
-
if (!pre) {
|
|
94
|
-
console.error("<pre> element not found");
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// TODO: Find dependencies
|
|
98
|
-
const sql = pre.innerText;
|
|
99
|
-
let results, tbody;
|
|
100
|
-
const db = await Database.open('file:db?vfs=memdb');
|
|
101
|
-
try {
|
|
102
|
-
// TODO: Execute dependencies
|
|
103
|
-
// TODO: Report errors in output
|
|
104
|
-
for await (const res of db.query(sql)) {
|
|
105
|
-
if (!results) {
|
|
106
|
-
// TODO: Remove previous result table
|
|
107
|
-
results = document.createElement('div');
|
|
108
|
-
results.classList.add('pst-scrollable-table-container',
|
|
109
|
-
'tdoc-sql-results');
|
|
110
|
-
const table = addChild(results, 'table');;
|
|
111
|
-
table.classList.add('table');
|
|
112
|
-
const thead = addChild(table, 'thead');
|
|
113
|
-
const tr = addChild(thead, 'tr');
|
|
114
|
-
tr.classList.add('row-odd');
|
|
115
|
-
for (const col of res.columnNames) {
|
|
116
|
-
const th = addChild(tr, 'th')
|
|
117
|
-
th.classList.add('text-center');
|
|
118
|
-
th.appendChild(text(col));
|
|
119
|
-
}
|
|
120
|
-
tbody = addChild(table, 'tbody');
|
|
121
|
-
}
|
|
122
|
-
const tr = addChild(tbody, 'tr');
|
|
123
|
-
tr.classList.add(res.rowNumber % 2 === 0 ? 'row-odd' : 'row-even');
|
|
124
|
-
for (const val of res.row) {
|
|
125
|
-
const td = addChild(tr, 'td')
|
|
126
|
-
td.classList.add('text-center');
|
|
127
|
-
td.appendChild(text(val));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (results) exec.after(results);
|
|
131
|
-
} finally {
|
|
132
|
-
await db.close();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
await waitLoaded();
|
|
137
|
-
console.info("SQLite version:", (await Database.config()).version.libVersion);
|
|
138
|
-
|
|
139
|
-
for (const el of document.querySelectorAll('div.tdoc-exec.highlight-sql')) {
|
|
140
|
-
await execute(el);
|
|
141
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/demo/module-workers-polyfill.min.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-node.mjs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{t_doc_common-0.4.dev1 → t_doc_common-0.5}/ext/sqlite-wasm/sqlite-wasm/jswasm/sqlite3-worker1.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|