diff --git a/.envrc b/.envrc index 4a4726a..3550a30 100644 --- a/.envrc +++ b/.envrc @@ -1 +1 @@ -use_nix +use flake diff --git a/.gitignore b/.gitignore index 3686b21..896a78a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.vsix node_modules out +.direnv diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..249fd07 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1692525914, + "narHash": "sha256-MUgZ9/9mE/EbEQA6JPdcQHkjoR5fgvaKhpy6UO67uEc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "475d5ae2c4cb87b904545bdb547af05681198fcc", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f261b22 --- /dev/null +++ b/flake.nix @@ -0,0 +1,17 @@ +{ + description = "A very basic flake"; + + inputs = { + nixpkgs = { + url = "github:NixOS/nixpkgs/nixos-23.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils = { url = "github:numtide/flake-utils"; }; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let pkgs = import nixpkgs { inherit system; }; + in { devShell = import ./shell.nix { inherit pkgs; }; }); +} + diff --git a/nix/sources.json b/nix/sources.json deleted file mode 100644 index a264a1d..0000000 --- a/nix/sources.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "niv": { - "branch": "master", - "description": "Easy dependency management for Nix projects", - "homepage": "https://github.com/nmattia/niv", - "owner": "nmattia", - "repo": "niv", - "rev": "5830a4dd348d77e39a0f3c4c762ff2663b602d4c", - "sha256": "1d3lsrqvci4qz2hwjrcnd8h5vfkg8aypq3sjd4g3izbc8frwz5sm", - "type": "tarball", - "url": "https://github.com/nmattia/niv/archive/5830a4dd348d77e39a0f3c4c762ff2663b602d4c.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, - "nixpkgs": { - "branch": "nixos-22.11", - "description": "Nix Packages collection", - "homepage": "", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "913a47cd064cc06440ea84e5e0452039a85781f0", - "sha256": "1vnxxjf5d6fmn5hrgyy9ck4wpq273iymg99cbanqvziqzsky15x1", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/913a47cd064cc06440ea84e5e0452039a85781f0.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - } -} diff --git a/nix/sources.nix b/nix/sources.nix deleted file mode 100644 index 9a01c8a..0000000 --- a/nix/sources.nix +++ /dev/null @@ -1,194 +0,0 @@ -# This file has been generated by Niv. - -let - - # - # The fetchers. fetch_ fetches specs of type . - # - - fetch_file = pkgs: name: spec: - let - name' = sanitizeName name + "-src"; - in - if spec.builtin or true then - builtins_fetchurl { inherit (spec) url sha256; name = name'; } - else - pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; - - fetch_tarball = pkgs: name: spec: - let - name' = sanitizeName name + "-src"; - in - if spec.builtin or true then - builtins_fetchTarball { name = name'; inherit (spec) url sha256; } - else - pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; - - fetch_git = name: spec: - let - ref = - if spec ? ref then spec.ref else - if spec ? branch then "refs/heads/${spec.branch}" else - if spec ? tag then "refs/tags/${spec.tag}" else - abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; - submodules = if spec ? submodules then spec.submodules else false; - submoduleArg = - let - nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0; - emptyArgWithWarning = - if submodules == true - then - builtins.trace - ( - "The niv input \"${name}\" uses submodules " - + "but your nix's (${builtins.nixVersion}) builtins.fetchGit " - + "does not support them" - ) - {} - else {}; - in - if nixSupportsSubmodules - then { inherit submodules; } - else emptyArgWithWarning; - in - builtins.fetchGit - ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg); - - fetch_local = spec: spec.path; - - fetch_builtin-tarball = name: throw - ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. - $ niv modify ${name} -a type=tarball -a builtin=true''; - - fetch_builtin-url = name: throw - ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. - $ niv modify ${name} -a type=file -a builtin=true''; - - # - # Various helpers - # - - # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 - sanitizeName = name: - ( - concatMapStrings (s: if builtins.isList s then "-" else s) - ( - builtins.split "[^[:alnum:]+._?=-]+" - ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) - ) - ); - - # The set of packages used when specs are fetched using non-builtins. - mkPkgs = sources: system: - let - sourcesNixpkgs = - import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; - hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; - hasThisAsNixpkgsPath = == ./.; - in - if builtins.hasAttr "nixpkgs" sources - then sourcesNixpkgs - else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then - import {} - else - abort - '' - Please specify either (through -I or NIX_PATH=nixpkgs=...) or - add a package called "nixpkgs" to your sources.json. - ''; - - # The actual fetching function. - fetch = pkgs: name: spec: - - if ! builtins.hasAttr "type" spec then - abort "ERROR: niv spec ${name} does not have a 'type' attribute" - else if spec.type == "file" then fetch_file pkgs name spec - else if spec.type == "tarball" then fetch_tarball pkgs name spec - else if spec.type == "git" then fetch_git name spec - else if spec.type == "local" then fetch_local spec - else if spec.type == "builtin-tarball" then fetch_builtin-tarball name - else if spec.type == "builtin-url" then fetch_builtin-url name - else - abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; - - # If the environment variable NIV_OVERRIDE_${name} is set, then use - # the path directly as opposed to the fetched source. - replace = name: drv: - let - saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; - ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; - in - if ersatz == "" then drv else - # this turns the string into an actual Nix path (for both absolute and - # relative paths) - if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; - - # Ports of functions for older nix versions - - # a Nix version of mapAttrs if the built-in doesn't exist - mapAttrs = builtins.mapAttrs or ( - f: set: with builtins; - listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) - ); - - # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 - range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); - - # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 - stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); - - # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 - stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); - concatMapStrings = f: list: concatStrings (map f list); - concatStrings = builtins.concatStringsSep ""; - - # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 - optionalAttrs = cond: as: if cond then as else {}; - - # fetchTarball version that is compatible between all the versions of Nix - builtins_fetchTarball = { url, name ? null, sha256 }@attrs: - let - inherit (builtins) lessThan nixVersion fetchTarball; - in - if lessThan nixVersion "1.12" then - fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) - else - fetchTarball attrs; - - # fetchurl version that is compatible between all the versions of Nix - builtins_fetchurl = { url, name ? null, sha256 }@attrs: - let - inherit (builtins) lessThan nixVersion fetchurl; - in - if lessThan nixVersion "1.12" then - fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) - else - fetchurl attrs; - - # Create the final "sources" from the config - mkSources = config: - mapAttrs ( - name: spec: - if builtins.hasAttr "outPath" spec - then abort - "The values in sources.json should not have an 'outPath' attribute" - else - spec // { outPath = replace name (fetch config.pkgs name spec); } - ) config.sources; - - # The "config" used by the fetchers - mkConfig = - { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null - , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) - , system ? builtins.currentSystem - , pkgs ? mkPkgs sources system - }: rec { - # The sources, i.e. the attribute set of spec name to spec - inherit sources; - - # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers - inherit pkgs; - }; - -in -mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/package.json b/package.json index 95e5ffb..18fea00 100644 --- a/package.json +++ b/package.json @@ -164,6 +164,20 @@ "default": false, "type": "boolean" }, + "markdown-preview-enhanced.previewColorScheme": { + "type": "string", + "enum": [ + "selectedPreviewTheme", + "systemColorScheme", + "editorColorScheme" + ], + "default": "selectedPreviewTheme", + "markdownEnumDescriptions": [ + "Use the `markdown-preview-enhanced.previewTheme` setting.", + "Follow system color scheme. If set to true, then the theme of markdown preview will automatically switch between light and dark when your system switch between light and dark. For example, if you set the current preview theme to `github-light.css`, then when your system is dark, the preview theme will be switched to `github-dark.css` automatically. If set to false, then the theme of markdown preview will not be changed automatically.", + "Use the same theme as the editor (light or dark). If set to true, then the theme of markdown preview will automatically switch between light and dark when you switch between vscode light and dark theme. For example, if you set the current preview theme to `github-light.css`, then when you switch to vscode dark theme, the preview theme will be switched to `github-dark.css` automatically. If set to false, then the theme of markdown preview will not be changed automatically." + ] + }, "markdown-preview-enhanced.enableTypographer": { "description": "Enable smartypants and other sweet transforms.", "default": false, @@ -323,6 +337,24 @@ "solarized-dark.css", "solarized-light.css", "vue.css" + ], + "markdownEnumDescriptions": [ + "Atom Dark", + "Atom Light", + "Atom Material", + "GitHub Dark", + "GitHub Light", + "Gothic", + "Medium", + "Monokai", + "Newsprint", + "Night", + "None", + "One Dark", + "One Light", + "Solarized Dark", + "Solarized Light", + "Vue" ] }, "markdown-preview-enhanced.revealjsTheme": { @@ -481,6 +513,11 @@ "description": "Hide the default VSCode markdown preview extension buttons. Restarting the editor is required to make this config take effect.", "default": true, "type": "boolean" + }, + "markdown-preview-enhanced.jsdelivrCdnHost": { + "markdownDescription": "jsDelivr CDN host. Example values: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`", + "default": "cdn.jsdelivr.net", + "type": "string" } } }, @@ -547,7 +584,7 @@ ] }, "dependencies": { - "@shd101wyy/mume": "0.7.6", + "@shd101wyy/mume": "0.7.7", "@types/vfile": "^3.0.2" }, "devDependencies": { diff --git a/shell.nix b/shell.nix index 060db3d..08d5c5f 100644 --- a/shell.nix +++ b/shell.nix @@ -1,4 +1,9 @@ -let - sources = import ./nix/sources.nix; - pkgs = import sources.nixpkgs { }; -in pkgs.mkShell { buildInputs = with pkgs; [ nodejs-16_x yarn ]; } +{ pkgs ? import { } }: +with pkgs; +mkShell { + buildInputs = [ nodejs yarn ]; + shellHook = '' + # ... + ''; +} + diff --git a/src/config.ts b/src/config.ts index b791124..7aec013 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,6 +9,12 @@ import { import * as vscode from "vscode"; import { PathResolver } from "./utils/path-resolver"; +export enum PreviewColorScheme { + selectedPreviewTheme = "selectedPreviewTheme", + systemColorScheme = "systemColorScheme", + editorColorScheme = "editorColorScheme", +} + export class MarkdownPreviewEnhancedConfig implements MarkdownEngineConfig { public static getCurrentConfig() { return new MarkdownPreviewEnhancedConfig(); @@ -56,12 +62,14 @@ export class MarkdownPreviewEnhancedConfig implements MarkdownEngineConfig { public readonly puppeteerArgs: string[]; public readonly plantumlServer: string; public readonly hideDefaultVSCodeMarkdownPreviewButtons: boolean; + public readonly jsdelivrCdnHost: string; // preview config public readonly scrollSync: boolean; public readonly liveUpdate: boolean; public readonly singlePreview: boolean; public readonly automaticallyShowPreviewOfMarkdownBeingEdited: boolean; + public readonly previewColorScheme: PreviewColorScheme; private constructor() { const config = vscode.workspace.getConfiguration( @@ -120,6 +128,9 @@ export class MarkdownPreviewEnhancedConfig implements MarkdownEngineConfig { this.automaticallyShowPreviewOfMarkdownBeingEdited = config.get( "automaticallyShowPreviewOfMarkdownBeingEdited", ); + this.previewColorScheme = config.get( + "previewColorScheme", + ); this.enableHTML5Embed = config.get("enableHTML5Embed"); this.HTML5EmbedUseImageSyntax = config.get( @@ -146,6 +157,7 @@ export class MarkdownPreviewEnhancedConfig implements MarkdownEngineConfig { this.hideDefaultVSCodeMarkdownPreviewButtons = config.get( "hideDefaultVSCodeMarkdownPreviewButtons", ); + this.jsdelivrCdnHost = config.get("jsdelivrCdnHost"); } public isEqualTo(otherConfig: MarkdownPreviewEnhancedConfig) { diff --git a/src/extension.ts b/src/extension.ts index 71f4787..b0b645a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,6 +10,7 @@ import { isMarkdownFile, MarkdownPreviewEnhancedView, } from "./preview-content-provider"; +import { PreviewColorScheme } from "./config"; let editorScrollDelay = Date.now(); @@ -221,8 +222,16 @@ export function activate(context: vscode.ExtensionContext) { ); } - function webviewFinishLoading(uri) { + function webviewFinishLoading( + uri: string, + { + systemColorScheme, + }: { + systemColorScheme: "light" | "dark"; + }, + ) { const sourceUri = vscode.Uri.parse(uri); + contentProvider.setSystemColorScheme(systemColorScheme); contentProvider.updateMarkdown(sourceUri); } @@ -603,6 +612,21 @@ export function activate(context: vscode.ExtensionContext) { }), ); + // Changed editor color theme + context.subscriptions.push( + vscode.window.onDidChangeActiveColorTheme((theme) => { + const config = vscode.workspace.getConfiguration( + "markdown-preview-enhanced", + ); + if ( + config.get("previewColorScheme") === + PreviewColorScheme.editorColorScheme + ) { + contentProvider.updateConfiguration(true); + } + }), + ); + /* context.subscriptions.push(vscode.workspace.onDidOpenTextDocument((textDocument)=> { // console.log('onDidOpenTextDocument', textDocument.uri) diff --git a/src/preview-content-provider.ts b/src/preview-content-provider.ts index 6a8e7e9..621a254 100644 --- a/src/preview-content-provider.ts +++ b/src/preview-content-provider.ts @@ -6,7 +6,8 @@ import { tmpdir } from "os"; import * as path from "path"; import * as vscode from "vscode"; import { TextEditor, Uri } from "vscode"; -import { MarkdownPreviewEnhancedConfig } from "./config"; +import { MarkdownPreviewEnhancedConfig, PreviewColorScheme } from "./config"; +import { PreviewTheme } from "@shd101wyy/mume/out/src/markdown-engine-config"; // http://www.typescriptlang.org/play/ // https://github.com/Microsoft/vscode/blob/master/extensions/markdown/media/main.js @@ -44,6 +45,8 @@ export class MarkdownPreviewEnhancedView { private config: MarkdownPreviewEnhancedConfig; + private systemColorScheme: "light" | "dark" = "light"; + public constructor(private context: vscode.ExtensionContext) { this.config = MarkdownPreviewEnhancedConfig.getCurrentConfig(); @@ -336,13 +339,17 @@ export class MarkdownPreviewEnhancedView { public initMarkdownEngine(sourceUri: Uri): MarkdownEngine { let engine = this.getEngine(sourceUri); if (!engine) { + const previewTheme = this.getPreviewTheme( + this.config.previewTheme, + this.config.previewColorScheme, + ); engine = new MarkdownEngine({ filePath: this.getFilePath(sourceUri), projectDirectoryPath: this.getProjectDirectoryPath( sourceUri, vscode.workspace.workspaceFolders, ), - config: this.config, + config: { ...this.config, previewTheme }, }); this.engineMaps[sourceUri.fsPath] = engine; this.jsAndCssFilesMaps[sourceUri.fsPath] = []; @@ -766,9 +773,35 @@ export class MarkdownPreviewEnhancedView { } } - public updateConfiguration() { + private getEditorColorScheme(): "light" | "dark" { + if ( + [ + vscode.ColorThemeKind.Light, + vscode.ColorThemeKind.HighContrastLight, + ].find((themeKind) => { + return vscode.window.activeColorTheme.kind === themeKind; + }) + ) { + return "light"; + } else { + return "dark"; + } + } + + public setSystemColorScheme(colorScheme: "light" | "dark") { + if (this.systemColorScheme !== colorScheme) { + this.systemColorScheme = colorScheme; + if ( + this.config.previewColorScheme === PreviewColorScheme.systemColorScheme + ) { + this.updateConfiguration(true); + } + } + } + + public updateConfiguration(forceUpdate = false) { const newConfig = MarkdownPreviewEnhancedConfig.getCurrentConfig(); - if (!this.config.isEqualTo(newConfig)) { + if (forceUpdate || !this.config.isEqualTo(newConfig)) { // if `singlePreview` setting is changed, close all previews. if (this.config.singlePreview !== newConfig.singlePreview) { this.closeAllPreviews(this.config.singlePreview); @@ -778,7 +811,12 @@ export class MarkdownPreviewEnhancedView { for (const fsPath in this.engineMaps) { if (this.engineMaps.hasOwnProperty(fsPath)) { const engine = this.engineMaps[fsPath]; - engine.updateConfiguration(newConfig); + const previewTheme = this.getPreviewTheme( + newConfig.previewTheme, + newConfig.previewColorScheme, + ); + // Update markdown engine configuration + engine.updateConfiguration({ ...newConfig, previewTheme }); } } @@ -788,6 +826,49 @@ export class MarkdownPreviewEnhancedView { } } + private getPreviewThemeByLightOrDark( + theme: PreviewTheme, + color: "light" | "dark", + ): PreviewTheme { + switch (theme) { + case "atom-dark.css": + case "atom-light.css": { + return color === "light" ? "atom-light.css" : "atom-dark.css"; + } + case "github-dark.css": + case "github-light.css": { + return color === "light" ? "github-light.css" : "github-dark.css"; + } + case "one-light.css": + case "one-dark.css": { + return color === "light" ? "one-light.css" : "one-dark.css"; + } + case "solarized-light.css": + case "solarized-dark.css": { + return color === "light" ? "solarized-light.css" : "solarized-dark.css"; + } + default: { + return theme; + } + } + } + + private getPreviewTheme( + theme: PreviewTheme, + colorScheme: PreviewColorScheme, + ): PreviewTheme { + if (colorScheme === PreviewColorScheme.editorColorScheme) { + return this.getPreviewThemeByLightOrDark( + theme, + this.getEditorColorScheme(), + ); + } else if (colorScheme === PreviewColorScheme.systemColorScheme) { + return this.getPreviewThemeByLightOrDark(theme, this.systemColorScheme); + } else { + return theme; + } + } + public openImageHelper(sourceUri: Uri) { if (sourceUri.scheme === "markdown-preview-enhanced") { return vscode.window.showWarningMessage("Please focus a markdown file."); diff --git a/yarn.lock b/yarn.lock index ea7a8fb..d6839ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,10 +51,10 @@ dependencies: any-observable "^0.3.0" -"@shd101wyy/mume@0.7.6": - version "0.7.6" - resolved "https://registry.yarnpkg.com/@shd101wyy/mume/-/mume-0.7.6.tgz#dc29b619e6b00b422b6d8cdf5d5af4f13c7482ed" - integrity sha512-oWIjY/KX8I6jq8Eye7ZlsMOJukxB6hb49gseto7hW5GXCDNV/35oZ66lqQO2SoIoyDcf3kiUNfyzmVUeFB/o/g== +"@shd101wyy/mume@0.7.7": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@shd101wyy/mume/-/mume-0.7.7.tgz#901be6cd595ad14e0f9eb56ebe2ea4850ea2a8bd" + integrity sha512-SY5rMSPBmtQk1CG9RD4B76kLIuJEMHVujH7UqWC7z+tfeggiNMfjcdSfNeEBonSEhOispgqQJJ9lR/dXoIjMrw== dependencies: babyparse "^0.4.6" cheerio "1.0.0-rc.3"