mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-10 19:03:17 +02:00
#352 - Custom placeholders now support scripting
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
### 🎨 Enhancements
|
### 🎨 Enhancements
|
||||||
|
|
||||||
|
- [#352](https://github.com/estruyf/vscode-front-matter/issues/352): Custom placeholders now support scripting
|
||||||
- [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy
|
- [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy
|
||||||
- [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies
|
- [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies
|
||||||
- [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead
|
- [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType';
|
|||||||
import { isValidFile } from './../helpers/isValidFile';
|
import { isValidFile } from './../helpers/isValidFile';
|
||||||
import { SETTING_AUTO_UPDATE_DATE, SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX, CONFIG_KEY, SETTING_DATE_FORMAT, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_CONTENT_PLACEHOLDERS, TelemetryEvent } from './../constants';
|
import { SETTING_AUTO_UPDATE_DATE, SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX, CONFIG_KEY, SETTING_DATE_FORMAT, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_CONTENT_PLACEHOLDERS, TelemetryEvent } from './../constants';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { Field, TaxonomyType } from "../models";
|
import { CustomPlaceholder, Field, TaxonomyType } from "../models";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { ArticleHelper, Settings, SlugHelper } from '../helpers';
|
import { ArticleHelper, Settings, SlugHelper } from '../helpers';
|
||||||
import { Notifications } from '../helpers/Notifications';
|
import { Notifications } from '../helpers/Notifications';
|
||||||
@@ -225,8 +225,8 @@ export class Article {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the fields containing a custom placeholder that depends on slug
|
// Update the fields containing a custom placeholder that depends on slug
|
||||||
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
|
const placeholders = Settings.get<CustomPlaceholder[]>(SETTING_CONTENT_PLACEHOLDERS);
|
||||||
const customPlaceholders = placeholders?.filter(p => p.value.includes("{{slug}}"));
|
const customPlaceholders = placeholders?.filter(p => p.value && p.value.includes("{{slug}}"));
|
||||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||||
for (const customPlaceholder of (customPlaceholders || [])) {
|
for (const customPlaceholder of (customPlaceholders || [])) {
|
||||||
const customPlaceholderFields = contentType.fields.filter(f => f.default === `{{${customPlaceholder.id}}}`);
|
const customPlaceholderFields = contentType.fields.filter(f => f.default === `{{${customPlaceholder.id}}}`);
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export class Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frontMatter.data) {
|
if (frontMatter.data) {
|
||||||
frontMatter.data = ArticleHelper.updatePlaceholders(frontMatter.data, titleValue);
|
frontMatter.data = await ArticleHelper.updatePlaceholders(frontMatter.data, titleValue, newFilePath);
|
||||||
|
|
||||||
frontMatter = Article.updateDate(frontMatter);
|
frontMatter = Article.updateDate(frontMatter);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { CustomPlaceholder } from './../models/CustomPlaceholder';
|
||||||
import { Uri, workspace } from 'vscode';
|
import { Uri, workspace } from 'vscode';
|
||||||
import { MarkdownFoldingProvider } from './../providers/MarkdownFoldingProvider';
|
import { MarkdownFoldingProvider } from './../providers/MarkdownFoldingProvider';
|
||||||
import { DEFAULT_CONTENT_TYPE, DEFAULT_CONTENT_TYPE_NAME } from './../constants/ContentType';
|
import { DEFAULT_CONTENT_TYPE, DEFAULT_CONTENT_TYPE_NAME } from './../constants/ContentType';
|
||||||
@@ -22,6 +23,8 @@ import { fromMarkdown } from 'mdast-util-from-markdown';
|
|||||||
import { Link, Parent } from 'mdast-util-from-markdown/lib';
|
import { Link, Parent } from 'mdast-util-from-markdown/lib';
|
||||||
import { Content } from 'mdast';
|
import { Content } from 'mdast';
|
||||||
import { processKnownPlaceholders } from './PlaceholderHelper';
|
import { processKnownPlaceholders } from './PlaceholderHelper';
|
||||||
|
import { CustomScript } from './CustomScript';
|
||||||
|
import { Folders } from '../commands/Folders';
|
||||||
|
|
||||||
export class ArticleHelper {
|
export class ArticleHelper {
|
||||||
private static notifiedFiles: string[] = [];
|
private static notifiedFiles: string[] = [];
|
||||||
@@ -368,7 +371,7 @@ export class ArticleHelper {
|
|||||||
* @param title
|
* @param title
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public static updatePlaceholders(data: any, title: string) {
|
public static async updatePlaceholders(data: any, title: string, filePath: string) {
|
||||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||||
const fmData = Object.assign({}, data);
|
const fmData = Object.assign({}, data);
|
||||||
|
|
||||||
@@ -384,7 +387,7 @@ export class ArticleHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmData[fieldName] = processKnownPlaceholders(fmData[fieldName], title, dateFormat);
|
fmData[fieldName] = processKnownPlaceholders(fmData[fieldName], title, dateFormat);
|
||||||
fmData[fieldName] = this.processCustomPlaceholders(fmData[fieldName], title);
|
fmData[fieldName] = await this.processCustomPlaceholders(fmData[fieldName], title, filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmData;
|
return fmData;
|
||||||
@@ -396,16 +399,44 @@ export class ArticleHelper {
|
|||||||
* @param title
|
* @param title
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public static processCustomPlaceholders(value: string, title: string) {
|
public static async processCustomPlaceholders(value: string, title: string, filePath: string) {
|
||||||
if (value && typeof value === "string") {
|
if (value && typeof value === "string") {
|
||||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||||
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
|
const placeholders = Settings.get<CustomPlaceholder[]>(SETTING_CONTENT_PLACEHOLDERS);
|
||||||
if (placeholders && placeholders.length > 0) {
|
if (placeholders && placeholders.length > 0) {
|
||||||
for (const placeholder of placeholders) {
|
for (const placeholder of placeholders) {
|
||||||
if (value.includes(`{{${placeholder.id}}}`)) {
|
if (value.includes(`{{${placeholder.id}}}`)) {
|
||||||
|
|
||||||
|
let placeHolderValue = placeholder.value || "";
|
||||||
|
if (placeholder.script) {
|
||||||
|
const wsFolder = Folders.getWorkspaceFolder();
|
||||||
|
const script = { title: placeholder.id, script: placeholder.script, command: placeholder.command };
|
||||||
|
let output: string | any = await CustomScript.executeScript(script, wsFolder?.fsPath || "", `'${filePath}' '${title}'`);
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
// Check if the output needs to be parsed
|
||||||
|
if (output.includes("{") && output.includes("}")) {
|
||||||
|
try {
|
||||||
|
output = JSON.parse(output);
|
||||||
|
} catch (e) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output = output.split("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
placeHolderValue = output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const regex = new RegExp(`{{${placeholder.id}}}`, "g");
|
const regex = new RegExp(`{{${placeholder.id}}}`, "g");
|
||||||
const updatedValue = processKnownPlaceholders(placeholder.value, title, dateFormat);
|
const updatedValue = processKnownPlaceholders(placeHolderValue, title, dateFormat);
|
||||||
value = value.replace(regex, updatedValue);
|
|
||||||
|
if (value === `{{${placeholder.id}}}`) {
|
||||||
|
value = updatedValue;
|
||||||
|
} else {
|
||||||
|
value = value.replace(regex, updatedValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -526,7 +526,7 @@ export class ContentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: any = this.processFields(contentType, titleValue, templateData?.data || {});
|
let data: any = await this.processFields(contentType, titleValue, templateData?.data || {}, newFilePath);
|
||||||
|
|
||||||
data = ArticleHelper.updateDates(Object.assign({}, data));
|
data = ArticleHelper.updateDates(Object.assign({}, data));
|
||||||
|
|
||||||
@@ -553,7 +553,7 @@ export class ContentType {
|
|||||||
* @param contentType
|
* @param contentType
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
private static processFields(obj: IContentType | Field, titleValue: string, data: any) {
|
private static async processFields(obj: IContentType | Field, titleValue: string, data: any, filePath: string) {
|
||||||
|
|
||||||
if (obj.fields) {
|
if (obj.fields) {
|
||||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||||
@@ -561,19 +561,19 @@ export class ContentType {
|
|||||||
if (field.name === "title") {
|
if (field.name === "title") {
|
||||||
if (field.default) {
|
if (field.default) {
|
||||||
data[field.name] = processKnownPlaceholders(field.default, titleValue, dateFormat);
|
data[field.name] = processKnownPlaceholders(field.default, titleValue, dateFormat);
|
||||||
data[field.name] = ArticleHelper.processCustomPlaceholders(data[field.name], titleValue);
|
data[field.name] = await ArticleHelper.processCustomPlaceholders(data[field.name], titleValue, filePath);
|
||||||
} else {
|
} else {
|
||||||
data[field.name] = titleValue;
|
data[field.name] = titleValue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (field.type === "fields") {
|
if (field.type === "fields") {
|
||||||
data[field.name] = this.processFields(field, titleValue, {});
|
data[field.name] = await this.processFields(field, titleValue, {}, filePath);
|
||||||
} else {
|
} else {
|
||||||
const defaultValue = field.default;
|
const defaultValue = field.default;
|
||||||
|
|
||||||
if (typeof defaultValue === "string") {
|
if (typeof defaultValue === "string") {
|
||||||
data[field.name] = processKnownPlaceholders(defaultValue, titleValue, dateFormat);
|
data[field.name] = processKnownPlaceholders(defaultValue, titleValue, dateFormat);
|
||||||
data[field.name] = ArticleHelper.processCustomPlaceholders(data[field.name], titleValue);
|
data[field.name] = await ArticleHelper.processCustomPlaceholders(data[field.name], titleValue, filePath);
|
||||||
} else {
|
} else {
|
||||||
data[field.name] = typeof defaultValue !== "undefined" ? defaultValue : "";
|
data[field.name] = typeof defaultValue !== "undefined" ? defaultValue : "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ export class CustomScript {
|
|||||||
* @param args
|
* @param args
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private static async executeScript(script: ICustomScript, wsPath: string, args: string): Promise<string> {
|
public static async executeScript(script: ICustomScript, wsPath: string, args: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
// Check the command to use
|
// Check the command to use
|
||||||
@@ -264,6 +264,11 @@ export class CustomScript {
|
|||||||
reject(error.message);
|
reject(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stdout && stdout.endsWith(`\n`)) {
|
||||||
|
// Remove empty line at the end of the string
|
||||||
|
stdout = stdout.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
resolve(stdout);
|
resolve(stdout);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -322,11 +322,18 @@ export class DataListener extends BaseListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static updatePlaceholder(field: string, value: string, title: string) {
|
/**
|
||||||
|
* Update the placeholder
|
||||||
|
* @param field
|
||||||
|
* @param value
|
||||||
|
* @param title
|
||||||
|
*/
|
||||||
|
private static async updatePlaceholder(field: string, value: string, title: string) {
|
||||||
if (field && value) {
|
if (field && value) {
|
||||||
|
const crntFile = window.activeTextEditor?.document;
|
||||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||||
value = processKnownPlaceholders(value, title || "", dateFormat);
|
value = processKnownPlaceholders(value, title || "", dateFormat);
|
||||||
value = ArticleHelper.processCustomPlaceholders(value, title || "");
|
value = await ArticleHelper.processCustomPlaceholders(value, title || "", crntFile?.uri.fsPath || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendMsg(Command.updatePlaceholder, { field, value });
|
this.sendMsg(Command.updatePlaceholder, { field, value });
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export interface CustomPlaceholder {
|
||||||
|
id: string;
|
||||||
|
value?: string;
|
||||||
|
script?: string;
|
||||||
|
command?: string
|
||||||
|
}
|
||||||
@@ -118,7 +118,7 @@ export interface CustomScript {
|
|||||||
output?: "notification" | "editor";
|
output?: "notification" | "editor";
|
||||||
outputType?: string;
|
outputType?: string;
|
||||||
type?: ScriptType;
|
type?: ScriptType;
|
||||||
command?: CommandType;
|
command?: CommandType | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PreviewSettings {
|
export interface PreviewSettings {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './BlockFieldData';
|
export * from './BlockFieldData';
|
||||||
export * from './Choice';
|
export * from './Choice';
|
||||||
export * from './ContentFolder';
|
export * from './ContentFolder';
|
||||||
|
export * from './CustomPlaceholder';
|
||||||
export * from './CustomTaxonomyData';
|
export * from './CustomTaxonomyData';
|
||||||
export * from './DashboardData';
|
export * from './DashboardData';
|
||||||
export * from './DataFile';
|
export * from './DataFile';
|
||||||
|
|||||||
Reference in New Issue
Block a user