diff --git a/src/clipboard/base_clipboard.ts b/src/clipboard/base_clipboard.ts new file mode 100644 index 0000000..52e9f85 --- /dev/null +++ b/src/clipboard/base_clipboard.ts @@ -0,0 +1,28 @@ +import { URL } from "url"; +import { ClipboardType, IClipboard } from "../clipboard_interface"; + +export abstract class BaseClipboard implements IClipboard { + abstract getImage(imagePath: string): Promise; + abstract getTextPlain(): Promise; + abstract getTextHtml(): Promise; + abstract copyImage(imageFile: URL): Promise; + abstract copyTextPlain(textFile: URL): Promise; + abstract copyTextHtml(htmlFile: URL): Promise; + abstract getContentType(): Promise | ClipboardType>; + + abstract onDetectType(types: string[]): Set; + + detectType(types: string[]): Set | ClipboardType { + if (!types) { + return ClipboardType.Unknown; + } + + const detectedTypes = this.onDetectType(types); + if (detectedTypes.size == 1) { + return detectedTypes.values().next().value; + } else if (detectedTypes.size > 1) { + return detectedTypes; + } + return ClipboardType.Unknown; + } +} diff --git a/src/clipboard/darwin.ts b/src/clipboard/darwin.ts index dfab2c0..fca2073 100644 --- a/src/clipboard/darwin.ts +++ b/src/clipboard/darwin.ts @@ -3,6 +3,7 @@ import { ClipboardType, IClipboard } from "../clipboard_interface"; import { getShell } from "../os"; import * as path from "path"; import { stripFinalNewline } from "../utils"; +import { BaseClipboard } from "./base_clipboard"; function darwin_HextoHtml(str: string) { const regex = /«data HTML(.*?)»/; @@ -19,49 +20,7 @@ function darwin_HextoHtml(str: string) { return buff.toString("utf8"); } -/** - * Detected the type of content in the clipboard - * Detect order: Image > Html > Text - * @param types string[] - * @returns ClipboardType - */ -function detectType(types: string[]): ClipboardType { - if (!types) { - return ClipboardType.Unknown; - } - - const detectedTypes = new Set(); - for (const type of types) { - switch (type) { - case "Text": - detectedTypes.add(ClipboardType.Text); - break; - case "HTML": - detectedTypes.add(ClipboardType.Html); - break; - case "Image": - detectedTypes.add(ClipboardType.Image); - break; - } - } - // Set priority based on which to return type - const priorityOrdering = [ - ClipboardType.Image, - ClipboardType.Html, - ClipboardType.Text, - ]; - if ( - detectedTypes.has(ClipboardType.Image) && - detectedTypes.has(ClipboardType.Html) - ) { - return ClipboardType.Html; - } - for (const type of priorityOrdering) if (detectedTypes.has(type)) return type; - // No known types detected - return ClipboardType.Unknown; -} - -class DarwinClipboard implements IClipboard { +class DarwinClipboard extends BaseClipboard { SCRIPT_PATH = "../../res/scripts/"; async copyImage(imageFile: URL): Promise { @@ -115,7 +74,26 @@ class DarwinClipboard implements IClipboard { return false; } } - async getContentType(): Promise { + + onDetectType(types: string[]): Set { + const detectedTypes = new Set(); + for (const type of types) { + switch (type) { + case "Text": + detectedTypes.add(ClipboardType.Text); + break; + case "HTML": + detectedTypes.add(ClipboardType.Html); + break; + case "Image": + detectedTypes.add(ClipboardType.Image); + break; + } + } + return detectedTypes; + } + + async getContentType(): Promise | ClipboardType> { const script = path.join( __dirname, this.SCRIPT_PATH, @@ -128,7 +106,7 @@ class DarwinClipboard implements IClipboard { console.debug("getClipboardContentType", data); const types = data.split(/\r\n|\n|\r/); - return detectType(types); + return this.detectType(types); } catch (e) { return ClipboardType.Unknown; } @@ -168,4 +146,4 @@ class DarwinClipboard implements IClipboard { } } -export { DarwinClipboard, detectType }; +export { DarwinClipboard }; diff --git a/src/clipboard/linux.ts b/src/clipboard/linux.ts index a6300d5..752a07b 100644 --- a/src/clipboard/linux.ts +++ b/src/clipboard/linux.ts @@ -3,53 +3,9 @@ import { ClipboardType, IClipboard } from "../clipboard_interface"; import { getShell } from "../os"; import * as path from "path"; import { stripFinalNewline } from "../utils"; +import { BaseClipboard } from "./base_clipboard"; -/** - * Detected the type of content in the clipboard - * Detect order: Image > Html > Text - * @param types string[] - * @returns ClipboardType - */ -function detectType(types: string[]): ClipboardType { - if (!types) { - return ClipboardType.Unknown; - } - - const detectedTypes = new Set(); - for (const type of types) { - switch (type) { - case "no xclip": - console.error("You need to install xclip command first."); - return ClipboardType.Unknown; - case "image/png": - detectedTypes.add(ClipboardType.Image); - break; - case "text/html": - detectedTypes.add(ClipboardType.Html); - break; - default: - detectedTypes.add(ClipboardType.Text); - break; - } - } - // Set priority based on which to return type - const priorityOrdering = [ - ClipboardType.Image, - ClipboardType.Html, - ClipboardType.Text, - ]; - if ( - detectedTypes.has(ClipboardType.Image) && - detectedTypes.has(ClipboardType.Html) - ) { - return ClipboardType.Html; - } - for (const type of priorityOrdering) if (detectedTypes.has(type)) return type; - // No known types detected - return ClipboardType.Unknown; -} - -class LinuxClipboard implements IClipboard { +class LinuxClipboard extends BaseClipboard { SCRIPT_PATH = "../../res/scripts/"; async copyImage(imageFile: URL): Promise { @@ -103,7 +59,30 @@ class LinuxClipboard implements IClipboard { return false; } } - async getContentType(): Promise { + onDetectType(types: string[]): Set { + const detectedTypes = new Set(); + + for (const type of types) { + switch (type) { + case "no xclip": + console.error("You need to install xclip command first."); + detectedTypes.add(ClipboardType.Unknown); + return detectedTypes; + case "image/png": + detectedTypes.add(ClipboardType.Image); + break; + case "text/html": + detectedTypes.add(ClipboardType.Html); + break; + default: + detectedTypes.add(ClipboardType.Text); + break; + } + } + return detectedTypes; + } + + async getContentType(): Promise | ClipboardType> { const script = path.join( __dirname, this.SCRIPT_PATH, @@ -116,7 +95,7 @@ class LinuxClipboard implements IClipboard { console.debug("getClipboardContentType", data); const types = data.split(/\r\n|\n|\r/); - return detectType(types); + return this.detectType(types); } catch (e) { return ClipboardType.Unknown; } @@ -156,4 +135,4 @@ class LinuxClipboard implements IClipboard { } } -export { LinuxClipboard, detectType }; +export { LinuxClipboard }; diff --git a/src/clipboard/win10.ts b/src/clipboard/win10.ts index b2cc52b..5a20cfc 100644 --- a/src/clipboard/win10.ts +++ b/src/clipboard/win10.ts @@ -3,53 +3,9 @@ import { ClipboardType, IClipboard } from "../clipboard_interface"; import { getShell } from "../os"; import * as path from "path"; import { stripFinalNewline } from "../utils"; +import { BaseClipboard } from "./base_clipboard"; -/** - * Detected the type of content in the clipboard - * Detect order: Image > Html > Text - * @param types string[] - * @returns ClipboardType - */ -function detectType(types: string[]): ClipboardType { - if (!types) { - return ClipboardType.Unknown; - } - - const detectedTypes = new Set(); - for (const type of types) { - switch (type) { - case "PNG": - case "Bitmap": - case "DeviceIndependentBitmap": - detectedTypes.add(ClipboardType.Image); - break; - case "HTML Format": - detectedTypes.add(ClipboardType.Html); - break; - case "Text": - case "UnicodeText": - detectedTypes.add(ClipboardType.Text); - break; - } - } - // Set priority based on which to return type - const priorityOrdering = [ - ClipboardType.Image, - ClipboardType.Html, - ClipboardType.Text, - ]; - if ( - detectedTypes.has(ClipboardType.Image) && - detectedTypes.has(ClipboardType.Html) - ) { - return ClipboardType.Html; - } - for (const type of priorityOrdering) if (detectedTypes.has(type)) return type; - // No known types detected - return ClipboardType.Unknown; -} - -class Win10Clipboard implements IClipboard { +class Win10Clipboard extends BaseClipboard { SCRIPT_PATH = "../../res/scripts/"; async copyImage(imageFile: URL): Promise { @@ -103,7 +59,27 @@ class Win10Clipboard implements IClipboard { return false; } } - async getContentType(): Promise { + onDetectType(types: string[]): Set { + const detectedTypes = new Set(); + for (const type of types) { + switch (type) { + case "PNG": + case "Bitmap": + case "DeviceIndependentBitmap": + detectedTypes.add(ClipboardType.Image); + break; + case "HTML Format": + detectedTypes.add(ClipboardType.Html); + break; + case "Text": + case "UnicodeText": + detectedTypes.add(ClipboardType.Text); + break; + } + } + return detectedTypes; + } + async getContentType(): Promise | ClipboardType> { const script = path.join( __dirname, this.SCRIPT_PATH, @@ -116,7 +92,7 @@ class Win10Clipboard implements IClipboard { console.debug("getClipboardContentType", data); const types = data.split(/\r\n|\n|\r/); - return detectType(types); + return this.detectType(types); } catch (e) { return ClipboardType.Unknown; } @@ -156,4 +132,4 @@ class Win10Clipboard implements IClipboard { } } -export { Win10Clipboard, detectType }; +export { Win10Clipboard }; diff --git a/src/clipboard/win32.ts b/src/clipboard/win32.ts index f6363cf..cd5cc1d 100644 --- a/src/clipboard/win32.ts +++ b/src/clipboard/win32.ts @@ -3,53 +3,9 @@ import { ClipboardType, IClipboard } from "../clipboard_interface"; import { getShell } from "../os"; import * as path from "path"; import { stripFinalNewline } from "../utils"; +import { BaseClipboard } from "./base_clipboard"; -/** - * Detected the type of content in the clipboard - * Detect order: Image > Html > Text - * @param types string[] - * @returns ClipboardType - */ -function detectType(types: string[]): ClipboardType { - if (!types) { - return ClipboardType.Unknown; - } - - const detectedTypes = new Set(); - for (const type of types) { - switch (type) { - case "PNG": - case "Bitmap": - case "DeviceIndependentBitmap": - detectedTypes.add(ClipboardType.Image); - break; - case "HTML Format": - detectedTypes.add(ClipboardType.Html); - break; - case "Text": - case "UnicodeText": - detectedTypes.add(ClipboardType.Text); - break; - } - } - // Set priority based on which to return type - const priorityOrdering = [ - ClipboardType.Image, - ClipboardType.Html, - ClipboardType.Text, - ]; - if ( - detectedTypes.has(ClipboardType.Image) && - detectedTypes.has(ClipboardType.Html) - ) { - return ClipboardType.Html; - } - for (const type of priorityOrdering) if (detectedTypes.has(type)) return type; - // No known types detected - return ClipboardType.Unknown; -} - -class Win32Clipboard implements IClipboard { +class Win32Clipboard extends BaseClipboard { SCRIPT_PATH = "../../res/scripts/"; async copyImage(imageFile: URL): Promise { @@ -103,7 +59,29 @@ class Win32Clipboard implements IClipboard { return false; } } - async getContentType(): Promise { + + onDetectType(types: string[]): Set { + const detectedTypes = new Set(); + for (const type of types) { + switch (type) { + case "PNG": + case "Bitmap": + case "DeviceIndependentBitmap": + detectedTypes.add(ClipboardType.Image); + break; + case "HTML Format": + detectedTypes.add(ClipboardType.Html); + break; + case "Text": + case "UnicodeText": + detectedTypes.add(ClipboardType.Text); + break; + } + } + return detectedTypes; + } + + async getContentType(): Promise | ClipboardType> { const script = path.join( __dirname, this.SCRIPT_PATH, @@ -116,7 +94,7 @@ class Win32Clipboard implements IClipboard { console.debug("getClipboardContentType", data); const types = data.split(/\r\n|\n|\r/); - return detectType(types); + return this.detectType(types); } catch (e) { return ClipboardType.Unknown; } @@ -156,4 +134,4 @@ class Win32Clipboard implements IClipboard { } } -export { Win32Clipboard, detectType }; +export { Win32Clipboard }; diff --git a/src/clipboard/wsl.ts b/src/clipboard/wsl.ts index 4ffed81..8124c6e 100644 --- a/src/clipboard/wsl.ts +++ b/src/clipboard/wsl.ts @@ -3,6 +3,7 @@ import { ClipboardType, IClipboard } from "../clipboard_interface"; import { getShell, runCommand } from "../os"; import * as path from "path"; import { stripFinalNewline } from "../utils"; +import { BaseClipboard } from "./base_clipboard"; async function pathToWin(path: string): Promise { const newPath = await runCommand("wslpath", ["-m", path]); @@ -14,52 +15,7 @@ async function pathToUnix(path: string): Promise { return stripFinalNewline(newPath); } -/** - * Detected the type of content in the clipboard - * Detect order: Image > Html > Text - * @param types string[] - * @returns ClipboardType - */ -function detectType(types: string[]): ClipboardType { - if (!types) { - return ClipboardType.Unknown; - } - - const detectedTypes = new Set(); - for (const type of types) { - switch (type) { - case "PNG": - case "Bitmap": - case "DeviceIndependentBitmap": - detectedTypes.add(ClipboardType.Image); - break; - case "HTML Format": - detectedTypes.add(ClipboardType.Html); - break; - case "Text": - case "UnicodeText": - detectedTypes.add(ClipboardType.Text); - break; - } - } - // Set priority based on which to return type - const priorityOrdering = [ - ClipboardType.Image, - ClipboardType.Html, - ClipboardType.Text, - ]; - if ( - detectedTypes.has(ClipboardType.Image) && - detectedTypes.has(ClipboardType.Html) - ) { - return ClipboardType.Html; - } - for (const type of priorityOrdering) if (detectedTypes.has(type)) return type; - // No known types detected - return ClipboardType.Unknown; -} - -class WslClipboard implements IClipboard { +class WslClipboard extends BaseClipboard { SCRIPT_PATH = "../../res/scripts/"; async copyImage(imageFile: URL): Promise { @@ -113,7 +69,27 @@ class WslClipboard implements IClipboard { return false; } } - async getContentType(): Promise { + onDetectType(types: string[]): Set { + const detectedTypes = new Set(); + for (const type of types) { + switch (type) { + case "PNG": + case "Bitmap": + case "DeviceIndependentBitmap": + detectedTypes.add(ClipboardType.Image); + break; + case "HTML Format": + detectedTypes.add(ClipboardType.Html); + break; + case "Text": + case "UnicodeText": + detectedTypes.add(ClipboardType.Text); + break; + } + } + return detectedTypes; + } + async getContentType(): Promise | ClipboardType> { const script = path.join( __dirname, this.SCRIPT_PATH, @@ -126,7 +102,7 @@ class WslClipboard implements IClipboard { console.debug("getClipboardContentType", data); const types = data.split(/\r\n|\n|\r/); - return detectType(types); + return this.detectType(types); } catch (e) { return ClipboardType.Unknown; } @@ -170,4 +146,4 @@ class WslClipboard implements IClipboard { } } -export { WslClipboard, detectType }; +export { WslClipboard }; diff --git a/src/clipboard_interface.ts b/src/clipboard_interface.ts index e04e779..cfa6a56 100644 --- a/src/clipboard_interface.ts +++ b/src/clipboard_interface.ts @@ -1,13 +1,13 @@ import { URL } from "node:url"; enum ClipboardType { - Unknown = -1, - Html = 0, - Text, - Image, + Unknown = "unknown", + Html = "html", + Text = "text", + Image = "image", } interface IClipboard { - getContentType(): Promise; + getContentType(): Promise | ClipboardType>; getImage(imagePath: string): Promise; getTextPlain(): Promise; getTextHtml(): Promise;