Skip to content

Instantly share code, notes, and snippets.

@kat0h
Created September 24, 2021 11:31
Show Gist options
  • Save kat0h/d186c66a12b8a83f53d8c23f68a01d22 to your computer and use it in GitHub Desktop.
Save kat0h/d186c66a12b8a83f53d8c23f68a01d22 to your computer and use it in GitHub Desktop.
Markdownをリアルタイムにプレビューするやーつ(denops.vim :MDP)
import { Denops } from "https://deno.land/x/denops_std@v1.11.3/mod.ts";
import { execute } from "https://deno.land/x/denops_std@v1.11.3/helper/mod.ts";
import * as op from "https://deno.land/x/denops_std@v1.11.3/option/mod.ts";
import MarkdownIt from "https://esm.sh/markdown-it";
import { listenAndServe } from "https://deno.land/std@0.108.0/http/server_legacy.ts";
import {
acceptWebSocket,
WebSocket,
} from "https://deno.land/std@0.108.0/ws/mod.ts";
import { open } from "https://deno.land/x/open@v0.0.2/index.ts";
import * as autocmd from "https://deno.land/x/denops_std@v1.11.3/autocmd/mod.ts";
// Global state
// websocket
let socket: WebSocket;
let bufnr: number;
// Markdown renderer
const md = new MarkdownIt({ html: true });
function handleWs(sock: WebSocket) {
socket = sock;
}
const getlines = async (denops: Denops, bufnr: number): Promise<string[]> => {
return await denops.call('getbufline', bufnr, 1, "$") as string[]
}
export const startServer = async (port: number, body: string) => {
listenAndServe(":" + port.toString(), (req) => {
if (req.method === "GET" && req.url === "/") {
req.respond({
status: 200,
body: body,
headers: new Headers({
"content-type": "text/html",
}),
});
} else if (req.method === "GET" && req.url === "/ws") {
acceptWebSocket({
conn: req.conn,
bufWriter: req.w,
bufReader: req.r,
headers: req.headers,
}).then(handleWs).catch(async (_) => {
await req.respond({ status: 400 });
});
} else {
req.respond({ status: 404, body: "404" });
}
}).catch(() => {
console.error("MDP server has already started");
});
await open(`http://localhost:${port.toString()}/`);
console.log("MDP server started");
};
const reflesh = async (denops: Denops) => {
const buf = (await getlines(denops, bufnr)).join("\n");
const data = {
buf: md.render(buf),
};
await socket.send(JSON.stringify(data));
}
export function main(denops: Denops) {
denops.dispatcher = {
async preview_open(): Promise<void> {
// check filetype
console.log(await op.filetype.get(denops) as string);
if (await op.filetype.get(denops) as string !== "markdown") {
console.log("this file is not a markdown file");
return;
}
// get bufnr
bufnr = await denops.call("bufnr") as number;
const port = 8765;
const body = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css">
<title>test</title>
<script>
const socket = new WebSocket('ws://localhost:'+location.port + '/ws');
socket.addEventListener('message', function (event) {
var res = JSON.parse(event.data)
document.getElementById('render').innerHTML = res.buf
})
</script>
</head>
<body>
<article class="markdown-body" id="render">
${md.render((await getlines(denops, bufnr)).join("\n"))}
</article>
</body>
</html>
`
await autocmd.group(denops, denops.name, (helper) => {
helper.define(
["TextChanged", "TextChangedI", "TextChangedP"],
"<buffer>",
`call denops#notify("${denops.name}", "preview_reflash", [])`,
);
});
startServer(port, body);
},
async preview_reflash(): Promise<void> {
await reflesh(denops)
},
};
execute(
denops,
`
command! MDP call denops#notify('${denops.name}', 'preview_open', [])
`,
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment