├── .gitignore ├── .vscodeignore ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── CHANGELOG.md ├── .eslintrc.json ├── src ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts └── extension.ts ├── tsconfig.json ├── settings.json ├── LICENSE ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | package-lock.json 6 | 7 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "note-macros" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.0.1] 10 | - Initial Release -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/class-name-casing": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off", 11 | "debug.javascript.suggestPrettyPrinting": false, 12 | "cSpell.words": [ 13 | "Ev", 14 | "Eväkallio's", 15 | "Hykin's", 16 | "Jani", 17 | "kallio's" 18 | ] 19 | } -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "note-macros": { 3 | "dailyNote": [ 4 | { 5 | "type": "note", 6 | "directory": "Daily", 7 | "extension": ".md", 8 | "name": "daily-note", 9 | "date": "yyyy-mm-dd" 10 | } 11 | ], 12 | "weeklyNote": [ 13 | { 14 | "type": "note", 15 | "directory": "Weekly", 16 | "extension": ".md", 17 | "name": "weekly-note", 18 | "date": "yyyy-W" 19 | } 20 | ], 21 | "monthlyNote": [ 22 | { 23 | "type": "note", 24 | "directory": "Monthly", 25 | "extension": ".md", 26 | "name": "monthly-note", 27 | "date": "yyyy-mm" 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "${defaultBuildTask}" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "${defaultBuildTask}" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT Licence (MIT) 2 | 3 | Copyright 2020 Kevin Neely 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "note-macros", 3 | "displayName": "note-macros", 4 | "description": "An all in one extension for defining Note Macros and executing them from the Command Pallette.", 5 | "version": "0.0.3", 6 | "repository": "https://github.com/kneely/note-macros", 7 | "author": "Kevin Neely ", 8 | "publisher": "NeelyInnovations", 9 | "license": "MIT", 10 | "engines": { 11 | "vscode": "^1.47.0" 12 | }, 13 | "categories": [ 14 | "Other" 15 | ], 16 | "activationEvents": [ 17 | "*" 18 | ], 19 | "main": "./out/extension", 20 | "contributes": { 21 | "configuration": { 22 | "type": "object", 23 | "title": "Macros configuration", 24 | "properties": { 25 | "note-macros": {} 26 | } 27 | }, 28 | "commands": [ 29 | { 30 | "command": "note-macro.run", 31 | "title": "Note Macros: Run A Macro" 32 | }, 33 | { 34 | "command": "note-macro.list-builtin-commands", 35 | "title": "Macro Dev: List all the commands that can be used in macros" 36 | } 37 | ] 38 | }, 39 | "scripts": { 40 | "vscode:prepublish": "npm run compile", 41 | "compile": "tsc -p ./", 42 | "lint": "eslint src --ext ts", 43 | "watch": "tsc -watch -p ./", 44 | "pretest": "npm run compile && npm run lint", 45 | "test": "node ./out/test/runTest.js" 46 | }, 47 | "devDependencies": { 48 | "@types/vscode": "^1.47.0", 49 | "@types/glob": "^7.1.1", 50 | "@types/mocha": "^7.0.2", 51 | "@types/node": "^13.11.0", 52 | "eslint": "^6.8.0", 53 | "@typescript-eslint/parser": "^2.30.0", 54 | "@typescript-eslint/eslint-plugin": "^2.30.0", 55 | "glob": "^7.1.6", 56 | "mocha": "^7.1.2", 57 | "typescript": "^3.8.3", 58 | "vscode-test": "^1.3.0" 59 | }, 60 | "dependencies": { 61 | "@types/dateformat": "^3.0.1", 62 | "dateformat": "^3.0.3" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note Macros 2 | 3 | Heavily inspired by [Foam's](https://foambubble.github.io/foam/) [Daily Note](https://foambubble.github.io/foam/daily-notes) feature and [Jeff Hykin's](https://github.com/jeff-hykin/macro-commander) code. 4 | 5 | # Intended Use 6 | 7 | This extension was originally developed to go hand in hand with [Foam](https://foambubble.github.io/foam/). 8 | 9 | >Foam is a personal knowledge management and sharing system inspired by Roam Research, built on Visual Studio Code and GitHub. 10 | 11 | You theoretically could also use this with other Note Taking solutions with vscode. 12 | 13 | # Installation 14 | 15 | To install search note-macros in vscode or head to [note-macros](https://marketplace.visualstudio.com/items?itemName=NeelyInnovations.note-macros) 16 | 17 | # Features 18 | 19 | This extension was heavily inspired by Jeff Hykin's [macro-commander](https://github.com/jeff-hykin/macro-commander). In addition to the functionality mentioned below you are able to use macro-commander's [functionality](https://github.com/jeff-hykin/macro-commander#what-are-some-macro-examples). 20 | 21 | ## Create Custom Note Macros 22 | 23 | Create your own custom macros by adding them to your `settings.json` (Code|File > Preferences > User Settings). A full example can be found at [settings.json](settings.json) 24 | 25 | For example: 26 | 27 | This macro creates a Weekly note in the Weekly note Directory. 28 | 29 | ```json 30 | { 31 | "note-macros": { 32 | "Weekly": [ 33 | { 34 | "type": "note", 35 | "directory": "Weekly", 36 | "extension": ".md", 37 | "name": "weekly-note", 38 | "date": "yyyy-W" 39 | }, 40 | ] 41 | } 42 | } 43 | ``` 44 | 45 | ### Explanation of fields 46 | 47 | ```json 48 | "type": "note" 49 | ``` 50 | 51 | If your macro does not execute check this field first. This field was introduced to separate the existing functionality of [macro-commander](https://github.com/jeff-hykin/macro-commander) and my work. In the future this field will also separate the [Zettelkasten](https://zettelkasten.de/posts/overview/) functionality. 52 | 53 | ```json 54 | "directory": "Weekly" 55 | ``` 56 | 57 | The directory your note will be created. 58 | 59 | ```json 60 | "extension": ".md", 61 | ``` 62 | 63 | The extension that will be used. If not supplied this will default to markdown but can be changed. 64 | 65 | ```json 66 | "name": "weekly-note", 67 | ``` 68 | 69 | This will be the name of the note. Both the file name and note title will be effected by this. 70 | 71 | ```json 72 | "date": "yyyy-W" 73 | ``` 74 | 75 | This is the date format for your note. For additional formats please go to [dateFormat](https://github.com/felixge/node-dateformat#mask-options). **This will default to `yyyy-mm-dd`.** 76 | 77 | Your macros can run any built-in VS Code action, and even actions from other extensions. 78 | To see all the names of possible actions VS Code can run, see `Default Keyboard Shortcuts` (Code|File > Preferences > Keyboard Shortcuts) 79 | 80 | ## Add Keybindings to Run your Macros 81 | 82 | in `keybindings.json` (Code|File > Preferences > Keyboard Shortcuts) add bindings to your macros: 83 | 84 | ```json 85 | { 86 | "key": "ctrl+cmd+/", 87 | "command": "note-macros.Weekly" 88 | } 89 | ``` 90 | 91 | Notice that `note-macros.my_macro_name` has to match what you named your macro. 92 | 93 | ## Executing Snippets As Part Of A Macro 94 | 95 | > **Release 0.0.1 Snippets are not functioning correctly!** 96 | > 97 | > I am leaving this in here in case it works for someone else. If it works for you please open an [Issue](https://github.com/kneely/note-macros/issues) to let me know. 98 | 99 | Macros can also execute any of your snippets which is super neat. Just insert the same text that you would normally type for the snippet, followed by the `insertSnippet` command: 100 | 101 | ```json 102 | {"command": "type", "args": {"text": "mySnippetPrefixHere" }}, 103 | "insertSnippet" 104 | ``` 105 | 106 | ```json 107 | { 108 | "macros": { 109 | "Weekly": [ 110 | { 111 | "type": "note", 112 | "directory": "Weekly", 113 | "extension": ".md", 114 | "name": "weekly-note", 115 | "date": "yyyy-W" 116 | } 117 | ], 118 | "doMySnippet": [ 119 | { "command": "editor.action.insertSnippet", "args": ":daily" } 120 | ] 121 | } 122 | } 123 | ``` 124 | 125 | ## Run macro From command pallette 126 | 127 | Simply use `Ctrl+P` or `Alt+P` depend on your os, and type `Note Macros: Run A Macro` then chose the macro you want to execute. 128 | 129 | ## Available Commands for Macros 130 | 131 | To list all available commands for your macros use `Ctrl+P` or `Alt+P` depend on your os, and type `Macro Dev: List all the commands that can be used in macros` then chose the macro you want to execute. 132 | 133 | 134 | # Roadmap 135 | 136 | ## Current Release 137 | - [x] Creation of completely Custom Notes 138 | 139 | ## Next Release 140 | 141 | - [ ] Fix snippet functionality. 142 | - [ ] Creation of [Zettelkasten](https://zettelkasten.de/posts/overview/) notes 143 | 144 | ## Future 145 | 146 | As of right now Custom Notes and Zettelkasten notes complete my initial vision of this extension. My new vision is for this extension to become a one stop shop for defining quick commands from `settings.json`. If you have an idea please open an [Issue](https://github.com/kneely/note-macros/issues) and we will discuss. 147 | 148 | # Issues 149 | 150 | This extension will be extensively used and tested on Windows and Linux. I do not have access to a MacOS machine. With that being said I cannot test on Mac. If you run into any issues on any environment please open an [Issue](https://github.com/kneely/note-macros/issues). 151 | 152 | # Credit 153 | 154 | This extension combines the my work with [Jani Eväkallio's](https://github.com/jevakallio) work and [Jeff Hykin's](https://github.com/jeff-hykin) work. My vision and code would not be possible without them. 155 | 156 | # License 157 | 158 | Note Macros is released under the [MIT License](https://github.com/kneely/note-macros/blob/master/LICENSE). -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import { workspace, Uri, Selection } from "vscode"; 2 | import fs = require("fs"); 3 | import dateFormat = require("dateformat"); 4 | import { execSync } from "child_process"; 5 | 6 | /* eslint-disable eqeqeq */ 7 | const { window } = require("vscode"); 8 | const vscode = require("vscode"); 9 | 10 | // 11 | // globals 12 | // 13 | let activeContext: any; 14 | let disposables: any[] = []; 15 | let macros: any = {}; 16 | let invalidMacroNames = ["has", "get", "update", "inspect"]; 17 | 18 | // 19 | // register commands 20 | // 21 | 22 | // create a command for running macros by name 23 | vscode.commands.registerCommand("note-macro.run", async () => { 24 | let macroNames = Object.keys(macros).filter( 25 | (each) => macros[each] instanceof Array 26 | ); 27 | let result = await window.showQuickPick(macroNames); 28 | executeMacro(result); 29 | }); 30 | 31 | // command that helps with creating new macros 32 | vscode.commands.registerCommand( 33 | "note-macro.list-builtin-commands", 34 | async () => { 35 | let commands = await vscode.commands.getCommands(); 36 | let result = await window.showQuickPick(commands); 37 | if (result != null) { 38 | await vscode.commands.executeCommand(result); 39 | } 40 | } 41 | ); 42 | 43 | // 44 | // helpers 45 | // 46 | 47 | // see https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex 48 | function escapeRegExp(string: string) { 49 | return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string 50 | } 51 | 52 | function flushEventStack() { 53 | // this is a sleep timer for 0 seconds, which sounds dumb 54 | // the reason it's useful is because it puts a function on the BOTTOM of the javascript event stack 55 | // and then we wait for it to occur 56 | // this means runs all of the already-scheduled things to occur 57 | // which is ideal because it makes pop ups and other events happen in a more sequential/timely order 58 | return new Promise((r) => setTimeout(r, 0)); 59 | } 60 | 61 | // 62 | // on first load 63 | // 64 | exports.activate = function activate(context: any) { 65 | loadMacros(context); 66 | activeContext = context; 67 | // whenever settings is changed 68 | vscode.workspace.onDidChangeConfiguration(() => { 69 | // dispose of macros 70 | for (let disposable of disposables) { 71 | disposable.dispose(); 72 | } 73 | // reload them 74 | loadMacros(activeContext); 75 | }); 76 | }; 77 | 78 | exports.deactivate = function deactivate() {}; 79 | 80 | // 81 | // create macros from settings 82 | // 83 | function loadMacros(context: { subscriptions: any[] }) { 84 | // get the macros from the settings file 85 | macros = vscode.workspace.getConfiguration("note-macros"); 86 | 87 | // look at each macro 88 | for (const name in macros) { 89 | // skip the things that are not arrays 90 | if (!(macros[name] instanceof Array)) { 91 | continue; 92 | } 93 | // register each one as a command 94 | const disposable = vscode.commands.registerCommand( 95 | `note-macros.${name}`, 96 | () => executeMacro(name) 97 | ); 98 | context.subscriptions.push(disposable); 99 | disposables.push(disposable); 100 | } 101 | } 102 | 103 | async function executeMacro(name: string) { 104 | // iterate over every action in the macro 105 | for (const action of macros[name]) { 106 | console.log(`action is:`, action); 107 | 108 | // if its a string assume its a command 109 | if (typeof action == "string") { 110 | await vscode.commands.executeCommand(action); 111 | await flushEventStack(); 112 | // otherwise check if its an object 113 | } else if (action instanceof Object) { 114 | // 115 | // Check if its a javascript macro 116 | // 117 | if (typeof action.javascript == "string") { 118 | await eval(`(async()=>{${action.javascript}})()`); 119 | await flushEventStack(); 120 | continue; 121 | // if its an array, convert the array to a string 122 | } else if (action.javascript instanceof Array) { 123 | let javacsriptAction = action.javascript.join("\n"); 124 | await eval(`(async()=>{${javacsriptAction}})()`); 125 | await flushEventStack(); 126 | continue; 127 | } 128 | // 129 | // Check for injections 130 | // 131 | let replacements = []; 132 | let actionCopy = JSON.parse(JSON.stringify(action)); 133 | if (action.injections) { 134 | for (let eachInjection of action.injections) { 135 | // 136 | // Compute the value the user provided 137 | // 138 | let value = eval(eachInjection.withResultOf); 139 | if (value instanceof Promise) { 140 | value = await value; 141 | } 142 | value = `${value}`; 143 | // 144 | // replace it in the arguments 145 | // 146 | let replacer = (name: string) => { 147 | if (typeof name == "string") { 148 | return name.replace( 149 | RegExp(escapeRegExp(eachInjection.replace), "g"), 150 | value 151 | ); 152 | } 153 | return name; 154 | }; 155 | for (let eachKey in actionCopy.args) { 156 | // if its a string value, then perform a replacement 157 | // TODO, this is currently shallow, it should probably be recursive 158 | if (typeof actionCopy.args[eachKey] == "string") { 159 | actionCopy.args[eachKey] = replacer(actionCopy.args[eachKey]); 160 | } 161 | } 162 | 163 | // convert arrays to strings 164 | let hiddenConsole = actionCopy.hiddenConsole; 165 | if (hiddenConsole instanceof Array) { 166 | hiddenConsole = hiddenConsole.join("\n"); 167 | } 168 | if (typeof hiddenConsole == "string") { 169 | hiddenConsole += "\n"; 170 | } 171 | 172 | // replace it in the console command 173 | actionCopy.hiddenConsole = replacer(hiddenConsole); 174 | } 175 | } 176 | // 177 | // run the command 178 | // 179 | actionCopy.hiddenConsole && execSync(actionCopy.hiddenConsole); 180 | actionCopy.command && 181 | (await vscode.commands.executeCommand( 182 | actionCopy.command, 183 | actionCopy.args 184 | )); 185 | // Get Note Directory 186 | function noteDirectory() { 187 | if (typeof action.directory == "string") { 188 | return action.directory; 189 | } 190 | } 191 | // Get File Extension 192 | function noteExtension() { 193 | if (typeof action.extension == "string") { 194 | return action.extension; 195 | } else { 196 | return ".md"; 197 | } 198 | } 199 | 200 | //Get Date Format 201 | function dateFormatted() { 202 | if (typeof action.date == "string") { 203 | const now = new Date(); 204 | return dateFormat(now, action.date); 205 | } else { 206 | const now = new Date(); 207 | return dateFormat(now, "yyyy-mm-dd"); 208 | } 209 | } 210 | 211 | function noteFileName() { 212 | if (typeof action.name == "string") { 213 | return `${dateFormatted()}-${action.name}`; 214 | } 215 | } 216 | 217 | function notePath() { 218 | const rootDir = vscode.workspace.rootPath; 219 | const noteDir = noteDirectory(); 220 | 221 | return `${rootDir}/${noteDir}`; 222 | } 223 | 224 | function newNote() { 225 | return `${notePath()}/${noteFileName()}${noteExtension()}`; 226 | } 227 | 228 | async function createNoteIfNotExists() { 229 | if (await pathExists()) { 230 | return false; 231 | } 232 | 233 | await createNoteDirectoryIfNotExists(); 234 | 235 | await fs.promises.writeFile(newNote(), `# ${noteFileName()}`); 236 | return true; 237 | } 238 | 239 | async function createNoteDirectoryIfNotExists() { 240 | if (!(await pathExists())) { 241 | await fs.promises.mkdir(notePath(), { recursive: true }); 242 | } 243 | } 244 | 245 | async function focusNote() { 246 | const document = await workspace.openTextDocument(Uri.file(newNote())); 247 | const editor = await window.showTextDocument(document); 248 | 249 | // Move the cursor to end of the file 250 | const { lineCount } = editor.document; 251 | const { range } = editor.document.lineAt(lineCount - 1); 252 | editor.selection = new Selection(range.end, range.end); 253 | } 254 | 255 | async function pathExists() { 256 | const path = newNote(); 257 | return fs.promises 258 | .access(path, fs.constants.F_OK) 259 | .then(() => true) 260 | .catch(() => false); 261 | } 262 | 263 | if (action.type === "note") { 264 | await createNoteIfNotExists(); 265 | await focusNote(); 266 | console.log(`Completed openNote`); 267 | await flushEventStack(); 268 | } 269 | } 270 | } 271 | } 272 | --------------------------------------------------------------------------------