mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-12-23 08:47:50 +00:00
feat: add font list export panel in summary tool (#322)
* feat(vscode/summary): add font list export pannel * feat: json/csv format, export to file and state persistence
This commit is contained in:
parent
1c653d5fd2
commit
8784a07b2b
8 changed files with 494 additions and 10 deletions
|
|
@ -519,7 +519,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1",
|
||||
"vscode-variables": "^0.1.3"
|
||||
"vscode-variables": "^0.1.3",
|
||||
"editor-tools": "file:../../tools/editor-tools"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.8.10",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import * as vscode from "vscode";
|
||||
import * as path from "path";
|
||||
import { readFile } from "fs/promises";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { getFocusingFile, getLastFocusingDoc } from "./extension";
|
||||
import { fontsExportConfigure, fontsExportDefaultConfigure } from "editor-tools/src/features/summary";
|
||||
|
||||
async function loadHTMLFile(context: vscode.ExtensionContext, relativePath: string) {
|
||||
const filePath = path.resolve(context.extensionPath, relativePath);
|
||||
|
|
@ -38,6 +39,22 @@ export function getUserPackageData(context: vscode.ExtensionContext) {
|
|||
return userPackageData;
|
||||
}
|
||||
|
||||
const FONTS_EXPORT_CONFIGURE_VERSION = "0.0.1";
|
||||
|
||||
export function getFontsExportConfigure(context: vscode.ExtensionContext) {
|
||||
const defaultConfigure: Versioned<fontsExportConfigure> = {
|
||||
version: FONTS_EXPORT_CONFIGURE_VERSION,
|
||||
data: fontsExportDefaultConfigure,
|
||||
};
|
||||
|
||||
const configure = context.globalState.get("fontsExportConfigure", defaultConfigure);
|
||||
if (configure?.version !== FONTS_EXPORT_CONFIGURE_VERSION) {
|
||||
return defaultConfigure;
|
||||
}
|
||||
|
||||
return configure;
|
||||
}
|
||||
|
||||
export async function activateEditorTool(
|
||||
context: vscode.ExtensionContext,
|
||||
tool: "template-gallery" | "tracing" | "summary" | "symbol-view"
|
||||
|
|
@ -110,6 +127,14 @@ async function activateEditorToolAt(
|
|||
});
|
||||
break;
|
||||
}
|
||||
case "saveFontsExportConfigure": {
|
||||
const data = message.data;
|
||||
context.globalState.update("fontsExportConfigure", {
|
||||
version: FONTS_EXPORT_CONFIGURE_VERSION,
|
||||
data,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "initTemplate": {
|
||||
const packageSpec = message.packageSpec;
|
||||
const initArgs = [packageSpec];
|
||||
|
|
@ -220,6 +245,18 @@ async function activateEditorToolAt(
|
|||
|
||||
break;
|
||||
}
|
||||
case "saveDataToFile": {
|
||||
let { data, path, option } = message;
|
||||
if (typeof path !== "string") {
|
||||
const uri = await vscode.window.showSaveDialog(option);
|
||||
path = uri?.fsPath;
|
||||
}
|
||||
if (typeof path !== "string") {
|
||||
return;
|
||||
}
|
||||
await writeFile(path, data);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.error("Unknown message type", message.type);
|
||||
break;
|
||||
|
|
@ -270,6 +307,8 @@ async function activateEditorToolAt(
|
|||
break;
|
||||
}
|
||||
case "summary": {
|
||||
const fontsExportConfigure = getFontsExportConfigure(context);
|
||||
const fontsExportConfigureData = JSON.stringify(fontsExportConfigure.data);
|
||||
const [docMetrics, serverInfo] = await fetchSummaryInfo();
|
||||
|
||||
if (!docMetrics || !serverInfo) {
|
||||
|
|
@ -284,6 +323,7 @@ async function activateEditorToolAt(
|
|||
return;
|
||||
}
|
||||
|
||||
html = html.replace(":[[preview:FontsExportConfigure]]:", btoa(fontsExportConfigureData));
|
||||
html = html.replace(":[[preview:DocumentMetrics]]:", btoa(docMetrics));
|
||||
html = html.replace(":[[preview:ServerInfo]]:", btoa(serverInfo));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"csv-stringify": "^6.5.0",
|
||||
"detypify-service": "0.2.4",
|
||||
"minisearch": "^6.3.0",
|
||||
"vanjs-core": "^1.5.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import van, { ChildDom } from "vanjs-core";
|
||||
import { requestRevealPath } from "../vscode";
|
||||
const { div, a, span, code, br } = van.tags;
|
||||
import van, { ChildDom, State } from "vanjs-core";
|
||||
import { stringify as csvStringify } from "csv-stringify/browser/esm/sync";
|
||||
import { requestRevealPath, requestSaveFontsExportConfigure, saveDataToFile } from "../vscode";
|
||||
import { CopyIcon } from "../icons";
|
||||
import { startModal } from "../components/modal";
|
||||
const { div, a, span, code, br, button, form, textarea, label, input } = van.tags;
|
||||
|
||||
interface ServerInfo {
|
||||
root: string;
|
||||
|
|
@ -168,6 +171,24 @@ export const Summary = () => {
|
|||
),
|
||||
div(
|
||||
{ class: `tinymist-card`, style: "flex: 1; width: 100%; padding: 10px" },
|
||||
div(
|
||||
{ style: "position: relative; width: 100%; height: 0px" },
|
||||
button(
|
||||
{
|
||||
class: "tinymist-button",
|
||||
style: "position: absolute; top: 0px; right: 0px",
|
||||
onclick: () => {
|
||||
startModal(
|
||||
div(
|
||||
{ style: "height: calc(100% - 20px); box-sizing: border-box; padding-top: 4px" },
|
||||
fontsExportPannel({ fonts: docMetrics.val.fontInfo, sources: docMetrics.val.spanInfo.sources }),
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
CopyIcon(),
|
||||
),
|
||||
),
|
||||
div(
|
||||
van.derive(
|
||||
() => `This document uses ${docMetrics.val.fontInfo.length} fonts.`
|
||||
|
|
@ -266,6 +287,365 @@ export const Summary = () => {
|
|||
);
|
||||
};
|
||||
|
||||
interface fontsExportPannelProps {
|
||||
fonts: FontInfo[],
|
||||
sources: FontSource[],
|
||||
}
|
||||
|
||||
interface fontInfoWithSource extends Omit<FontInfo, "source"> {
|
||||
source: FontSource | null,
|
||||
}
|
||||
|
||||
export type fontsCSVHeader = "name" | "postscript" | "style" | "weight" | "stretch" | "location" | "path";
|
||||
|
||||
interface csvFieldExtractor<H, T> {
|
||||
fieldName: H,
|
||||
extractor: (input: T) => string | number,
|
||||
}
|
||||
|
||||
type fontCSVFieldExtractor = csvFieldExtractor<fontsCSVHeader, fontInfoWithSource>
|
||||
|
||||
class fontsCSVGenerator {
|
||||
public static readonly fieldExtractors: fontCSVFieldExtractor[] = [
|
||||
{
|
||||
fieldName: "name",
|
||||
extractor: info => info.fullName ?? "",
|
||||
},
|
||||
{
|
||||
fieldName: "postscript",
|
||||
extractor: info => info.postscriptName,
|
||||
},
|
||||
{
|
||||
fieldName: "style",
|
||||
extractor: info => info.style ?? "",
|
||||
},
|
||||
{
|
||||
fieldName: "weight",
|
||||
extractor: info => info.weight ?? "",
|
||||
},
|
||||
{
|
||||
fieldName: "stretch",
|
||||
extractor: info => info.stretch ?? "",
|
||||
},
|
||||
{
|
||||
fieldName: "location",
|
||||
extractor: info => {
|
||||
switch (info.source?.kind ?? "") {
|
||||
case "fs": return "fileSystem";
|
||||
case "memory": return "memory";
|
||||
default: return "unknown";
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: "path",
|
||||
extractor: info => info.source?.kind === "fs" ? info.source.path : "",
|
||||
}
|
||||
];
|
||||
|
||||
public generate(fonts: fontInfoWithSource[], config: fontsExportCSVConfigure): string {
|
||||
const fields = fontsCSVGenerator.fieldExtractors.filter(field => config.fields.includes(field.fieldName));
|
||||
const headers = fields.map(field => field.fieldName);
|
||||
|
||||
let rows = fonts.map(font => fields.map(field => field.extractor(font)));
|
||||
|
||||
// If only field is file path, do a dedupp
|
||||
if (fields.length === 1 && fields[0].fieldName === "path") {
|
||||
const dedup = new Set();
|
||||
rows = rows.reduce((acc, item) => {
|
||||
const path = item[0];
|
||||
if (!dedup.has(path)) {
|
||||
dedup.add(path);
|
||||
acc.push(item);
|
||||
}
|
||||
return acc;
|
||||
}, [] as typeof rows);
|
||||
}
|
||||
|
||||
return csvStringify(rows, {
|
||||
header: config.header,
|
||||
columns: headers,
|
||||
delimiter: config.delimiter,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export type fontLocation = FontSource extends { kind: (infer Kind) } ? Kind : never;
|
||||
|
||||
export interface fontsExportCSVConfigure {
|
||||
header: boolean,
|
||||
delimiter: string,
|
||||
fields: fontsCSVHeader[],
|
||||
}
|
||||
|
||||
export interface fontsExportJSONConfigure {
|
||||
indent: number,
|
||||
}
|
||||
|
||||
export interface fontsExportFormatConfigure {
|
||||
csv: fontsExportCSVConfigure,
|
||||
json: fontsExportJSONConfigure,
|
||||
}
|
||||
|
||||
export type fontsExportFormat = keyof fontsExportFormatConfigure;
|
||||
|
||||
interface fontsExportCommonConfigure {
|
||||
format: fontsExportFormat,
|
||||
filters: {
|
||||
location: fontLocation[],
|
||||
},
|
||||
}
|
||||
|
||||
export type fontsExportConfigure = fontsExportCommonConfigure & fontsExportFormatConfigure;
|
||||
|
||||
export const fontsExportDefaultConfigure: fontsExportConfigure = {
|
||||
format: "csv",
|
||||
filters: {
|
||||
location: ["fs"],
|
||||
},
|
||||
csv: {
|
||||
header: false,
|
||||
delimiter: ",",
|
||||
fields: ["name", "path"],
|
||||
},
|
||||
json: {
|
||||
indent: 2,
|
||||
},
|
||||
};
|
||||
|
||||
let savedConfigureData = `:[[preview:FontsExportConfigure]]:`;
|
||||
|
||||
const fontsExportPannel = ({ fonts, sources }: fontsExportPannelProps) => {
|
||||
const savedConfigure: fontsExportConfigure = savedConfigureData.startsWith(":")
|
||||
? fontsExportDefaultConfigure
|
||||
: JSON.parse(atob(savedConfigureData));
|
||||
|
||||
const exportFormat = van.state<fontsExportFormat>(savedConfigure.format);
|
||||
const locationFilter = van.state<fontLocation[]>(savedConfigure.filters.location);
|
||||
const csvConfigure = van.state<fontsExportCSVConfigure>(savedConfigure.csv);
|
||||
const jsonConfigure = van.state<fontsExportJSONConfigure>(savedConfigure.json);
|
||||
|
||||
// Save state when changed
|
||||
van.derive(() => {
|
||||
const configure: fontsExportConfigure = {
|
||||
format: exportFormat.val,
|
||||
filters: {
|
||||
location: locationFilter.val,
|
||||
},
|
||||
csv: csvConfigure.val,
|
||||
json: jsonConfigure.val,
|
||||
};
|
||||
|
||||
savedConfigureData = btoa(JSON.stringify(configure));
|
||||
requestSaveFontsExportConfigure(configure);
|
||||
});
|
||||
|
||||
const data: fontInfoWithSource[] = fonts.map(font => {
|
||||
let source = typeof font.source === "number" ? sources[font.source] : null;
|
||||
return Object.assign({}, font, { source });
|
||||
});
|
||||
|
||||
const filteredData = van.derive(() => {
|
||||
return data.filter(font => locationFilter.val.includes(font.source?.kind ?? "" as any));
|
||||
});
|
||||
|
||||
const exportText = van.derive<string>(() => {
|
||||
switch (exportFormat.val) {
|
||||
case "csv": {
|
||||
const csvGenerator = new fontsCSVGenerator();
|
||||
return csvGenerator.generate(filteredData.val, csvConfigure.val);
|
||||
}
|
||||
case "json": {
|
||||
return JSON.stringify(filteredData.val, null, jsonConfigure.val.indent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const titleWidth = 72;
|
||||
const rowGap = 8;
|
||||
|
||||
const labelInputGap = 4;
|
||||
const itemGap = 10;
|
||||
const groupGap = 20;
|
||||
|
||||
const labeledInput = (
|
||||
title: string, el: HTMLInputElement,
|
||||
{ labelStyle } = { labelStyle: "" }
|
||||
) =>span({ style: `display: inline-flex; column-gap: ${labelInputGap}px; align-items: center` },
|
||||
label({ for: el.id, style: labelStyle }, title), el,
|
||||
);
|
||||
|
||||
const makeArrayCheckbox = (
|
||||
id: string, value: string, state: State<string[]> | string[],
|
||||
) => {
|
||||
const checked = Array.isArray(state) ? state.includes(value) : state.val.includes(value);
|
||||
return input({
|
||||
id, type: "checkbox", style: "margin: 0px",
|
||||
value, checked,
|
||||
onchange: (e: any) => {
|
||||
if (e.target.checked) {
|
||||
Array.isArray(state) ? state.push(e.target.value) : state.val = [...state.rawVal, e.target.value];
|
||||
} else {
|
||||
if (Array.isArray(state)) {
|
||||
let index = state.indexOf(e.target.value);
|
||||
if (index !== -1) {
|
||||
state.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
state.val = state.val.filter(v => v !== e.target.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const filtersUI = () => div({ class: "flex-col", style: `row-gap: ${rowGap}px` },
|
||||
div({ class: "flex-row", style: "align-items: center" },
|
||||
div({ style: `width: ${titleWidth}px` }, "Location"),
|
||||
div({ class: "flex-row", style: `flex: 1; flex-wrap: wrap; column-gap: ${itemGap}px` },
|
||||
labeledInput("FileSystem", makeArrayCheckbox("filter-locations-fs", "fs", locationFilter)),
|
||||
labeledInput("Memory", makeArrayCheckbox("filter-locations-memory", "memory", locationFilter)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const chooseExportFormatUI = () => div({ class: "flex-row", style: "align-items: center" },
|
||||
div({ style: `width: ${titleWidth}px` }, "Format"),
|
||||
div({ class: "flex-row", style: `flex: 1; flex-wrap: wrap; column-gap: ${itemGap}px`},
|
||||
labeledInput("CSV", input({
|
||||
id: "export-format-csv", type: "radio", name: "export-format", style: "margin: 0px",
|
||||
checked: exportFormat.val === "csv",
|
||||
onchange: (e) => {
|
||||
if (e.target.checked) {
|
||||
exportFormat.val = "csv";
|
||||
}
|
||||
},
|
||||
})),
|
||||
labeledInput("JSON", input({
|
||||
id: "export-format-json", type: "radio", name: "export-format", style: "margin: 0px",
|
||||
checked: exportFormat.val === "json",
|
||||
onchange: (e) => {
|
||||
if (e.target.checked) {
|
||||
exportFormat.val = "json";
|
||||
}
|
||||
},
|
||||
})),
|
||||
),
|
||||
);
|
||||
|
||||
const csvConfigureUI = () => form(
|
||||
{
|
||||
class: "flex-col", style: `row-gap: ${rowGap}px`,
|
||||
onchange: (_e) => {
|
||||
csvConfigure.val = Object.assign({}, csvConfigure.val);
|
||||
},
|
||||
onsubmit: (e) => e.preventDefault(),
|
||||
},
|
||||
div({ class: "flex-row", style: "align-items: center" },
|
||||
div({ style: `width: ${titleWidth}px` }, "Settings"),
|
||||
div({ class: "flex-row", style: `flex: 1; flex-wrap: wrap; column-gap: ${groupGap}px`},
|
||||
labeledInput("Header", input({
|
||||
id: "csv-header", type: "checkbox", style: "margin: 0px",
|
||||
checked: csvConfigure.val.header,
|
||||
onchange: e => csvConfigure.rawVal.header = e.target.checked
|
||||
})),
|
||||
labeledInput("Delimiter:", input({
|
||||
id: "csv-delimiter", type: "input", style: `width: 40px`,
|
||||
value: csvConfigure.val.delimiter,
|
||||
oninput: e => csvConfigure.rawVal.delimiter = e.target.value,
|
||||
onkeydown: e => e.stopPropagation(), // prevent modal window closed by space when input
|
||||
})),
|
||||
),
|
||||
),
|
||||
div(
|
||||
{ class: "flex-row", style: "align-items: center"},
|
||||
div({ style: `width: ${titleWidth}px` }, "Fields"),
|
||||
div({ class: "flex-row", style: `flex: 1; flex-wrap: wrap; column-gap: ${itemGap}px`},
|
||||
...fontsCSVGenerator.fieldExtractors
|
||||
.map(fe => fe.fieldName)
|
||||
.map(field => labeledInput(field, makeArrayCheckbox(`csv-field-${field}`, field, csvConfigure.rawVal.fields))),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const jsonConfigureUI = () => form(
|
||||
{
|
||||
onchange: (_e) => {
|
||||
jsonConfigure.val = Object.assign({}, jsonConfigure.val);
|
||||
},
|
||||
onsubmit: (e) => e.preventDefault(),
|
||||
},
|
||||
div({ class: "flex-row", style: "align-items: center" },
|
||||
div({ style: `width: ${titleWidth}px` }, "Settings"),
|
||||
div({ class: "flex-row", style: `flex: 1; flex-wrap: wrap; column-gap: ${groupGap}px`},
|
||||
labeledInput("Indent:", input({
|
||||
id: "json-indent", type: "number", style: "width: 40px;",
|
||||
min: "0", max: "8", step: "2", value: jsonConfigure.val.indent,
|
||||
onchange: e => jsonConfigure.rawVal.indent = parseInt(e.target.value, 10),
|
||||
}), { labelStyle: "margin-right: 0.5em" }),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const exportFormatConfigureUI = () => {
|
||||
let ui;
|
||||
switch (exportFormat.val) {
|
||||
case "csv": {
|
||||
ui = csvConfigureUI();
|
||||
break;
|
||||
}
|
||||
case "json": {
|
||||
ui = jsonConfigureUI();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ui;
|
||||
};
|
||||
|
||||
return div({ class: "flex-col", style: `row-gap: ${rowGap}px; width: 100%; height: 100%` },
|
||||
filtersUI,
|
||||
chooseExportFormatUI,
|
||||
exportFormatConfigureUI,
|
||||
textarea(
|
||||
{
|
||||
class: "tinymist-code",
|
||||
style: "resize: none; width: 100%; flex: 1; white-space: pre; overflow-wrap: normal; overflow-x: scroll",
|
||||
readOnly: true, onkeydown: e => e.stopPropagation(),
|
||||
},
|
||||
exportText,
|
||||
),
|
||||
div(
|
||||
{ style: `display: flex; align-items: center; column-gap:${itemGap}px` },
|
||||
button(
|
||||
{
|
||||
class: "tinymist-button",
|
||||
style: "flex: 1",
|
||||
onclick: () => {
|
||||
const filterName = `${exportFormat.val.toLocaleUpperCase()} file`;
|
||||
saveDataToFile({
|
||||
data: exportText.val,
|
||||
option: {
|
||||
filters: {
|
||||
[filterName]: [exportFormat.val],
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
"Export",
|
||||
),
|
||||
button(
|
||||
{
|
||||
class: "tinymist-button",
|
||||
style: "flex: 1",
|
||||
onclick: () => navigator.clipboard.writeText(exportText.val),
|
||||
},
|
||||
"Copy",
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
interface SpanInfo {
|
||||
sources: FontSource[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,3 +47,20 @@ export const AddIcon = (sz: number = 16) =>
|
|||
<path d="M7.75 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.5v4.25a.75.75 0 0 1-1.5 0V8.5H2.75a.75.75 0 0 1 0-1.5H7V2.75A.75.75 0 0 1 7.75 2Z"></path>
|
||||
</svg>`,
|
||||
});
|
||||
|
||||
export const CopyIcon = (sz: number = 16) =>
|
||||
div({
|
||||
class: "tinymist-icon",
|
||||
style: `height: ${sz}px; width: ${sz}px;`,
|
||||
innerHTML: `<svg width="${sz}px" height="${sz}px" viewBox="0 0 16 16" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect class="stroke-based" width="9.8202543" height="11.792212" x="1.742749" y="3.4055943" ry="0.49967012" />
|
||||
<path class="stroke-based" d="m 5.1841347,0.82574918 9.0495613,0.0341483 V 12.129165" />
|
||||
<path class="stroke-based" d="M 3.6542046,6.2680732 H 9.3239071" />
|
||||
<path class="stroke-based" d="M 3.6542046,12.48578 H 7.7302609" />
|
||||
<path class="stroke-based" d="M 3.6542046,9.3769264 H 7.7302609" />
|
||||
</g>
|
||||
</svg>`,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ body {
|
|||
transition: color 0.05s;
|
||||
}
|
||||
|
||||
.tinymist-code {
|
||||
font-family: Cascadia Code, Consolas, SF Mono, DejaVu Sans Mono, monospace;
|
||||
}
|
||||
|
||||
#tinymist-app, .tinymist-main-window {
|
||||
margin: 24px 28px;
|
||||
}
|
||||
|
|
@ -167,11 +171,11 @@ body.typst-preview-light .tinymist-button.warning.activated {
|
|||
background: rgba(243, 202, 99, 0.9);
|
||||
}
|
||||
|
||||
.tinymist-icon path {
|
||||
.tinymist-icon :is(path, rect) {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.tinymist-icon path.stroke-based {
|
||||
.tinymist-icon :is(path, rect).stroke-based {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import van from "vanjs-core";
|
||||
import type { fontsExportConfigure } from "./features/summary";
|
||||
|
||||
const vscodeAPI = typeof acquireVsCodeApi !== "undefined" && acquireVsCodeApi();
|
||||
|
||||
|
|
@ -69,6 +70,12 @@ export function requestSavePackageData(data: any) {
|
|||
}
|
||||
}
|
||||
|
||||
export function requestSaveFontsExportConfigure(data: fontsExportConfigure) {
|
||||
if (vscodeAPI?.postMessage) {
|
||||
vscodeAPI.postMessage({ type: "saveFontsExportConfigure", data });
|
||||
}
|
||||
}
|
||||
|
||||
export function requestInitTemplate(packageSpec: string) {
|
||||
if (vscodeAPI?.postMessage) {
|
||||
vscodeAPI.postMessage({ type: "initTemplate", packageSpec });
|
||||
|
|
@ -106,3 +113,9 @@ export function requestTextEdit(edit: TextEdit) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function saveDataToFile({data, path, option}: { data: string, path?: string, option?: any}) {
|
||||
if (vscodeAPI?.postMessage) {
|
||||
vscodeAPI.postMessage({ type: "saveDataToFile", data, path, option});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
yarn.lock
34
yarn.lock
|
|
@ -993,6 +993,11 @@ css-what@^6.1.0:
|
|||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
|
||||
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
|
||||
|
||||
csv-stringify@^6.5.0:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-6.5.0.tgz#7b1491893c917e018a97de9bf9604e23b88647c2"
|
||||
integrity sha512-edlXFVKcUx7r8Vx5zQucsuMg4wb/xT6qyz+Sr1vnLrdXqlLD1+UKyWNyZ9zn6mUW1ewmGxrpVwAcChGF0HQ/2Q==
|
||||
|
||||
debug@^3.2.7:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||
|
|
@ -1122,6 +1127,14 @@ eastasianwidth@^0.2.0:
|
|||
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||
|
||||
"editor-tools@file:tools/editor-tools":
|
||||
version "0.0.0"
|
||||
dependencies:
|
||||
csv-stringify "^6.5.0"
|
||||
detypify-service "0.2.4"
|
||||
minisearch "^6.3.0"
|
||||
vanjs-core "^1.5.0"
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
|
|
@ -2800,8 +2813,16 @@ std-env@^3.3.3:
|
|||
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2"
|
||||
integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
|
||||
name string-width-cjs
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
|
|
@ -2853,7 +2874,14 @@ string_decoder@^1.1.1:
|
|||
dependencies:
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue