You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit b5db6da
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,6 +20,8 @@
20
20
- An export now names its images by the file names `media/` holds them under. Every markdown image reference a question holds — in the question's text, a part's text, a worked solution, a final answer or an answer box's wording — is rewritten to the file name the image was carried under, so a document writing `` exports as `` beside `media/train.png`, and Lambda Feedback finds the figure where it looks for one. A file two questions use is carried once. Where two different files have the same name, in2lambda names the second as Lambda Feedback's own exports name an image, `question_001_<Title>_0001.png`. Reading an export back is unchanged, because an export already names its images this way.
21
21
- A draft can freeze more than one document, which is how a sheet written as a question file and a separate solutions file is drafted. `in2lambda source add questions.docx solutions.docx` freezes them as source 1 and source 2 of the one `questions.draft.json`, and `in2lambda source add solutions.docx --draft questions.docx` adds a file to an existing draft as its next source. Every block id and line range of a source after the first carries that source's number — `2/b3`, `2/s10:14` — and `1/b3` names the block `b3` names. A field quoted from a source records which source it came from, so that the same line number in two documents is two places. `in2lambda source show` prints each source under its number and its name. `in2lambda spec run` runs the spec over every source: the first source is laid out as the spec's `layout` says, and in any source after it the `question` selector picks out the marker written above each question's solutions while every other match is a solution, paired onto the questions and parts of the first source as `in2lambda convert -a` pairs an answers file. A draft now holds `sources`, a list of `{source, hash, blocks}` in the order they were frozen, in place of those three keys at the top level, so a draft written before this release is refused as a draft in2lambda did not write; `in2lambda source add --start-over` freezes the document again. Four changes to the Python API break existing scripts: `in2lambda.source.add` takes a list of files and the draft to freeze them into; `in2lambda.source.frozen` returns the markdown of every source and `in2lambda.draft.apply` takes the markdown of every source, in place of one; `in2lambda.spec.fields` takes one `(blocks, markdown)` pair per source in place of its `elements` and `markdown` arguments; and `in2lambda.spec.Field` carries the number of the source its ranges are lines of, which every caller constructing a `Field` must pass.
22
22
- Every command that works on a draft takes `--draft`, naming either the draft or the source it was frozen from: `in2lambda source show`, each `in2lambda draft` command, `in2lambda spec run`, `in2lambda validate`, `in2lambda build` and `in2lambda render`. Left off, each command uses the one draft in the current directory, and where the directory holds more than one draft, the command is refused, naming them. `in2lambda spec run` resolves its SPEC from the draft's directory. The Python functions behind those commands take the draft's path in place of a directory: `in2lambda.source.frozen`, `in2lambda.source.show`, `in2lambda.draft.execute`, `in2lambda.draft.replay`, `in2lambda.draft.spec_command`, `in2lambda.draft.report.validate`, `in2lambda.draft.export.build` and `in2lambda.draft.export.render`. `in2lambda.source.draft_of` returns the path of a document's draft, and `in2lambda.source.find` resolves `--draft` for the command line.
23
+
- `in2lambda source add` records the blocks nested inside a block as well as the top-level blocks, so that a sheet written as one list — each question an item, each part an item of a list inside that item — holds a block per part for a spec to select. A list item and a fenced div, which is what pandoc writes a `\begin{solution}` environment as, are the two blocks that hold blocks of their own. A list item or div holding a single element other than a list is one block. A nested block's id is the id of the block holding it and a number, such as `b3.1` and `b3.2.1`, and the block carries a `depth`: 1 for a top-level element, 2 for a block inside one. A block spans the blocks nested inside it. A fenced div spans the lines its content is written on, and not the `:::` lines pandoc wrote around it. `in2lambda source show` prints the ids against the line each block starts on, indented two spaces for each level below the top, so that a line starting a block and the first block inside it carries both ids. A spec selects a nested block by `depth`, as in `part: ListItem depth=2`. A block whose children hold a role holds no role itself, so one selector may match a block and its children. `in2lambda validate` reports the children of a block with children, in place of the block itself, as being in no field. A draft frozen from a document holding nothing nested is written as it was before this release and replays. A draft frozen before this release from a document holding a list does not replay, because freezing that document now records blocks the draft does not hold; `in2lambda source add --start-over` freezes the document again.
24
+
- A spec written before this release can match blocks it did not match before, because a selector that names no `depth` now matches a block nested inside a list item or a `solution` environment as well as a top-level block. The `PartsOneSol` example ships a `solution` environment holding two paragraphs and a display maths, which pandoc writes as a `Para` as well, so a spec reading `question: Para` now matches all three of them; the div holding them then holds no role, and the run writes three questions the document does not write in place of the first question's worked solution. The second question's worked solution survives, because that `solution` environment holds one element and stays one block. Write `depth=1` on each selector — `question: Para depth=1` — to keep the meaning the selector had before this release. One change to the Python API breaks existing scripts: `in2lambda.spec.Selector.matches` takes a list of `(block, element)` pairs in place of a list of panflute elements, so a caller matching a selector itself passes each `in2lambda.source.Block` beside its element.
23
25
-`in2lambda convert FILE PartsOneSol` now exports the worked solution a document writes in a `solution` environment. Pandoc writes that environment as a Div whose classes hold `solution`, and the filter recognised only a Div whose first block reads `Solution`, so a document using the environment exported every question with an empty worked solution. A Div whose first block reads `Solution` is still recognised.
24
26
- Importing `in2lambda.katex_convert` no longer writes a file called `log` into the working directory. That module reports what it changed in an expression to the `in2lambda.katex_convert` logger, which is silent unless the application configures logging.
25
27
-`in2lambda convert` now reads a .docx that holds an image. in2lambda looks in the document for the directories a `\graphicspath` names, and read the document as UTF-8 text to find them. A .docx is a zip file, so converting a Word document holding a figure raised `UnicodeDecodeError`. in2lambda now reads a document that is not UTF-8 text as naming no directory, which is what a .docx names.
Copy file name to clipboardExpand all lines: docs/source/spec.md
+41-1Lines changed: 41 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -71,13 +71,14 @@ A selector is a block type followed by any number of constraints:
71
71
```
72
72
73
73
The type is a pandoc element: `Header`, `Para`, `ListItem`. A selector that omits the type matches
74
-
any block. A constraint names one of three attributes:
74
+
any block. A constraint names one of four attributes:
75
75
76
76
| Attribute | Meaning |
77
77
|-----------|---------|
78
78
| `level` | A heading's level. `level=2` matches `##`. |
79
79
| `text` | The whole block as text, with the markup removed. |
80
80
| `label` | The first word of that text, which usually numbers a question. |
81
+
| `depth` | How deep the block sits. `depth=1` matches a top-level element of the document, `depth=2` a block nested inside one. See [Nested blocks](#nested-blocks). |
81
82
82
83
`=`matches the whole value. `~` matches a regular expression anywhere in the value. `after
83
84
SELECTOR,` requires the block to follow the first block that the named selector matches, which is
@@ -92,6 +93,45 @@ reads `(a)` as a list marker. Its value is dedented as pandoc reads the item: th
92
93
the first line, and the same width of indentation off every line below it. Use `strip` for the
93
94
labels pandoc does not read as a marker, such as `Q1. ` and `Solution: `.
94
95
96
+
(nested-blocks)=
97
+
## Nested blocks
98
+
99
+
Many sheets are written as one list: each question is an item, and the parts of a question are a
100
+
list nested inside that item. `in2lambda source add` records the blocks inside a block as well as
101
+
the top-level blocks, so that a selector reaches a part.
102
+
103
+
A list item and a fenced div, which is what pandoc writes a `\begin{solution}` environment as, are
104
+
the two blocks that hold blocks of their own. A list item or div holding a single element other
105
+
than a list is that element, and stays one block. A nested block's id is the id of the block
106
+
holding it and a number: `b3`holds `b3.1` and `b3.2`, and `b3.2` holds `b3.2.1`. `in2lambda source
107
+
show` prints the ids against the line each block starts on, indented two spaces for each level
108
+
below the top.
109
+
110
+
A block spans the blocks nested inside it, so `depth` distinguishes a question from its parts:
111
+
112
+
```yaml
113
+
question: Para depth=2
114
+
part: Para depth=3
115
+
solution: Div
116
+
layout: PartSolPartSol
117
+
```
118
+
119
+
That spec reads a sheet whose questions are top-level list items. The question is the item's own
120
+
paragraph `b3.1`, and not the whole item `b3`. The `PartSolPartSol` layout pairs each solution
121
+
with the part written above it.
122
+
123
+
A block whose children hold a role holds no role itself. Writing `b3` into `q1.text` and `b3.2`
124
+
into `q1.p1.text` would be two fields quoted from the same lines, which no command writes. A spec
125
+
quotes the item's own paragraphs into the question and the nested items into the parts. So one
126
+
selector may match a block and its children, and in2lambda assigns the role to the children.
127
+
128
+
A fenced div spans the lines its content is written on. The `:::` lines pandoc wrote around the
129
+
content are pandoc's, as a list marker is, and no field quotes them.
130
+
131
+
`in2lambda validate`reports the children of a block with children, in place of the block itself,
132
+
as being in no field. A block with children spans the blank lines and the fences between those
0 commit comments