document-cli 1.10.0 → 1.11.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 +3 -3
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{tui-BVeYd0ry.js → tui-DWXPty2k.js} +189 -176
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ graph TD
|
|
|
41
41
|
|
|
42
42
|
## Why
|
|
43
43
|
|
|
44
|
-
`documents.js` is a library, not a tool — everything it does happens through function calls from TypeScript/JavaScript. Most people who want to convert a docx to a PDF, extract an `.odb` table to CSV, or poke at a PDF's structure from a terminal don't want to write a script to do it. `document-cli` is that missing entry point: every one of documents.js's 27 direct conversion pairs, its generic converter, its `.odm`/`.odb` extraction functions, and its PDF inspector become a single command-line invocation, and its
|
|
44
|
+
`documents.js` is a library, not a tool — everything it does happens through function calls from TypeScript/JavaScript. Most people who want to convert a docx to a PDF, extract an `.odb` table to CSV, or poke at a PDF's structure from a terminal don't want to write a script to do it. `document-cli` is that missing entry point: every one of documents.js's 27 direct conversion pairs, its generic converter, its `.odm`/`.odb` extraction functions, and its PDF inspector become a single command-line invocation, and its seven live-view editors (docx/pptx/odt/odp/ods/odg/markdown) become a keyboard-driven terminal app that never needs a code editor open at all.
|
|
45
45
|
|
|
46
46
|
The CLI and the TUI are deliberately not two separate implementations of the same logic. The TUI's own document-opening, saving, and PDF-export code (`src/tui/format/`) calls the identical `documents.js` functions the CLI commands call — `openDocx`/`createDocx`/`docxToPdf` and their five siblings per format, plus `readOdbTables`/`readPdf` for the two read-only sources — so there is exactly one place either surface can drift from what documents.js itself does: nowhere.
|
|
47
47
|
|
|
@@ -165,9 +165,9 @@ Diagnostics and the summary line always go to stderr; stdout is reserved for the
|
|
|
165
165
|
|
|
166
166
|
Launch it either bare (`document-cli`, with no arguments) or explicitly with `document-cli tui [file]` — both open the same app; the explicit form additionally opens `file` immediately, skipping the launcher screen. The TUI needs an interactive terminal: a bare invocation with redirected stdout prints help text instead, and an explicit `tui` invocation with redirected stdout fails outright, since there's no terminal for Ink to draw into.
|
|
167
167
|
|
|
168
|
-
It supports the same
|
|
168
|
+
It supports the same seven formats documents.js's live-view editors cover — docx, pptx, odt, odp, ods, odg, markdown — each with a full navigate/edit/save experience built on that format's editor (paragraphs and runs for docx/odt/markdown, slides and shapes for pptx/odp, sheets and cells for ods, pages and vectors/shapes for odg), plus undo (whole-document snapshots taken before each committed mutation), search, a command palette, and PDF export straight from the open document. On a pptx or odp slide, `a` from the shape list also adds a real table (rows then columns, a two-step prompt) alongside the existing textbox/image choices, and `n` opens the slide's own speaker notes for either format — `PptxSlide` and `OdpSlide` both carry a real `.notes` getter/setter, so notes editing was never odp-specific, only gated that way until this phase removed the gate.
|
|
169
169
|
|
|
170
|
-
Markdown (`.md`/`.markdown`)
|
|
170
|
+
Markdown (`.md`/`.markdown`) shares the same paragraph/run/table body-list screens docx and odt already use, through documents.js's own `MarkdownEditor` (`openMarkdown`/`createMarkdownEditor`) — a genuine live view over a mutable `ContentDocument`, the same live-view contract every other editor here follows, even though there is no `XmlElement` tree underneath it the way there is for docx/odt (`MarkdownEditor.toMarkdownText()` re-serialises the whole document fresh on every call, rather than exposing a `toBytes()`). Appending a paragraph, appending a run, and toggling bold/italic all go through the identical reducer actions docx/odt use; a markdown run has no underline, colour, font family, or font size at all (CommonMark/GFM has no construct for any of the four), so those keys — along with image insertion, which `MarkdownParagraph` has no counterpart for — are simply absent from a markdown paragraph's own key hints rather than opening a prompt that could only end in a warning. A markdown table can be created and its cells edited through the same 'T' wizard and table-view screens docx/odt use, but GFM tables have no cell-merge concept, so a merge requested alongside table creation still creates the table (unmerged) and reports why the merge itself didn't happen. `:view-source` (markdown documents only) shows the literal text the document was opened with side by side with what a save would write right now — these can genuinely differ even with no edits made this session, from a heading-style, bullet-marker, or line-ending choice the writer normalises. Every save re-serialises the whole document fresh through `buildMarkdownText`, a deliberate, permanent consequence of structured editing rather than something to work around. Diagnostics from the read side (a clamped heading level, a dropped front-matter key, a fenced code block's own info string with nowhere to go, …) now surface into the same diagnostics panel a PDF export's own substitutions already populate, the moment a `.md` file is opened, not only on export. documents.js's own `createMarkdownEditor()` exists now, but this TUI does not yet wire a "new markdown document" flow into `:new`/the new-document picker, so a markdown document can still only be opened from an existing file.
|
|
171
171
|
|
|
172
172
|
Three further formats open read-only: a `.odb` browses its tables and rows with no write path at all (documents.js's own `.odb` support has no write direction to offer), a `.pdf` browses its pages and positioned items rather than being edited in place, and a `.xlsx` opens as a converted PDF preview — documents.js has no xlsx editor to hold a live view into, so opening one runs `xlsxToPdf` once at open time and browses the result through the identical page-list/page-items/item-detail screens a real `.pdf` uses, with the original bytes kept alongside so a later export re-runs `xlsxToPdf` with the caller's own fonts and diagnostics rather than reusing the fixed preview conversion. A `.odb` additionally browses its *structure* alongside its data: `f` from the table list opens the form browser and `r` the report browser, each listing what the database declares and opening one to show it in full — a form's own data source and field-bound controls (sub-forms nested under their parent), a report's data-source command, band and group structure, and every `rpt:` formula. Both are rendered through the same `src/odb-structure.ts` the `odb-forms`/`odb-reports` commands print, so the two views cannot drift apart, and search filters by line (`/SUM` narrows a long report to its aggregate expressions). A standalone `.odf` formula document has no TUI editor either — nothing to edit interactively, only a PDF conversion.
|
|
173
173
|
|
package/dist/cli.js
CHANGED
|
@@ -1194,7 +1194,7 @@ function registerSetMetadataCommand(program) {
|
|
|
1194
1194
|
}
|
|
1195
1195
|
//#endregion
|
|
1196
1196
|
//#region package.json
|
|
1197
|
-
var version = "1.
|
|
1197
|
+
var version = "1.11.0";
|
|
1198
1198
|
//#endregion
|
|
1199
1199
|
//#region src/program.ts
|
|
1200
1200
|
function createProgram() {
|
|
@@ -1221,7 +1221,7 @@ function createProgram() {
|
|
|
1221
1221
|
//#region src/cli.ts
|
|
1222
1222
|
async function launchTui(startPath, signal) {
|
|
1223
1223
|
try {
|
|
1224
|
-
const { runTui } = await import("./tui-
|
|
1224
|
+
const { runTui } = await import("./tui-DWXPty2k.js");
|
|
1225
1225
|
await runTui({
|
|
1226
1226
|
startPath,
|
|
1227
1227
|
signal
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as formatDocxExtrasLines, f as loadProvidedFonts, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, p as formatToExtension, r as formatOdbFormLines, t as describeOdbForm } from "./odb-structure-Du1w_hOU.js";
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { buildDocxPackage, buildOdtPackage, bytesToBase64, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPdf, openPptx, parseXml, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, writePdf, xlsxToPdf } from "documents.js";
|
|
3
|
+
import { buildDocxPackage, buildOdtPackage, bytesToBase64, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openMarkdown, openOdg, openOdp, openOds, openOdt, openPdf, openPptx, parseXml, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, writePdf, xlsxToPdf } from "documents.js";
|
|
4
4
|
import { basename, dirname, extname, join } from "node:path";
|
|
5
5
|
import { cellReference, columnIndexToLetters, decodePackage as decodePackage$1, encodePackage as encodePackage$1 } from "odf.js";
|
|
6
6
|
import { readdirSync } from "node:fs";
|
|
@@ -39,7 +39,7 @@ async function exportToPdf(openDocument, destinationPath, options) {
|
|
|
39
39
|
if (openDocument.format === "odb" || openDocument.format === "pdf") throw new Error(`A ${openDocument.format} document has no export-to-PDF path -- ${openDocument.format === "pdf" ? "save it directly instead" : "it is a read-only source with nothing to convert"}`);
|
|
40
40
|
const pdfOptions = toPdfOptions(options, await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal }));
|
|
41
41
|
if (openDocument.format === "markdown") {
|
|
42
|
-
const pdfBytes = markdownToPdf(encodeMarkdownText(openDocument.
|
|
42
|
+
const pdfBytes = markdownToPdf(encodeMarkdownText(openDocument.editor.toMarkdownText()), pdfOptions);
|
|
43
43
|
await writeFile(destinationPath, pdfBytes);
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
@@ -75,7 +75,7 @@ function detectFormat(path) {
|
|
|
75
75
|
//#endregion
|
|
76
76
|
//#region src/tui/format/open-document.ts
|
|
77
77
|
const ODB_EXTENSION = ".odb";
|
|
78
|
-
async function openDocumentAtPath(path) {
|
|
78
|
+
async function openDocumentAtPath(path, options = {}) {
|
|
79
79
|
const bytes = new Uint8Array(await readFile(path));
|
|
80
80
|
if (path.toLowerCase().endsWith(ODB_EXTENSION)) {
|
|
81
81
|
const pkg = decodePackage$1(bytes);
|
|
@@ -129,11 +129,20 @@ async function openDocumentAtPath(path) {
|
|
|
129
129
|
path
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
-
case "markdown":
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
case "markdown": {
|
|
133
|
+
const text = decodeMarkdownText(bytes);
|
|
134
|
+
return {
|
|
135
|
+
format,
|
|
136
|
+
editor: openMarkdown(text, { sink: (diagnostic) => {
|
|
137
|
+
options.onDiagnostic?.({
|
|
138
|
+
severity: diagnostic.severity,
|
|
139
|
+
message: diagnostic.message
|
|
140
|
+
});
|
|
141
|
+
} }),
|
|
142
|
+
originalText: text,
|
|
143
|
+
path
|
|
144
|
+
};
|
|
145
|
+
}
|
|
137
146
|
case "xlsx": return {
|
|
138
147
|
format,
|
|
139
148
|
layout: readPdf(xlsxToPdf(bytes)),
|
|
@@ -189,7 +198,7 @@ function createNewDocument(format) {
|
|
|
189
198
|
async function saveDocumentTo(openDocument, path) {
|
|
190
199
|
if (openDocument.format === "odb" || openDocument.format === "xlsx") throw new Error(`A ${openDocument.format} document is opened read-only and cannot be written back`);
|
|
191
200
|
if (openDocument.format === "markdown") {
|
|
192
|
-
await writeFile(path, encodeMarkdownText(openDocument.
|
|
201
|
+
await writeFile(path, encodeMarkdownText(openDocument.editor.toMarkdownText()));
|
|
193
202
|
return;
|
|
194
203
|
}
|
|
195
204
|
await writeFile(path, openDocument.editor.toBytes());
|
|
@@ -233,7 +242,7 @@ function selectionKeyFor(screen) {
|
|
|
233
242
|
case "pdfPageList":
|
|
234
243
|
case "exportOptions":
|
|
235
244
|
case "saveAsPrompt":
|
|
236
|
-
case "
|
|
245
|
+
case "viewSource":
|
|
237
246
|
case "metadata": return screen.kind;
|
|
238
247
|
case "filePicker": return `filePicker:${screen.purpose}:${screen.cwd}`;
|
|
239
248
|
case "paragraphDetail":
|
|
@@ -256,19 +265,18 @@ function selectionKeyFor(screen) {
|
|
|
256
265
|
case "odbFormDetail": return `odbFormDetail:${screen.formName}`;
|
|
257
266
|
case "odbReportDetail": return `odbReportDetail:${screen.reportName}`;
|
|
258
267
|
case "odbReportRender": return `odbReportRender:${screen.reportName}`;
|
|
259
|
-
case "markdownLineEditor": return `markdownLineEditor:${screen.lineIndex}`;
|
|
260
268
|
}
|
|
261
269
|
}
|
|
262
270
|
function rootScreenForFormat(format) {
|
|
263
271
|
switch (format) {
|
|
264
272
|
case "docx":
|
|
265
|
-
case "odt":
|
|
273
|
+
case "odt":
|
|
274
|
+
case "markdown": return { kind: "bodyList" };
|
|
266
275
|
case "pptx":
|
|
267
276
|
case "odp": return { kind: "slideList" };
|
|
268
277
|
case "ods": return { kind: "sheetList" };
|
|
269
278
|
case "odg": return { kind: "pageList" };
|
|
270
279
|
case "odb": return { kind: "odbTableList" };
|
|
271
|
-
case "markdown": return { kind: "markdownLineList" };
|
|
272
280
|
case "pdf":
|
|
273
281
|
case "xlsx": return { kind: "pdfPageList" };
|
|
274
282
|
}
|
|
@@ -397,7 +405,8 @@ function documentWithPath(doc, path) {
|
|
|
397
405
|
};
|
|
398
406
|
case "markdown": return {
|
|
399
407
|
format: "markdown",
|
|
400
|
-
|
|
408
|
+
editor: doc.editor,
|
|
409
|
+
originalText: doc.originalText,
|
|
401
410
|
path
|
|
402
411
|
};
|
|
403
412
|
case "xlsx": return {
|
|
@@ -451,8 +460,11 @@ function reopenEditable(doc, bytes) {
|
|
|
451
460
|
}
|
|
452
461
|
}
|
|
453
462
|
}
|
|
463
|
+
function toUndoSnapshot(doc) {
|
|
464
|
+
return doc.format === "markdown" ? encodeMarkdownText(doc.editor.toMarkdownText()) : doc.editor.toBytes();
|
|
465
|
+
}
|
|
454
466
|
function mutate(state, doc, apply) {
|
|
455
|
-
const snapshot = doc
|
|
467
|
+
const snapshot = toUndoSnapshot(doc);
|
|
456
468
|
apply();
|
|
457
469
|
return {
|
|
458
470
|
...state,
|
|
@@ -492,22 +504,15 @@ function mergePptxTableCells(table, startRow, startColumn, rowSpan, colSpan) {
|
|
|
492
504
|
}
|
|
493
505
|
}
|
|
494
506
|
}
|
|
495
|
-
function mutateMarkdown(state, doc, source) {
|
|
496
|
-
const snapshot = encodeMarkdownText(doc.source);
|
|
497
|
-
return {
|
|
498
|
-
...state,
|
|
499
|
-
openDocument: {
|
|
500
|
-
...doc,
|
|
501
|
-
source
|
|
502
|
-
},
|
|
503
|
-
hasUnsavedChanges: true,
|
|
504
|
-
undoStack: pushSnapshot(state.undoStack, snapshot)
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
507
|
function wrongDocument(state, expected) {
|
|
508
508
|
return withStatus(state, "warning", `That action needs ${expected}; the open document is ${state.openDocument === void 0 ? "no document" : state.openDocument.format}`);
|
|
509
509
|
}
|
|
510
510
|
function wordprocessingDocument(state) {
|
|
511
|
+
const doc = state.openDocument;
|
|
512
|
+
if (doc === void 0) return;
|
|
513
|
+
return doc.format === "docx" || doc.format === "odt" || doc.format === "markdown" ? doc : void 0;
|
|
514
|
+
}
|
|
515
|
+
function styledWordprocessingDocument(state) {
|
|
511
516
|
const doc = state.openDocument;
|
|
512
517
|
if (doc === void 0) return;
|
|
513
518
|
return doc.format === "docx" || doc.format === "odt" ? doc : void 0;
|
|
@@ -571,17 +576,15 @@ function vectorHostDocument(state) {
|
|
|
571
576
|
if (doc === void 0) return;
|
|
572
577
|
return doc.format === "odg" || doc.format === "odp" ? doc : void 0;
|
|
573
578
|
}
|
|
574
|
-
function markdownDocument(state) {
|
|
575
|
-
const doc = state.openDocument;
|
|
576
|
-
if (doc === void 0) return;
|
|
577
|
-
return doc.format === "markdown" ? doc : void 0;
|
|
578
|
-
}
|
|
579
579
|
function paragraphAt(doc, blockIndex) {
|
|
580
580
|
return doc.editor.paragraphs()[blockIndex];
|
|
581
581
|
}
|
|
582
582
|
function tableAt(doc, tableIndex) {
|
|
583
583
|
return doc.editor.tables()[tableIndex];
|
|
584
584
|
}
|
|
585
|
+
function tableCellAt(table, row, column) {
|
|
586
|
+
return table.rows()[row]?.cells()[column];
|
|
587
|
+
}
|
|
585
588
|
function shapeAt(doc, containerIndex, shapeIndex) {
|
|
586
589
|
if (doc.format === "odg") return doc.editor.pages()[containerIndex]?.shapes()[shapeIndex];
|
|
587
590
|
return doc.editor.slides()[containerIndex]?.shapes()[shapeIndex];
|
|
@@ -591,7 +594,7 @@ function sheetAt(doc, sheetIndex) {
|
|
|
591
594
|
}
|
|
592
595
|
function withRun(state, blockIndex, runIndex, apply) {
|
|
593
596
|
const doc = wordprocessingDocument(state);
|
|
594
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
597
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
595
598
|
const paragraph = paragraphAt(doc, blockIndex);
|
|
596
599
|
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${blockIndex}`);
|
|
597
600
|
const run = paragraph.runs()[runIndex];
|
|
@@ -600,6 +603,17 @@ function withRun(state, blockIndex, runIndex, apply) {
|
|
|
600
603
|
apply(run);
|
|
601
604
|
});
|
|
602
605
|
}
|
|
606
|
+
function withStyledRun(state, blockIndex, runIndex, apply) {
|
|
607
|
+
const doc = styledWordprocessingDocument(state);
|
|
608
|
+
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
609
|
+
const paragraph = doc.editor.paragraphs()[blockIndex];
|
|
610
|
+
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${blockIndex}`);
|
|
611
|
+
const run = paragraph.runs()[runIndex];
|
|
612
|
+
if (run === void 0) return withStatus(state, "warning", `Paragraph ${blockIndex} has no run at index ${runIndex}`);
|
|
613
|
+
return mutate(state, doc, () => {
|
|
614
|
+
apply(run);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
603
617
|
function withShape(state, containerIndex, shapeIndex, apply) {
|
|
604
618
|
const doc = shapeHostDocument(state);
|
|
605
619
|
if (doc === void 0) return wrongDocument(state, "a pptx, odp or odg document");
|
|
@@ -761,8 +775,15 @@ function appReducer(state, action) {
|
|
|
761
775
|
};
|
|
762
776
|
case "APPEND_PARAGRAPH": {
|
|
763
777
|
const doc = wordprocessingDocument(state);
|
|
764
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
778
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
765
779
|
return mutate(state, doc, () => {
|
|
780
|
+
if (doc.format === "markdown") {
|
|
781
|
+
doc.editor.body.appendParagraph({
|
|
782
|
+
text: action.text,
|
|
783
|
+
styleId: action.styleId
|
|
784
|
+
});
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
766
787
|
doc.editor.body.appendParagraph({
|
|
767
788
|
text: action.text,
|
|
768
789
|
styleId: action.styleId,
|
|
@@ -771,9 +792,9 @@ function appReducer(state, action) {
|
|
|
771
792
|
});
|
|
772
793
|
}
|
|
773
794
|
case "SET_PARAGRAPH_ALIGNMENT": {
|
|
774
|
-
const doc =
|
|
795
|
+
const doc = styledWordprocessingDocument(state);
|
|
775
796
|
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
776
|
-
const paragraph =
|
|
797
|
+
const paragraph = doc.editor.paragraphs()[action.blockIndex];
|
|
777
798
|
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
|
|
778
799
|
return mutate(state, doc, () => {
|
|
779
800
|
paragraph.alignment = action.alignment;
|
|
@@ -781,7 +802,7 @@ function appReducer(state, action) {
|
|
|
781
802
|
}
|
|
782
803
|
case "APPEND_RUN": {
|
|
783
804
|
const doc = wordprocessingDocument(state);
|
|
784
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
805
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
785
806
|
const paragraph = paragraphAt(doc, action.blockIndex);
|
|
786
807
|
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
|
|
787
808
|
return mutate(state, doc, () => {
|
|
@@ -797,50 +818,60 @@ function appReducer(state, action) {
|
|
|
797
818
|
case "TOGGLE_RUN_ITALIC": return withRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
798
819
|
run.italic = !run.italic;
|
|
799
820
|
});
|
|
800
|
-
case "TOGGLE_RUN_UNDERLINE": return
|
|
821
|
+
case "TOGGLE_RUN_UNDERLINE": return withStyledRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
801
822
|
run.underline = !run.underline;
|
|
802
823
|
});
|
|
803
|
-
case "SET_RUN_COLOR": return
|
|
824
|
+
case "SET_RUN_COLOR": return withStyledRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
804
825
|
run.color = action.color;
|
|
805
826
|
});
|
|
806
|
-
case "SET_RUN_FONT_FAMILY": return
|
|
827
|
+
case "SET_RUN_FONT_FAMILY": return withStyledRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
807
828
|
run.fontFamily = action.fontFamily;
|
|
808
829
|
});
|
|
809
|
-
case "SET_RUN_FONT_SIZE": return
|
|
830
|
+
case "SET_RUN_FONT_SIZE": return withStyledRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
810
831
|
run.sizePt = action.sizePt;
|
|
811
832
|
});
|
|
812
833
|
case "APPEND_TABLE": {
|
|
813
834
|
const doc = wordprocessingDocument(state);
|
|
814
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
815
|
-
|
|
835
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
836
|
+
let mergeUnsupported = false;
|
|
837
|
+
const nextState = mutateGuarded(state, doc, () => {
|
|
816
838
|
const table = doc.editor.body.appendTable({
|
|
817
839
|
rows: action.rows,
|
|
818
840
|
columns: action.columns
|
|
819
841
|
});
|
|
820
|
-
if (action.merge
|
|
842
|
+
if (action.merge === void 0) return;
|
|
843
|
+
if (!("mergeCells" in table)) {
|
|
844
|
+
mergeUnsupported = true;
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
table.mergeCells(action.merge.startRow, action.merge.startColumn, action.merge.rowSpan, action.merge.colSpan);
|
|
821
848
|
});
|
|
849
|
+
return mergeUnsupported ? withStatus(nextState, "warning", "Markdown tables do not support merged cells -- the table was created without merging") : nextState;
|
|
822
850
|
}
|
|
823
851
|
case "MERGE_TABLE_CELLS": {
|
|
824
852
|
const doc = wordprocessingDocument(state);
|
|
825
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
853
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
826
854
|
const table = tableAt(doc, action.tableIndex);
|
|
827
855
|
if (table === void 0) return withStatus(state, "warning", `There is no table at index ${action.tableIndex}`);
|
|
856
|
+
if (!("mergeCells" in table)) return withStatus(state, "warning", "Markdown tables do not support merged cells");
|
|
828
857
|
return mutateGuarded(state, doc, () => {
|
|
829
858
|
table.mergeCells(action.startRow, action.startColumn, action.rowSpan, action.colSpan);
|
|
830
859
|
});
|
|
831
860
|
}
|
|
832
861
|
case "SET_TABLE_CELL_TEXT": {
|
|
833
862
|
const doc = wordprocessingDocument(state);
|
|
834
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
863
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
835
864
|
const table = tableAt(doc, action.tableIndex);
|
|
836
865
|
if (table === void 0) return withStatus(state, "warning", `There is no table at index ${action.tableIndex}`);
|
|
866
|
+
const cell = tableCellAt(table, action.row, action.column);
|
|
867
|
+
if (cell === void 0) return withStatus(state, "warning", `There is no cell at row ${action.row}, column ${action.column} of table ${action.tableIndex}`);
|
|
837
868
|
return mutate(state, doc, () => {
|
|
838
|
-
setCellText(
|
|
869
|
+
setCellText(cell, action.text);
|
|
839
870
|
});
|
|
840
871
|
}
|
|
841
872
|
case "ADD_LIST_ITEM": {
|
|
842
873
|
const doc = wordprocessingDocument(state);
|
|
843
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
874
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
844
875
|
if (doc.format === "odt") {
|
|
845
876
|
const list = doc.editor.lists()[action.blockIndex];
|
|
846
877
|
if (list === void 0) return withStatus(state, "warning", `There is no list at index ${action.blockIndex}`);
|
|
@@ -859,7 +890,7 @@ function appReducer(state, action) {
|
|
|
859
890
|
}
|
|
860
891
|
case "SET_LIST_ITEM_TEXT": {
|
|
861
892
|
const doc = wordprocessingDocument(state);
|
|
862
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
893
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
863
894
|
if (doc.format !== "odt") return wrongDocument(state, "an odt document (lists are an odt-only concept)");
|
|
864
895
|
const list = doc.editor.lists()[action.blockIndex];
|
|
865
896
|
if (list === void 0) return withStatus(state, "warning", `There is no list at index ${action.blockIndex}`);
|
|
@@ -871,16 +902,16 @@ function appReducer(state, action) {
|
|
|
871
902
|
}
|
|
872
903
|
case "ADD_LIST": {
|
|
873
904
|
const doc = wordprocessingDocument(state);
|
|
874
|
-
if (doc === void 0) return wrongDocument(state, "a docx or
|
|
905
|
+
if (doc === void 0) return wrongDocument(state, "a docx, odt or markdown document");
|
|
875
906
|
if (doc.format !== "odt") return wrongDocument(state, "an odt document (lists are an odt-only concept)");
|
|
876
907
|
return mutate(state, doc, () => {
|
|
877
908
|
doc.editor.body.appendList();
|
|
878
909
|
});
|
|
879
910
|
}
|
|
880
911
|
case "INSERT_PARAGRAPH_IMAGE": {
|
|
881
|
-
const doc =
|
|
912
|
+
const doc = styledWordprocessingDocument(state);
|
|
882
913
|
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
883
|
-
const paragraph =
|
|
914
|
+
const paragraph = doc.editor.paragraphs()[action.blockIndex];
|
|
884
915
|
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
|
|
885
916
|
return mutate(state, doc, () => {
|
|
886
917
|
paragraph.insertImageAfter({
|
|
@@ -1259,11 +1290,6 @@ function appReducer(state, action) {
|
|
|
1259
1290
|
item.widthPt = action.widthPt;
|
|
1260
1291
|
item.heightPt = action.heightPt;
|
|
1261
1292
|
});
|
|
1262
|
-
case "SET_MARKDOWN_SOURCE": {
|
|
1263
|
-
const doc = markdownDocument(state);
|
|
1264
|
-
if (doc === void 0) return wrongDocument(state, "a markdown document");
|
|
1265
|
-
return mutateMarkdown(state, doc, action.source);
|
|
1266
|
-
}
|
|
1267
1293
|
case "APPEND_DIAGNOSTIC": return {
|
|
1268
1294
|
...state,
|
|
1269
1295
|
diagnostics: [...state.diagnostics, action.diagnostic]
|
|
@@ -1297,7 +1323,7 @@ function appReducer(state, action) {
|
|
|
1297
1323
|
if (snapshot === void 0) return withStatus(state, "info", "There is nothing to undo");
|
|
1298
1324
|
const restored = doc.format === "markdown" ? {
|
|
1299
1325
|
...doc,
|
|
1300
|
-
|
|
1326
|
+
editor: openMarkdown(decodeMarkdownText(snapshot))
|
|
1301
1327
|
} : reopenEditable(doc, snapshot);
|
|
1302
1328
|
return withStatus({
|
|
1303
1329
|
...state,
|
|
@@ -1413,6 +1439,11 @@ const COMMANDS = [
|
|
|
1413
1439
|
usage: ":undo",
|
|
1414
1440
|
description: "Undo the last change"
|
|
1415
1441
|
},
|
|
1442
|
+
{
|
|
1443
|
+
name: "view-source",
|
|
1444
|
+
usage: ":view-source",
|
|
1445
|
+
description: "Compare a markdown document as opened vs. as it will save now"
|
|
1446
|
+
},
|
|
1416
1447
|
{
|
|
1417
1448
|
name: "help",
|
|
1418
1449
|
usage: ":help",
|
|
@@ -1531,7 +1562,12 @@ async function runCommand(line, state, dispatch) {
|
|
|
1531
1562
|
dispatch({
|
|
1532
1563
|
type: "OPEN_FILE_SUCCESS",
|
|
1533
1564
|
path,
|
|
1534
|
-
doc: await openDocumentAtPath(path)
|
|
1565
|
+
doc: await openDocumentAtPath(path, { onDiagnostic: (diagnostic) => {
|
|
1566
|
+
dispatch({
|
|
1567
|
+
type: "APPEND_DIAGNOSTIC",
|
|
1568
|
+
diagnostic
|
|
1569
|
+
});
|
|
1570
|
+
} })
|
|
1535
1571
|
});
|
|
1536
1572
|
} catch (error) {
|
|
1537
1573
|
dispatch({
|
|
@@ -1548,6 +1584,16 @@ async function runCommand(line, state, dispatch) {
|
|
|
1548
1584
|
case "undo":
|
|
1549
1585
|
dispatch({ type: "UNDO" });
|
|
1550
1586
|
return;
|
|
1587
|
+
case "view-source":
|
|
1588
|
+
if (doc?.format !== "markdown") {
|
|
1589
|
+
warn(dispatch, ":view-source only applies to an open markdown document");
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
dispatch({
|
|
1593
|
+
type: "PUSH_SCREEN",
|
|
1594
|
+
screen: { kind: "viewSource" }
|
|
1595
|
+
});
|
|
1596
|
+
return;
|
|
1551
1597
|
case "help":
|
|
1552
1598
|
dispatch({
|
|
1553
1599
|
type: "OPEN_OVERLAY",
|
|
@@ -2218,9 +2264,12 @@ function parseNumberField(raw, fallback) {
|
|
|
2218
2264
|
}
|
|
2219
2265
|
//#endregion
|
|
2220
2266
|
//#region src/tui/screens/shared/paragraph-family.tsx
|
|
2267
|
+
function supportsRunStyleExtras(run) {
|
|
2268
|
+
return "underline" in run;
|
|
2269
|
+
}
|
|
2221
2270
|
function paragraphFamilyDocument(openDocument) {
|
|
2222
2271
|
if (openDocument === void 0) return;
|
|
2223
|
-
return openDocument.format === "docx" || openDocument.format === "odt" ? openDocument : void 0;
|
|
2272
|
+
return openDocument.format === "docx" || openDocument.format === "odt" || openDocument.format === "markdown" ? openDocument : void 0;
|
|
2224
2273
|
}
|
|
2225
2274
|
function liveParagraphAt(doc, blockIndex) {
|
|
2226
2275
|
return doc.editor.paragraphs()[blockIndex];
|
|
@@ -2746,14 +2795,17 @@ function ParagraphRunsView(props) {
|
|
|
2746
2795
|
dimColor: true,
|
|
2747
2796
|
children: "(no runs -- press 'a' to append one)"
|
|
2748
2797
|
});
|
|
2749
|
-
return /* @__PURE__ */ jsx(Box, { children: props.runs.map((run, index) =>
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2798
|
+
return /* @__PURE__ */ jsx(Box, { children: props.runs.map((run, index) => {
|
|
2799
|
+
const styled = supportsRunStyleExtras(run);
|
|
2800
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2801
|
+
bold: run.bold,
|
|
2802
|
+
italic: run.italic,
|
|
2803
|
+
underline: styled && run.underline,
|
|
2804
|
+
color: styled && run.color !== void 0 ? layoutColorToHex(run.color) : void 0,
|
|
2805
|
+
inverse: index === props.selectedRunIndex,
|
|
2806
|
+
children: run.text.length === 0 ? "<empty run>" : run.text
|
|
2807
|
+
}, index);
|
|
2808
|
+
}) });
|
|
2757
2809
|
}
|
|
2758
2810
|
function ParagraphDetailScreen() {
|
|
2759
2811
|
const state = useAppState();
|
|
@@ -2826,7 +2878,7 @@ function ParagraphDetailScreen() {
|
|
|
2826
2878
|
});
|
|
2827
2879
|
return;
|
|
2828
2880
|
}
|
|
2829
|
-
if (input === "I") {
|
|
2881
|
+
if (input === "I" && doc?.format !== "markdown") {
|
|
2830
2882
|
setImageWizardOpen(true);
|
|
2831
2883
|
return;
|
|
2832
2884
|
}
|
|
@@ -2851,6 +2903,7 @@ function ParagraphDetailScreen() {
|
|
|
2851
2903
|
});
|
|
2852
2904
|
return;
|
|
2853
2905
|
}
|
|
2906
|
+
if (!supportsRunStyleExtras(selectedRun)) return;
|
|
2854
2907
|
if (input === "u") {
|
|
2855
2908
|
dispatch({
|
|
2856
2909
|
type: "TOGGLE_RUN_UNDERLINE",
|
|
@@ -2875,7 +2928,7 @@ function ParagraphDetailScreen() {
|
|
|
2875
2928
|
});
|
|
2876
2929
|
if (doc === void 0) return /* @__PURE__ */ jsx(Text, {
|
|
2877
2930
|
color: "red",
|
|
2878
|
-
children: "ParagraphDetailScreen requires an open docx or
|
|
2931
|
+
children: "ParagraphDetailScreen requires an open docx, odt or markdown document."
|
|
2879
2932
|
});
|
|
2880
2933
|
if (paragraph === void 0) return /* @__PURE__ */ jsxs(Text, {
|
|
2881
2934
|
color: "red",
|
|
@@ -2962,7 +3015,7 @@ function ParagraphDetailScreen() {
|
|
|
2962
3015
|
placeholder: "e.g. 12",
|
|
2963
3016
|
onChange: setFontSizeInput,
|
|
2964
3017
|
onSubmit: (value) => {
|
|
2965
|
-
const sizePt = parseNumberField(value, selectedRun
|
|
3018
|
+
const sizePt = parseNumberField(value, selectedRun !== void 0 && supportsRunStyleExtras(selectedRun) ? selectedRun.sizePt ?? DEFAULT_RUN_SIZE_PT : DEFAULT_RUN_SIZE_PT);
|
|
2966
3019
|
if (sizePt <= 0) dispatch({
|
|
2967
3020
|
type: "SET_STATUS",
|
|
2968
3021
|
severity: "warning",
|
|
@@ -3015,7 +3068,12 @@ function ParagraphDetailScreen() {
|
|
|
3015
3068
|
/* @__PURE__ */ jsxs(Text, {
|
|
3016
3069
|
dimColor: true,
|
|
3017
3070
|
children: [
|
|
3018
|
-
"<- / -> move, Enter edit text, b/i
|
|
3071
|
+
"<- / -> move, Enter edit text, b/i",
|
|
3072
|
+
doc.format === "markdown" ? "" : "/u",
|
|
3073
|
+
" toggle",
|
|
3074
|
+
doc.format === "markdown" ? "" : ", c colour, f font, s size",
|
|
3075
|
+
", a append run",
|
|
3076
|
+
doc.format === "markdown" ? "" : ", I image",
|
|
3019
3077
|
doc.format === "docx" ? ", m formula" : "",
|
|
3020
3078
|
", Esc back"
|
|
3021
3079
|
]
|
|
@@ -3050,7 +3108,7 @@ function RunEditorScreen() {
|
|
|
3050
3108
|
});
|
|
3051
3109
|
if (doc === void 0) return /* @__PURE__ */ jsx(Text, {
|
|
3052
3110
|
color: "red",
|
|
3053
|
-
children: "RunEditorScreen requires an open docx or
|
|
3111
|
+
children: "RunEditorScreen requires an open docx, odt or markdown document."
|
|
3054
3112
|
});
|
|
3055
3113
|
const paragraph = liveParagraphAt(doc, screen.blockIndex);
|
|
3056
3114
|
if (paragraph === void 0) return /* @__PURE__ */ jsxs(Text, {
|
|
@@ -3209,7 +3267,7 @@ function TableViewScreen() {
|
|
|
3209
3267
|
});
|
|
3210
3268
|
if (doc === void 0) return /* @__PURE__ */ jsx(Text, {
|
|
3211
3269
|
color: "red",
|
|
3212
|
-
children: "TableViewScreen requires an open docx or
|
|
3270
|
+
children: "TableViewScreen requires an open docx, odt or markdown document."
|
|
3213
3271
|
});
|
|
3214
3272
|
if (table === void 0) return /* @__PURE__ */ jsxs(Text, {
|
|
3215
3273
|
color: "red",
|
|
@@ -3283,7 +3341,7 @@ function TableCellDetailScreen() {
|
|
|
3283
3341
|
});
|
|
3284
3342
|
if (doc === void 0) return /* @__PURE__ */ jsx(Text, {
|
|
3285
3343
|
color: "red",
|
|
3286
|
-
children: "TableCellDetailScreen requires an open docx or
|
|
3344
|
+
children: "TableCellDetailScreen requires an open docx, odt or markdown document."
|
|
3287
3345
|
});
|
|
3288
3346
|
if (cell === void 0) return /* @__PURE__ */ jsxs(Text, {
|
|
3289
3347
|
color: "red",
|
|
@@ -3430,123 +3488,67 @@ function DocxExtrasScreen() {
|
|
|
3430
3488
|
});
|
|
3431
3489
|
}
|
|
3432
3490
|
//#endregion
|
|
3433
|
-
//#region src/tui/screens/editors/markdown/
|
|
3434
|
-
function
|
|
3435
|
-
if (openDocument?.format !== "markdown") throw new Error("A markdown editing screen rendered without an open markdown document; the app router only reaches this screen group from markdownLineList, which is only ever the root screen of an open markdown document.");
|
|
3436
|
-
return openDocument;
|
|
3437
|
-
}
|
|
3438
|
-
//#endregion
|
|
3439
|
-
//#region src/tui/screens/editors/markdown/line-list.tsx
|
|
3440
|
-
function MarkdownLineListScreen() {
|
|
3441
|
-
const state = useAppState();
|
|
3442
|
-
const dispatch = useAppDispatch();
|
|
3443
|
-
const doc = requireMarkdownDocument(state.openDocument);
|
|
3444
|
-
const query = state.searchQuery.trim().toLowerCase();
|
|
3445
|
-
const allLines = doc.source.split("\n").map((line, lineIndex) => ({
|
|
3446
|
-
line,
|
|
3447
|
-
lineIndex
|
|
3448
|
-
}));
|
|
3449
|
-
const lines = query === "" ? allLines : allLines.filter((entry) => entry.line.toLowerCase().includes(query));
|
|
3450
|
-
const { selectedIndex } = useNavigationInput({
|
|
3451
|
-
itemCount: lines.length,
|
|
3452
|
-
onSelect: (index) => {
|
|
3453
|
-
const entry = lines[index];
|
|
3454
|
-
if (entry === void 0) return;
|
|
3455
|
-
dispatch({
|
|
3456
|
-
type: "PUSH_SCREEN",
|
|
3457
|
-
screen: {
|
|
3458
|
-
kind: "markdownLineEditor",
|
|
3459
|
-
lineIndex: entry.lineIndex
|
|
3460
|
-
}
|
|
3461
|
-
});
|
|
3462
|
-
},
|
|
3463
|
-
onBack: () => {
|
|
3464
|
-
dispatch({ type: "POP_SCREEN" });
|
|
3465
|
-
},
|
|
3466
|
-
isActive: !anyOverlayOpen(state)
|
|
3467
|
-
});
|
|
3468
|
-
return /* @__PURE__ */ jsxs(Box, {
|
|
3469
|
-
flexDirection: "column",
|
|
3470
|
-
children: [/* @__PURE__ */ jsxs(Text, {
|
|
3471
|
-
bold: true,
|
|
3472
|
-
children: [
|
|
3473
|
-
"Lines (",
|
|
3474
|
-
lines.length,
|
|
3475
|
-
" of ",
|
|
3476
|
-
allLines.length,
|
|
3477
|
-
")"
|
|
3478
|
-
]
|
|
3479
|
-
}), /* @__PURE__ */ jsx(ListView, {
|
|
3480
|
-
items: lines,
|
|
3481
|
-
selectedIndex,
|
|
3482
|
-
emptyMessage: query === "" ? "This document has no lines." : `No lines match "${state.searchQuery}".`,
|
|
3483
|
-
renderItem: ({ line, lineIndex }, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
3484
|
-
color: isSelected ? "cyan" : void 0,
|
|
3485
|
-
inverse: isSelected,
|
|
3486
|
-
children: [
|
|
3487
|
-
lineIndex + 1,
|
|
3488
|
-
": ",
|
|
3489
|
-
line === "" ? "(blank)" : line
|
|
3490
|
-
]
|
|
3491
|
-
})
|
|
3492
|
-
})]
|
|
3493
|
-
});
|
|
3494
|
-
}
|
|
3495
|
-
//#endregion
|
|
3496
|
-
//#region src/tui/screens/editors/markdown/line-editor.tsx
|
|
3497
|
-
function MarkdownLineEditorScreen() {
|
|
3491
|
+
//#region src/tui/screens/editors/markdown/view-source.tsx
|
|
3492
|
+
function MarkdownViewSourceScreen() {
|
|
3498
3493
|
const state = useAppState();
|
|
3499
3494
|
const dispatch = useAppDispatch();
|
|
3500
3495
|
const screen = currentScreen(state);
|
|
3501
3496
|
const doc = state.openDocument;
|
|
3502
|
-
|
|
3497
|
+
useInput((_input, key) => {
|
|
3498
|
+
if (key.escape) dispatch({ type: "POP_SCREEN" });
|
|
3499
|
+
}, { isActive: !anyOverlayOpen(state) && screen.kind === "viewSource" });
|
|
3500
|
+
if (screen.kind !== "viewSource") return /* @__PURE__ */ jsx(Text, {
|
|
3503
3501
|
color: "red",
|
|
3504
|
-
children: "
|
|
3502
|
+
children: "MarkdownViewSourceScreen rendered outside a viewSource screen."
|
|
3505
3503
|
});
|
|
3506
3504
|
if (doc?.format !== "markdown") return /* @__PURE__ */ jsx(Text, {
|
|
3507
3505
|
color: "red",
|
|
3508
|
-
children: "
|
|
3509
|
-
});
|
|
3510
|
-
const lines = doc.source.split("\n");
|
|
3511
|
-
const line = lines[screen.lineIndex];
|
|
3512
|
-
if (line === void 0) return /* @__PURE__ */ jsxs(Text, {
|
|
3513
|
-
color: "red",
|
|
3514
|
-
children: [
|
|
3515
|
-
"There is no line at index ",
|
|
3516
|
-
screen.lineIndex,
|
|
3517
|
-
"."
|
|
3518
|
-
]
|
|
3506
|
+
children: "view-source requires an open markdown document."
|
|
3519
3507
|
});
|
|
3508
|
+
const asItWillSaveNow = doc.editor.toMarkdownText();
|
|
3520
3509
|
return /* @__PURE__ */ jsxs(Box, {
|
|
3521
3510
|
flexDirection: "column",
|
|
3522
3511
|
children: [
|
|
3523
|
-
/* @__PURE__ */
|
|
3512
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3524
3513
|
bold: true,
|
|
3525
|
-
children:
|
|
3514
|
+
children: "As opened"
|
|
3526
3515
|
}),
|
|
3527
|
-
/* @__PURE__ */ jsx(
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
nextLines[screen.lineIndex] = text;
|
|
3532
|
-
dispatch({
|
|
3533
|
-
type: "SET_MARKDOWN_SOURCE",
|
|
3534
|
-
source: nextLines.join("\n")
|
|
3535
|
-
});
|
|
3536
|
-
dispatch({ type: "POP_SCREEN" });
|
|
3537
|
-
},
|
|
3538
|
-
onCancel: () => {
|
|
3539
|
-
dispatch({ type: "POP_SCREEN" });
|
|
3540
|
-
}
|
|
3516
|
+
/* @__PURE__ */ jsx(Text, { children: doc.originalText ?? "(this document was created fresh, with no original text to compare against)" }),
|
|
3517
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3518
|
+
bold: true,
|
|
3519
|
+
children: "As it will save right now"
|
|
3541
3520
|
}),
|
|
3521
|
+
/* @__PURE__ */ jsx(Text, { children: asItWillSaveNow }),
|
|
3542
3522
|
/* @__PURE__ */ jsx(Text, {
|
|
3543
3523
|
dimColor: true,
|
|
3544
|
-
children: "
|
|
3524
|
+
children: "Esc back"
|
|
3545
3525
|
})
|
|
3546
3526
|
]
|
|
3547
3527
|
});
|
|
3548
3528
|
}
|
|
3549
3529
|
//#endregion
|
|
3530
|
+
//#region src/tui/screens/editors/markdown/index.tsx
|
|
3531
|
+
function MarkdownBodyListScreen() {
|
|
3532
|
+
const state = useAppState();
|
|
3533
|
+
const dispatch = useAppDispatch();
|
|
3534
|
+
const doc = state.openDocument;
|
|
3535
|
+
if (doc?.format !== "markdown") return /* @__PURE__ */ jsxs(Text, {
|
|
3536
|
+
color: "red",
|
|
3537
|
+
children: [
|
|
3538
|
+
"MarkdownBodyListScreen requires an open markdown document, found ",
|
|
3539
|
+
doc === void 0 ? "no open document" : doc.format,
|
|
3540
|
+
"."
|
|
3541
|
+
]
|
|
3542
|
+
});
|
|
3543
|
+
const adapter = createParagraphFamilyAdapter({
|
|
3544
|
+
formatLabel: "markdown",
|
|
3545
|
+
paragraphs: () => doc.editor.paragraphs(),
|
|
3546
|
+
tables: () => doc.editor.tables(),
|
|
3547
|
+
dispatch
|
|
3548
|
+
});
|
|
3549
|
+
return /* @__PURE__ */ jsx(ParagraphFamilyBodyList, { adapter });
|
|
3550
|
+
}
|
|
3551
|
+
//#endregion
|
|
3550
3552
|
//#region src/tui/screens/editors/odb/shared.ts
|
|
3551
3553
|
function requireOdbDocument(openDocument) {
|
|
3552
3554
|
if (openDocument?.format !== "odb") throw new Error("An .odb browsing screen rendered without an open .odb document; the app router only reaches this screen group from odbTableList, which is only ever the root screen of an open .odb document.");
|
|
@@ -8545,7 +8547,12 @@ function FilePickerScreen() {
|
|
|
8545
8547
|
function openAtPath(path) {
|
|
8546
8548
|
(async () => {
|
|
8547
8549
|
try {
|
|
8548
|
-
const doc = await openDocumentAtPath(path)
|
|
8550
|
+
const doc = await openDocumentAtPath(path, { onDiagnostic: (diagnostic) => {
|
|
8551
|
+
dispatch({
|
|
8552
|
+
type: "APPEND_DIAGNOSTIC",
|
|
8553
|
+
diagnostic
|
|
8554
|
+
});
|
|
8555
|
+
} });
|
|
8549
8556
|
dispatch({
|
|
8550
8557
|
type: "OPEN_FILE_SUCCESS",
|
|
8551
8558
|
path,
|
|
@@ -8896,7 +8903,7 @@ function metadataFor(doc) {
|
|
|
8896
8903
|
case "odp": return readOdpContent(doc.editor.toPackage()).metadata;
|
|
8897
8904
|
case "ods": return readOdsContent(doc.editor.toPackage()).metadata;
|
|
8898
8905
|
case "odg": return readOdgContent(doc.editor.toPackage()).metadata;
|
|
8899
|
-
case "markdown": return readMarkdownContent(doc.
|
|
8906
|
+
case "markdown": return readMarkdownContent(doc.editor.toMarkdownText()).metadata;
|
|
8900
8907
|
case "pdf":
|
|
8901
8908
|
case "xlsx": return doc.layout.metadata;
|
|
8902
8909
|
case "odb": throw new Error("A .odb database has no document-level metadata -- it is a table/form/report container, not a single document with its own title/author/etc.");
|
|
@@ -8961,7 +8968,9 @@ function ScreenBody({ screen }) {
|
|
|
8961
8968
|
case "launcher": return /* @__PURE__ */ jsx(LauncherScreen, {});
|
|
8962
8969
|
case "filePicker": return /* @__PURE__ */ jsx(FilePickerScreen, {});
|
|
8963
8970
|
case "newDocumentPicker": return /* @__PURE__ */ jsx(NewDocumentPickerScreen, {});
|
|
8964
|
-
case "bodyList":
|
|
8971
|
+
case "bodyList":
|
|
8972
|
+
if (format === "odt") return /* @__PURE__ */ jsx(OdtBodyListScreen, {});
|
|
8973
|
+
return format === "markdown" ? /* @__PURE__ */ jsx(MarkdownBodyListScreen, {}) : /* @__PURE__ */ jsx(DocxBodyListScreen, {});
|
|
8965
8974
|
case "docxExtras": return /* @__PURE__ */ jsx(DocxExtrasScreen, {});
|
|
8966
8975
|
case "paragraphDetail": return /* @__PURE__ */ jsx(ParagraphDetailScreen, {});
|
|
8967
8976
|
case "runEditor": return /* @__PURE__ */ jsx(RunEditorScreen, {});
|
|
@@ -8987,8 +8996,7 @@ function ScreenBody({ screen }) {
|
|
|
8987
8996
|
case "odbReportList": return /* @__PURE__ */ jsx(OdbReportListScreen, {});
|
|
8988
8997
|
case "odbReportDetail": return /* @__PURE__ */ jsx(OdbReportDetailScreen, {});
|
|
8989
8998
|
case "odbReportRender": return /* @__PURE__ */ jsx(OdbReportRenderScreen, {});
|
|
8990
|
-
case "
|
|
8991
|
-
case "markdownLineEditor": return /* @__PURE__ */ jsx(MarkdownLineEditorScreen, {});
|
|
8999
|
+
case "viewSource": return /* @__PURE__ */ jsx(MarkdownViewSourceScreen, {});
|
|
8992
9000
|
case "pdfPageList": return /* @__PURE__ */ jsx(PdfPageListScreen, {});
|
|
8993
9001
|
case "pdfPageItems": return /* @__PURE__ */ jsx(PdfPageItemsScreen, {});
|
|
8994
9002
|
case "pdfItemDetail": return /* @__PURE__ */ jsx(PdfItemDetailScreen, {});
|
|
@@ -9034,7 +9042,12 @@ function AppShell({ startPath }) {
|
|
|
9034
9042
|
let cancelled = false;
|
|
9035
9043
|
(async () => {
|
|
9036
9044
|
try {
|
|
9037
|
-
const doc = await openDocumentAtPath(startPath)
|
|
9045
|
+
const doc = await openDocumentAtPath(startPath, { onDiagnostic: (diagnostic) => {
|
|
9046
|
+
dispatch({
|
|
9047
|
+
type: "APPEND_DIAGNOSTIC",
|
|
9048
|
+
diagnostic
|
|
9049
|
+
});
|
|
9050
|
+
} });
|
|
9038
9051
|
if (!cancelled) dispatch({
|
|
9039
9052
|
type: "OPEN_FILE_SUCCESS",
|
|
9040
9053
|
path: startPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "CLI and interactive Ink TUI for documents.js: every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and editor as a scriptable command or a terminal app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|