mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-03-28 17:42:40 +01:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1f0e0ab58 | ||
|
|
5f7f847ff8 | ||
|
|
2c4dbeb1eb | ||
|
|
17164df11f | ||
|
|
228c46084d | ||
|
|
e838f18abc | ||
|
|
3d6359bc2e | ||
|
|
57b710cc61 | ||
|
|
7796d52ff9 | ||
|
|
f8f539be0d | ||
|
|
fc96c8922c | ||
|
|
c84af8493b | ||
|
|
6f288ff757 | ||
|
|
0e04e687fa | ||
|
|
cec3cbee3a | ||
|
|
c6f40194b4 | ||
|
|
6c591a90bd | ||
|
|
bece544934 | ||
|
|
c40fcba088 | ||
|
|
ea9f8a2651 | ||
|
|
b9b927c800 | ||
|
|
bc0f2e7bf7 | ||
|
|
b18f5e1e36 | ||
|
|
8b05da5a76 | ||
|
|
0062117c3b | ||
|
|
1d485adbca | ||
|
|
9f2aa34aac | ||
|
|
46a7a49e7c | ||
|
|
61ae29c37a |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,5 +1,32 @@
|
||||
# Change Log
|
||||
|
||||
## [10.6.0] - 2024-11-06 - [Release notes](https://beta.frontmatter.codes/updates/v10.6.0)
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#878](https://github.com/estruyf/vscode-front-matter/issues/878): Allow the `select all` button to work on other pages when there is a selection present
|
||||
- [#882](https://github.com/estruyf/vscode-front-matter/issues/882): Dynamic evaluation of the `node` executable path
|
||||
- [#884](https://github.com/estruyf/vscode-front-matter/issues/884): Hide WYSIWYG actions when the file is in git diff mode
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#859](https://github.com/estruyf/vscode-front-matter/issues/859): Fix label in the data view dropdown field
|
||||
- [#876](https://github.com/estruyf/vscode-front-matter/issues/876): Fix snippet type on the snippet card
|
||||
- [#879](https://github.com/estruyf/vscode-front-matter/issues/879): Fix for auto updating last modified date on save
|
||||
- [#885](https://github.com/estruyf/vscode-front-matter/issues/885): Fix content relationship for none i18n content
|
||||
|
||||
## [10.5.1] - 2024-10-23
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#873](https://github.com/estruyf/vscode-front-matter/issues/873): Add retry logic to get the AI model for calling GitHub Copilot
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#872](https://github.com/estruyf/vscode-front-matter/issues/872): Check the default field value as well for the field's `when` clause
|
||||
- [#874](https://github.com/estruyf/vscode-front-matter/issues/874): Fix media snippet markup insertion to article content's
|
||||
- [#875](https://github.com/estruyf/vscode-front-matter/issues/875): Clean up the exclamation marks from the file name when creating new content
|
||||
|
||||
## [10.5.0] - 2024-10-21 - [Release notes](https://beta.frontmatter.codes/updates/v10.5.0)
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
@@ -131,7 +131,8 @@
|
||||
}
|
||||
|
||||
.article__tags__dropbox.open {
|
||||
border: 1px solid rgba(0, 0, 0, 0.9);
|
||||
border: 1px solid var(--vscode-focusBorder);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.article__tags ul {
|
||||
|
||||
671
package-lock.json
generated
671
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@@ -3,7 +3,7 @@
|
||||
"displayName": "Front Matter CMS",
|
||||
"description": "Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice like: Hugo, Jekyll, Docusaurus, NextJs, Gatsby, and many more...",
|
||||
"icon": "assets/frontmatter-teal-128x128.png",
|
||||
"version": "10.5.0",
|
||||
"version": "10.6.0",
|
||||
"preview": false,
|
||||
"publisher": "eliostruyf",
|
||||
"galleryBanner": {
|
||||
@@ -31,7 +31,7 @@
|
||||
"l10n": "./l10n",
|
||||
"categories": [
|
||||
"AI",
|
||||
"Other"
|
||||
"Visualization"
|
||||
],
|
||||
"keywords": [
|
||||
"Front Matter",
|
||||
@@ -2421,32 +2421,32 @@
|
||||
"editor/title": [{
|
||||
"command": "frontMatter.markup.heading",
|
||||
"group": "navigation@-133",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.bold",
|
||||
"group": "navigation@-132",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.italic",
|
||||
"group": "navigation@-131",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.hyperlink",
|
||||
"group": "navigation@-130",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.insertSnippet",
|
||||
"group": "navigation@-129",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:dashboard:snippets:enabled"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:dashboard:snippets:enabled && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.insertMedia",
|
||||
"group": "navigation@-128",
|
||||
"when": "frontMatter:file:isValid == true"
|
||||
"when": "frontMatter:file:isValid == true && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.i18n.createOrOpen",
|
||||
@@ -2456,37 +2456,37 @@
|
||||
{
|
||||
"command": "frontMatter.markup.options",
|
||||
"group": "navigation@-126",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.orderedlist",
|
||||
"group": "1_markup@1",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.unorderedlist",
|
||||
"group": "1_markup@2",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.tasklist",
|
||||
"group": "1_markup@3",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.code",
|
||||
"group": "1_markup@4",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.codeblock",
|
||||
"group": "1_markup@5",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.markup.blockquote",
|
||||
"group": "1_markup@6",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg && activeEditor == 'workbench.editors.files.textFileEditor'"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.dashboard",
|
||||
|
||||
@@ -52,7 +52,7 @@ export class Article {
|
||||
*
|
||||
* @param subscriptions - The array of subscriptions to register the commands with.
|
||||
*/
|
||||
public static async registerCommands(subscriptions: unknown[]) {
|
||||
public static registerCommands(subscriptions: unknown[]) {
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.setLastModifiedDate, Article.setLastModifiedDate)
|
||||
);
|
||||
@@ -66,6 +66,15 @@ export class Article {
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.insertSnippet, Article.insertSnippet));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers event listeners for the Article class.
|
||||
*
|
||||
* @param subscriptions - An array to which the event listener will be added.
|
||||
*/
|
||||
public static registerListeners(subscriptions: unknown[]) {
|
||||
subscriptions.push(workspace.onWillSaveTextDocument(Article.autoUpdate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the article date
|
||||
*/
|
||||
@@ -369,15 +378,15 @@ export class Article {
|
||||
* Article auto updater
|
||||
* @param event
|
||||
*/
|
||||
public static async autoUpdate(event: TextDocumentWillSaveEvent) {
|
||||
public static autoUpdate(event: TextDocumentWillSaveEvent) {
|
||||
const document = event.document;
|
||||
if (document && ArticleHelper.isSupportedFile(document)) {
|
||||
const autoUpdate = Settings.get(SETTING_AUTO_UPDATE_DATE);
|
||||
|
||||
// Is article located in one of the content folders
|
||||
const folders = await Folders.getCachedOrFresh();
|
||||
const folders = Folders.getCached();
|
||||
const documentPath = parseWinPath(document.fileName);
|
||||
const folder = folders.find((f) => documentPath.startsWith(f.path));
|
||||
const folder = folders?.find((f) => documentPath.startsWith(f.path));
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ function Select({
|
||||
...props
|
||||
}: SelectFieldProps) {
|
||||
const multiple = fieldType === Array;
|
||||
|
||||
return (
|
||||
<div className="autoform__select_field" {...filterDOMProps(props)}>
|
||||
<LabelField label={label} id={id} required={required} />
|
||||
@@ -84,11 +85,12 @@ function Select({
|
||||
}}
|
||||
ref={inputRef}
|
||||
value={value ?? ''}
|
||||
className='text-[var(--vscode-foreground)] bg-[var(--vscode-list-activeSelectionBackground)] rounded-[2px] active:border-transparent disabled:opacity-40 disabled:cursor-not-allowed focus:outline-none'
|
||||
style={{ width: '100%', padding: '0.5rem' }}
|
||||
>
|
||||
{(!!placeholder || !required || value === undefined) && !multiple && (
|
||||
{(!required || value === undefined) && !multiple && (
|
||||
<option value="" disabled={required} hidden={required}>
|
||||
{placeholder || label}
|
||||
{""}
|
||||
</option>
|
||||
)}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ export const ItemSelection: React.FunctionComponent<IItemSelectionProps> = ({
|
||||
<div className={`${cssNames} group-hover:block`}>
|
||||
<VSCodeCheckbox
|
||||
className={show ? "" : " shadow-[0_0_3px_var(--frontmatter-border-preserve)]"}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onChange={() => {
|
||||
onMultiSelect(filePath);
|
||||
}}
|
||||
|
||||
@@ -4,8 +4,7 @@ import { CommandLineIcon, PencilIcon, TrashIcon, ChevronDownIcon, XMarkIcon, Eye
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { MultiSelectedItemsAtom, PagedItems, SelectedItemActionAtom, SelectedMediaFolderSelector, SettingsSelector } from '../../state';
|
||||
import { ActionsBarItem } from './ActionsBarItem';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { LocalizationKey, localize } from '../../../localization';
|
||||
import { Alert } from '../Modals/Alert';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
@@ -68,8 +67,14 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
}, [selectedFiles]);
|
||||
|
||||
const selectAllItems = React.useCallback(() => {
|
||||
setSelectedFiles([...pagedItems]);
|
||||
}, [pagedItems]);
|
||||
const allSelected = [...selectedFiles, ...pagedItems];
|
||||
setSelectedFiles(Array.from(new Set(allSelected)));
|
||||
}, [selectedFiles, pagedItems]);
|
||||
|
||||
const hasAllItemsSelectedOnPage = React.useMemo(() => {
|
||||
const selectedItemsOnPage = selectedFiles.filter((file) => pagedItems.includes(file));
|
||||
return selectedItemsOnPage.length >= pagedItems.length;
|
||||
}, [selectedFiles, pagedItems]);
|
||||
|
||||
const languageActions = React.useMemo(() => {
|
||||
const actions: React.ReactNode[] = [];
|
||||
@@ -92,7 +97,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
})
|
||||
}}>
|
||||
<LanguageIcon className={`mr-2 h-4 w-4`} aria-hidden={true} />
|
||||
<span>{l10n.t(LocalizationKey.commonTranslate)}</span>
|
||||
<span>{localize(LocalizationKey.commonTranslate)}</span>
|
||||
</ActionsBarItem>
|
||||
)
|
||||
|
||||
@@ -107,7 +112,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
className='flex items-center text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]'
|
||||
>
|
||||
<LanguageIcon className="mr-2 h-4 w-4" aria-hidden={true} />
|
||||
<span>{l10n.t(LocalizationKey.commonLanguages)}</span>
|
||||
<span>{localize(LocalizationKey.commonLanguages)}</span>
|
||||
<ChevronDownIcon className="ml-2 h-4 w-4" aria-hidden={true} />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
@@ -163,7 +168,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
disabled={selectedFiles.length === 0}
|
||||
>
|
||||
<CommandLineIcon className="mr-2 h-4 w-4" aria-hidden={true} />
|
||||
<span>{l10n.t(LocalizationKey.commonScripts)}</span>
|
||||
<span>{localize(LocalizationKey.commonScripts)}</span>
|
||||
<ChevronDownIcon className="ml-2 h-4 w-4" aria-hidden={true} />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
@@ -197,10 +202,10 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
<ActionsBarItem
|
||||
disabled={selectedFiles.length === 0 || selectedFiles.length > 1}
|
||||
onClick={viewFile}
|
||||
title={l10n.t(LocalizationKey.commonView)}
|
||||
title={localize(LocalizationKey.commonView)}
|
||||
>
|
||||
<EyeIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonView)}</span>
|
||||
<span>{localize(LocalizationKey.commonView)}</span>
|
||||
</ActionsBarItem>
|
||||
|
||||
{
|
||||
@@ -211,10 +216,10 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
messageHandler.send(DashboardMessage.rename, selectedFiles[0]);
|
||||
setSelectedFiles([]);
|
||||
}}
|
||||
title={l10n.t(LocalizationKey.commonRename)}
|
||||
title={localize(LocalizationKey.commonRename)}
|
||||
>
|
||||
<RenameIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonRename)}</span>
|
||||
<span>{localize(LocalizationKey.commonRename)}</span>
|
||||
</ActionsBarItem>
|
||||
)
|
||||
}
|
||||
@@ -228,10 +233,10 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
path: selectedFiles[0],
|
||||
action: 'edit'
|
||||
})}
|
||||
title={l10n.t(LocalizationKey.commonEdit)}
|
||||
title={localize(LocalizationKey.commonEdit)}
|
||||
>
|
||||
<PencilIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonEdit)}</span>
|
||||
<span>{localize(LocalizationKey.commonEdit)}</span>
|
||||
</ActionsBarItem>
|
||||
</>
|
||||
)
|
||||
@@ -245,10 +250,10 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
className='hover:text-[var(--vscode-statusBarItem-errorBackground)]'
|
||||
disabled={selectedFiles.length === 0}
|
||||
onClick={() => setShowAlert(true)}
|
||||
title={l10n.t(LocalizationKey.commonDelete)}
|
||||
title={localize(LocalizationKey.commonDelete)}
|
||||
>
|
||||
<TrashIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonDelete)}</span>
|
||||
<span>{localize(LocalizationKey.commonDelete)}</span>
|
||||
</ActionsBarItem>
|
||||
</div>
|
||||
|
||||
@@ -258,33 +263,33 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
<ActionsBarItem
|
||||
className='flex items-center hover:text-[var(--vscode-statusBarItem-warningBackground)]'
|
||||
onClick={() => setSelectedFiles([])}
|
||||
title={l10n.t(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}
|
||||
title={localize(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}
|
||||
>
|
||||
<XMarkIcon className="w-4 h-4 mr-1" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}</span>
|
||||
<span>{localize(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}</span>
|
||||
</ActionsBarItem>
|
||||
)
|
||||
}
|
||||
|
||||
<ActionsBarItem
|
||||
disabled={selectedFiles.length === pagedItems.length}
|
||||
disabled={hasAllItemsSelectedOnPage}
|
||||
onClick={selectAllItems}
|
||||
title={l10n.t(LocalizationKey.dashboardHeaderActionsBarSelectAll)}
|
||||
title={localize(LocalizationKey.dashboardHeaderActionsBarSelectAll)}
|
||||
>
|
||||
<div className='w-4 h-4 inline-flex items-center justify-center border border-[var(--vscode-sideBar-foreground)] group-hover:border-[var(--vscode-statusBarItem-warningBackground)] rounded mr-1'>
|
||||
<CheckIcon className="w-3 h-3" aria-hidden="true" />
|
||||
</div>
|
||||
<span>{l10n.t(LocalizationKey.dashboardHeaderActionsBarSelectAll)}</span>
|
||||
<span>{localize(LocalizationKey.dashboardHeaderActionsBarSelectAll)}</span>
|
||||
</ActionsBarItem>
|
||||
</div>
|
||||
</div >
|
||||
|
||||
{showAlert && (
|
||||
<Alert
|
||||
title={`${l10n.t(LocalizationKey.dashboardHeaderActionsBarAlertDeleteTitle)}`}
|
||||
description={l10n.t(LocalizationKey.dashboardHeaderActionsBarAlertDeleteDescription)}
|
||||
okBtnText={l10n.t(LocalizationKey.commonDelete)}
|
||||
cancelBtnText={l10n.t(LocalizationKey.commonCancel)}
|
||||
title={`${localize(LocalizationKey.dashboardHeaderActionsBarAlertDeleteTitle)}`}
|
||||
description={localize(LocalizationKey.dashboardHeaderActionsBarAlertDeleteDescription)}
|
||||
okBtnText={localize(LocalizationKey.commonDelete)}
|
||||
cancelBtnText={localize(LocalizationKey.commonCancel)}
|
||||
dismiss={() => setShowAlert(false)}
|
||||
trigger={onDeleteConfirm}
|
||||
/>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { LanguageFilter } from '../Filters/LanguageFilter';
|
||||
|
||||
export interface IFiltersProps { }
|
||||
|
||||
export const Filters: React.FunctionComponent<IFiltersProps> = (_: React.PropsWithChildren<IFiltersProps>) => {
|
||||
export const Filters: React.FunctionComponent<IFiltersProps> = () => {
|
||||
const [crntFilters, setCrntFilters] = useRecoilState(FiltersAtom);
|
||||
const [crntTag, setCrntTag] = useRecoilState(TagAtom);
|
||||
const [crntCategory, setCrntCategory] = useRecoilState(CategoryAtom);
|
||||
|
||||
@@ -183,7 +183,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
|
||||
<div className='inline-block mr-1 mt-1 text-xs text-[var(--vscode-button-secondaryForeground)] bg-[var(--vscode-button-secondaryBackground)] border border-[var(--frontmatter-border)] rounded px-1 py-0.5'>
|
||||
{
|
||||
snippet.isMediaSnippet ? l10n.t(LocalizationKey.dashboardSnippetsViewItemTypeContent) : l10n.t(LocalizationKey.dashboardSnippetsViewItemTypeMedia)
|
||||
snippet.isMediaSnippet ? l10n.t(LocalizationKey.dashboardSnippetsViewItemTypeMedia) : l10n.t(LocalizationKey.dashboardSnippetsViewItemTypeContent)
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import ContentProvider from './providers/ContentProvider';
|
||||
import { PagesListener } from './listeners/dashboard';
|
||||
import { ModeSwitch } from './services/ModeSwitch';
|
||||
import { PagesParser } from './services/PagesParser';
|
||||
import { ContentType, Telemetry, Extension } from './helpers';
|
||||
import { ContentType, Extension } from './helpers';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import {
|
||||
Backers,
|
||||
@@ -121,8 +121,9 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// Register the taxonomy commands
|
||||
Taxonomy.registerCommands(subscriptions);
|
||||
|
||||
// Register all the article commands
|
||||
// Register all the article commands and listeners
|
||||
Article.registerCommands(subscriptions);
|
||||
Article.registerListeners(subscriptions);
|
||||
|
||||
// Template creation
|
||||
Template.registerCommands();
|
||||
@@ -181,9 +182,6 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// Automatically run the command
|
||||
triggerPageUpdate(`main`);
|
||||
|
||||
// Listener for file edit changes
|
||||
subscriptions.push(vscode.workspace.onWillSaveTextDocument(handleAutoDateUpdate));
|
||||
|
||||
// Listener for file saves
|
||||
subscriptions.push(PagesListener.saveFileWatcher());
|
||||
|
||||
@@ -241,16 +239,13 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// Subscribe all commands
|
||||
subscriptions.push(PanelView, collapseAll, fmStatusBarItem);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`𝖥𝗋𝗈𝗇𝗍 𝖬𝖺𝗍𝗍𝖾𝗋 𝖢𝖬𝖲 𝖺𝖼𝗍𝗂𝗏𝖺𝗍𝖾𝖽! 𝖱𝖾𝖺𝖽𝗒 𝗍𝗈 𝗌𝗍𝖺𝗋𝗍 𝗐𝗋𝗂𝗍𝗂𝗇𝗀... 👩💻🧑💻👨💻`);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
export function deactivate() {}
|
||||
|
||||
const handleAutoDateUpdate = (e: vscode.TextDocumentWillSaveEvent) => {
|
||||
Article.autoUpdate(e);
|
||||
};
|
||||
|
||||
const triggerPageUpdate = (location: string) => {
|
||||
Logger.verbose(`Trigger page update: ${location}`);
|
||||
pageUpdateDebouncer(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Settings } from './SettingsHelper';
|
||||
import { CommandType, EnvironmentType } from './../models/PanelSettings';
|
||||
import { CommandType } from './../models/PanelSettings';
|
||||
import { CustomScript as ICustomScript, ScriptType } from '../models/PanelSettings';
|
||||
import { window, env as vscodeEnv, ProgressLocation, Uri, commands } from 'vscode';
|
||||
import { ArticleHelper, Logger, MediaHelpers } from '.';
|
||||
@@ -13,9 +13,8 @@ import { Dashboard } from '../commands/Dashboard';
|
||||
import { DashboardCommand } from '../dashboardWebView/DashboardCommand';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { SETTING_CUSTOM_SCRIPTS } from '../constants';
|
||||
import { existsAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { evaluateCommand, existsAsync, getPlatform } from '../utils';
|
||||
import { LocalizationKey, localize } from '../localization';
|
||||
|
||||
export class CustomScript {
|
||||
/**
|
||||
@@ -101,7 +100,7 @@ export class CustomScript {
|
||||
);
|
||||
} else {
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptSingleRunArticleWarning, script.title)
|
||||
localize(LocalizationKey.helpersCustomScriptSingleRunArticleWarning, script.title)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +116,7 @@ export class CustomScript {
|
||||
|
||||
if (!folders || folders.length === 0) {
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptBulkRunNoFilesWarning, script.title)
|
||||
localize(LocalizationKey.helpersCustomScriptBulkRunNoFilesWarning, script.title)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -127,7 +126,7 @@ export class CustomScript {
|
||||
window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: l10n.t(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
title: localize(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
cancellable: false
|
||||
},
|
||||
async (_, __) => {
|
||||
@@ -173,7 +172,7 @@ export class CustomScript {
|
||||
): Promise<void> {
|
||||
if (!path) {
|
||||
Notifications.error(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptRunMediaScriptNoFolderWarning, script.title)
|
||||
localize(LocalizationKey.helpersCustomScriptRunMediaScriptNoFolderWarning, script.title)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -182,7 +181,7 @@ export class CustomScript {
|
||||
window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: l10n.t(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
title: localize(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
cancellable: false
|
||||
},
|
||||
async () => {
|
||||
@@ -309,7 +308,10 @@ export class CustomScript {
|
||||
throw new Error(`Couldn't update article.`);
|
||||
}
|
||||
Notifications.info(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptShowOutputFrontMatterSuccess, script.title)
|
||||
localize(
|
||||
LocalizationKey.helpersCustomScriptShowOutputFrontMatterSuccess,
|
||||
script.title
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if (data.fmAction) {
|
||||
@@ -345,10 +347,12 @@ export class CustomScript {
|
||||
window
|
||||
.showInformationMessage(
|
||||
`${script.title}: ${output}`,
|
||||
l10n.t(LocalizationKey.helpersCustomScriptShowOutputCopyOutputAction)
|
||||
localize(LocalizationKey.helpersCustomScriptShowOutputCopyOutputAction)
|
||||
)
|
||||
.then((value) => {
|
||||
if (value === l10n.t(LocalizationKey.helpersCustomScriptShowOutputCopyOutputAction)) {
|
||||
if (
|
||||
value === localize(LocalizationKey.helpersCustomScriptShowOutputCopyOutputAction)
|
||||
) {
|
||||
vscodeEnv.clipboard.writeText(output);
|
||||
}
|
||||
});
|
||||
@@ -356,7 +360,7 @@ export class CustomScript {
|
||||
}
|
||||
} else {
|
||||
Notifications.info(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptShowOutputSuccess, script.title)
|
||||
localize(LocalizationKey.helpersCustomScriptShowOutputSuccess, script.title)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -373,7 +377,7 @@ export class CustomScript {
|
||||
wsPath: string,
|
||||
args: string
|
||||
): Promise<string> {
|
||||
const osType = os.type();
|
||||
const platform = getPlatform();
|
||||
|
||||
// Check the command to use
|
||||
let command = script.nodeBin || 'node';
|
||||
@@ -381,6 +385,10 @@ export class CustomScript {
|
||||
command = script.command;
|
||||
}
|
||||
|
||||
if (script.command === CommandType.Node && platform !== 'windows') {
|
||||
command = await evaluateCommand(CommandType.Node);
|
||||
}
|
||||
|
||||
let scriptPath = join(wsPath, script.script);
|
||||
if (script.script.includes(WORKSPACE_PLACEHOLDER)) {
|
||||
scriptPath = Folders.getAbsFilePath(script.script);
|
||||
@@ -388,19 +396,15 @@ export class CustomScript {
|
||||
|
||||
// Check if there is an environments overwrite required
|
||||
if (script.environments) {
|
||||
let crntType: EnvironmentType | null = null;
|
||||
if (osType === 'Windows_NT') {
|
||||
crntType = 'windows';
|
||||
} else if (osType === 'Darwin') {
|
||||
crntType = 'macos';
|
||||
} else {
|
||||
crntType = 'linux';
|
||||
}
|
||||
|
||||
const environment = script.environments.find((e) => e.type === crntType);
|
||||
const environment = script.environments.find((e) => e.type === platform);
|
||||
if (environment && environment.script && environment.command) {
|
||||
if (await CustomScript.validateCommand(environment.command)) {
|
||||
command = environment.command;
|
||||
|
||||
if (command === CommandType.Node && platform !== 'windows') {
|
||||
command = await evaluateCommand(CommandType.Node);
|
||||
}
|
||||
|
||||
scriptPath = join(wsPath, environment.script);
|
||||
if (environment.script.includes(WORKSPACE_PLACEHOLDER)) {
|
||||
scriptPath = Folders.getAbsFilePath(environment.script);
|
||||
@@ -414,12 +418,12 @@ export class CustomScript {
|
||||
throw new Error(`Script not found: ${scriptPath}`);
|
||||
}
|
||||
|
||||
if (osType === 'Windows_NT' && command.toLowerCase() === 'powershell') {
|
||||
if (platform === 'windows' && command.toLowerCase() === 'powershell') {
|
||||
command = `${command} -File`;
|
||||
}
|
||||
|
||||
const fullScript = `${command} "${scriptPath}" ${args}`;
|
||||
Logger.info(l10n.t(LocalizationKey.helpersCustomScriptExecuting, fullScript));
|
||||
Logger.info(localize(LocalizationKey.helpersCustomScriptExecuting, fullScript));
|
||||
|
||||
const output: string = await CustomScript.executeScriptAsync(fullScript, wsPath);
|
||||
|
||||
@@ -502,7 +506,7 @@ export class CustomScript {
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
Logger.error(l10n.t(LocalizationKey.helpersCustomScriptValidateCommandError, command));
|
||||
Logger.error(localize(LocalizationKey.helpersCustomScriptValidateCommandError, command));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GitListener } from './../listeners/general/GitListener';
|
||||
import { basename, join } from 'path';
|
||||
import { join } from 'path';
|
||||
import { workspace } from 'vscode';
|
||||
import { Folders } from '../commands/Folders';
|
||||
import { Project } from '../commands/Project';
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
SETTING_MEDIA_SUPPORTED_MIMETYPES,
|
||||
SETTING_TAXONOMY_CUSTOM,
|
||||
SETTING_TEMPLATES_ENABLED,
|
||||
SETTING_GIT_ENABLED,
|
||||
SETTING_DASHBOARD_CONTENT_PAGINATION,
|
||||
SETTING_SNIPPETS_WRAPPER,
|
||||
SETTING_DASHBOARD_CONTENT_CARD_DATE,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
SETTING_MEDIA_SUPPORTED_MIMETYPES
|
||||
} from '../constants';
|
||||
import { SortingOption } from '../dashboardWebView/models';
|
||||
import { MediaInfo, MediaPaths, SortOrder, SortType } from '../models';
|
||||
import { BlockFieldData, MediaInfo, MediaPaths, SortOrder, SortType } from '../models';
|
||||
import { basename, join, parse, dirname, relative } from 'path';
|
||||
import { statSync } from 'fs';
|
||||
import { Uri, workspace, window, Position } from 'vscode';
|
||||
@@ -376,7 +376,18 @@ export class MediaHelpers {
|
||||
* Insert an image into the front matter or contents
|
||||
* @param data
|
||||
*/
|
||||
public static async insertMediaToMarkdown(data: any) {
|
||||
public static async insertMediaToMarkdown(data: {
|
||||
file: string;
|
||||
relPath: string;
|
||||
snippet: string;
|
||||
position: Position;
|
||||
title?: string;
|
||||
alt?: string;
|
||||
caption?: string;
|
||||
fieldName: string;
|
||||
parents: string[];
|
||||
blockData: BlockFieldData;
|
||||
}) {
|
||||
if (data?.file && data?.relPath) {
|
||||
await EditorHelper.showFile(data.file);
|
||||
Dashboard.resetViewData();
|
||||
@@ -444,7 +455,7 @@ export class MediaHelpers {
|
||||
const docType = Wysiwyg.getDocType(filePath);
|
||||
|
||||
let snippet = data.snippet || '';
|
||||
if (!data.Snippet) {
|
||||
if (!snippet) {
|
||||
if (docType === 'markdown') {
|
||||
snippet = `${isFile ? '' : '!'}[${caption}](${FrameworkDetector.relAssetPathUpdate(
|
||||
relPath,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const illegalRe = /[/?<>\\:*|"]/g;
|
||||
const illegalRe = /[/?<>\\:*|"!.,;{}[\]()_+=~`@#$%^&]/g;
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const controlRe = /[\x00-\x1F\x80-\x9F]/g;
|
||||
const controlRe = /[\x00-\x1f\x80-\x9f]/g;
|
||||
const reservedRe = /^\.+$/;
|
||||
const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
|
||||
const windowsTrailingRe = /[. ]+$/;
|
||||
@@ -9,6 +9,7 @@ function sanitize(input: string, replacement: string) {
|
||||
if (typeof input !== 'string') {
|
||||
throw new Error('Input must be string');
|
||||
}
|
||||
|
||||
const sanitized = input
|
||||
.replace(illegalRe, replacement)
|
||||
.replace(controlRe, replacement)
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from '../../constants';
|
||||
import { SettingsListener } from './SettingsListener';
|
||||
import { Terminal } from '../../services';
|
||||
import { existsAsync, readFileAsync } from '../../utils';
|
||||
import { evaluateCommand, existsAsync, getPlatform, readFileAsync } from '../../utils';
|
||||
import { join } from 'path';
|
||||
|
||||
export class SsgListener extends BaseListener {
|
||||
@@ -170,7 +170,12 @@ export class SsgListener extends BaseListener {
|
||||
workspace.fs.copy(scriptPath, tempScriptPath, { overwrite: true });
|
||||
}
|
||||
|
||||
const fullScript = `node "${tempScriptPath.fsPath}" "${contentConfigFile.fsPath}"`;
|
||||
let nodeExecPath = 'node';
|
||||
const platform = getPlatform();
|
||||
if (platform !== 'windows') {
|
||||
nodeExecPath = await evaluateCommand('node');
|
||||
}
|
||||
const fullScript = `${nodeExecPath} "${tempScriptPath.fsPath}" "${contentConfigFile.fsPath}"`;
|
||||
|
||||
try {
|
||||
const result: string = await SsgListener.executeScript(fullScript, wsFolder?.fsPath || '');
|
||||
|
||||
@@ -115,7 +115,12 @@ export class DataListener extends BaseListener {
|
||||
}
|
||||
|
||||
private static async copilotSuggestTitle(command: string, requestId?: string, title?: string) {
|
||||
if (!command || !requestId || !title) {
|
||||
if (!command || !requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!title) {
|
||||
this.sendRequestError(command, requestId, 'No title provided');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,17 +39,21 @@ export class FieldsListener extends BaseListener {
|
||||
return;
|
||||
}
|
||||
|
||||
const isLocaleEnabled = await i18n.isLocaleEnabled(data.activePath);
|
||||
const activeLocale = await i18n.getLocale(data.activePath);
|
||||
if (!activeLocale?.locale) {
|
||||
if (isLocaleEnabled && !activeLocale?.locale) {
|
||||
return;
|
||||
}
|
||||
|
||||
PagesListener.getPagesData(false, async (pages) => {
|
||||
const fuseKeys: Fuse.FuseOptionKey[] = [{ name: 'fmContentType', weight: 1 }];
|
||||
|
||||
if (isLocaleEnabled && data.sameLocale) {
|
||||
fuseKeys.push({ name: 'fmLocale.locale', weight: 1 });
|
||||
}
|
||||
|
||||
const fuseOptions: Fuse.IFuseOptions<Page> = {
|
||||
keys: [
|
||||
{ name: 'fmContentType', weight: 1 },
|
||||
...(data.sameLocale ? [{ name: 'fmLocale.locale', weight: 1 }] : [])
|
||||
],
|
||||
keys: fuseKeys,
|
||||
findAllMatches: true,
|
||||
threshold: 0
|
||||
};
|
||||
@@ -60,11 +64,14 @@ export class FieldsListener extends BaseListener {
|
||||
);
|
||||
const fuseIndex = Fuse.parseIndex(pagesIndex);
|
||||
const fuse = new Fuse(pages || [], fuseOptions, fuseIndex);
|
||||
|
||||
const andExpression: Fuse.Expression[] = [{ fmContentType: data.type ?? '' }];
|
||||
if (isLocaleEnabled && activeLocale?.locale && data.sameLocale) {
|
||||
andExpression.push({ 'fmLocale.locale': activeLocale.locale });
|
||||
}
|
||||
|
||||
const results = fuse.search({
|
||||
$and: [
|
||||
{ fmContentType: data.type! },
|
||||
...(data.sameLocale ? [{ 'fmLocale.locale': activeLocale.locale }] : [])
|
||||
]
|
||||
$and: andExpression
|
||||
});
|
||||
const pageResults = results.map((page) => page.item);
|
||||
|
||||
|
||||
3
src/models/ShellSetting.ts
Normal file
3
src/models/ShellSetting.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface ShellSetting {
|
||||
path: string;
|
||||
}
|
||||
@@ -22,6 +22,7 @@ export * from './Mode';
|
||||
export * from './PanelSettings';
|
||||
export * from './PostMessageData';
|
||||
export * from './Project';
|
||||
export * from './ShellSetting';
|
||||
export * from './Snippets';
|
||||
export * from './SortOrder';
|
||||
export * from './SortType';
|
||||
|
||||
@@ -15,7 +15,8 @@ export interface IFieldCollectionProps {
|
||||
parentFields: string[],
|
||||
blockData?: BlockFieldData,
|
||||
onFieldUpdate?: (field: string | undefined, value: any, parents: string[]) => void,
|
||||
parentBlock?: string | null
|
||||
parentBlock?: string | null,
|
||||
triggerUpdateOnDefault?: boolean
|
||||
) => (JSX.Element | null)[] | undefined;
|
||||
onChange: (field: string | undefined, value: any, parents: string[]) => void;
|
||||
}
|
||||
|
||||
@@ -55,8 +55,10 @@ export interface IWrapperFieldProps {
|
||||
parentFields: string[],
|
||||
blockData?: BlockFieldData,
|
||||
onFieldUpdate?: (field: string | undefined, value: any, parents: string[]) => void,
|
||||
parentBlock?: string | null
|
||||
parentBlock?: string | null,
|
||||
triggerUpdateOnDefault?: boolean
|
||||
) => (JSX.Element | null)[] | undefined;
|
||||
triggerUpdateOnDefault?: boolean;
|
||||
}
|
||||
|
||||
export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
@@ -72,7 +74,8 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
parentBlock,
|
||||
onSendUpdate,
|
||||
unsetFocus,
|
||||
renderFields
|
||||
renderFields,
|
||||
triggerUpdateOnDefault
|
||||
}: React.PropsWithChildren<IWrapperFieldProps>) => {
|
||||
const [fieldValue, setFieldValue] = useState<any | undefined>(undefined);
|
||||
const [customFields, setCustomFields] = useState<{
|
||||
@@ -110,7 +113,9 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
value = getDate(value) || null;
|
||||
}
|
||||
|
||||
//onSendUpdate(field.name, value, parentFields);
|
||||
if (triggerUpdateOnDefault) {
|
||||
onSendUpdate(field.name, value, parentFields);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the field value contains a placeholder
|
||||
@@ -140,7 +145,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [field, parent]);
|
||||
}, [field, parent, triggerUpdateOnDefault]);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.fmExternal && window.fmExternal.getCustomFields) {
|
||||
@@ -437,7 +442,9 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
subMetadata,
|
||||
[...parentFields, field.name],
|
||||
blockData,
|
||||
onSendUpdate
|
||||
onSendUpdate,
|
||||
null,
|
||||
true
|
||||
)}
|
||||
</div>
|
||||
</FieldBoundary>
|
||||
|
||||
@@ -61,7 +61,8 @@ const Metadata: React.FunctionComponent<IMetadataProps> = ({
|
||||
blockData?: BlockFieldData,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onFieldUpdate?: (field: string | undefined, value: any, parents: string[]) => void,
|
||||
parentBlock?: string | null
|
||||
parentBlock?: string | null,
|
||||
triggerUpdateOnDefault?: boolean
|
||||
): (JSX.Element | null)[] | undefined => {
|
||||
if (!ctFields || !settings) {
|
||||
return;
|
||||
@@ -83,6 +84,7 @@ const Metadata: React.FunctionComponent<IMetadataProps> = ({
|
||||
onSendUpdate={onFieldUpdate || onSendUpdate}
|
||||
unsetFocus={unsetFocus}
|
||||
renderFields={renderFields}
|
||||
triggerUpdateOnDefault={triggerUpdateOnDefault}
|
||||
/>
|
||||
));
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export default function useDropdownStyle(inputRef: React.MutableRefObject<HTMLInputElement | null>, inputHeight?: string) {
|
||||
const bottomStyle = `calc(100% - ${inputHeight || '38px'})`;
|
||||
const bottomStyle = `calc(100% - ${inputHeight || '5px'})`;
|
||||
const listItemHeight = 28;
|
||||
|
||||
const getDropdownStyle = useCallback((isOpen) => {
|
||||
|
||||
@@ -839,6 +839,8 @@ vscode-divider {
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
||||
&:disabled {
|
||||
background: none;
|
||||
filter: brightness(100%);
|
||||
@@ -947,6 +949,8 @@ vscode-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
|
||||
span {
|
||||
margin-right: 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
LanguageModelChatResponse,
|
||||
extensions,
|
||||
lm,
|
||||
version as VscodeVersion
|
||||
version as VscodeVersion,
|
||||
LanguageModelChat
|
||||
} from 'vscode';
|
||||
import { Logger, Settings, TaxonomyHelper } from '../helpers';
|
||||
import {
|
||||
@@ -14,6 +15,7 @@ import {
|
||||
} from '../constants';
|
||||
import { TagType } from '../panelWebView/TagType';
|
||||
import { TaxonomyType } from '../models';
|
||||
import { sleep } from '../utils';
|
||||
|
||||
export class Copilot {
|
||||
private static personality =
|
||||
@@ -51,7 +53,7 @@ export class Copilot {
|
||||
LanguageModelChatMessage.User(`The title of the blog post is """${title}""".`)
|
||||
];
|
||||
|
||||
const chatResponse = await this.getChatResponse(messages);
|
||||
const chatResponse = await Copilot.getChatResponse(messages);
|
||||
if (!chatResponse) {
|
||||
return;
|
||||
}
|
||||
@@ -100,7 +102,7 @@ Response format: a single string wrapped in double quotes, e.g., "Boost your web
|
||||
);
|
||||
}
|
||||
|
||||
const chatResponse = await this.getChatResponse(messages);
|
||||
const chatResponse = await Copilot.getChatResponse(messages);
|
||||
|
||||
if (!chatResponse) {
|
||||
return;
|
||||
@@ -179,7 +181,7 @@ Example: SEO, website optimization, digital marketing.`
|
||||
);
|
||||
}
|
||||
|
||||
const chatResponse = await this.getChatResponse(messages);
|
||||
const chatResponse = await Copilot.getChatResponse(messages);
|
||||
|
||||
if (!chatResponse) {
|
||||
return;
|
||||
@@ -211,6 +213,9 @@ Example: SEO, website optimization, digital marketing.`
|
||||
|
||||
try {
|
||||
const model = await this.getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
chatResponse = await model.sendRequest(messages, {}, new CancellationTokenSource().token);
|
||||
} catch (err) {
|
||||
Logger.error(`Copilot:getChatResponse:: ${(err as Error).message}`);
|
||||
@@ -229,7 +234,7 @@ Example: SEO, website optimization, digital marketing.`
|
||||
* Retrieves the chat model for the Copilot service.
|
||||
* @returns A Promise that resolves to the chat model.
|
||||
*/
|
||||
private static async getModel() {
|
||||
private static async getModel(retry = 0): Promise<LanguageModelChat | undefined> {
|
||||
// const models = await lm.selectChatModels();
|
||||
// console.log(models);
|
||||
const [model] = await lm.selectChatModels({
|
||||
@@ -237,6 +242,11 @@ Example: SEO, website optimization, digital marketing.`
|
||||
family: Settings.get<string>(SETTING_COPILOT_FAMILY) || 'gpt-4o-mini'
|
||||
});
|
||||
|
||||
if ((!model || !model.sendRequest) && retry <= 5) {
|
||||
await sleep(1000);
|
||||
return Copilot.getModel(retry + 1);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { workspace, window, ThemeIcon, TerminalOptions } from 'vscode';
|
||||
import * as os from 'os';
|
||||
import { Folders } from '../commands';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
interface ShellSetting {
|
||||
path: string;
|
||||
}
|
||||
import { LocalizationKey, localize } from '../localization';
|
||||
import { getShellPath } from '../utils';
|
||||
|
||||
export class Terminal {
|
||||
public static readonly terminalName: string = 'Local server';
|
||||
@@ -15,7 +10,7 @@ export class Terminal {
|
||||
* Return the shell path for the current platform
|
||||
*/
|
||||
public static get shell() {
|
||||
const shell: string | { path: string } | undefined = Terminal.getShellPath();
|
||||
const shell: string | { path: string } | undefined = getShellPath();
|
||||
let shellPath: string | undefined = undefined;
|
||||
|
||||
if (typeof shell !== 'string' && !!shell) {
|
||||
@@ -47,7 +42,7 @@ export class Terminal {
|
||||
const terminalOptions: TerminalOptions = {
|
||||
name: Terminal.terminalName,
|
||||
iconPath: new ThemeIcon('server-environment'),
|
||||
message: l10n.t(
|
||||
message: localize(
|
||||
LocalizationKey.servicesTerminalOpenLocalServerTerminalTerminalOptionMessage
|
||||
)
|
||||
};
|
||||
@@ -90,46 +85,4 @@ export class Terminal {
|
||||
return localServerTerminal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the automation profile for the current platform
|
||||
* @returns
|
||||
*/
|
||||
private static getShellPath(): string | ShellSetting | undefined {
|
||||
const platform = Terminal.getPlatform();
|
||||
const terminalSettings = workspace.getConfiguration('terminal');
|
||||
|
||||
const automationProfile = terminalSettings.get<string | ShellSetting>(
|
||||
`integrated.automationProfile.${platform}`
|
||||
);
|
||||
if (!!automationProfile) {
|
||||
return automationProfile;
|
||||
}
|
||||
|
||||
const defaultProfile = terminalSettings.get<string>(`integrated.defaultProfile.${platform}`);
|
||||
const profiles = terminalSettings.get<{ [prop: string]: ShellSetting }>(
|
||||
`integrated.profiles.${platform}`
|
||||
);
|
||||
|
||||
if (defaultProfile && profiles && profiles[defaultProfile]) {
|
||||
return profiles[defaultProfile];
|
||||
}
|
||||
|
||||
return terminalSettings.get(`integrated.shell.${platform}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current platform
|
||||
* @returns
|
||||
*/
|
||||
private static getPlatform = (): 'windows' | 'linux' | 'osx' => {
|
||||
const platform = os.platform();
|
||||
if (platform === 'win32') {
|
||||
return 'windows';
|
||||
} else if (platform === 'darwin') {
|
||||
return 'osx';
|
||||
}
|
||||
|
||||
return 'linux';
|
||||
};
|
||||
}
|
||||
|
||||
30
src/utils/evaluateCommand.ts
Normal file
30
src/utils/evaluateCommand.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { exec } from 'child_process';
|
||||
import { getShellPath } from '../utils';
|
||||
import { Logger } from '../helpers';
|
||||
|
||||
/**
|
||||
* Evaluate the command dynamically using `which` command
|
||||
* @param command
|
||||
* @returns
|
||||
*/
|
||||
export const evaluateCommand = (command: string): Promise<string> => {
|
||||
const shell = getShellPath();
|
||||
let shellPath: string | undefined = undefined;
|
||||
if (typeof shell !== 'string' && !!shell) {
|
||||
shellPath = shell.path;
|
||||
} else {
|
||||
shellPath = shell || undefined;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`which ${command}`, { shell: shellPath }, (error, stdout) => {
|
||||
if (error) {
|
||||
Logger.error(`Error evaluating command: ${command}`);
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(stdout.trim());
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -22,7 +22,17 @@ export const fieldWhenClause = (field: Field, parent: IMetadata, allFields?: Fie
|
||||
}
|
||||
}
|
||||
|
||||
const whenValue = parent[when.fieldRef];
|
||||
let whenValue = parent[when.fieldRef];
|
||||
|
||||
// If the value is not yet set, check if the field has a default value.
|
||||
if (
|
||||
typeof whenValue === 'undefined' &&
|
||||
parentField &&
|
||||
typeof parentField.default !== 'undefined'
|
||||
) {
|
||||
whenValue = parentField.default as string | IMetadata | string[] | null;
|
||||
}
|
||||
|
||||
if (when.caseSensitive || typeof when.caseSensitive === 'undefined') {
|
||||
return caseSensitive(when, field, whenValue);
|
||||
} else {
|
||||
@@ -61,7 +71,7 @@ const caseInsensitive = (
|
||||
*/
|
||||
const caseSensitive = (
|
||||
when: WhenClause,
|
||||
field: Field,
|
||||
_: Field,
|
||||
whenValue: string | IMetadata | string[] | null
|
||||
) => {
|
||||
switch (when.operator) {
|
||||
|
||||
20
src/utils/getPlatform.ts
Normal file
20
src/utils/getPlatform.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as os from 'os';
|
||||
|
||||
/**
|
||||
* Determines the current operating system platform.
|
||||
*
|
||||
* @returns {'windows' | 'linux' | 'osx'} - A string representing the platform:
|
||||
* - 'windows' for Windows OS
|
||||
* - 'osx' for macOS
|
||||
* - 'linux' for Linux OS
|
||||
*/
|
||||
export const getPlatform = (): 'windows' | 'linux' | 'osx' => {
|
||||
const platform = os.platform();
|
||||
if (platform === 'win32') {
|
||||
return 'windows';
|
||||
} else if (platform === 'darwin') {
|
||||
return 'osx';
|
||||
}
|
||||
|
||||
return 'linux';
|
||||
};
|
||||
36
src/utils/getShellPath.ts
Normal file
36
src/utils/getShellPath.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { workspace } from 'vscode';
|
||||
import { ShellSetting } from '../models';
|
||||
import { getPlatform } from './getPlatform';
|
||||
|
||||
/**
|
||||
* Retrieves the shell path configuration based on the current platform and terminal settings.
|
||||
*
|
||||
* This method checks for the following configurations in order:
|
||||
* 1. `integrated.automationProfile.<platform>`: Returns the automation profile if it exists.
|
||||
* 2. `integrated.defaultProfile.<platform>` and `integrated.profiles.<platform>`: Returns the shell setting from the default profile if it exists.
|
||||
* 3. `integrated.shell.<platform>`: Returns the shell setting if the above configurations are not found.
|
||||
*
|
||||
* @returns {string | ShellSetting | undefined} The shell path configuration or undefined if not found.
|
||||
*/
|
||||
export const getShellPath = (): string | ShellSetting | undefined => {
|
||||
const platform = getPlatform();
|
||||
const terminalSettings = workspace.getConfiguration('terminal');
|
||||
|
||||
const automationProfile = terminalSettings.get<string | ShellSetting>(
|
||||
`integrated.automationProfile.${platform}`
|
||||
);
|
||||
if (!!automationProfile) {
|
||||
return automationProfile;
|
||||
}
|
||||
|
||||
const defaultProfile = terminalSettings.get<string>(`integrated.defaultProfile.${platform}`);
|
||||
const profiles = terminalSettings.get<{ [prop: string]: ShellSetting }>(
|
||||
`integrated.profiles.${platform}`
|
||||
);
|
||||
|
||||
if (defaultProfile && profiles && profiles[defaultProfile]) {
|
||||
return profiles[defaultProfile];
|
||||
}
|
||||
|
||||
return terminalSettings.get(`integrated.shell.${platform}`);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './cn';
|
||||
export * from './copyFileAsync';
|
||||
export * from './encodeEmoji';
|
||||
export * from './evaluateCommand';
|
||||
export * from './existsAsync';
|
||||
export * from './fetchWithTimeout';
|
||||
export * from './fieldWhenClause';
|
||||
@@ -8,6 +9,8 @@ export * from './flattenObjectKeys';
|
||||
export * from './getDescriptionField';
|
||||
export * from './getExtensibilityScripts';
|
||||
export * from './getLocalizationFile';
|
||||
export * from './getPlatform';
|
||||
export * from './getShellPath';
|
||||
export * from './getTitleField';
|
||||
export * from './getWebviewJsFiles';
|
||||
export * from './ignoreMsgCommand';
|
||||
@@ -20,6 +23,7 @@ export * from './readdirAsync';
|
||||
export * from './renameAsync';
|
||||
export * from './rmdirAsync';
|
||||
export * from './sentryInit';
|
||||
export * from './sleep';
|
||||
export * from './sortPages';
|
||||
export * from './unlinkAsync';
|
||||
export * from './writeFileAsync';
|
||||
|
||||
1
src/utils/sleep.ts
Normal file
1
src/utils/sleep.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
Reference in New Issue
Block a user