diff --git a/app/src/ipc_dev.ts b/app/src/ipc_dev.ts index b641772..9078347 100644 --- a/app/src/ipc_dev.ts +++ b/app/src/ipc_dev.ts @@ -1,14 +1,20 @@ -import { readLines } from 'https://deno.land/std@0.159.0/io/buffer.ts'; -import { normalize } from 'https://deno.land/std@0.159.0/path/mod.ts'; +import { TextLineStream } from '@std/streams'; +import { normalize } from '@std/path'; import { render } from './markdownit.ts'; export default async function (socket: WebSocket) { const decoder = new TextDecoder(); const encoder = new TextEncoder(); - for await (const line of readLines(Deno.stdin)) { - const [action, ...args] = line.split(':'); + const readable = Deno.stdin.readable + .pipeThrough(new TextDecoderStream()) + .pipeThrough(new TextLineStream()); + const reader = readable.getReader(); + while (true) { + const { value, done } = await reader.read(); + if (!value) break; + const [action, ...args] = value?.split(':'); switch (action) { case 'show': try { @@ -39,5 +45,6 @@ export default async function (socket: WebSocket) { default: break; } + if (done) break; } } diff --git a/app/src/log.ts b/app/src/log.ts index 722e138..36ccd37 100644 --- a/app/src/log.ts +++ b/app/src/log.ts @@ -1,11 +1,6 @@ -import { parseArgs } from 'https://deno.land/std@0.217.0/cli/parse_args.ts'; -import { dirname, join, normalize } from 'https://deno.land/std@0.217.0/path/mod.ts'; -import { - getLogger, - LogRecord, - RotatingFileHandler, - setup, -} from 'https://deno.land/std@0.217.0/log/mod.ts'; +import { parseArgs } from '@std/cli'; +import { dirname, join, normalize } from '@std/path'; +import { getLogger, LogRecord, RotatingFileHandler, setup } from '@std/log'; const __args = parseArgs(Deno.args); diff --git a/app/src/main.ts b/app/src/main.ts index c82d914..7979bcb 100644 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -1,6 +1,6 @@ -import { parseArgs } from 'https://deno.land/std@0.217.0/cli/parse_args.ts'; -import { dirname, fromFileUrl, join, normalize } from 'https://deno.land/std@0.217.0/path/mod.ts'; -import { open } from 'https://deno.land/x/open@v0.0.6/index.ts'; +import { parseArgs } from '@std/cli'; +import { dirname, fromFileUrl, join, normalize } from '@std/path'; +import { open } from 'openView'; import { readChunks } from './read.ts'; import log from './log.ts'; import { render } from './markdownit.ts'; diff --git a/app/src/markdownit.ts b/app/src/markdownit.ts index 204845b..3ed3baa 100644 --- a/app/src/markdownit.ts +++ b/app/src/markdownit.ts @@ -1,13 +1,15 @@ import { hashCode, uniqueIdGen } from './util.ts'; -import { parseArgs } from 'https://deno.land/std@0.217.0/cli/parse_args.ts'; -import { default as highlight } from 'https://cdn.skypack.dev/highlight.js@11.9.0'; -// @deno-types="https://esm.sh/v135/@types/markdown-it@13.0.7/index.d.ts"; -import MarkdownIt from 'https://esm.sh/markdown-it@14.0.0'; -import { full as MarkdownItEmoji } from 'https://esm.sh/markdown-it-emoji@3.0.0'; -import { default as MarkdownItFootnote } from 'https://esm.sh/markdown-it-footnote@4.0.0'; -import { default as MarkdownItTaskLists } from 'https://esm.sh/markdown-it-task-lists@2.1.1'; -import { default as MarkdownItTexmath } from 'https://esm.sh/markdown-it-texmath@1.0.0'; -import Katex from 'https://esm.sh/katex@0.16.9'; +import { parseArgs } from '@std/cli'; +import { default as highlight } from 'highlightJs'; +// @deno-types="https://esm.sh/v135/@types/markdown-it@14.1.1/index.d.ts"; +import MarkdownIt from 'markdown-it'; +import { full as MarkdownItEmoji } from 'markdown-it-emoji'; +import { default as MarkdownItFootnote } from 'markdown-it-footnote'; +import { default as MarkdownItTaskLists } from 'markdown-it-task-lists'; +import { default as MarkdownItTexmath } from 'markdown-it-texmath'; +import { markdownItFancyListPlugin as MarkdownItFancyLists } from 'markdown-it-fancy-lists'; +import { default as MarkdownItGitHubAlerts } from 'markdown-github-alerts'; +import Katex from 'katex'; const __args = parseArgs(Deno.args); @@ -16,18 +18,22 @@ const md = new MarkdownIt('default', { typographer: true, linkify: true, langPrefix: 'language-', - highlight: __args['syntax'] && ((code, language) => { - if (language && highlight.getLanguage(language)) { - try { - return highlight.highlight(code, { language }).value; - } catch { - return code; + breaks: true, + highlight: __args['syntax'] && + ((code, language) => { + if (language && highlight.getLanguage(language)) { + try { + return highlight.highlight(code, { language }).value; + } catch { + return code; + } } - } - return ''; - }), -}).use(MarkdownItEmoji) + return ''; + }), +}) + .use(MarkdownItEmoji) + .use(MarkdownItFancyLists) .use(MarkdownItFootnote) .use(MarkdownItTaskLists, { enabled: false, label: true }) .use(MarkdownItTexmath, { @@ -38,7 +44,8 @@ const md = new MarkdownIt('default', { strict: false, throwOnError: false, }, - }); + }) + .use(MarkdownItGitHubAlerts); md.renderer.rules.link_open = (tokens, idx, options) => { const token = tokens[idx]; @@ -100,7 +107,7 @@ md.renderer.rules.fence = (() => { const fence = md.renderer.rules.fence!; const escapeHtml = md.utils.escapeHtml; const regex = new RegExp( - /^(?---[\s\S]+---)?\s*(?(?flowchart|sequenceDiagram|gantt|classDiagram|stateDiagram|pie|journey|C4Context|erDiagram|requirementDiagram|gitGraph)[\s\S]+)/, + /^(?---[\s\S]+---)?\s*(?(?flowchart|sequenceDiagram|gantt|classDiagram|stateDiagram|pie|journey|C4Context|erDiagram|requirementDiagram|gitGraph|graph)[\s\S]+)/, ); return (tokens, idx, options, env, self) => { diff --git a/app/src/read.ts b/app/src/read.ts index 29d66b8..b7fc709 100644 --- a/app/src/read.ts +++ b/app/src/read.ts @@ -1,4 +1,4 @@ -import type { Reader } from 'https://deno.land/std@0.217.0/io/types.ts'; +import type { Reader } from '@std/io'; async function read(reader: Reader, buffer: Uint8Array) { let read = 0; diff --git a/app/src/webview.ts b/app/src/webview.ts index b45ad98..fbcf4f6 100644 --- a/app/src/webview.ts +++ b/app/src/webview.ts @@ -1,5 +1,5 @@ -import { Webview } from 'https://deno.land/x/webview@0.7.6/mod.ts'; -import { parseArgs } from 'https://deno.land/std@0.217.0/cli/parse_args.ts'; +import { Webview } from 'webview'; +import { parseArgs } from '@std/cli'; const { url, theme, serverUrl } = parseArgs(Deno.args); diff --git a/client/src/mermaid.ts b/client/src/mermaid.ts index f7bf536..02698a7 100644 --- a/client/src/mermaid.ts +++ b/client/src/mermaid.ts @@ -1,7 +1,7 @@ -import Mermaid from 'https://cdn.skypack.dev/@types/mermaid?dts'; +import type { Mermaid } from 'mermaid'; import { getInjectConfig } from './util.ts'; -declare const mermaid: typeof Mermaid; +declare const mermaid: Mermaid; function init() { const peek = getInjectConfig(); diff --git a/client/src/script.ts b/client/src/script.ts index 6f2cb30..cb75217 100644 --- a/client/src/script.ts +++ b/client/src/script.ts @@ -1,7 +1,7 @@ import { debounce, findLast, getInjectConfig } from './util.ts'; -import { slidingWindows } from 'https://deno.land/std@0.217.0/collections/sliding_windows.ts'; +import { slidingWindows } from '@std/collections'; // @deno-types="https://raw.githubusercontent.com/patrick-steele-idem/morphdom/master/index.d.ts" -import morphdom from 'https://esm.sh/morphdom@2.7.2?no-dts'; +import morphdom from 'morphdom'; import mermaid from './mermaid.ts'; const window = globalThis; diff --git a/deno.json b/deno.json index 06ce105..b3d3fe7 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "tasks": { - "build": "deno run --allow-run --allow-net --allow-read --allow-write --allow-env --no-check scripts/build.js", + "build": "deno run --allow-run --allow-net --allow-read --allow-write --allow-env --no-check --unstable-bundle --allow-ffi scripts/build.js", "build:watch": "deno task build --watch", "build:fast": "FAST=true deno task --quiet build", "build:debug": "DEBUG=true deno task build", @@ -9,10 +9,38 @@ "start:dev": "DENO_ENV=development deno task start" }, "compilerOptions": { - "lib": ["dom", "deno.ns", "deno.unstable"] + "lib": [ + "dom", + "deno.ns", + "deno.unstable" + ] }, "imports": { - "node:punycode": "https://deno.land/x/punycode/punycode.js" + "github-markdown-css": "npm:github-markdown-css@^5.9.0", + "lightningcss": "npm:lightningcss@^1.32.0", + "mermaid-min": "https://cdn.jsdelivr.net/npm/mermaid@11.14.0/dist/mermaid.min.js", + "katex-css": "https://cdn.jsdelivr.net/npm/katex@0.16.45/dist/katex.min.css", + "openView": "https://deno.land/x/open@v1.0.0/index.ts", + "highlightJs": "npm:highlight.js@^11.11.1", + "markdown-it": "https://esm.sh/markdown-it@14.1.1", + "markdown-it-emoji": "https://esm.sh/markdown-it-emoji@3.0.0", + "markdown-it-footnote": "https://esm.sh/markdown-it-footnote@4.0.0", + "markdown-it-task-lists": "https://esm.sh/markdown-it-task-lists@2.1.1", + "markdown-it-texmath": "https://esm.sh/markdown-it-texmath@1.0.0", + "markdown-it-fancy-lists": "https://esm.sh/markdown-it-fancy-lists@1.3.2", + "markdown-github-alerts": "https://esm.sh/markdown-it-github-alerts@1.0.1", + "katex": "https://esm.sh/katex@0.16.45", + "webview": "https://deno.land/x/webview@0.9.0/mod.ts", + "mermaid": "npm:mermaid@^11.0.0", + "morphdom": "https://esm.sh/morphdom@2.7.8", + "emit": "https://deno.land/x/emit@0.40.0/mod.ts", + "@denosaurs/plug": "jsr:@denosaurs/plug@^1.1.0", + "@std/log": "jsr:@std/log@^0.224.14", + "@std/path": "jsr:@std/path@^1.1.4", + "@std/collections": "jsr:@std/collections@^1.1.6", + "@std/cli": "jsr:@std/cli@^1.0.28", + "@std/io": "jsr:@std/io@^0.225.3", + "@std/streams": "jsr:@std/streams@^1.0.17" }, "fmt": { "options": { diff --git a/lua/peek/config.lua b/lua/peek/config.lua index 15ca57e..dc18b4e 100644 --- a/lua/peek/config.lua +++ b/lua/peek/config.lua @@ -54,21 +54,19 @@ end function module.setup(incoming) incoming = incoming or {} - vim.validate({ - config = { incoming, 'table' }, - }) + vim.validate("config", incoming, 'table') - vim.validate({ - close_on_bdelete = { incoming.close_on_bdelete, 'boolean', true }, - auto_load = { incoming.auto_load, 'boolean', true }, - syntax = { incoming.syntax, 'boolean', true }, - theme = { incoming.theme, optional(one_of({ 'dark', 'light' })), '"dark" or "light"' }, - update_on_change = { incoming.update_on_change, 'boolean', true }, - throttle_at = { incoming.throttle_at, 'number', true }, - throttle_time = { incoming.throttle_time, optional(one_of({ 'auto', of_type('number') })), '"auto" or number' }, - app = { incoming.app, optional(one_of({ of_type('string'), every(of_type('string')) })), 'string or string[]' }, - filetype = { incoming.filetype, optional(every(of_type('string'))), 'string[]' }, - }) + vim.validate("close_on_bdelete", incoming.close_on_bdelete, 'boolean', true) + vim.validate("auto_load", incoming.auto_load, 'boolean', true) + vim.validate("syntax", incoming.syntax, 'boolean', true) + vim.validate("theme", incoming.theme, optional(one_of({ 'dark', 'light' })), '"dark" or "light"') + vim.validate("update_on_change", incoming.update_on_change, 'boolean', true) + vim.validate("throttle_at", incoming.throttle_at, 'number', true) + vim.validate("throttle_time", incoming.throttle_time, + optional(one_of({ 'auto', of_type('number') })), '"auto" or number') + vim.validate("app", incoming.app, + optional(one_of({ of_type('string'), every(of_type('string')) })), 'string or string[]') + vim.validate("filetype", incoming.filetype, optional(every(of_type('string'))), 'string[]') config = vim.tbl_extend('force', config, incoming) end diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3874eb0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "peek.nvim", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/scripts/build.js b/scripts/build.js index e9f9870..247c66d 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,14 +1,11 @@ -import { bundle } from 'https://deno.land/x/emit@0.38.1/mod.ts'; +import { transform as minifyCss } from 'lightningcss'; const DEBUG = Deno.env.get('DEBUG'); -const { compilerOptions, imports } = JSON.parse(Deno.readTextFileSync('deno.json')); -const bundleOptions = { compilerOptions, importMap: { imports } }; function logPublicContent() { console.table( - Array.from(Deno.readDirSync('public')).reduce((table, entry) => { + [...Deno.readDirSync('public')].reduce((table, entry) => { const { size, mtime } = Deno.statSync('public/' + entry.name); - table[entry.name] = { size, modified: new Date(mtime).toLocaleTimeString('en-GB', { @@ -22,23 +19,47 @@ function logPublicContent() { fractionalSecondDigits: 3, }), }; - return table; }, {}), ); } async function emit(src, out) { - return Deno.writeTextFile(out, (await bundle(src, bundleOptions)).code); + const res = await Deno.bundle({ + entrypoints: [src], + platform: 'browser', + outputPath: out, + format: 'esm', + inlineImports: true, + }); + if (!res.success) { + throw new Error(`Failed to bundle ${src}. ${res.errors.join('\n')}`); + } } -async function download(src, out, transform = (uint8array) => uint8array) { +async function downloadAndMinify( + src, + out, + { transform = (uint8array) => uint8array, minifyDownload = false } = {}, +) { Deno.mkdirSync(out.split('/').slice(0, -1).join('/'), { recursive: true }); - const res = await fetch(src); + const resolvedUrl = import.meta.resolve(src); + const res = await fetch(resolvedUrl); if (!res.ok) { - throw new Error(`Failed to fetch ${src}. ${res.status} ${res.statusText}`); + throw new Error(`Failed to fetch ${resolvedUrl}. ${res.status} ${res.statusText}`); + } + + let transformed = transform(new Uint8Array(await res.arrayBuffer())); + if (minifyDownload) { + const { code } = minifyCss({ + minify: true, + code: transformed, + filename: out, + }); + transformed = code; } - Deno.writeFileSync(out, transform(new Uint8Array(await res.arrayBuffer()))); + + Deno.writeFileSync(out, transformed); } if (DEBUG) { @@ -51,33 +72,20 @@ if (DEBUG) { const result = await Promise.allSettled([ emit('app/src/main.ts', 'public/main.bundle.js'), - emit('app/src/webview.ts', 'public/webview.js'), - emit('client/src/script.ts', 'public/script.bundle.js'), - - download( - 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css', - 'public/github-markdown.min.css', - (uint8array) => { - return new TextEncoder().encode( - new TextDecoder().decode(uint8array) + downloadAndMinify('github-markdown-css', 'public/github-markdown.min.css', { + transform: (uint8array) => + new TextEncoder().encode( + new TextDecoder() + .decode(uint8array) .replace('@media (prefers-color-scheme:dark)', '[data-theme=dark]') .replace('@media (prefers-color-scheme:light)', '[data-theme=light]'), - ); - }, - ), - - download( - 'https://cdn.jsdelivr.net/npm/mermaid@10.9.0/dist/mermaid.min.js', - 'public/mermaid.min.js', - ), - - download( - 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css', - 'public/katex.min.css', - ), - + ), + minifyDownload: true, + }), + downloadAndMinify('mermaid-min', 'public/mermaid.min.js'), + downloadAndMinify('katex-css', 'public/katex.min.css', { minifyDownload: true }), ...[ 'KaTeX_AMS-Regular.woff2', 'KaTeX_Caligraphic-Bold.woff2', @@ -100,16 +108,18 @@ const result = await Promise.allSettled([ 'KaTeX_Size4-Regular.woff2', 'KaTeX_Typewriter-Regular.woff2', ].map((font) => - download( - `https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/fonts/${font}`, + downloadAndMinify( + `https://cdn.jsdelivr.net/npm/katex@0.16.45/dist/fonts/${font}`, `public/fonts/${font}`, - ) + ), ), ]); -result.forEach((res) => { - if (res.status === 'rejected') console.error(res.reason); -}); +for (const res of result) { + if (res.status === 'rejected') { + console.error(res.reason); + } +} if (DEBUG) { logPublicContent();