add openInEditor plugin

Base code is from https://github.com/pixeldesu/pixelde.su but adopted
for my use

pyrox.dev 9ee52a22 29bb3893

verified
Changed files
+119
plugins
src
_components
static
+1
.env.dev
···
export LUME_DRAFTS="true"
+
export PRODUCTION="false"
+1
.env.prod
···
export LUME_DRAFTS="false"
+
export PRODUCTION="true"
+14
_config.ts
···
// Validation
import validateHTML from "./plugins/validateHTML.ts";
+
// Open in Editor
+
import openInEditor from "./plugins/openInEditor.ts";
+
// Disabled Plugins:
// import nav from "lume/plugins/nav.ts";
// import og_images from "lume/plugins/og_images.ts";
···
// Minify HTML Output
site.use(minify_html({
options: {
+
do_not_minify_doctype: true,
+
keep_closing_tags: false,
keep_html_and_head_opening_tags: true,
keep_spaces_between_attributes: true,
+
ensure_spec_compliant_unquoted_attribute_values: true,
+
keep_comments: false,
},
}));
···
],
}),
);
+
+
// Open in Editor in Dev mode
+
site.data("production", Deno.env.get("PRODUCTION"));
+
if (Deno.env.get("PRODUCTION") == "false") {
+
site.use(openInEditor());
+
site.add("static/scripts/open-in-editor.js");
+
}
// Get current commit as a version number
// Taken from https://github.com/pixeldesu/pixelde.su/blob/main/_config.ts
+75
plugins/openInEditor.ts
···
+
// deno-lint-ignore-file no-explicit-any
+
// ^- NOTE: No idea for the typing of markdown-it plugin context, so we disable this check
+
// Taken from https://github.com/pixeldesu/pixelde.su/blob/main/plugins/markdown-it/vscode.ts and edited for my use
+
+
import "lume/types.ts";
+
+
// Cache object for frontmatter line counts so we only reload files once
+
const FRONTMATTER_LINE_CACHE: Record<string, number> = {};
+
+
function markdownItOpenInEditor(md: any) {
+
// Override the default paragraph renderer
+
const defaultRender = md.renderer.rules.paragraph_open ||
+
function (
+
tokens: Record<number, any>,
+
idx: number,
+
options: any,
+
_env: any,
+
self: any,
+
) {
+
return self.renderToken(tokens, idx, options);
+
};
+
+
md.renderer.rules.paragraph_open = function (
+
tokens: Record<number, any>,
+
idx: number,
+
options: any,
+
env: any,
+
self: any,
+
) {
+
const token = tokens[idx];
+
const filePath = env.data.page.src.entry.src || "";
+
+
// FIXME: This is extremely ugly, having to reload the file to get the full context to
+
// calculate the line number offset for the frontmatter. For some reason this is
+
// pretty fast however, so I'll let it slide for now.
+
if (!FRONTMATTER_LINE_CACHE[filePath]) {
+
FRONTMATTER_LINE_CACHE[filePath] = countFrontMatterLines(
+
Deno.readTextFileSync(filePath),
+
);
+
}
+
const lineNumber = FRONTMATTER_LINE_CACHE[filePath] +
+
(token.map ? token.map[0] : 1);
+
+
// Create a wrapper element with context to open the file in VS Code
+
const clickableElementStart = `<div data-editor-file="${filePath}:${lineNumber}">`;
+
+
return clickableElementStart +
+
defaultRender(tokens, idx, options, env, self);
+
};
+
+
md.renderer.rules.paragraph_close = function (
+
tokens: Record<number, any>,
+
idx: number,
+
options: any,
+
_env: any,
+
self: any,
+
) {
+
return self.renderToken(tokens, idx, options) + "</div>";
+
};
+
}
+
+
function countFrontMatterLines(content: string) {
+
const frontMatterPattern = /^---\s*\n([\s\S]*?)\n---\s*\n/;
+
const match = content.match(frontMatterPattern);
+
if (match) {
+
return match[0].split("\n").length;
+
}
+
return 0;
+
}
+
+
export default function () {
+
return function (site: Lume.Site) {
+
site.hooks.addMarkdownItPlugin(markdownItOpenInEditor);
+
};
+
}
+3
src/_components/head.vto
···
{{# Page Metadata #}}
<link rel="canonical" href="{{ url |> url(true) }}" />
<title>{{ title }}</title>
+
{{ if production == "false" }}
+
<script defer="defer" src="/static/scripts/open-in-editor.js"></script>
+
{{ /if }}
+11
src/static/scripts/open-in-editor.js
···
+
// Taken from https://github.com/pixeldesu/pixelde.su/blob/main/src/assets/js/modules/vscode.js
+
// Adopted by dish
+
const editorTargets = document.querySelectorAll("[data-editor-file]");
+
editorTargets.forEach((target) => {
+
target.addEventListener("click", (event) => {
+
globalThis.open(
+
`zed://file/${event.currentTarget.dataset.editorFile}`,
+
"_self",
+
);
+
});
+
});
+14
src/static/styles.css
···
--color-crust: var(--ctp-crust);
}
+
@layer components {
+
[data-editor-file] {
+
@apply transition-all rounded-md;
+
}
+
[data-editor-file]:hover {
+
@apply transition-all outline-blue outline-2 outline-offset-4
+
dark:bg-blue/10 bg-blue/10 pl-1;
+
}
+
}
+
@utility h-entry {
a {
@apply text-blue underline;
···
.callout-content {
@apply overflow-x-auto pl-2;
+
+
[data-editor-file]:hover {
+
@apply relative top-2 mr-2;
+
}
}
&[data-callout="todo"],
&[data-callout="info"],