├── .gitignore ├── LICENSE ├── README.md ├── esbuild.config.json ├── hot-reload.bat ├── manifest.json ├── package.json ├── rollup.config.js ├── src ├── main.ts ├── settings.ts └── view.ts ├── styles.css ├── tsconfig.json └── versions.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | *.iml 3 | .idea 4 | 5 | # npm 6 | node_modules 7 | package-lock.json 8 | 9 | # build 10 | main.js 11 | *.js.map 12 | 13 | # obsidian 14 | data.json 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Zsolt Viczián 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # (Jacvascript) \*.JS and (Style) \*.CSS Editor 2 | 3 | A minimalistic solution to view js and css files in Obsidian. Including support for editing css snippets and themes from the Obsidian config folder. 4 | 5 | ![image](https://user-images.githubusercontent.com/14358394/132396744-05ee5a1e-c6e5-489c-adf3-446cd88b9935.png) 6 | ![image](https://user-images.githubusercontent.com/14358394/132396815-a7edf2c8-e5a5-4a6d-9b88-74ad4af25221.png) 7 | ![image](https://user-images.githubusercontent.com/14358394/132872044-d48eb232-d5f0-4fa1-8c75-18765c70a855.png) 8 | 9 | In settings you can set up a mirror folder for css snippets and themes. With this, you can make them available for edit within Obsidian. 10 | 11 | You can configure the styling of code mirror with a css snippet. More on CodeMirror styling [here](https://codemirror.net/lib/codemirror.css). 12 | 13 | ### A skeleton for your code-view.css snippet 14 | You can use this code to configure colors for CodeView. 15 | 16 | ```css 17 | :root { 18 | --cm-keyword: #c792ea; 19 | --cm-atom: #f78c6c; 20 | --cm-number: #ff5370; 21 | --cm-type: #decb6b; 22 | --cm-def: #82aaff; 23 | --cm-property: #c792ea; 24 | --cm-variable: #f07178; 25 | --cm-variable-2: #eeffff; 26 | --cm-variable-3: #f07178; 27 | --cm-definition: #82aaff; 28 | --cm-callee: #89ddff; 29 | --cm-qualifier: #decb6b; 30 | --cm-operator: #89ddff; 31 | --cm-hr: #98e342; 32 | --cm-link: #696d70; 33 | --cm-error-bg: #ff5370; 34 | --cm-header: #da7dae; 35 | --cm-builtin: #ffcb6b; 36 | --cm-meta: #ffcb6b; 37 | --cm-matching-bracket: #ffffff; 38 | --cm-tag: #ff5370; 39 | --cm-tag-in-comment: #ff5370; 40 | --cm-string-2: #f07178; 41 | --cm-bracket: #ff5370; 42 | --cm-comment: #676e95; 43 | --cm-string: #c3e88d; 44 | --cm-attribute: #c792ea; 45 | --cm-attribute-in-comment: #c792ea; 46 | --cm-background-color: #292d3e; 47 | --cm-active-line-background-color: #353a50; 48 | --cm-foreground-color: #d4d4d4; 49 | } 50 | ``` 51 | 52 | ### CodeView styling 53 | Note how the ContentEl for the CodeView markdown view receives a .CodeView class. You can use this to specifically target styling of CodeView. 54 | 55 | ```css 56 | .CodeView .cm-header {color: var(--cm-header) !important;} 57 | .CodeView .cm-negative {color: var(--cm-negative) !important;} 58 | .CodeView .cm-positive {color: var(--cm-positive) !important;} 59 | 60 | .CodeView .cm-header {font-weight: bold;} 61 | .CodeView .cm-strong {font-weight: bold;} 62 | .CodeView .cm-em {font-style: italic;} 63 | .CodeView .cm-link {text-decoration: underline;} 64 | .CodeView .cm-strikethrough {text-decoration: line-through;} 65 | 66 | .CodeView .cm-keyword {color: var(--cm-keyword) !important;} 67 | .CodeView .cm-atom {color: var(--cm-atom) !important;} 68 | .CodeView .cm-number {color: var(--cm-number) !important;} 69 | .CodeView .cm-def {color: var(--cm-def) !important;} 70 | .CodeView .cm-variable {color: var(--cm-variable) !important;} 71 | .CodeView .cm-property {color: var(--cm-property) !important;} 72 | .CodeView .cm-operator {color: var(--cm-operator) !important;} 73 | .CodeView .cm-variable-2 {color: var(--cm-variable-2) !important;} 74 | .CodeView .cm-variable-3 {color: var(--cm-variable-3) !important;} 75 | .CodeView .cm-type {color: var(--cm-type) !important;} 76 | .CodeView .cm-comment {color: var(--cm-comment) !important;} 77 | .CodeView .cm-string {color: var(--cm-string) !important;} 78 | .CodeView .cm-string-2 {color: var(--cm-string-2) !important;} 79 | .CodeView .cm-meta {color: var(--cm-meta) !important;} 80 | .CodeView .cm-qualifier {color: var(--cm-qualifier) !important;} 81 | .CodeView .cm-builtin {color: var(--cm-builtin) !important;} 82 | .CodeView .cm-bracket {color: var(--cm-bracket) !important;} 83 | .CodeView .cm-tag {color: var(--cm-tag) !important;} 84 | .CodeView .cm-attribute {color: var(--cm-attribute) !important;} 85 | .CodeView .cm-hr {color: var(--cm-hr) !important;} 86 | .CodeView .cm-link {color: var(--cm-link) !important;} 87 | .CodeView .cm-error {color: var(--cm-error) !important; background: var(--cm-error-bg) !important;} 88 | .CodeView .cm-invalidchar {color: var(--cm-invalidchar) !important;} 89 | 90 | .CodeView .cm-active-line-background-color {background: var(--cm-active-line-background-color) !important;} 91 | .CodeView .cm-attribute-in-comment {color: var(--cm-attribute-in-comment) !important;} 92 | .CodeView .cm-callee {color: var(--cm-callee) !important;} 93 | .CodeView .cm-definition {color: var(--cm-definition) !important;} 94 | .CodeView .cm-tag-in-comment {color: var(--cm-tag-in-comment) !important;} 95 | ``` 96 | -------------------------------------------------------------------------------- /esbuild.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "minify": true 3 | } -------------------------------------------------------------------------------- /hot-reload.bat: -------------------------------------------------------------------------------- 1 | obsidian-plugin dev -S=./styles.css -e="esbuild.config.json" -v="../../Obsidian/Demo" ./main.js -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-codeview", 3 | "name": "CodeView", 4 | "version": "0.0.4", 5 | "minAppVersion": "0.12.12", 6 | "description": "Allow opening js and css files.", 7 | "author": "zsviczian", 8 | "authorUrl": "https://zsolt.blog", 9 | "isDesktopOnly": true 10 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-codeview", 3 | "version": "0.0.4", 4 | "description": "Allow opening js and css files.", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "rollup --config rollup.config.js -w", 8 | "build": "rollup --config rollup.config.js --environment BUILD:production" 9 | }, 10 | "keywords": [], 11 | "author": "zsviczian", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@rollup/plugin-commonjs": "^18.0.0", 15 | "@rollup/plugin-node-resolve": "^11.2.1", 16 | "@rollup/plugin-typescript": "^8.2.1", 17 | "@types/node": "^14.14.37", 18 | "obsidian": "^0.12.11", 19 | "rollup": "^2.32.1", 20 | "tslib": "^2.2.0", 21 | "typescript": "^4.2.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from "@rollup/plugin-typescript"; 2 | import { nodeResolve } from "@rollup/plugin-node-resolve"; 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | 5 | const isProd = process.env.BUILD === "production"; 6 | 7 | const banner = `/* 8 | THIS IS A GENERATED/BUNDLED FILE BY ROLLUP 9 | if you want to view the source visit the plugins github repository 10 | */ 11 | `; 12 | 13 | export default { 14 | input: "./src/main.ts", 15 | output: { 16 | dir: ".", 17 | sourcemap: "inline", 18 | sourcemapExcludeSources: isProd, 19 | format: "cjs", 20 | exports: "default", 21 | banner, 22 | }, 23 | external: ["obsidian"], 24 | plugins: [typescript(), nodeResolve({ browser: true }), commonjs()], 25 | }; 26 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Menu, 3 | MenuItem, 4 | normalizePath, 5 | Plugin, 6 | TAbstractFile, 7 | TFile, 8 | TFolder, 9 | WorkspaceLeaf 10 | } from "obsidian"; 11 | import CodeView from "./view"; 12 | import { 13 | CodeViewSettings, 14 | DEFAULT_SETTINGS, 15 | CodeViewSettingTab 16 | } from "./settings"; 17 | 18 | export default class CodeViewPlugin extends Plugin { 19 | public settings: CodeViewSettings; 20 | 21 | async onload (): Promise { 22 | await this.loadSettings (); 23 | this.addSettingTab (new CodeViewSettingTab (this.app, this)); 24 | const register = (ext: string) => { 25 | try { 26 | this.registerView (ext, (leaf: WorkspaceLeaf) => new CodeView (leaf,ext, this)); 27 | this.registerExtensions ([ext], ext); 28 | } catch (e) { 29 | console.log ("CodeView can't register extension: " + ext); 30 | } 31 | } 32 | register ("js"); 33 | register ("css"); 34 | this.addFileMenuItem ("javascript","js"); 35 | this.addFileMenuItem ("css","css"); 36 | 37 | this.addCommand ({ 38 | id: "codeview-mirror", 39 | name: "Refresh mirror of snippets and themes", 40 | checkCallback: (checking: boolean) => { 41 | if (checking) { 42 | return this.settings.mirroringEnabled; 43 | } else { 44 | this.runMirror (); 45 | return true; 46 | } 47 | }, 48 | }); 49 | 50 | const self = this; 51 | this.app.workspace.onLayoutReady (()=> { 52 | self.runMirror (); 53 | const deleteEventHandler = async (file:TFile) => { 54 | if (!(file instanceof TFile)) return; 55 | if (!(this.settings.mirroringEnabled && this.settings.fileEventHandlerEnabled)) return; 56 | const [vaultPath,realPath] = self.getMirrorPath (file.name,file.path,file.extension); 57 | if (!realPath) return; 58 | //@ts-ignore 59 | self.app.vault.adapter.fs.rm (realPath,{force:true},()=>{}); 60 | } 61 | self.registerEvent (self.app.vault.on ("delete",deleteEventHandler)); 62 | 63 | const renameEventHandler = async (file:TAbstractFile,oldPath:string) => { 64 | if (!(file instanceof TFile)) return; 65 | if (!(this.settings.mirroringEnabled && this.settings.fileEventHandlerEnabled)) return; 66 | const [newVaultPath,newRealPath] = self.getMirrorPath (file.name,file.path,file.extension); 67 | const pathParts = this.splitPath (oldPath); 68 | const [oldVaultPath,oldRealPath] = self.getMirrorPath (pathParts.filename,oldPath,pathParts.extension); 69 | if(!newVaultPath && !oldVaultPath) return; 70 | if(newVaultPath && !oldVaultPath) { 71 | //file moved into folder 72 | //@ts-ignore 73 | await this.app.vault.adapter.fsPromises.writeFile (newRealPath,await this.app.vault.read(file)); 74 | return; 75 | } 76 | if(!newRealPath && oldRealPath) { 77 | //file moved out of folder 78 | //@ts-ignore 79 | self.app.vault.adapter.fs.rm (oldRealPath,{force:true},()=>{}); 80 | return; 81 | } 82 | //file renamed within folder 83 | //@ts-ignore 84 | this.app.vault.adapter.fsPromises.rename (oldRealPath,newRealPath); 85 | }; 86 | self.registerEvent (self.app.vault.on ("rename",renameEventHandler)); 87 | }) 88 | } 89 | 90 | private addFileMenuItem (cmMode:string, ext: string) { 91 | this.registerEvent (this.app.workspace.on ("file-menu", (menu: Menu, file: TFile) => { 92 | menu.addItem ((item: MenuItem) => { 93 | item.setTitle (`Add ${ext} file`) 94 | .onClick(async (evt) => { 95 | let folderpath = file.path; 96 | if(file instanceof TFile) { 97 | folderpath = normalizePath (file.path.substr (0,file.path.lastIndexOf (file.name))); 98 | } 99 | const fpath = this.getNewUniqueFilepath ("untitled",ext,folderpath); 100 | await this.app.vault.create (fpath,""); 101 | const leaf = this.app.workspace.getLeaf(); 102 | leaf.setViewState ({type:ext,state: {file: fpath}}); 103 | }) 104 | }); 105 | })); 106 | } 107 | 108 | private getNewUniqueFilepath (basename:string, ext:string, folderpath:string):string { 109 | let fpath = normalizePath (`${folderpath}/${basename}.${ext}`); 110 | let i = 0; 111 | while (this.app.vault.getAbstractFileByPath (fpath)) { 112 | fpath = normalizePath (`${folderpath}/${basename}_${i++}.${ext}`); 113 | } 114 | return fpath; 115 | } 116 | 117 | splitPath (filepath: string):{filename: string, extension: string} { 118 | const lastSlash = filepath.lastIndexOf ("/"); 119 | const lastDot = filepath.lastIndexOf ("."); 120 | return { 121 | filename: lastSlash===-1 ? filepath : filepath.substr (lastSlash+1), 122 | extension: lastDot===-1 ? "" : filepath.substr (lastDot+1), 123 | }; 124 | } 125 | 126 | async checkAndCreateFolder (folderpath:string) { 127 | folderpath = normalizePath (folderpath); 128 | let folder = this.app.vault.getAbstractFileByPath (folderpath); 129 | if (folder && folder instanceof TFolder) return; 130 | await this.app.vault.createFolder (folderpath); 131 | } 132 | 133 | public async runMirror() { 134 | if (!this.settings.mirroringEnabled) return; 135 | await this.checkAndCreateFolder (this.settings.mirrorFolderPath); 136 | const configDir = this.app.vault.configDir; 137 | 138 | const run = async (type: string) => { 139 | await this.checkAndCreateFolder (`${this.settings.mirrorFolderPath}/${type}`); 140 | //@ts-ignore 141 | const path = this.app.vault.adapter.getFullRealPath (`${configDir}/${type}`) 142 | //@ts-ignore 143 | this.app.vault.adapter.fs.readdir (path,"",(e,files) => { 144 | if(e) { 145 | console.log (e); 146 | return; 147 | } 148 | files.forEach (async (cssFile:string) => { 149 | const snippetVaultPath = `${configDir}/${type}/${cssFile}`; 150 | const snippetMirrorPath = normalizePath (`${this.settings.mirrorFolderPath}/${type}/${cssFile}`); 151 | const snippetMirrorFile = this.app.vault.getAbstractFileByPath (snippetMirrorPath); 152 | //@ts-ignore 153 | const snippetString = await this.app.vault.readRaw (snippetVaultPath); 154 | if (!snippetMirrorFile) { 155 | this.app.vault.create (snippetMirrorPath,snippetString); 156 | } 157 | else { 158 | this.app.vault.modify (snippetMirrorFile as TFile,snippetString); 159 | } 160 | }); 161 | }); 162 | } 163 | 164 | run ("snippets"); 165 | run ("themes"); 166 | } 167 | 168 | public getMirrorPath (fileName:string,filePath:string,extension:string):[string,string] { 169 | if (!(this.settings.mirroringEnabled && extension==="css")) return [null,null]; 170 | const snippetMirrorPath = normalizePath (`${this.settings.mirrorFolderPath}/snippets/${fileName}`); 171 | const themeMirrorPath = normalizePath (`${this.settings.mirrorFolderPath}/themes/${fileName}`); 172 | let type = null; 173 | if (snippetMirrorPath === filePath) type = "snippets"; 174 | if (themeMirrorPath === filePath) type = "themes"; 175 | if (type) { 176 | const configDir = this.app.vault.configDir; 177 | const vaultPath = `${configDir}/${type}/${fileName}` 178 | //@ts-ignore 179 | const realPath = this.app.vault.adapter.getFullRealPath (`${configDir}/${type}/${fileName}`); 180 | return [vaultPath,realPath]; 181 | } 182 | return [null,null]; 183 | } 184 | 185 | public async saveSettings () { 186 | await this.saveData (this.settings); 187 | } 188 | 189 | private async loadSettings () { 190 | this.settings = Object.assign ({}, DEFAULT_SETTINGS, await this.loadData ()); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/settings.ts: -------------------------------------------------------------------------------- 1 | import { 2 | App, 3 | PluginSettingTab, 4 | Setting, 5 | normalizePath, 6 | ToggleComponent 7 | } from 'obsidian'; 8 | import type CodeViewPlugin from "./main"; 9 | 10 | export interface CodeViewSettings { 11 | mirrorFolderPath: string, 12 | mirroringEnabled: boolean, 13 | fileEventHandlerEnabled: boolean, 14 | } 15 | 16 | export const DEFAULT_SETTINGS: CodeViewSettings = { 17 | mirrorFolderPath: 'CSS-snippets-themes', 18 | mirroringEnabled: false, 19 | fileEventHandlerEnabled: false, 20 | } 21 | 22 | export class CodeViewSettingTab extends PluginSettingTab { 23 | plugin: CodeViewPlugin; 24 | requestMirrorRefresh: boolean; 25 | 26 | constructor (app: App, plugin: CodeViewPlugin) { 27 | super (app, plugin); 28 | this.plugin = plugin; 29 | } 30 | 31 | async hide () { 32 | this.plugin.settings.mirrorFolderPath = normalizePath (this.plugin.settings.mirrorFolderPath); 33 | await this.plugin.saveSettings (); 34 | if (this.requestMirrorRefresh) { 35 | await this.plugin.runMirror (); 36 | } 37 | } 38 | 39 | display (): void { 40 | //@ts-ignore 41 | const configDir = this.plugin.app.vault.configDir; 42 | this.requestMirrorRefresh = false; 43 | let {containerEl} = this; 44 | this.containerEl.empty (); 45 | 46 | containerEl.createEl ("p",null, (el) => { 47 | el.textContent = `While I made every effort to make CodeView simple and safe, there is always a risk. Please read the below carefully. `+ 48 | `It is always best to have a backup of your data, in this case a backup of your js code, your css themes and snippets.`; 49 | }) 50 | 51 | let mirrorToggle:ToggleComponent; 52 | new Setting (containerEl) 53 | .setName ("Enable css snippets and themes mirroring") 54 | .setDesc (`If you turn this on then "${configDir}/snippets" and "${configDir}/themes" will be copied to the mirror folder specified below. The ` + 55 | `mirror does not actively monitor the snippets and themes folders. If you place new files in snippets or themes these will be picked up ` + 56 | `when you restart Obsidian, or when you run "Refresh mirror of snippets and themes" from Command Palette`) 57 | .addToggle (toggle => { 58 | mirrorToggle = toggle; 59 | toggle 60 | .setValue (this.plugin.settings.mirroringEnabled) 61 | .onChange (async (value) => { 62 | this.plugin.settings.mirroringEnabled = value; 63 | await this.plugin.saveSettings (); 64 | this.requestMirrorRefresh = value; 65 | }) 66 | }); 67 | 68 | new Setting (containerEl) 69 | .setName ("CSS snippet mirror folder") 70 | .setDesc (`Folder to use as a mirror of the "${configDir}/snippets" and "${configDir}/themes" css files.`) 71 | .addText (text => text 72 | .setPlaceholder ('Mirror folder path') 73 | .setValue (this.plugin.settings.mirrorFolderPath) 74 | .onChange (async (value) => { 75 | mirrorToggle.setValue (false); 76 | this.plugin.settings.mirrorFolderPath = value; 77 | await this.plugin.saveSettings (); 78 | })); 79 | 80 | new Setting (containerEl) 81 | .setName ("Enable file event handlers for snippets and themes") 82 | .setDesc (`⚠⚡⚠⚡⚠⚡ Make sure you have a backup of your snippets and themes. Only turn this on if you know what you are doing. \n` + 83 | `If you delete a file from your mirror folder it will be deleted from "${configDir}/snippets" or "${configDir}/themes" respectively. `+ 84 | `Note that moving a file out of the mirror folder will also delete the snippet or theme from the "${configDir}/" folder. Moving it back will create it in the "${configDir}/" folder. ` + 85 | `If you rename a file in the mirror folder, the snippet or theme file will be renamed as well. ` + 86 | `If you rename, move, or delete the complete mirror folder, the snippet and theme files will get deleted. If you move the mirror folder back to the configured location, files will be created again in the "${configDir}/" folders.` + 87 | `The file event handlers will only run if both mirroring is enabled and event handlers are enabled. `) 88 | .addToggle (toggle => toggle 89 | .setValue (this.plugin.settings.fileEventHandlerEnabled) 90 | .onChange (async (value) => { 91 | this.plugin.settings.fileEventHandlerEnabled = value; 92 | await this.plugin.saveSettings (); 93 | }) 94 | ); 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/view.ts: -------------------------------------------------------------------------------- 1 | import { MarkdownView, normalizePath, WorkspaceLeaf } from "obsidian"; 2 | import type CodeViewPlugin from "./main"; 3 | 4 | export default class CodeView extends MarkdownView { 5 | //File extension 6 | private ext: string; 7 | private plugin: CodeViewPlugin; 8 | 9 | constructor (leaf: WorkspaceLeaf,ext: string, plugin: CodeViewPlugin) { 10 | super (leaf); 11 | this.ext = ext; 12 | console.log (ext); 13 | this.plugin = plugin; 14 | this.app.workspace.onLayoutReady (()=>{ 15 | this.contentEl.addClass ("CodeView") 16 | }); 17 | } 18 | 19 | public async setViewData (data: string, clear?: boolean) { 20 | switch (this.file.extension) { 21 | case "js": this.sourceMode.cmEditor.setOption ("mode", "javascript"); break; 22 | case "css": this.sourceMode.cmEditor.setOption ("mode", "css"); break; 23 | } 24 | const [vaultPath,realPath] = this.plugin.getMirrorPath (this.file.name,this.file.path,this.file.extension); 25 | if (vaultPath) { 26 | try { 27 | //@ts-ignore 28 | data = await this.plugin.app.vault.readRaw (vaultPath); 29 | } catch (e) { 30 | console.log (e); 31 | } 32 | } 33 | super.setViewData (data, clear); 34 | }; 35 | 36 | async save (clear?:boolean) { 37 | const [vaultPath,realPath] = this.plugin.getMirrorPath (this.file.name,this.file.path,this.file.extension); 38 | if (realPath) { 39 | //@ts-ignore 40 | await this.plugin.app.vault.adapter.fsPromises.writeFile (realPath,this.data); 41 | } 42 | await super.save (clear); 43 | } 44 | 45 | canAcceptExtension (extension: string): boolean { 46 | return extension == this.ext; 47 | } 48 | 49 | getViewType (): string { 50 | return this.ext; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /*https://codemirror.net/lib/codemirror.css*/ 2 | .CodeView .cm-header {color: var(--cm-header) !important;} 3 | .CodeView .cm-negative {color: var(--cm-negative) !important;} 4 | .CodeView .cm-positive {color: var(--cm-positive) !important;} 5 | 6 | .CodeView .cm-header {font-weight: bold;} 7 | .CodeView .cm-strong {font-weight: bold;} 8 | .CodeView .cm-em {font-style: italic;} 9 | .CodeView .cm-link {text-decoration: underline;} 10 | .CodeView .cm-strikethrough {text-decoration: line-through;} 11 | 12 | .CodeView .cm-keyword {color: var(--cm-keyword) !important;} 13 | .CodeView .cm-atom {color: var(--cm-atom) !important;} 14 | .CodeView .cm-number {color: var(--cm-number) !important;} 15 | .CodeView .cm-def {color: var(--cm-def) !important;} 16 | .CodeView .cm-variable {color: var(--cm-variable) !important;} 17 | .CodeView .cm-property {color: var(--cm-property) !important;} 18 | .CodeView .cm-operator {color: var(--cm-operator) !important;} 19 | .CodeView .cm-variable-2 {color: var(--cm-variable-2) !important;} 20 | .CodeView .cm-variable-3 {color: var(--cm-variable-3) !important;} 21 | .CodeView .cm-type {color: var(--cm-type) !important;} 22 | .CodeView .cm-comment {color: var(--cm-comment) !important;} 23 | .CodeView .cm-string {color: var(--cm-string) !important;} 24 | .CodeView .cm-string-2 {color: var(--cm-string-2) !important;} 25 | .CodeView .cm-meta {color: var(--cm-meta) !important;} 26 | .CodeView .cm-qualifier {color: var(--cm-qualifier) !important;} 27 | .CodeView .cm-builtin {color: var(--cm-builtin) !important;} 28 | .CodeView .cm-bracket {color: var(--cm-bracket) !important;} 29 | .CodeView .cm-tag {color: var(--cm-tag) !important;} 30 | .CodeView .cm-attribute {color: var(--cm-attribute) !important;} 31 | .CodeView .cm-hr {color: var(--cm-hr) !important;} 32 | .CodeView .cm-link {color: var(--cm-link) !important;} 33 | .CodeView .cm-error {color: var(--cm-error) !important; background: var(--cm-error-bg) !important;} 34 | .CodeView .cm-invalidchar {color: var(--cm-invalidchar) !important;} 35 | 36 | .CodeView .cm-active-line-background-color {background: var(--cm-active-line-background-color) !important;} 37 | .CodeView .cm-attribute-in-comment {color: var(--cm-attribute-in-comment) !important;} 38 | .CodeView .cm-callee {color: var(--cm-callee) !important;} 39 | .CodeView .cm-definition {color: var(--cm-definition) !important;} 40 | .CodeView .cm-tag-in-comment {color: var(--cm-tag-in-comment) !important;} 41 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "es6", 8 | "allowJs": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "lib": [ 13 | "dom", 14 | "es5", 15 | "scripthost", 16 | "es2015" 17 | ], 18 | "allowSyntheticDefaultImports": true, 19 | }, 20 | "include": [ 21 | "**/*.ts" 22 | ] 23 | } -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "0.0.4": "0.12.12" 3 | } --------------------------------------------------------------------------------