Skip to content

Commit 5645e96

Browse files
committed
feat: sheet parser for drop-paste feature
1 parent 4e94607 commit 5645e96

File tree

4 files changed

+59
-3
lines changed

4 files changed

+59
-3
lines changed

editors/vscode/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,7 @@
11721172
"test": "rimraf test-dist/ && tsc -p tsconfig.test.json && node test-dist/test/runTests.js"
11731173
},
11741174
"dependencies": {
1175+
"cheerio": "^1.0.0",
11751176
"cpr": "^3.0.1",
11761177
"esbuild-plugin-polyfill-node": "^0.3.0",
11771178
"node-fetch": "^3.3.2",

editors/vscode/src/features/drop-paste.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
typstPasteUriEditKind,
1616
Schemes,
1717
} from "./drop-paste.def";
18+
import { convertHtmlToTypst } from "./html-table-converter";
1819

1920
export function dragAndDropActivate(context: vscode.ExtensionContext) {
2021
context.subscriptions.push(
@@ -58,7 +59,7 @@ class DropOrPasteContext<A extends DropPasteAction> {
5859
private context: vscode.DocumentPasteEditContext | undefined,
5960
private document: vscode.TextDocument,
6061
private token: vscode.CancellationToken,
61-
) {}
62+
) { }
6263

6364
private readonly _yieldTo = [
6465
vscode.DocumentDropOrPasteEditKind.Text,
@@ -90,6 +91,19 @@ class DropOrPasteContext<A extends DropPasteAction> {
9091
dataTransfer: vscode.DataTransfer,
9192
): Promise<boolean> {
9293
{
94+
const htmlData = await dataTransfer.get("text/html")?.asString();
95+
if (htmlData) {
96+
const snippet = await convertHtmlToTypst(htmlData);
97+
const additionalEdits = new vscode.WorkspaceEdit();
98+
additionalEdits.replace(this.document.uri, ranges[0], snippet);
99+
this.resolved.push({
100+
snippet: new vscode.SnippetString(""),
101+
additionalEdits,
102+
yieldTo: [],
103+
});
104+
return this.wrapRangeAsLinkContent();
105+
}
106+
93107
const mediaFiles = await this.takeMediaFiles(dataTransfer);
94108
if (mediaFiles) {
95109
const edit = await this.handleMediaFiles(ranges, mediaFiles);
@@ -595,7 +609,7 @@ export class UriList {
595609

596610
constructor(
597611
public readonly entries: ReadonlyArray<{ readonly uri: vscode.Uri; readonly str: string }>,
598-
) {}
612+
) { }
599613
}
600614

601615
function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import * as cheerio from 'cheerio';
2+
3+
export async function convertHtmlToTypst(html: string): Promise<string> {
4+
const $ = cheerio.load(html);
5+
const table = $('table').first();
6+
if (!table.length) {
7+
throw new Error('Table element not found. Please check the HTML content.');
8+
}
9+
10+
const rows = table.find('tr');
11+
if (!rows.length) {
12+
throw new Error('No tr tag found in the table.');
13+
}
14+
15+
const firstRow = rows.first();
16+
const firstRowCells = firstRow.find('td, th');
17+
const columnCount = firstRowCells.toArray().reduce((count, cell) => {
18+
const colspanAttr = $(cell).attr('colspan');
19+
return count + (Number(colspanAttr) || 1);
20+
}, 0);
21+
22+
let out = `#table(\n columns: ${columnCount},\n`;
23+
24+
rows.each((_, rowElem) => {
25+
out += ' ';
26+
const row = $(rowElem);
27+
const cells = row.find('td, th');
28+
cells.each((_, cellElem) => {
29+
const cell = $(cellElem);
30+
const rowspan = Number(cell.attr('rowspan')) || 1;
31+
const colspan = Number(cell.attr('colspan')) || 1;
32+
const spanOpts =
33+
`${rowspan > 1 ? `rowspan: ${rowspan}, ` : ''}${colspan > 1 ? `colspan: ${colspan}, ` : ''}`;
34+
const content = cell.text().trim();
35+
out += spanOpts ? `table.cell(${spanOpts})[${content}], ` : `[${content}], `;
36+
});
37+
out += '\n';
38+
});
39+
40+
return out + ')';
41+
}

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,7 @@ cheerio-select@^2.1.0:
12981298
domhandler "^5.0.3"
12991299
domutils "^3.0.1"
13001300

1301-
cheerio@^1.0.0-rc.9:
1301+
cheerio@^1.0.0, cheerio@^1.0.0-rc.9:
13021302
version "1.0.0"
13031303
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0.tgz#1ede4895a82f26e8af71009f961a9b8cb60d6a81"
13041304
integrity sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==

0 commit comments

Comments
 (0)