From bd983fd4698e694a7b691a272c0a3676112bc967 Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Mon, 19 Sep 2022 16:48:51 +0530 Subject: [PATCH 1/8] add json format for copy as command --- packages/plugin-core/package.json | 8 +++ .../plugin-core/src/commands/CopyAsCommand.ts | 66 +++++++++++++++++++ packages/plugin-core/src/commands/index.ts | 2 + .../src/commands/pods/ExportPodV2Command.ts | 12 ++-- .../src/commands/pods/JSONExportPodCommand.ts | 4 +- .../src/components/pods/PodCommandFactory.ts | 49 +++++++++----- .../src/components/pods/PodControls.ts | 23 ++++++- packages/plugin-core/src/constants.ts | 5 ++ packages/pods-core/src/index.ts | 8 +++ 9 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 packages/plugin-core/src/commands/CopyAsCommand.ts diff --git a/packages/plugin-core/package.json b/packages/plugin-core/package.json index e3c1e378e0..33f335f236 100644 --- a/packages/plugin-core/package.json +++ b/packages/plugin-core/package.json @@ -244,6 +244,10 @@ "command": "dendron.copyCodespaceURL", "title": "Dendron: Copy Codespace URL" }, + { + "command": "dendron.copyAs", + "title": "Dendron: Copy As" + }, { "command": "dendron.delete", "title": "Dendron: Delete" @@ -660,6 +664,10 @@ "command": "dendron.copyCodespaceURL", "when": "dendron:pluginActive && shellExecutionSupported" }, + { + "command": "dendron.copyAs", + "when": "dendron:pluginActive && shellExecutionSupported" + }, { "command": "dendron.delete", "when": "dendron:pluginActive && shellExecutionSupported" diff --git a/packages/plugin-core/src/commands/CopyAsCommand.ts b/packages/plugin-core/src/commands/CopyAsCommand.ts new file mode 100644 index 0000000000..7592a3527c --- /dev/null +++ b/packages/plugin-core/src/commands/CopyAsCommand.ts @@ -0,0 +1,66 @@ +import { assertUnreachable } from "@dendronhq/common-all"; +import { + CopyAsFormat, + getAllCopyAsFormat, + JSONV2PodConfig, + PodExportScope, + PodV2Types, +} from "@dendronhq/pods-core"; +import { PodCommandFactory } from "../components/pods/PodCommandFactory"; +import { PodUIControls } from "../components/pods/PodControls"; +import { DENDRON_COMMANDS } from "../constants"; +import { BaseCommand, CodeCommandInstance } from "./base"; + +type CommandOutput = void; +type CommandInput = CodeCommandInstance; +type CommandOpts = CodeCommandInstance; + +/** + * Command that will find the appropriate export command to run, and then run + * it. This is the UI entry point for all export pod functionality. + */ +export class CopyAsCommand extends BaseCommand< + CommandOpts, + CommandOutput, + CommandInput +> { + public format: CopyAsFormat[]; + key = DENDRON_COMMANDS.COPY_AS.key; + + constructor(_name?: string) { + super(_name); + this.format = getAllCopyAsFormat(); + } + + async gatherInputs() { + const format = await PodUIControls.promtToSelectCopyAsFormat(); + + if (!format) { + return; + } + switch (format) { + case CopyAsFormat.JSON: { + const config: JSONV2PodConfig = { + destination: "clipboard", + exportScope: PodExportScope.Note, + podType: PodV2Types.JSONExportV2, + podId: "copyAs.json", // dummy value, required property + }; + return PodCommandFactory.createPodCommandForStoredConfig({ config }); + } + default: + assertUnreachable(format); + } + } + + /** + * no-op + */ + async enrichInputs(inputs: CommandInput): Promise { + return inputs; + } + + async execute(opts: CommandOpts) { + opts.run(); + } +} diff --git a/packages/plugin-core/src/commands/index.ts b/packages/plugin-core/src/commands/index.ts index bf5f03c313..926ddd0fb6 100644 --- a/packages/plugin-core/src/commands/index.ts +++ b/packages/plugin-core/src/commands/index.ts @@ -87,6 +87,7 @@ import { CreateNoteCommand } from "./CreateNoteCommand"; import { MergeNoteCommand } from "./MergeNoteCommand"; import { CopyCodespaceURL } from "./CopyCodespaceURL"; import { MoveSelectionToCommand } from "./MoveSelectionToCommand"; +import { CopyAsCommand } from "./CopyAsCommand"; /** * Note: this does not contain commands that have parametered constructors, as @@ -181,6 +182,7 @@ const ALL_COMMANDS = [ MergeNoteCommand, CreateNoteCommand, CopyCodespaceURL, + CopyAsCommand, ] as CodeCommandConstructor[]; export { ALL_COMMANDS }; diff --git a/packages/plugin-core/src/commands/pods/ExportPodV2Command.ts b/packages/plugin-core/src/commands/pods/ExportPodV2Command.ts index 2a7b99713b..f39ca0bf6c 100644 --- a/packages/plugin-core/src/commands/pods/ExportPodV2Command.ts +++ b/packages/plugin-core/src/commands/pods/ExportPodV2Command.ts @@ -48,10 +48,10 @@ export class ExportPodV2Command extends BaseCommand< // If a podId is passed in, use this instead of prompting the user if (args?.podId) { - return PodCommandFactory.createPodCommandForStoredConfig( - { podId: args.podId }, - args.exportScope - ); + return PodCommandFactory.createPodCommandForStoredConfig({ + configId: { podId: args.podId }, + exportScope: args.exportScope, + }); } const exportChoice = await PodUIControls.promptForExportConfigOrNewExport(); @@ -66,7 +66,9 @@ export class ExportPodV2Command extends BaseCommand< } return PodCommandFactory.createPodCommandForPodType(podType); } else { - return PodCommandFactory.createPodCommandForStoredConfig(exportChoice); + return PodCommandFactory.createPodCommandForStoredConfig({ + configId: exportChoice, + }); } } diff --git a/packages/plugin-core/src/commands/pods/JSONExportPodCommand.ts b/packages/plugin-core/src/commands/pods/JSONExportPodCommand.ts index 69c1885e06..3b8b9e92ac 100644 --- a/packages/plugin-core/src/commands/pods/JSONExportPodCommand.ts +++ b/packages/plugin-core/src/commands/pods/JSONExportPodCommand.ts @@ -110,9 +110,11 @@ export class JSONExportPodCommand extends BaseExportPodCommand< exportReturnValue: JSONExportReturnType; config: RunnableJSONV2PodConfig; }) { + let successMessage = "Finished running JSON export pod."; const data = exportReturnValue.data?.exportedNotes; if (_.isString(data) && config.destination === "clipboard") { vscode.env.clipboard.writeText(data); + successMessage += " Content is copied to the clipboard"; } if (ResponseUtil.hasError(exportReturnValue)) { const errorMsg = `Finished JSON Export. Error encountered: ${ErrorFactory.safeStringify( @@ -120,7 +122,7 @@ export class JSONExportPodCommand extends BaseExportPodCommand< )}`; this.L.error(errorMsg); } else { - vscode.window.showInformationMessage("Finished running JSON export pod."); + vscode.window.showInformationMessage(successMessage); } } diff --git a/packages/plugin-core/src/components/pods/PodCommandFactory.ts b/packages/plugin-core/src/components/pods/PodCommandFactory.ts index 18a32c74bd..a2fe1ba8b6 100644 --- a/packages/plugin-core/src/components/pods/PodCommandFactory.ts +++ b/packages/plugin-core/src/components/pods/PodCommandFactory.ts @@ -22,27 +22,46 @@ export class PodCommandFactory { * @param configId * @returns A pod command configured with the found configuration */ - public static createPodCommandForStoredConfig( - configId: Pick, - exportScope?: PodExportScope - ): CodeCommandInstance { - const storedConfig = PodV2ConfigManager.getPodConfigById({ - podsDir: path.join(getExtension().podsDir, "custom"), - opts: configId, - }); - - if (!storedConfig) { + public static createPodCommandForStoredConfig({ + configId, + exportScope, + config, + }: { + configId?: Pick; + exportScope?: PodExportScope; + config?: ExportPodConfigurationV2 & { destination?: string }; + }): CodeCommandInstance { + // configId is a required param for all cases except when called from CopyAsCommand. It sends a predefined config + if (!configId && !config) { throw new DendronError({ - message: `No pod config with id ${configId.podId} found.`, + message: `Please provide a config id to continue.`, }); } - // overrides the exportScope of stored config with the exportScope passed in args - if (exportScope) { - storedConfig.exportScope = exportScope; + let podType: PodV2Types; + let storedConfig: ExportPodConfigurationV2 | undefined; + if (config) { + podType = config.podType; + storedConfig = config; + } else { + storedConfig = PodV2ConfigManager.getPodConfigById({ + podsDir: path.join(getExtension().podsDir, "custom"), + opts: configId!, + }); + + if (!storedConfig) { + throw new DendronError({ + message: `No pod config with id ${configId!.podId} found.`, + }); + } + // overrides the exportScope of stored config with the exportScope passed in args + if (exportScope) { + storedConfig.exportScope = exportScope; + } + podType = storedConfig.podType; } let cmdWithArgs: CodeCommandInstance; const extension = ExtensionProvider.getExtension(); - switch (storedConfig.podType) { + switch (podType) { case PodV2Types.AirtableExportV2: { const airtableCmd = new AirtableExportPodCommand(extension); cmdWithArgs = { diff --git a/packages/plugin-core/src/components/pods/PodControls.ts b/packages/plugin-core/src/components/pods/PodControls.ts index 7075c97bdf..da7e084b19 100644 --- a/packages/plugin-core/src/components/pods/PodControls.ts +++ b/packages/plugin-core/src/components/pods/PodControls.ts @@ -2,10 +2,12 @@ import { assertUnreachable, DVault, VaultUtils } from "@dendronhq/common-all"; import { DLogger } from "@dendronhq/common-server"; import { HistoryEvent } from "@dendronhq/engine-server"; import { + CopyAsFormat, ExportPodConfigurationV2, ExternalConnectionManager, ExternalService, ExternalTarget, + getAllCopyAsFormat, PodExportScope, PodUtils, PodV2ConfigManager, @@ -28,7 +30,7 @@ import { NoteLookupProviderUtils } from "../lookup/NoteLookupProviderUtils"; */ export class PodUIControls { /** - * Prompts the user with a quick-pick to select a {@link PodConfigurationV2} + * Prompts the user with a quick-pick to select a {@link ExportPodConfigurationV2} * by its podId. Furthermore, there is an option to create a new export * configuration intead. * @returns @@ -552,4 +554,23 @@ export class PodUIControls { }); return podIdQuickPick?.label; } + + /** + * Prompt user to select the copy as format + */ + public static async promtToSelectCopyAsFormat(): Promise< + CopyAsFormat | undefined + > { + const items = getAllCopyAsFormat().map((value) => { + return { + label: value, + detail: `Format Dendron note to ${value} and copy it to the clipboard`, + }; + }); + const formatQuickPick = await VSCodeUtils.showQuickPick(items, { + title: "Pick the format to convert", + ignoreFocusOut: true, + }); + return formatQuickPick?.label as CopyAsFormat; + } } diff --git a/packages/plugin-core/src/constants.ts b/packages/plugin-core/src/constants.ts index fc971ee14f..a3ae2975bb 100644 --- a/packages/plugin-core/src/constants.ts +++ b/packages/plugin-core/src/constants.ts @@ -513,6 +513,11 @@ export const DENDRON_COMMANDS: { [key: string]: CommandEntry } = { title: `${CMD_PREFIX} Copy Codespace URL`, when: `${DendronContext.PLUGIN_ACTIVE} && shellExecutionSupported`, }, + COPY_AS: { + key: "dendron.copyAs", + title: `${CMD_PREFIX} Copy As`, + when: `${DendronContext.PLUGIN_ACTIVE} && shellExecutionSupported`, + }, DELETE: { key: "dendron.delete", title: `${CMD_PREFIX} Delete`, diff --git a/packages/pods-core/src/index.ts b/packages/pods-core/src/index.ts index 402dad2835..b0128813dc 100644 --- a/packages/pods-core/src/index.ts +++ b/packages/pods-core/src/index.ts @@ -73,4 +73,12 @@ export function getAllImportPods(): PodClassEntryV4[] { ]; } +export enum CopyAsFormat { + "JSON" = "JSON", +} + +export function getAllCopyAsFormat(): CopyAsFormat[] { + return [CopyAsFormat.JSON]; +} + export { JSONSchemaType, Client, Page, TitlePropertyValue }; From 0f79925f76788318f36a01422cb917b9ebc5d072 Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Mon, 19 Sep 2022 18:41:08 +0530 Subject: [PATCH 2/8] add test --- .../plugin-core/src/commands/CopyAsCommand.ts | 9 ++++ .../test/suite-integ/CopyAsCommand.test.ts | 50 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts diff --git a/packages/plugin-core/src/commands/CopyAsCommand.ts b/packages/plugin-core/src/commands/CopyAsCommand.ts index 7592a3527c..56ecae91cb 100644 --- a/packages/plugin-core/src/commands/CopyAsCommand.ts +++ b/packages/plugin-core/src/commands/CopyAsCommand.ts @@ -6,9 +6,11 @@ import { PodExportScope, PodV2Types, } from "@dendronhq/pods-core"; +import _ from "lodash"; import { PodCommandFactory } from "../components/pods/PodCommandFactory"; import { PodUIControls } from "../components/pods/PodControls"; import { DENDRON_COMMANDS } from "../constants"; +import { VSCodeUtils } from "../vsCodeUtils"; import { BaseCommand, CodeCommandInstance } from "./base"; type CommandOutput = void; @@ -32,6 +34,13 @@ export class CopyAsCommand extends BaseCommand< this.format = getAllCopyAsFormat(); } + async sanityCheck(_opts?: Partial | undefined) { + if (_.isUndefined(VSCodeUtils.getActiveTextEditor())) { + return "you must have a note open to execute this command"; + } + return; + } + async gatherInputs() { const format = await PodUIControls.promtToSelectCopyAsFormat(); diff --git a/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts b/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts new file mode 100644 index 0000000000..1ae4e40aee --- /dev/null +++ b/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts @@ -0,0 +1,50 @@ +import { CopyAsFormat } from "@dendronhq/pods-core"; +import { describe } from "mocha"; +import sinon from "sinon"; +import { CopyAsCommand } from "../../commands/CopyAsCommand"; +import { PodUIControls } from "../../components/pods/PodControls"; +import { ExtensionProvider } from "../../ExtensionProvider"; +import { WSUtilsV2 } from "../../WSUtilsV2"; +import { describeSingleWS } from "../testUtilsV3"; +import { expect } from "../testUtilsv2"; +import { PodCommandFactory } from "../../components/pods/PodCommandFactory"; +import { VSCodeUtils } from "../../vsCodeUtils"; +import { window } from "vscode"; + +suite("CopyAsCommand", function () { + describe("GIVEN CopyAs command is run", () => { + describeSingleWS( + "WHEN the format selected is JSON", + { timeout: 5e3 }, + () => { + test("THEN json formatted note must be copied to clipboard", async () => { + const { engine } = ExtensionProvider.getDWorkspace(); + const targetNote = (await engine.findNotes({ fname: "root" }))[0]; + await WSUtilsV2.instance().openNote(targetNote); + const factorySpy = sinon.spy( + PodCommandFactory, + "createPodCommandForStoredConfig" + ); + const cmd = new CopyAsCommand(); + sinon + .stub(PodUIControls, "promtToSelectCopyAsFormat") + .resolves(CopyAsFormat.JSON); + await cmd.run(); + const out = factorySpy.returnValues[0]; + expect(out.key).toEqual("dendron.jsonexportv2"); + }); + test("AND NO note is open THEN throw error", async () => { + await VSCodeUtils.closeAllEditors(); + + const windowSpy = sinon.spy(window, "showErrorMessage"); + const cmd = new CopyAsCommand(); + await cmd.run(); + const errorMsg = windowSpy.getCall(0).args[0]; + expect(errorMsg).toEqual( + "you must have a note open to execute this command" + ); + }); + } + ); + }); +}); From 1fcad6712e45fa3c707d9408c615d5a20518f865 Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Mon, 19 Sep 2022 19:16:00 +0530 Subject: [PATCH 3/8] added copy as for markdpwn format --- .../plugin-core/src/commands/CopyAsCommand.ts | 10 +++++++++ .../commands/pods/MarkdownExportPodCommand.ts | 6 ++--- .../test/suite-integ/CopyAsCommand.test.ts | 22 +++++++++++++++++++ packages/pods-core/src/index.ts | 3 ++- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/plugin-core/src/commands/CopyAsCommand.ts b/packages/plugin-core/src/commands/CopyAsCommand.ts index 56ecae91cb..c2293686c9 100644 --- a/packages/plugin-core/src/commands/CopyAsCommand.ts +++ b/packages/plugin-core/src/commands/CopyAsCommand.ts @@ -3,6 +3,7 @@ import { CopyAsFormat, getAllCopyAsFormat, JSONV2PodConfig, + MarkdownV2PodConfig, PodExportScope, PodV2Types, } from "@dendronhq/pods-core"; @@ -57,6 +58,15 @@ export class CopyAsCommand extends BaseCommand< }; return PodCommandFactory.createPodCommandForStoredConfig({ config }); } + case CopyAsFormat.MARKDOWN: { + const config: MarkdownV2PodConfig = { + destination: "clipboard", + exportScope: PodExportScope.Note, + podType: PodV2Types.MarkdownExportV2, + podId: "copyAs.markdown", // dummy value, required property + }; + return PodCommandFactory.createPodCommandForStoredConfig({ config }); + } default: assertUnreachable(format); } diff --git a/packages/plugin-core/src/commands/pods/MarkdownExportPodCommand.ts b/packages/plugin-core/src/commands/pods/MarkdownExportPodCommand.ts index dbdb2468e0..35a0f71482 100644 --- a/packages/plugin-core/src/commands/pods/MarkdownExportPodCommand.ts +++ b/packages/plugin-core/src/commands/pods/MarkdownExportPodCommand.ts @@ -123,8 +123,10 @@ export class MarkdownExportPodCommand extends BaseExportPodCommand< config: RunnableMarkdownV2PodConfig; }) { const data = exportReturnValue.data?.exportedNotes; + let successMessage = "Finished running Markdown export pod."; if (_.isString(data) && config.destination === "clipboard") { vscode.env.clipboard.writeText(data); + successMessage += " Content is copied to the clipboard"; } const count = data?.length ?? 0; if (ResponseUtil.hasError(exportReturnValue)) { @@ -133,9 +135,7 @@ export class MarkdownExportPodCommand extends BaseExportPodCommand< )}`; this.L.error(errorMsg); } else { - vscode.window.showInformationMessage( - "Finished running Markdown export pod." - ); + vscode.window.showInformationMessage(successMessage); } } diff --git a/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts b/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts index 1ae4e40aee..e4bfa425f3 100644 --- a/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts +++ b/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts @@ -46,5 +46,27 @@ suite("CopyAsCommand", function () { }); } ); + describeSingleWS( + "WHEN the format selected is Markdown", + { timeout: 5e3 }, + () => { + test("THEN markdown formatted note must be copied to clipboard", async () => { + const { engine } = ExtensionProvider.getDWorkspace(); + const targetNote = (await engine.findNotes({ fname: "root" }))[0]; + await WSUtilsV2.instance().openNote(targetNote); + const factorySpy = sinon.spy( + PodCommandFactory, + "createPodCommandForStoredConfig" + ); + const cmd = new CopyAsCommand(); + sinon + .stub(PodUIControls, "promtToSelectCopyAsFormat") + .resolves(CopyAsFormat.MARKDOWN); + await cmd.run(); + const out = factorySpy.returnValues[0]; + expect(out.key).toEqual("dendron.markdownexportv2"); + }); + } + ); }); }); diff --git a/packages/pods-core/src/index.ts b/packages/pods-core/src/index.ts index b0128813dc..b7402cc768 100644 --- a/packages/pods-core/src/index.ts +++ b/packages/pods-core/src/index.ts @@ -75,10 +75,11 @@ export function getAllImportPods(): PodClassEntryV4[] { export enum CopyAsFormat { "JSON" = "JSON", + "MARKDOWN" = "Markdown", } export function getAllCopyAsFormat(): CopyAsFormat[] { - return [CopyAsFormat.JSON]; + return [CopyAsFormat.JSON, CopyAsFormat.MARKDOWN]; } export { JSONSchemaType, Client, Page, TitlePropertyValue }; From 5c7ef1e14310a9a7a3382e818bdb2f4ea8a4d43c Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Wed, 21 Sep 2022 13:18:23 +0530 Subject: [PATCH 4/8] address Pr comments --- packages/plugin-core/src/commands/CopyAsCommand.ts | 11 ++--------- .../src/components/pods/PodCommandFactory.ts | 9 +++++++-- packages/pods-core/src/index.ts | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/plugin-core/src/commands/CopyAsCommand.ts b/packages/plugin-core/src/commands/CopyAsCommand.ts index c2293686c9..fd6151dab2 100644 --- a/packages/plugin-core/src/commands/CopyAsCommand.ts +++ b/packages/plugin-core/src/commands/CopyAsCommand.ts @@ -12,7 +12,7 @@ import { PodCommandFactory } from "../components/pods/PodCommandFactory"; import { PodUIControls } from "../components/pods/PodControls"; import { DENDRON_COMMANDS } from "../constants"; import { VSCodeUtils } from "../vsCodeUtils"; -import { BaseCommand, CodeCommandInstance } from "./base"; +import { BasicCommand, CodeCommandInstance } from "./base"; type CommandOutput = void; type CommandInput = CodeCommandInstance; @@ -22,7 +22,7 @@ type CommandOpts = CodeCommandInstance; * Command that will find the appropriate export command to run, and then run * it. This is the UI entry point for all export pod functionality. */ -export class CopyAsCommand extends BaseCommand< +export class CopyAsCommand extends BasicCommand< CommandOpts, CommandOutput, CommandInput @@ -72,13 +72,6 @@ export class CopyAsCommand extends BaseCommand< } } - /** - * no-op - */ - async enrichInputs(inputs: CommandInput): Promise { - return inputs; - } - async execute(opts: CommandOpts) { opts.run(); } diff --git a/packages/plugin-core/src/components/pods/PodCommandFactory.ts b/packages/plugin-core/src/components/pods/PodCommandFactory.ts index a2fe1ba8b6..ad55730672 100644 --- a/packages/plugin-core/src/components/pods/PodCommandFactory.ts +++ b/packages/plugin-core/src/components/pods/PodCommandFactory.ts @@ -43,14 +43,19 @@ export class PodCommandFactory { podType = config.podType; storedConfig = config; } else { + if (!configId) { + throw new DendronError({ + message: `Please provide a config id`, + }); + } storedConfig = PodV2ConfigManager.getPodConfigById({ podsDir: path.join(getExtension().podsDir, "custom"), - opts: configId!, + opts: configId, }); if (!storedConfig) { throw new DendronError({ - message: `No pod config with id ${configId!.podId} found.`, + message: `No pod config with id ${configId.podId} found.`, }); } // overrides the exportScope of stored config with the exportScope passed in args diff --git a/packages/pods-core/src/index.ts b/packages/pods-core/src/index.ts index b7402cc768..391a265898 100644 --- a/packages/pods-core/src/index.ts +++ b/packages/pods-core/src/index.ts @@ -79,7 +79,7 @@ export enum CopyAsFormat { } export function getAllCopyAsFormat(): CopyAsFormat[] { - return [CopyAsFormat.JSON, CopyAsFormat.MARKDOWN]; + return Object.values(CopyAsFormat); } export { JSONSchemaType, Client, Page, TitlePropertyValue }; From 99a02761d5c79670ae7d9a32ef19dba17aa07752 Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Wed, 21 Sep 2022 13:45:00 +0530 Subject: [PATCH 5/8] add getPodsDir method in ExtensionProvider --- packages/plugin-core/src/ExtensionProvider.ts | 9 +++++++++ .../plugin-core/src/components/pods/PodCommandFactory.ts | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/plugin-core/src/ExtensionProvider.ts b/packages/plugin-core/src/ExtensionProvider.ts index 26f55ea5b8..89ef82329b 100644 --- a/packages/plugin-core/src/ExtensionProvider.ts +++ b/packages/plugin-core/src/ExtensionProvider.ts @@ -1,4 +1,6 @@ import { DendronError } from "@dendronhq/common-all"; +import { PodUtils } from "@dendronhq/pods-core"; +import { ensureDirSync } from "fs-extra"; import _ from "lodash"; import { IDendronExtension } from "./dendronExtensionInterface"; import { IWSUtilsV2 } from "./WSUtilsV2Interface"; @@ -51,4 +53,11 @@ export class ExtensionProvider { static register(extension: IDendronExtension) { ExtensionProvider.extension = extension; } + + static getPodsDir() { + const { wsRoot } = ExtensionProvider.getDWorkspace(); + const podsDir = PodUtils.getPodDir({ wsRoot }); + ensureDirSync(podsDir); + return podsDir; + } } diff --git a/packages/plugin-core/src/components/pods/PodCommandFactory.ts b/packages/plugin-core/src/components/pods/PodCommandFactory.ts index ad55730672..f637523a8f 100644 --- a/packages/plugin-core/src/components/pods/PodCommandFactory.ts +++ b/packages/plugin-core/src/components/pods/PodCommandFactory.ts @@ -13,7 +13,6 @@ import { JSONExportPodCommand } from "../../commands/pods/JSONExportPodCommand"; import { MarkdownExportPodCommand } from "../../commands/pods/MarkdownExportPodCommand"; import { NotionExportPodCommand } from "../../commands/pods/NotionExportPodCommand"; import { ExtensionProvider } from "../../ExtensionProvider"; -import { getExtension } from "../../workspace"; export class PodCommandFactory { /** @@ -48,8 +47,9 @@ export class PodCommandFactory { message: `Please provide a config id`, }); } + storedConfig = PodV2ConfigManager.getPodConfigById({ - podsDir: path.join(getExtension().podsDir, "custom"), + podsDir: path.join(ExtensionProvider.getPodsDir(), "custom"), opts: configId, }); From 0ec47f1228fcfa90c129054a6e1232fa86030e5c Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Wed, 21 Sep 2022 16:25:50 +0530 Subject: [PATCH 6/8] add keybinding utils for copy as format --- packages/plugin-core/src/KeybindingUtils.ts | 38 +++++++++++++++++-- .../plugin-core/src/commands/CopyAsCommand.ts | 10 ++--- .../src/components/pods/PodControls.ts | 22 ++++++++++- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/packages/plugin-core/src/KeybindingUtils.ts b/packages/plugin-core/src/KeybindingUtils.ts index ea33ac6942..38f77b3141 100644 --- a/packages/plugin-core/src/KeybindingUtils.ts +++ b/packages/plugin-core/src/KeybindingUtils.ts @@ -344,12 +344,44 @@ export class KeybindingUtils { return result[0].key; } else if (result.length > 1) { throw new DendronError({ - message: KeybindingUtils.MULTIPLE_KEYBINDINGS_MSG_FMT, + message: this.getMultipleKeybindingsMsgFormat("pod"), }); } return undefined; } - static MULTIPLE_KEYBINDINGS_MSG_FMT = - "Multiple keybindings found for pod command shortcut."; + static getKeybindingsForCopyAsIfExists(format: string): string | undefined { + const { keybindingConfigPath } = this.getKeybindingConfigPath(); + + if (!fs.existsSync(keybindingConfigPath)) { + return undefined; + } + + const keybindings = readJSONWithCommentsSync(keybindingConfigPath); + + if (!KeybindingUtils.checkKeybindingsExist(keybindings)) { + return undefined; + } + + const result = keybindings.filter((item) => { + return ( + item.command && + item.command === DENDRON_COMMANDS.COPY_AS.key && + item.args === format + ); + }); + + if (result.length === 1 && result[0].key) { + return result[0].key; + } else if (result.length > 1) { + throw new DendronError({ + message: this.getMultipleKeybindingsMsgFormat("copy as"), + }); + } + return undefined; + } + + static getMultipleKeybindingsMsgFormat(cmd: string) { + return `Multiple keybindings found for ${cmd} command shortcut.`; + } } diff --git a/packages/plugin-core/src/commands/CopyAsCommand.ts b/packages/plugin-core/src/commands/CopyAsCommand.ts index fd6151dab2..d68a411e90 100644 --- a/packages/plugin-core/src/commands/CopyAsCommand.ts +++ b/packages/plugin-core/src/commands/CopyAsCommand.ts @@ -15,7 +15,6 @@ import { VSCodeUtils } from "../vsCodeUtils"; import { BasicCommand, CodeCommandInstance } from "./base"; type CommandOutput = void; -type CommandInput = CodeCommandInstance; type CommandOpts = CodeCommandInstance; /** @@ -25,7 +24,7 @@ type CommandOpts = CodeCommandInstance; export class CopyAsCommand extends BasicCommand< CommandOpts, CommandOutput, - CommandInput + CopyAsFormat > { public format: CopyAsFormat[]; key = DENDRON_COMMANDS.COPY_AS.key; @@ -35,15 +34,16 @@ export class CopyAsCommand extends BasicCommand< this.format = getAllCopyAsFormat(); } - async sanityCheck(_opts?: Partial | undefined) { + async sanityCheck() { if (_.isUndefined(VSCodeUtils.getActiveTextEditor())) { return "you must have a note open to execute this command"; } return; } - async gatherInputs() { - const format = await PodUIControls.promtToSelectCopyAsFormat(); + async gatherInputs(copyAsFormat?: CopyAsFormat) { + const format = + copyAsFormat || (await PodUIControls.promptToSelectCopyAsFormat()); if (!format) { return; diff --git a/packages/plugin-core/src/components/pods/PodControls.ts b/packages/plugin-core/src/components/pods/PodControls.ts index da7e084b19..dcd7a550c0 100644 --- a/packages/plugin-core/src/components/pods/PodControls.ts +++ b/packages/plugin-core/src/components/pods/PodControls.ts @@ -410,7 +410,9 @@ export class PodUIControls { } catch (e: any) { if ( e.message && - e.message.includes(KeybindingUtils.MULTIPLE_KEYBINDINGS_MSG_FMT) + e.message.includes( + KeybindingUtils.getMultipleKeybindingsMsgFormat("pod") + ) ) { keybinding = "Multiple Keybindings"; } @@ -558,12 +560,28 @@ export class PodUIControls { /** * Prompt user to select the copy as format */ - public static async promtToSelectCopyAsFormat(): Promise< + public static async promptToSelectCopyAsFormat(): Promise< CopyAsFormat | undefined > { const items = getAllCopyAsFormat().map((value) => { + let keybinding; + + try { + keybinding = + KeybindingUtils.getKeybindingsForCopyAsIfExists(value) || ""; + } catch (e: any) { + if ( + e.message && + e.message.includes( + KeybindingUtils.getMultipleKeybindingsMsgFormat("copy as") + ) + ) { + keybinding = "Multiple Keybindings"; + } + } return { label: value, + description: keybinding, detail: `Format Dendron note to ${value} and copy it to the clipboard`, }; }); From de937f1fd3c96479b7ea74341616f0cf2d5ca523 Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Wed, 21 Sep 2022 16:38:03 +0530 Subject: [PATCH 7/8] add test --- .../test/suite-integ/CopyAsCommand.test.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts b/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts index e4bfa425f3..951e085782 100644 --- a/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts +++ b/packages/plugin-core/src/test/suite-integ/CopyAsCommand.test.ts @@ -27,7 +27,7 @@ suite("CopyAsCommand", function () { ); const cmd = new CopyAsCommand(); sinon - .stub(PodUIControls, "promtToSelectCopyAsFormat") + .stub(PodUIControls, "promptToSelectCopyAsFormat") .resolves(CopyAsFormat.JSON); await cmd.run(); const out = factorySpy.returnValues[0]; @@ -60,7 +60,7 @@ suite("CopyAsCommand", function () { ); const cmd = new CopyAsCommand(); sinon - .stub(PodUIControls, "promtToSelectCopyAsFormat") + .stub(PodUIControls, "promptToSelectCopyAsFormat") .resolves(CopyAsFormat.MARKDOWN); await cmd.run(); const out = factorySpy.returnValues[0]; @@ -68,5 +68,24 @@ suite("CopyAsCommand", function () { }); } ); + describeSingleWS( + "WHEN the Markdown format is provided in keybinding args", + { timeout: 5e3 }, + () => { + test("THEN markdown formatted note must be copied to clipboard", async () => { + const { engine } = ExtensionProvider.getDWorkspace(); + const targetNote = (await engine.findNotes({ fname: "root" }))[0]; + await WSUtilsV2.instance().openNote(targetNote); + const factorySpy = sinon.spy( + PodCommandFactory, + "createPodCommandForStoredConfig" + ); + const cmd = new CopyAsCommand(); + await cmd.gatherInputs(CopyAsFormat.MARKDOWN); + const out = factorySpy.returnValues[0]; + expect(out.key).toEqual("dendron.markdownexportv2"); + }); + } + ); }); }); From 854a75da765a699249f62dd616dc9f290e20ec74 Mon Sep 17 00:00:00 2001 From: Harshita-mindfire Date: Fri, 23 Sep 2022 17:08:19 +0530 Subject: [PATCH 8/8] update keybindings --- packages/plugin-core/package.json | 6 ++++++ packages/plugin-core/src/commands/CopyAsCommand.ts | 6 ++++-- packages/plugin-core/src/constants.ts | 5 +++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/plugin-core/package.json b/packages/plugin-core/package.json index 33f335f236..91b5b657a5 100644 --- a/packages/plugin-core/package.json +++ b/packages/plugin-core/package.json @@ -1332,6 +1332,12 @@ "mac": "cmd+shift+r", "when": "editorFocus && dendron:pluginActive" }, + { + "command": "dendron.copyAs", + "key": "ctrl+k ctrl+c", + "mac": "cmd+k cmd+c", + "when": "dendron:pluginActive" + }, { "command": "dendron.delete", "key": "ctrl+shift+d", diff --git a/packages/plugin-core/src/commands/CopyAsCommand.ts b/packages/plugin-core/src/commands/CopyAsCommand.ts index d68a411e90..27e3b8c5f2 100644 --- a/packages/plugin-core/src/commands/CopyAsCommand.ts +++ b/packages/plugin-core/src/commands/CopyAsCommand.ts @@ -1,4 +1,4 @@ -import { assertUnreachable } from "@dendronhq/common-all"; +import { DendronError } from "@dendronhq/common-all"; import { CopyAsFormat, getAllCopyAsFormat, @@ -68,7 +68,9 @@ export class CopyAsCommand extends BasicCommand< return PodCommandFactory.createPodCommandForStoredConfig({ config }); } default: - assertUnreachable(format); + throw new DendronError({ + message: `${format} is not a valid copy as format. If you are using a keybinding, make sure the argument is one of the following values: ${getAllCopyAsFormat()}`, + }); } } diff --git a/packages/plugin-core/src/constants.ts b/packages/plugin-core/src/constants.ts index a3ae2975bb..374833bed5 100644 --- a/packages/plugin-core/src/constants.ts +++ b/packages/plugin-core/src/constants.ts @@ -516,6 +516,11 @@ export const DENDRON_COMMANDS: { [key: string]: CommandEntry } = { COPY_AS: { key: "dendron.copyAs", title: `${CMD_PREFIX} Copy As`, + keybindings: { + key: "ctrl+k ctrl+c", + mac: "cmd+k cmd+c", + when: "dendron:pluginActive", + }, when: `${DendronContext.PLUGIN_ACTIVE} && shellExecutionSupported`, }, DELETE: {