@pretextbook/markdown-style-pretext 0.1.5 → 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.1.5",
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",
@@ -38,7 +38,7 @@
38
38
  "vscode-languageserver-types": "^3.17.5"
39
39
  },
40
40
  "devDependencies": {
41
- "@pretextbook/remark-pretext": "^0.3.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");
@@ -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
- if (spec.snippet) return `${spec.name}\n${spec.snippet}\n:::`;
14
+ const head = nameLine(spec);
15
+ if (spec.snippet) return `${head}\n${spec.snippet}\n:::`;
15
16
  if (spec.hasNestedTasks) {
16
- return `${spec.name}\n:::task\n\t$0\n:::\n:::`;
17
+ return `${head}\n:::task\n\t$0\n:::\n:::`;
17
18
  }
18
- return `${spec.name}\n\t$0\n:::`;
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 `${spec.name}:\n\ttask:\n\t\t$0`;
46
+ return `${head}\n\ttask:\n\t\t$0`;
36
47
  }
37
- return `${spec.name}:\n\t$0`;
48
+ return `${head}\n\t$0`;
38
49
  }
39
50
 
40
51
  /**
@@ -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
@@ -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
  }