This plugin provides advanced paste commands and enables you to create custom transforms for pasting.
Usage: Assign a hotkey to the command that you want to use and then press the hotkey to paste the content.
Personally, I prefer to assign Alt+V to Smart Join
and Alt+Shift+V to Remove Blank Lines
.
Warning Never add untrusted scripts to the script directory BECAUSE IT MIGHT DESTROY YOUR VAULT OR WORSE!
You need to disable and re-enable this plugin in order to apply the changes to the script directory.
This plugin provides a default transform that is better than Obsidian built-in. You can disable it in the plugin settings (You need to restart obsidian to apply the changes).
It is compatible with the auto link title plugin but might not be compatible with some other plugins that mess with the clipboard.
If you have bind Ctrl+V to this command previously, you should unbind it because the underlying mechanism has changed.
The default transform will convert html to markdown using turndown and turndown-plugin-gfm. And it will remove empty headings and links.
This command trims all the lines and join them by a space before pasting. It will automatically join the words that are broken by hyphens.
This command is especially useful when pasting from a PDF file.
This command joins all the lines without trimming them before pasting.
This command removes all the blank lines before pasting.
This command is useful when you copy something from a web page and you find that there are too many blank lines when directly pasting into obsidian.
This command pastes the raw HTML of the copied content.
You can define your own custom transform by writing JavaScript.
*.js
or *.mjs
) in the script directory.
(You can't do it in obsidian. You need an editor like VSCode)The JavaScript source file will be imported as an ES Module.
To create a transform, you need to create an exported function:
export function myTransform(input) {
return input;
}
The function name (in start case) will become the name of your custom transform.
You can write multiple transforms in a single JavaScript source file.
By default, the input to your transform is the text in the clipboard.
To support other MIME types, you can set the type
field of your transform to "blob"
:
export async function myBlobTransform(input) {
if (!input.types.includes("text/html")) {
return { kind: "err", value: "No html found in clipboard!" };
}
const html = await input.getType("text/html");
return html.text();
}
myBlobTransform.type = "blob";
This way, the input to your transform is a
ClipboardItem
instead of a string
.
Your transform function should return either a string
or a TransformResult
(Of course, you can also return a Promise
that resolves to one of them).
A TransformResult
is a discriminated union. Its kind can only be ok
or err
.
When you return an ok
variant from your transform function,
the value
field should be the string of your final transformation result.
When you return an err
variant, a notice, in which the value
field will be displayed
as an error to the end user, will show up.
{ kind: "ok", value: "string" }
{ kind: "err", value: "An error occurred!" }
The transform function can take an optional second parameter utils
which is an object containing some useful helpers.
Currently, the turndown service is provided as a utility. You can call turndown.turndown
to convert html to markdown.
You can call saveAttachment
to save a blob to the vault. The function signature is:
saveAttachment: (name: string, ext: string, data: ArrayBuffer) =>
Promise<TFile>;
If you need more information about or control over the editor state, the Obsidian editor
object is provided as a utility.
lodash
, moment.js
and mime
are also provided as utilities. Check out the following example:
export async function myTransform(
input,
{ turndown, editor, _, moment, mime, saveAttachment }
) {
if (input.types.includes("text/html")) {
const html = await input.getType("text/html");
return turndown.turndown(await html.text());
}
const text = await input.getType("text/plain");
return text.text();
}
myTransform.type = "blob";
remark
and remark
plugins are also provided as utilities, which enables you to transform a Markdown AST. Check out the following example that removes all the images before pasting:
export async function noImage(
input,
{
turndown,
remark: {
remark,
remarkGfm,
remarkMath,
unistUtilVisit: { visit, SKIP },
},
}
) {
if (input.types.includes("text/html")) {
const html = await input.getType("text/html");
const md = turndown.turndown(await html.text());
return remark()
.use(remarkGfm)
.use(remarkMath)
.use(() => (tree, file) => {
visit(tree, "image", (node, index, parent) => {
parent.children.splice(index, 1);
return [SKIP, index];
});
})
.processSync(md)
.toString();
}
return { kind: "err", value: "No html found in clipboard!" };
}
noImage.type = "blob";
For now, the following remark related utilities are provided:
remark: {
unified: typeof import("unified").unified;
remark: typeof import("remark").remark;
remarkGfm: typeof import("remark-gfm").default;
remarkMath: typeof import("remark-math").default;
remarkParse: typeof import("remark-parse").default;
remarkStringify: typeof import("remark-stringify").default;
unistUtilVisit: typeof import("unist-util-visit");
unistUtilIs: typeof import("unist-util-is");
}
If you need more utilities, feel free to open an issue or submit a PR.