@pretextbook/markdown-style-pretext 0.1.4 → 0.2.0
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.
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @pretextbook/markdown-style-pretext
|
|
2
2
|
|
|
3
|
-
Editor intelligence for **Markdown-style PreTeXt** — CommonMark + GFM plus
|
|
3
|
+
Editor intelligence for **Markdown-style PreTeXt** — CommonMark + GFM tables plus
|
|
4
4
|
[remark-directive](https://github.com/remarkjs/remark-directive) extensions that convert to
|
|
5
5
|
PreTeXt via [`@pretextbook/remark-pretext`](../remark-pretext).
|
|
6
6
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pretextbook/markdown-style-pretext",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Editor intelligence (completions + validation) for Markdown-style PreTeXt documents",
|
|
5
5
|
"author": "Oscar Levin",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"test": "vitest run"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@pretextbook/latex-style-pretext": "^0.
|
|
37
|
+
"@pretextbook/latex-style-pretext": "^0.6.0",
|
|
38
38
|
"vscode-languageserver-types": "^3.17.5"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@pretextbook/remark-pretext": "^0.
|
|
41
|
+
"@pretextbook/remark-pretext": "^0.4.0"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
@@ -23,6 +23,13 @@ describe("container directive completions", () => {
|
|
|
23
23
|
expect(item?.textEdit?.newText).toBe("theorem\n\t$0\n:::");
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
+
it("gives :::table a title placeholder and a pipe-table body", () => {
|
|
27
|
+
const item = byLabel(complete(":::tab|"), "table");
|
|
28
|
+
expect(item?.textEdit?.newText).toBe(
|
|
29
|
+
"table[${1:Title}]\n| ${2:Header} | ${3:Header} |\n| --- | --- |\n| $4 | $0 |\n:::",
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
26
33
|
it("seeds a nested :::task for task-bearing directives", () => {
|
|
27
34
|
const item = byLabel(complete(":::exerc|"), "exercise");
|
|
28
35
|
expect(item?.textEdit?.newText).toContain(":::task");
|
|
@@ -106,6 +113,11 @@ describe("cross-reference completions", () => {
|
|
|
106
113
|
const items = complete(":::theorem{#thm:main}\nHi\n:::\n\nSee [it](#thm|");
|
|
107
114
|
expect(labels(items)).toContain("thm:main");
|
|
108
115
|
});
|
|
116
|
+
|
|
117
|
+
it("completes an empty `[](#…` link, and ids on headings", () => {
|
|
118
|
+
const items = complete("## Intro {#sec:intro}\n\nSee [](#sec|");
|
|
119
|
+
expect(labels(items)).toContain("sec:intro");
|
|
120
|
+
});
|
|
109
121
|
});
|
|
110
122
|
|
|
111
123
|
describe("suppression", () => {
|
|
@@ -11,11 +11,17 @@ import type { DirectiveSpec } from "../types";
|
|
|
11
11
|
* nested tasks seed a first `:::task` child so the structure is discoverable.
|
|
12
12
|
*/
|
|
13
13
|
export function containerInsertText(spec: DirectiveSpec): string {
|
|
14
|
-
|
|
14
|
+
const head = nameLine(spec);
|
|
15
|
+
if (spec.snippet) return `${head}\n${spec.snippet}\n:::`;
|
|
15
16
|
if (spec.hasNestedTasks) {
|
|
16
|
-
return `${
|
|
17
|
+
return `${head}\n:::task\n\t$0\n:::\n:::`;
|
|
17
18
|
}
|
|
18
|
-
return `${
|
|
19
|
+
return `${head}\n\t$0\n:::`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The directive name, plus a title placeholder when it needs one. */
|
|
23
|
+
function nameLine(spec: DirectiveSpec): string {
|
|
24
|
+
return spec.titled ? `${spec.name}[\${1:Title}]` : spec.name;
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
/** The bare closing fence, offered when a container directive is open. */
|
|
@@ -31,10 +37,15 @@ export function closeInsertText(): string {
|
|
|
31
37
|
* Task-bearing directives seed a nested `task:` child.
|
|
32
38
|
*/
|
|
33
39
|
export function pythonInsertText(spec: DirectiveSpec): string {
|
|
40
|
+
const head = `${nameLine(spec)}:`;
|
|
41
|
+
if (spec.snippet) {
|
|
42
|
+
const body = spec.snippet.split("\n").map((line) => `\t${line}`);
|
|
43
|
+
return [head, ...body].join("\n");
|
|
44
|
+
}
|
|
34
45
|
if (spec.hasNestedTasks) {
|
|
35
|
-
return `${
|
|
46
|
+
return `${head}\n\ttask:\n\t\t$0`;
|
|
36
47
|
}
|
|
37
|
-
return `${
|
|
48
|
+
return `${head}\n\t$0`;
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
/**
|
package/src/data/directives.ts
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
// - LEAF directives (`::name{…}`) are the PreTeXt Plus *include* syntax; the
|
|
12
12
|
// converter turns any `::name` into `<plus:name/>`, so no leaf name is ever
|
|
13
13
|
// "unknown". `LEAF_DIRECTIVES` below is only a convenience completion list.
|
|
14
|
-
// - TEXT directives (`:name[…]`) have no converter handler yet (they
|
|
15
|
-
//
|
|
14
|
+
// - TEXT directives (`:name[…]`) have no converter handler yet (they stay
|
|
15
|
+
// text), so this package neither completes nor lints them.
|
|
16
16
|
|
|
17
17
|
import { PLUS_TYPES, PLUS_TYPE_KIND } from "@pretextbook/latex-style-pretext";
|
|
18
18
|
import type { DirectiveSpec, DirectiveCategory } from "../types";
|
|
@@ -23,6 +23,8 @@ type ContainerSeed = {
|
|
|
23
23
|
requiresStatement: boolean;
|
|
24
24
|
hasNestedTasks?: boolean;
|
|
25
25
|
documentation?: string;
|
|
26
|
+
snippet?: string;
|
|
27
|
+
titled?: boolean;
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
const CONTAINER_SEEDS: Record<string, ContainerSeed> = {
|
|
@@ -82,6 +84,17 @@ const CONTAINER_SEEDS: Record<string, ContainerSeed> = {
|
|
|
82
84
|
solution: { category: "solution-like", requiresStatement: false },
|
|
83
85
|
hint: { category: "solution-like", requiresStatement: false },
|
|
84
86
|
answer: { category: "solution-like", requiresStatement: false },
|
|
87
|
+
|
|
88
|
+
// figure-like (a titled wrapper around one piece of content)
|
|
89
|
+
table: {
|
|
90
|
+
category: "figure-like",
|
|
91
|
+
requiresStatement: false,
|
|
92
|
+
titled: true,
|
|
93
|
+
snippet: "| ${2:Header} | ${3:Header} |\n| --- | --- |\n| $4 | $0 |",
|
|
94
|
+
documentation:
|
|
95
|
+
"A numbered, titled `<table>` around a pipe table (`<tabular>`). " +
|
|
96
|
+
"A pipe table on its own, outside `:::table`, is a bare `<tabular>`.",
|
|
97
|
+
},
|
|
85
98
|
};
|
|
86
99
|
|
|
87
100
|
/**
|
|
@@ -125,6 +138,8 @@ function seedToSpec(name: string, seed: ContainerSeed): DirectiveSpec {
|
|
|
125
138
|
hasNestedTasks: seed.hasNestedTasks,
|
|
126
139
|
childDirectives: children.length > 0 ? children : undefined,
|
|
127
140
|
documentation: seed.documentation,
|
|
141
|
+
snippet: seed.snippet,
|
|
142
|
+
titled: seed.titled,
|
|
128
143
|
};
|
|
129
144
|
}
|
|
130
145
|
|
|
@@ -23,6 +23,15 @@ describe("directive fence matching", () => {
|
|
|
23
23
|
expect(diags[0].message).toContain("no matching open");
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
+
it("accepts pipe tables, bare and in a :::table", () => {
|
|
27
|
+
expect(
|
|
28
|
+
getMarkdownDiagnostics(
|
|
29
|
+
"| A | $|x|$ |\n| - | - |\n| 1 | 2 |\n\n" +
|
|
30
|
+
":::table[Results]{#tbl-res}\n| A |\n| - |\n| 1 |\n:::\n",
|
|
31
|
+
),
|
|
32
|
+
).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
|
|
26
35
|
it("accepts nested containers written with flexible equal colons", () => {
|
|
27
36
|
expect(
|
|
28
37
|
getMarkdownDiagnostics(":::exercise\n:::task\nx\n:::\n:::\n"),
|
package/src/types.ts
CHANGED
|
@@ -14,9 +14,9 @@ export type { PretextFlavorLanguage, GetCompletionsParams };
|
|
|
14
14
|
* - `container` — `:::name` … `:::` (block), the workhorse (theorem, exercise…)
|
|
15
15
|
* - `leaf` — `::name{…}` (a self-closing block; the PreTeXt Plus include
|
|
16
16
|
* syntax, so *any* name is accepted and none is ever "unknown")
|
|
17
|
-
* - `text` — `:name[…]{…}` (inline). The converter
|
|
18
|
-
*
|
|
19
|
-
* nor linted (see the note in ./data/directives.ts).
|
|
17
|
+
* - `text` — `:name[…]{…}` (inline). The converter doesn't read these yet
|
|
18
|
+
* and leaves them as text, so they are recognized by the scanner but neither
|
|
19
|
+
* completed nor linted (see the note in ./data/directives.ts).
|
|
20
20
|
*/
|
|
21
21
|
export type DirectiveKind = "container" | "leaf" | "text";
|
|
22
22
|
|
|
@@ -34,7 +34,8 @@ export type DirectiveCategory =
|
|
|
34
34
|
| "example-like"
|
|
35
35
|
| "project-like"
|
|
36
36
|
| "exercise-like"
|
|
37
|
-
| "solution-like"
|
|
37
|
+
| "solution-like"
|
|
38
|
+
| "figure-like";
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Curated specification for a container directive. The direct analogue of the
|
|
@@ -68,8 +69,14 @@ export interface DirectiveSpec {
|
|
|
68
69
|
/**
|
|
69
70
|
* Override the auto-generated snippet body (LSP snippet syntax). The
|
|
70
71
|
* generator always supplies the `name` line and the closing `:::` fence, so
|
|
71
|
-
* this is the inner body only.
|
|
72
|
+
* this is the inner body only. Number its tab stops from `$2` when the
|
|
73
|
+
* spec is `titled`, since the title placeholder takes `$1`.
|
|
72
74
|
*/
|
|
73
75
|
snippet?: string;
|
|
76
|
+
/**
|
|
77
|
+
* The PreTeXt element needs a `<title>` (e.g. `table`), so the generated
|
|
78
|
+
* name line carries a `[Title]` placeholder.
|
|
79
|
+
*/
|
|
80
|
+
titled?: boolean;
|
|
74
81
|
documentation?: string;
|
|
75
82
|
}
|