@quarto/jupyterlab-quarto 0.1.44 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +48 -15
  3. package/lib/__tests__/jupyterlab_quarto.spec.d.ts +3 -0
  4. package/lib/__tests__/jupyterlab_quarto.spec.js +9 -0
  5. package/lib/ast/ast.d.ts +2 -0
  6. package/lib/ast/ast.js +40 -0
  7. package/lib/const.d.ts +4 -0
  8. package/lib/const.js +11 -0
  9. package/lib/hooks/codemirror.d.ts +5 -0
  10. package/lib/hooks/codemirror.js +77 -0
  11. package/lib/index.d.ts +5 -0
  12. package/lib/index.js +61 -0
  13. package/lib/manager.d.ts +8 -0
  14. package/lib/manager.js +115 -0
  15. package/lib/plugins/callouts.d.ts +2 -0
  16. package/lib/plugins/callouts.js +210 -0
  17. package/lib/plugins/cites.d.ts +2 -0
  18. package/lib/plugins/cites.js +166 -0
  19. package/lib/plugins/decorator.d.ts +2 -0
  20. package/lib/plugins/decorator.js +58 -0
  21. package/lib/plugins/divs.d.ts +5 -0
  22. package/lib/plugins/divs.js +111 -0
  23. package/lib/plugins/figure-divs.d.ts +2 -0
  24. package/lib/plugins/figure-divs.js +54 -0
  25. package/lib/plugins/figures.d.ts +16 -0
  26. package/lib/plugins/figures.js +98 -0
  27. package/lib/plugins/gridtables/common/gridtables/GetCells.d.ts +7 -0
  28. package/lib/plugins/gridtables/common/gridtables/GetCells.js +43 -0
  29. package/lib/plugins/gridtables/common/gridtables/GetColumnWidths.d.ts +7 -0
  30. package/lib/plugins/gridtables/common/gridtables/GetColumnWidths.js +22 -0
  31. package/lib/plugins/gridtables/common/markdown-it/ColumnAlignments.d.ts +7 -0
  32. package/lib/plugins/gridtables/common/markdown-it/ColumnAlignments.js +12 -0
  33. package/lib/plugins/gridtables/common/markdown-it/EmitTable.d.ts +4 -0
  34. package/lib/plugins/gridtables/common/markdown-it/EmitTable.js +64 -0
  35. package/lib/plugins/gridtables/common/markdown-it/GetCharCodeAtStartOfLine.d.ts +8 -0
  36. package/lib/plugins/gridtables/common/markdown-it/GetCharCodeAtStartOfLine.js +17 -0
  37. package/lib/plugins/gridtables/common/markdown-it/GetLine.d.ts +2 -0
  38. package/lib/plugins/gridtables/common/markdown-it/GetLine.js +9 -0
  39. package/lib/plugins/gridtables/common/markdown-it/ParseTable.d.ts +3 -0
  40. package/lib/plugins/gridtables/common/markdown-it/ParseTable.js +152 -0
  41. package/lib/plugins/gridtables/common/markdown-it/ParseTableResult.d.ts +12 -0
  42. package/lib/plugins/gridtables/common/markdown-it/ParseTableResult.js +17 -0
  43. package/lib/plugins/gridtables/index.d.ts +1 -0
  44. package/lib/plugins/gridtables/index.js +10 -0
  45. package/lib/plugins/gridtables/interfaces/markdown-it/IState.d.ts +10 -0
  46. package/lib/plugins/gridtables/interfaces/markdown-it/IState.js +5 -0
  47. package/lib/plugins/gridtables/interfaces/markdown-it/IToken.d.ts +6 -0
  48. package/lib/plugins/gridtables/interfaces/markdown-it/IToken.js +5 -0
  49. package/lib/plugins/gridtables/interfaces/markdown-it/TRuleFunction.d.ts +3 -0
  50. package/lib/plugins/gridtables/interfaces/markdown-it/TRuleFunction.js +5 -0
  51. package/lib/plugins/gridtables/rules/gridtable.d.ts +3 -0
  52. package/lib/plugins/gridtables/rules/gridtable.js +25 -0
  53. package/lib/plugins/index.d.ts +15 -0
  54. package/lib/plugins/index.js +21 -0
  55. package/lib/plugins/math.d.ts +6 -0
  56. package/lib/plugins/math.js +179 -0
  57. package/lib/plugins/mermaid/index.d.ts +4 -0
  58. package/lib/plugins/mermaid/index.js +60 -0
  59. package/lib/plugins/shortcodes.d.ts +3 -0
  60. package/lib/plugins/shortcodes.js +32 -0
  61. package/lib/plugins/spans.d.ts +2 -0
  62. package/lib/plugins/spans.js +37 -0
  63. package/lib/plugins/table-captions.d.ts +2 -0
  64. package/lib/plugins/table-captions.js +72 -0
  65. package/lib/plugins/utils/html.d.ts +11 -0
  66. package/lib/plugins/utils/html.js +50 -0
  67. package/lib/plugins/utils/markdownit.d.ts +15 -0
  68. package/lib/plugins/utils/markdownit.js +46 -0
  69. package/lib/plugins/utils/tok.d.ts +7 -0
  70. package/lib/plugins/utils/tok.js +13 -0
  71. package/lib/plugins/yaml.d.ts +2 -0
  72. package/lib/plugins/yaml.js +330 -0
  73. package/lib/providers/attrs.d.ts +1 -0
  74. package/lib/providers/attrs.js +15 -0
  75. package/lib/providers/callouts.d.ts +1 -0
  76. package/lib/providers/callouts.js +15 -0
  77. package/lib/providers/cites.d.ts +1 -0
  78. package/lib/providers/cites.js +15 -0
  79. package/lib/providers/decorator.d.ts +1 -0
  80. package/lib/providers/decorator.js +15 -0
  81. package/lib/providers/deflist.d.ts +1 -0
  82. package/lib/providers/deflist.js +15 -0
  83. package/lib/providers/divs.d.ts +1 -0
  84. package/lib/providers/divs.js +27 -0
  85. package/lib/providers/figure-divs.d.ts +1 -0
  86. package/lib/providers/figure-divs.js +15 -0
  87. package/lib/providers/figures.d.ts +1 -0
  88. package/lib/providers/figures.js +15 -0
  89. package/lib/providers/footnotes.d.ts +1 -0
  90. package/lib/providers/footnotes.js +15 -0
  91. package/lib/providers/gridtables.d.ts +1 -0
  92. package/lib/providers/gridtables.js +15 -0
  93. package/lib/providers/math.d.ts +1 -0
  94. package/lib/providers/math.js +104 -0
  95. package/lib/providers/mermaid.d.ts +1 -0
  96. package/lib/providers/mermaid.js +17 -0
  97. package/lib/providers/provider.d.ts +3 -0
  98. package/lib/providers/provider.js +12 -0
  99. package/lib/providers/shortcodes.d.ts +1 -0
  100. package/lib/providers/shortcodes.js +15 -0
  101. package/lib/providers/spans.d.ts +1 -0
  102. package/lib/providers/spans.js +15 -0
  103. package/lib/providers/sub.d.ts +1 -0
  104. package/lib/providers/sub.js +15 -0
  105. package/lib/providers/sup.d.ts +1 -0
  106. package/lib/providers/sup.js +15 -0
  107. package/lib/providers/table-captions.d.ts +1 -0
  108. package/lib/providers/table-captions.js +15 -0
  109. package/lib/providers/tasklists.d.ts +1 -0
  110. package/lib/providers/tasklists.js +15 -0
  111. package/lib/providers/yaml.d.ts +1 -0
  112. package/lib/providers/yaml.js +15 -0
  113. package/lib/types.d.ts +43 -0
  114. package/lib/types.js +1 -0
  115. package/lib/widgets.d.ts +14 -0
  116. package/lib/widgets.js +57 -0
  117. package/package.json +105 -39
  118. package/style/base.css +34 -33
  119. package/style/index.css +1 -1
  120. package/schema/plugin.json +0 -8
  121. package/src/@types/markdown-it-deflist.d.ts +0 -10
  122. package/src/@types/markdown-it-footnote.d.ts +0 -10
  123. package/src/@types/markdown-it-gridtables.d.ts +0 -10
  124. package/src/@types/markdown-it-implicit-figures.d.ts +0 -10
  125. package/src/@types/markdown-it-sub.d.ts +0 -10
  126. package/src/@types/markdown-it-sup.d.ts +0 -10
  127. package/src/@types/markdown-it-task-lists.d.ts +0 -10
@@ -0,0 +1,210 @@
1
+ import Token from 'markdown-it/lib/token';
2
+ import { addClass, readAttrValue } from './utils/markdownit';
3
+ import { kTokDivClose, kTokDivOpen } from './divs';
4
+ const kTokCalloutOpen = 'quarto_callout_open';
5
+ const kTokCalloutClose = 'quarto_callout_close';
6
+ const kTokCalloutTitleOpen = 'quarto_callout_title_open';
7
+ const kTokCalloutTitleClose = 'quarto_callout_title_close';
8
+ const kTokCalloutContentOpen = 'quarto_callout_content_open';
9
+ const kTokCalloutContentClose = 'quarto_callout_content_close';
10
+ const kCalloutPrefix = 'callout-';
11
+ const kCalloutRuleName = 'quarto-callouts';
12
+ export const calloutPlugin = (md) => {
13
+ // Handle pandoc-style divs
14
+ md.core.ruler.push(kCalloutRuleName, state => {
15
+ const noteStartCallout = (callout, depth) => {
16
+ if (calloutDepth === -1) {
17
+ calloutDepth = depth;
18
+ }
19
+ state.env['quarto-active-callout'] = callout;
20
+ };
21
+ const noteCloseCallout = () => {
22
+ calloutDepth = -1;
23
+ state.env['quarto-active-callout'] = undefined;
24
+ };
25
+ const activeCallout = () => {
26
+ return state.env['quarto-active-callout'];
27
+ };
28
+ const isCloseCallout = (depth) => {
29
+ return calloutDepth === depth;
30
+ };
31
+ const titleOpenTok = (title) => {
32
+ const token = new Token(kTokCalloutTitleOpen, '', 1);
33
+ token.tag = 'div';
34
+ token.attrs = [['class', 'callout-header']];
35
+ if (title) {
36
+ token.attrs.push(['title', title]);
37
+ }
38
+ return token;
39
+ };
40
+ const titleCloseTok = () => {
41
+ const token = new Token(kTokCalloutTitleClose, '', -1);
42
+ token.tag = 'div';
43
+ return token;
44
+ };
45
+ const contentOpenTok = () => {
46
+ const token = new Token(kTokCalloutContentOpen, '', 1);
47
+ token.tag = 'div';
48
+ token.attrs = [['class', 'callout-body-container callout-body']];
49
+ return token;
50
+ };
51
+ const contentCloseTok = () => {
52
+ const token = new Token(kTokCalloutContentClose, '', -1);
53
+ token.tag = 'div';
54
+ return token;
55
+ };
56
+ const outTokens = [];
57
+ let calloutDepth = -1;
58
+ let divDepth = 0;
59
+ // just started callout - process title
60
+ // finished processing title - process content
61
+ let calloutState = 'scanning';
62
+ for (const token of state.tokens) {
63
+ switch (calloutState) {
64
+ case 'add-title':
65
+ if (token.type === 'heading_open') {
66
+ outTokens.push(titleOpenTok());
67
+ calloutState = 'capturing-title';
68
+ }
69
+ else {
70
+ const callout = activeCallout();
71
+ outTokens.push(titleOpenTok(callout.title));
72
+ outTokens.push(titleCloseTok());
73
+ calloutState = 'add-body';
74
+ }
75
+ break;
76
+ case 'capturing-title':
77
+ if (token.type === 'heading_close') {
78
+ outTokens.push(titleCloseTok());
79
+ calloutState = 'add-body';
80
+ }
81
+ else {
82
+ outTokens.push(token);
83
+ }
84
+ break;
85
+ case 'add-body':
86
+ outTokens.push(contentOpenTok());
87
+ outTokens.push(token);
88
+ calloutState = 'capturing-body';
89
+ break;
90
+ case 'scanning':
91
+ default:
92
+ if (token.type === kTokDivOpen) {
93
+ divDepth++;
94
+ const callout = parseCallout(token.attrs);
95
+ if (callout) {
96
+ noteStartCallout(callout, divDepth);
97
+ calloutState = 'add-title';
98
+ const openCallout = new Token(kTokCalloutOpen, '', 1);
99
+ openCallout.attrs = openCallout.attrs || [];
100
+ openCallout.meta = callout;
101
+ outTokens.push(openCallout);
102
+ }
103
+ else {
104
+ outTokens.push(token);
105
+ }
106
+ }
107
+ else if (token.type === kTokDivClose) {
108
+ if (isCloseCallout(divDepth)) {
109
+ outTokens.push(contentCloseTok());
110
+ outTokens.push(new Token(kTokCalloutClose, '', -1));
111
+ noteCloseCallout();
112
+ }
113
+ else {
114
+ outTokens.push(token);
115
+ }
116
+ divDepth--;
117
+ }
118
+ else {
119
+ outTokens.push(token);
120
+ }
121
+ break;
122
+ }
123
+ }
124
+ state.tokens = outTokens;
125
+ return false;
126
+ });
127
+ md.renderer.rules[kTokCalloutOpen] = renderStartCallout;
128
+ md.renderer.rules[kTokCalloutClose] = renderEndCallout;
129
+ md.renderer.rules[kTokCalloutTitleOpen] = renderStartCalloutTitle;
130
+ md.renderer.rules[kTokCalloutTitleClose] = renderEndCalloutTitle;
131
+ };
132
+ // Render pandoc-style divs
133
+ function renderStartCallout(tokens, idx, _options, _env, self) {
134
+ const token = tokens[idx];
135
+ const callout = token.meta;
136
+ // Add classes decorating as callout
137
+ token.attrs = addClass(`callout ${callout.clz}`, token.attrs);
138
+ // Add class that reflects the style
139
+ token.attrs = addClass(appearanceClass(callout.appearance), token.attrs);
140
+ return `<div ${self.renderAttrs(token)}>`;
141
+ }
142
+ // Render pandoc-style divs
143
+ function renderEndCallout() {
144
+ return '</div>';
145
+ }
146
+ function renderStartCalloutTitle(tokens, idx) {
147
+ const token = tokens[idx];
148
+ const title = readAttrValue('title', token.attrs) || '';
149
+ const startContent = `
150
+ <div class="callout-header">
151
+ <div class="callout-icon-container">
152
+ <i class="callout-icon"></i>
153
+ </div>
154
+ <div class="callout-title-container">${title}
155
+ `;
156
+ return startContent;
157
+ }
158
+ function renderEndCalloutTitle() {
159
+ return '</div>\n</div>';
160
+ }
161
+ const calloutAppearance = (val) => {
162
+ if (val) {
163
+ switch (val) {
164
+ case 'minimal':
165
+ return 'minimal';
166
+ case 'simple':
167
+ return 'simple';
168
+ case 'default':
169
+ default:
170
+ return 'default';
171
+ }
172
+ }
173
+ else {
174
+ return 'default';
175
+ }
176
+ };
177
+ const parseCallout = (attrs) => {
178
+ if (attrs === null) {
179
+ return undefined;
180
+ }
181
+ const classAttr = attrs.find(attr => {
182
+ return attr[0] === 'class';
183
+ });
184
+ if (!classAttr) {
185
+ return undefined;
186
+ }
187
+ const classes = classAttr[1].split(' ');
188
+ const calloutClass = classes.find(clz => {
189
+ return clz.startsWith('callout-');
190
+ });
191
+ if (calloutClass) {
192
+ const type = calloutClass.replace(kCalloutPrefix, '');
193
+ const title = readAttrValue('title', attrs) ||
194
+ type.slice(0, 1).toUpperCase() + type.slice(1);
195
+ const appearance = calloutAppearance(readAttrValue('appearance', attrs));
196
+ return {
197
+ type: type || 'note',
198
+ clz: calloutClass,
199
+ title,
200
+ appearance
201
+ };
202
+ }
203
+ else {
204
+ return undefined;
205
+ }
206
+ };
207
+ const appearanceClass = (appearance) => {
208
+ const style = appearance || 'default';
209
+ return `callout-style-${style}`;
210
+ };
@@ -0,0 +1,2 @@
1
+ import type MarkdownIt from 'markdown-it/lib';
2
+ export declare const citationPlugin: (md: MarkdownIt) => void;
@@ -0,0 +1,166 @@
1
+ /*
2
+ * citation.ts
3
+ *
4
+ * Copyright (C) 2020-2023 Posit Software, PBC
5
+ *
6
+ */
7
+ const kTokCite = 'quarto_cite';
8
+ export const citationPlugin = (md) => {
9
+ // Very simple plugin example that surrounds @text with `code`
10
+ md.core.ruler.push('quarto-citation', state => {
11
+ const tokens = state.tokens;
12
+ for (const token of tokens) {
13
+ if (token.type === 'inline' && token.children) {
14
+ // Rebuild the child list
15
+ const children = [];
16
+ for (let i = 0; i < token.children.length; i++) {
17
+ const child = token.children[i];
18
+ if (child.type === 'text') {
19
+ const content = child.content;
20
+ const textToken = (text) => {
21
+ const newToken = new state.Token('text', '', 0);
22
+ newToken.content = text.join('');
23
+ return newToken;
24
+ };
25
+ let text = [];
26
+ const flushText = () => {
27
+ if (text.length) {
28
+ children.push(textToken(text));
29
+ text = [];
30
+ }
31
+ };
32
+ let cite = [];
33
+ const flushCite = () => {
34
+ var _a;
35
+ if (cite.length) {
36
+ // Determine the cite style
37
+ let style = cite[0] === '-' ? 'suppress-author' : 'in-text';
38
+ if (bracketCount > 0) {
39
+ style = 'normal';
40
+ }
41
+ // The classes
42
+ const clz = ['cite', style];
43
+ // If the cite ends in punctuation, trim that off and make that text
44
+ const puncText = [];
45
+ // Trim off ending punctuation
46
+ if ([
47
+ ':',
48
+ '.',
49
+ '#',
50
+ '$',
51
+ '%',
52
+ '&',
53
+ '-',
54
+ '+',
55
+ '?',
56
+ '<',
57
+ '>',
58
+ '~',
59
+ '/',
60
+ '!'
61
+ ].includes(cite[cite.length - 1])) {
62
+ puncText.push(cite[cite.length - 1]);
63
+ cite = cite.slice(0, -1);
64
+ }
65
+ // Make a cite token
66
+ const newToken = new state.Token(kTokCite, '', 0);
67
+ newToken.content = cite.join('');
68
+ newToken.attrs = newToken.attrs || [];
69
+ (_a = newToken.attrs) === null || _a === void 0 ? void 0 : _a.push(['class', clz.join(' ')]);
70
+ children.push(newToken);
71
+ cite = [];
72
+ if (puncText.length > 0) {
73
+ children.push(textToken(puncText));
74
+ }
75
+ }
76
+ };
77
+ let capture = 'text';
78
+ let bracketCount = 0;
79
+ for (let j = 0; j < content.length; j++) {
80
+ const char = content.charAt(j);
81
+ if (char === '@') {
82
+ if ((text.length === 1 && text[0] === '-') ||
83
+ (text.length > 1 &&
84
+ text[text.length - 1] === '-' &&
85
+ text[text.length - 2] === '[')) {
86
+ cite.push('-');
87
+ cite.push(char);
88
+ text.pop();
89
+ flushText();
90
+ capture = 'cite';
91
+ }
92
+ else if (text[text.length - 1] === ' ') {
93
+ flushText();
94
+ cite.push(char);
95
+ capture = 'cite';
96
+ }
97
+ else if (text[text.length - 1] === '-' &&
98
+ text[text.length - 2] === ' ') {
99
+ text = text.slice(0, -1);
100
+ flushText();
101
+ cite.push('-');
102
+ cite.push(char);
103
+ capture = 'cite';
104
+ }
105
+ else if (text[text.length - 1] === '[' &&
106
+ text[text.length - 2] === ' ') {
107
+ flushText();
108
+ cite.push(char);
109
+ capture = 'cite';
110
+ }
111
+ else if (text.length === 0) {
112
+ cite.push(char);
113
+ capture = 'cite';
114
+ }
115
+ else {
116
+ if (capture === 'cite') {
117
+ cite.push(char);
118
+ }
119
+ else {
120
+ text.push(char);
121
+ }
122
+ }
123
+ }
124
+ else if (char === ' ') {
125
+ capture = 'text';
126
+ flushCite();
127
+ text.push(char);
128
+ }
129
+ else if (char === '[') {
130
+ bracketCount++;
131
+ text.push(char);
132
+ }
133
+ else if (char === ']') {
134
+ bracketCount--;
135
+ capture = 'text';
136
+ flushCite();
137
+ text.push(char);
138
+ }
139
+ else {
140
+ if (capture === 'cite') {
141
+ cite.push(char);
142
+ }
143
+ else {
144
+ text.push(char);
145
+ }
146
+ }
147
+ }
148
+ flushCite();
149
+ flushText();
150
+ }
151
+ else {
152
+ children.push(child);
153
+ }
154
+ }
155
+ token.children = children.length > 0 ? children : null;
156
+ }
157
+ }
158
+ });
159
+ md.renderer.rules[kTokCite] = renderCite;
160
+ };
161
+ // Render pandoc-style divs
162
+ function renderCite(tokens, idx, _options, _env, self) {
163
+ const token = tokens[idx];
164
+ const citeContent = `<code ${self.renderAttrs(token)}>${token.content}</code>`;
165
+ return citeContent;
166
+ }
@@ -0,0 +1,2 @@
1
+ import type MarkdownIt from 'markdown-it/lib';
2
+ export declare const decoratorPlugin: (md: MarkdownIt) => void;
@@ -0,0 +1,58 @@
1
+ import Token from 'markdown-it/lib/token';
2
+ import { attributeDecorator, decorator } from './utils/html';
3
+ import { kTokDivOpen } from './divs';
4
+ import { kTokFigureOpen } from './figures';
5
+ import { kTokHeadingOpen, kTokTableOpen } from './utils/tok';
6
+ import { kTokMathBlock } from './math';
7
+ const kTokDecorator = 'quarto_decorator';
8
+ const kQuartoDecoratorOptions = 'quarto-decorator-options';
9
+ export const decoratorPlugin = (md) => {
10
+ md.core.ruler.push('quarto-decorator', state => {
11
+ const outTokens = [];
12
+ for (const token of state.tokens) {
13
+ if (token.type === 'fence' && !token.attrs && token.info) {
14
+ outTokens.push(decoratorTokForToken(token));
15
+ }
16
+ else if (token.type === kTokHeadingOpen && token.attrs) {
17
+ outTokens.push(decoratorTokForToken(token));
18
+ }
19
+ else if (token.type === kTokDivOpen && token.attrs) {
20
+ outTokens.push(decoratorTokForToken(token));
21
+ }
22
+ else if (token.type === kTokFigureOpen && token.attrs) {
23
+ outTokens.push(decoratorTokForToken(token, { hide: { attributes: true } }));
24
+ }
25
+ else if (token.type === kTokTableOpen && token.attrs) {
26
+ outTokens.push(decoratorTokForToken(token));
27
+ }
28
+ else if (token.type === kTokMathBlock && token.attrs) {
29
+ outTokens.push(decoratorTokForToken(token));
30
+ }
31
+ outTokens.push(token);
32
+ }
33
+ state.tokens = outTokens;
34
+ });
35
+ md.renderer.rules[kTokDecorator] = renderDecorator;
36
+ };
37
+ function decoratorTokForToken(token, options) {
38
+ const decoratorTok = new Token(kTokDecorator, 'div', 1);
39
+ decoratorTok.attrs = token.attrs;
40
+ decoratorTok.info = token.info;
41
+ if (options) {
42
+ decoratorTok.meta = decoratorTok.meta || {};
43
+ decoratorTok.meta[kQuartoDecoratorOptions] = options;
44
+ }
45
+ return decoratorTok;
46
+ }
47
+ // Render pandoc-style divs
48
+ function renderDecorator(tokens, idx) {
49
+ var _a;
50
+ const token = tokens[idx];
51
+ const decoratorOptions = (_a = token.meta) === null || _a === void 0 ? void 0 : _a[kQuartoDecoratorOptions];
52
+ if (token.info) {
53
+ return decorator([token.info]);
54
+ }
55
+ else {
56
+ return attributeDecorator(token, decoratorOptions);
57
+ }
58
+ }
@@ -0,0 +1,5 @@
1
+ import type MarkdownIt from 'markdown-it/lib';
2
+ export declare const kDivRuleName = "pandocDiv";
3
+ export declare const kTokDivOpen = "pandoc_div_open";
4
+ export declare const kTokDivClose = "pandoc_div_close";
5
+ export declare const divPlugin: (md: MarkdownIt) => void;
@@ -0,0 +1,111 @@
1
+ import { addClass } from './utils/markdownit';
2
+ export const kDivRuleName = 'pandocDiv';
3
+ export const kTokDivOpen = 'pandoc_div_open';
4
+ export const kTokDivClose = 'pandoc_div_close';
5
+ export const divPlugin = (md) => {
6
+ // Render pandoc-style divs
7
+ function renderStartDiv(tokens, idx, _options, _env, self) {
8
+ // Add a class to designate that this is a quarto dev
9
+ const token = tokens[idx];
10
+ token.attrs = addClass('quarto-div', token.attrs);
11
+ return `<div ${self.renderAttrs(token)}>`;
12
+ }
13
+ // Render pandoc-style divs
14
+ function renderEndDiv() {
15
+ return '</div>';
16
+ }
17
+ // TODO Implement a better test during validation run
18
+ // Handle pandoc-style divs
19
+ md.block.ruler.before('fence', kDivRuleName, (state, start, _end, silent) => {
20
+ // This is a validation run, can ignore
21
+ if (silent) {
22
+ return true;
23
+ }
24
+ // Get the line for parsing
25
+ const lineStart = state.bMarks[start] + state.tShift[start];
26
+ const lineEnd = state.eMarks[start];
27
+ const line = state.src.slice(lineStart, lineEnd);
28
+ // The current state of the divs (e.g. is there an open)
29
+ // div. Data structure holds key that is the number of colons
30
+ const divState = state.env.quartoOpenDivs || {};
31
+ const incrementDivCount = (fence) => {
32
+ var _a;
33
+ state.env.quartoDivLevel = ((_a = state.env.quartoDivLevel) !== null && _a !== void 0 ? _a : 0) + 1;
34
+ state.env.quartoOpenDivs = state.env.quartoOpenDivs || {};
35
+ const current = state.env.quartoOpenDivs[fence] || 0;
36
+ state.env.quartoOpenDivs[fence] = Math.max(0, current + 1);
37
+ };
38
+ const decrementDivCount = (fence) => {
39
+ state.env.quartoDivLevel--;
40
+ state.env.quartoOpenDivs = state.env.quartoOpenDivs || {};
41
+ const current = state.env.quartoOpenDivs[fence] || 0;
42
+ state.env.quartoOpenDivs[fence] = Math.max(0, current - 1);
43
+ };
44
+ // Three or more colons followed by a an optional brace with attributes
45
+ const divBraceRegex = /^(:::+)\s*(?:(\{[\s\S]+?\}))?$/;
46
+ // Three or more colons followed by a string with no braces
47
+ const divNoBraceRegex = /^(:::+)\s*(?:([^{}\s]+?))?$/;
48
+ const matchers = [divBraceRegex, divNoBraceRegex];
49
+ let match;
50
+ for (const matcher of matchers) {
51
+ match = matcher.exec(line);
52
+ if (match) {
53
+ break;
54
+ }
55
+ }
56
+ if (match) {
57
+ // There is a div here, is one already open?
58
+ const divFence = match[1];
59
+ const attr = match[2];
60
+ // Is this open?
61
+ let isOpenDiv = false;
62
+ const openCount = divState[divFence];
63
+ if (!openCount || openCount === 0) {
64
+ // There isn't an existing open div at this level (number of colons)
65
+ isOpenDiv = true;
66
+ }
67
+ else if (attr) {
68
+ // If it has attributes it is always open
69
+ isOpenDiv = true;
70
+ }
71
+ if (isOpenDiv) {
72
+ // Add to the open count (or set it to 1)
73
+ incrementDivCount(divFence);
74
+ // Make an open token
75
+ const token = state.push(kTokDivOpen, 'div', 1);
76
+ token.markup = line;
77
+ // Allow this to be parsed for attributes by markdown-it-attr
78
+ if (attr && attr.startsWith('{')) {
79
+ token.info = attr;
80
+ }
81
+ else if (attr) {
82
+ token.info = `{.${attr}}`;
83
+ }
84
+ token.block = true;
85
+ token.meta = {
86
+ line: state.line,
87
+ level: state.env.quartoDivLevel
88
+ };
89
+ }
90
+ else {
91
+ // Subtract from the open count (min zero)
92
+ const level = state.env.quartoDivLevel;
93
+ decrementDivCount(divFence);
94
+ // Make a close token
95
+ const token = state.push(kTokDivClose, 'div', -1);
96
+ token.markup = line;
97
+ token.meta = {
98
+ line: state.line,
99
+ level
100
+ };
101
+ }
102
+ state.line = start + 1;
103
+ return true;
104
+ }
105
+ else {
106
+ return false;
107
+ }
108
+ }, { alt: [] });
109
+ md.renderer.rules[kTokDivOpen] = renderStartDiv;
110
+ md.renderer.rules[kTokDivClose] = renderEndDiv;
111
+ };
@@ -0,0 +1,2 @@
1
+ import MarkdownIt from 'markdown-it';
2
+ export declare const figureDivsPlugin: (md: MarkdownIt) => void;
@@ -0,0 +1,54 @@
1
+ /*
2
+ * figure-divs.ts
3
+ *
4
+ * Copyright (C) 2020-2023 Posit Software, PBC
5
+ *
6
+ */
7
+ import { readAttrValue } from './utils/markdownit';
8
+ import { kTokInline, kTokParaClose, kTokParaOpen } from './utils/tok';
9
+ import { kTokDivClose, kTokDivOpen } from './divs';
10
+ import { kTokFigCaptionClose, kTokFigCaptionOpen, mutateToFigureTok } from './figures';
11
+ const kFigureDivRuleName = 'quarto-figure-divs';
12
+ const kFigurePrefix = 'fig-';
13
+ export const figureDivsPlugin = (md) => {
14
+ // Handle pandoc-style divs
15
+ md.core.ruler.push(kFigureDivRuleName, state => {
16
+ const isFigureDiv = [];
17
+ for (let i = 0; i < state.tokens.length; i++) {
18
+ const token = state.tokens[i];
19
+ if (token.type === kTokDivOpen) {
20
+ const id = readAttrValue('id', token.attrs);
21
+ if (id === null || id === void 0 ? void 0 : id.startsWith(kFigurePrefix)) {
22
+ isFigureDiv.push(true);
23
+ mutateToFigureTok(token, 'open');
24
+ }
25
+ else {
26
+ // Note the div, but not a figure div
27
+ isFigureDiv.push(false);
28
+ }
29
+ }
30
+ else if (token.type === kTokDivClose) {
31
+ const isFigDiv = isFigureDiv.pop();
32
+ if (isFigDiv) {
33
+ // If the preview token is paragraph, use that as the caption
34
+ if (i - 3 >= 0) {
35
+ const maybeParaStart = state.tokens[i - 3];
36
+ const maybeInline = state.tokens[i - 2];
37
+ const maybeParaEnd = state.tokens[i - 1];
38
+ if (maybeParaStart.type === kTokParaOpen &&
39
+ maybeParaEnd.type === kTokParaClose &&
40
+ maybeInline.type === kTokInline) {
41
+ mutateToFigCaption(state.tokens[i - 3], 'open');
42
+ mutateToFigCaption(state.tokens[i - 1], 'close');
43
+ }
44
+ }
45
+ mutateToFigureTok(token, 'close');
46
+ }
47
+ }
48
+ }
49
+ });
50
+ };
51
+ const mutateToFigCaption = (token, type) => {
52
+ token.tag = 'figcaption';
53
+ token.type = type === 'open' ? kTokFigCaptionClose : kTokFigCaptionOpen;
54
+ };
@@ -0,0 +1,16 @@
1
+ import MarkdownIt from 'markdown-it';
2
+ import Token from 'markdown-it/lib/token';
3
+ export interface FigureOptions {
4
+ dataType?: boolean;
5
+ link?: boolean;
6
+ figcaption?: boolean;
7
+ copyAttrs?: boolean;
8
+ tabindex?: boolean;
9
+ lazyLoading?: boolean;
10
+ }
11
+ export declare const kTokFigureOpen = "figure_open";
12
+ export declare const kTokFigureClose = "figure_close";
13
+ export declare const kTokFigCaptionOpen = "figcaption_open";
14
+ export declare const kTokFigCaptionClose = "figcaption_close";
15
+ export declare const mutateToFigureTok: (token: Token, type: 'open' | 'close') => void;
16
+ export declare function figuresPlugin(md: MarkdownIt, options: FigureOptions): void;