├── icon.png ├── tasks.gif ├── .gitignore ├── .vscodeignore ├── .vscode ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── CHANGELOG.md ├── tsconfig.json ├── src ├── test │ ├── runTest.ts │ └── suite │ │ └── index.ts ├── taskProvider.ts └── main.ts ├── LICENSE ├── .github └── workflows │ ├── publish.yml │ └── build.yml ├── tslint.json ├── README.md ├── package.json └── icon.svg /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perseus-me/vscode-hugo/HEAD/icon.png -------------------------------------------------------------------------------- /tasks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perseus-me/vscode-hugo/HEAD/tasks.gif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | src/extension.ts 6 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | out/**/*.map 5 | src/** 6 | .gitignore 7 | tsconfig.json 8 | vsc-extension-quickstart.md 9 | tslint.json -------------------------------------------------------------------------------- /.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 | "eg2.tslint" 6 | ] 7 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to the "vscode-hugo" extension will be documented in this file. 3 | 4 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 5 | 6 | ## [Unreleased] 7 | - Initial release -------------------------------------------------------------------------------- /.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 | "cSpell.enabled": false 10 | } -------------------------------------------------------------------------------- /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, 12 | "noUnusedLocals": true 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | ".vscode-test" 17 | ] 18 | } -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /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 the extension test runner script 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(err); 19 | console.error("Failed to run tests"); 20 | process.exit(1); 21 | } 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /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 | }); 10 | mocha.useColors(true); 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 | e(err); 34 | } 35 | }); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2020 Ruslan Nasonov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: checkout 15 | uses: actions/checkout@master 16 | - name: use Node.js 10.x 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node }} 20 | - name: npm install, compile, lint 21 | run: | 22 | npm install 23 | npm run compile 24 | npm run lint 25 | - name: test 26 | run: | 27 | export DISPLAY=':99.0' 28 | /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 29 | npm test 30 | - name: publish 31 | run: | 32 | git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" 33 | git config --global user.name "$GITHUB_ACTOR" 34 | git checkout master 35 | git diff 36 | ./node_modules/vsce/out/vsce publish -p ${{ secrets.VSCE_TOKEN }} minor 37 | - name: push 38 | uses: github-actions-x/commit@master 39 | with: 40 | github_token: ${{ secrets.GITHUB_TOKEN }} 41 | push_branch: 'master' 42 | commit_message: 'publish' 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.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": "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": "npm: watch" 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" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "npm: watch" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import-spacing": true, 4 | "indent": [ 5 | true, 6 | "spaces" 7 | ], 8 | "newline-before-return": false, 9 | "no-consecutive-blank-lines": true, 10 | "no-empty-line-after-opening-brace": false, 11 | "no-irregular-whitespace": true, 12 | "object-literal-key-quotes": [ 13 | true, 14 | "as-needed" 15 | ], 16 | "one-line": [ 17 | true, 18 | "check-open-brace", 19 | "check-catch", 20 | "check-else", 21 | "check-whitespace" 22 | ], 23 | "quotemark": [ 24 | true, 25 | "double" 26 | ], 27 | "space-within-parens": true, 28 | "typedef-whitespace": false, 29 | "no-unused-expression": true, 30 | "no-duplicate-variable": true, 31 | "no-shadowed-variable": true, 32 | "no-string-throw": true, 33 | "no-bitwise": true, 34 | "no-var-keyword": true, 35 | "no-trailing-whitespace": true, 36 | "curly": true, 37 | "class-name": true, 38 | "semicolon": [ 39 | true, 40 | "always" 41 | ], 42 | "triple-equals": true, 43 | "whitespace": [ 44 | true, 45 | "check-branch" 46 | ] 47 | } 48 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | os: [ubuntu-16.04, ubuntu-18.04] 16 | node: [10.x] 17 | 18 | steps: 19 | - name: checkout 20 | uses: actions/checkout@v1 21 | - name: use Node.js ${{ matrix.node }} 22 | uses: actions/setup-node@v1 23 | with: 24 | node-version: ${{ matrix.node }} 25 | - name: npm install 26 | run: | 27 | npm install 28 | - name: compile 29 | run: | 30 | npm run compile 31 | - name: lint 32 | run: | 33 | npm run lint 34 | - name: test 35 | run: | 36 | export DISPLAY=':99.0' 37 | /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 38 | npm test 39 | - name: build package 40 | run: | 41 | ./node_modules/vsce/out/vsce package 42 | echo "##[set-output name=version;]$(npm run package-version --silent)" 43 | id: build_package 44 | - name: save vsix 45 | uses: actions/upload-artifact@master 46 | with: 47 | name: ${{ format('vscode-hugo-{0}-{1}.vsix', steps.build_package.outputs.version, github.sha) }} 48 | path: ${{ format('vscode-hugo-{0}.vsix', steps.build_package.outputs.version) }} 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-hugo 2 | 3 | ![downloads](https://img.shields.io/vscode-marketplace/d/rusnasonov.vscode-hugo.svg) ![build](https://git.io/JeqHA) 4 | 5 | Integrate [Hugo](http://gohugo.io) with [VSCode](https://code.visualstudio.com). 6 | 7 | ## Tasks 8 | 9 | [VSCode Task](https://code.visualstudio.com/Docs/editor/tasks#_processing-task-output-with-problem-matchers) for Hugo. 10 | 11 | ![Tasks](https://github.com/rusnasonov/vscode-hugo/blob/master/tasks.gif) 12 | 13 | ### Build site 14 | 15 | Run `hugo` shell command. In VSCode run `Command Pallete` -> `Run tasks` -> `Build site`. 16 | 17 | Or press command + shift + b (control + shift + b for Windows and Linux) for select task in Build menu. If you setup `Default build task` command will be run without showing menu. 18 | 19 | ### Serve site 20 | 21 | Two possibilities: 22 | 23 | * Run `hugo server` shell command to start like final site. 24 | In VSCode run `Command Pallete` -> `Run tasks` -> `Serve site`. 25 | * Run `hugo server --buildDrafts` shell command to start site with draft page. 26 | In VSCode run `Command Pallete` -> `Run tasks` -> `Serve draft site`. 27 | 28 | 29 | ## Commands in Command Pallete 30 | 31 | `version` - show local version of Hugo. 32 | 33 | `remote version` - show remote version of Hugo. 34 | 35 | `create content` - create content in `content/` directory. 36 | 37 | `create content from archetype` - create content in `content/` directory from an archetype (https://gohugo.io/content-management/archetypes/) 38 | 39 | -------------------------------------------------------------------------------- /src/taskProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export class TaskProvider implements vscode.TaskProvider { 4 | provideTasks(): vscode.ProviderResult { 5 | return [ 6 | this.build(), 7 | this.serve(), 8 | this.serve_draft() 9 | ]; 10 | } 11 | 12 | private build(): vscode.Task { 13 | let build = new vscode.Task( 14 | {type: "hugo", task: ""}, 15 | "Build site", 16 | "hugo", 17 | new vscode.ShellExecution("hugo"), 18 | [] 19 | ); 20 | build.group = vscode.TaskGroup.Build; 21 | return build; 22 | } 23 | 24 | private serve(): vscode.Task { 25 | let serve = new vscode.Task( 26 | {type: "hugo", task: "server"}, 27 | "Serve site", 28 | "hugo", 29 | new vscode.ShellExecution("hugo server"), 30 | [] 31 | ); 32 | serve.group = vscode.TaskGroup.Build; 33 | serve.isBackground = true; 34 | return serve; 35 | } 36 | 37 | private serve_draft(): vscode.Task { 38 | let serve = new vscode.Task( 39 | {type: "hugo", task: "server draft"}, 40 | "Serve draft site", 41 | "hugo", 42 | new vscode.ShellExecution("hugo server --buildDrafts"), 43 | [] 44 | ); 45 | serve.group = vscode.TaskGroup.Build; 46 | serve.isBackground = true; 47 | return serve; 48 | } 49 | 50 | resolveTask(): vscode.ProviderResult { 51 | return undefined; 52 | } 53 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-hugo", 3 | "displayName": "Hugo Helper", 4 | "description": "Helper for Hugo static site generator", 5 | "version": "0.24.0", 6 | "publisher": "rusnasonov", 7 | "homepage": "https://github.com/rusnasonov/vscode-hugo/blob/master/README.md", 8 | "icon": "icon.png", 9 | "license": "SEE LICENSE IN LICENSE", 10 | "engines": { 11 | "vscode": "^1.43.0" 12 | }, 13 | "categories": [ 14 | "Other" 15 | ], 16 | "keywords": [ 17 | "Hugo", 18 | "Helper", 19 | "Static site generator" 20 | ], 21 | "author": "Ruslan Nasonov - rusnasonov.com", 22 | "repository": "https://github.com/rusnasonov/vscode-hugo.git", 23 | "bugs": { 24 | "url": "https://github.com/rusnasonov/vscode-hugo/issues" 25 | }, 26 | "activationEvents": [ 27 | "*" 28 | ], 29 | "main": "./out/main", 30 | "contributes": { 31 | "commands": [ 32 | { 33 | "command": "hugo.version", 34 | "title": "Hugo: version" 35 | }, 36 | { 37 | "command": "hugo.createContent", 38 | "title": "Hugo: create content" 39 | }, 40 | { 41 | "command": "hugo.remoteVersion", 42 | "title": "Hugo: remote version" 43 | }, 44 | { 45 | "command": "hugo.fromarchetype", 46 | "title": "Hugo: create content from archetype" 47 | } 48 | ], 49 | "taskDefinitions": [ 50 | { 51 | "type": "hugo", 52 | "required": [ 53 | "task" 54 | ], 55 | "properties": { 56 | "task": { 57 | "type": "string", 58 | "description": "The Hugo task" 59 | } 60 | } 61 | } 62 | ] 63 | }, 64 | "scripts": { 65 | "vscode:prepublish": "npm run compile", 66 | "compile": "tsc -p ./", 67 | "watch": "tsc -watch -p ./", 68 | "lint": "tslint --project ./", 69 | "package-version": "echo $npm_package_version" 70 | }, 71 | "devDependencies": { 72 | "@types/glob": "^7.1.1", 73 | "@types/mocha": "^5.2.6", 74 | "@types/node": "^11.13.7", 75 | "@types/vscode": "^1.43.0", 76 | "tslint": "^5.11.0", 77 | "typescript": "^3.4.5", 78 | "vsce": "^1.75.0", 79 | "vscode-test": "^1.3.0" 80 | }, 81 | "dependencies": { 82 | "axios": "^0.19.2" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import * as axios from "axios"; 3 | 4 | import * as cp from "child_process"; 5 | import * as path from "path"; 6 | import * as fs from "fs"; 7 | 8 | import { TaskProvider } from "./taskProvider"; 9 | 10 | export function activate(context: vscode.ExtensionContext) { 11 | const workspaceRoot = vscode.workspace.rootPath; 12 | if (!workspaceRoot) { 13 | return; 14 | } 15 | const hugo = new Hugo(workspaceRoot); 16 | if (!hugo.isHugoFolder()) { 17 | return; 18 | } 19 | const taskProvider = new TaskProvider(); 20 | vscode.tasks.registerTaskProvider("hugo", taskProvider); 21 | 22 | let version = vscode.commands.registerCommand("hugo.version", () => { 23 | hugo.version().then((v) => { 24 | vscode.window.showInformationMessage("Local version: " + v); 25 | }); 26 | }); 27 | 28 | let createContent = vscode.commands.registerCommand("hugo.createContent", () => { 29 | vscode.window.showQuickPick(hugo.sections()).then((sectionName) => { 30 | if (!sectionName) { 31 | return; 32 | } 33 | vscode.window.showInputBox({ placeHolder: `Create content in "${sectionName}"` }).then((fileName) => { 34 | if (!fileName) { 35 | return; 36 | } 37 | let fullFileName = path.join(sectionName, fileName.replace(/ /g, "-") + ".md"); 38 | 39 | hugo.new(fullFileName).then((p) => { 40 | // commands.executeCommand("vscode.open", right, opts); 41 | vscode.window.showTextDocument(vscode.Uri.parse("file://" + p)); 42 | }); 43 | }); 44 | }); 45 | 46 | }); 47 | 48 | let remoteVersion = vscode.commands.registerCommand("hugo.remoteVersion", () => { 49 | hugo.remoteVersion().then((v) => { 50 | vscode.window.showInformationMessage("Remote version: " + v); 51 | }); 52 | }); 53 | 54 | let fromArchetype = vscode.commands.registerCommand("hugo.fromarchetype", () => { 55 | vscode.window.showQuickPick(hugo.archetypes()).then((archetypeName) => { 56 | if (!archetypeName) { 57 | return; 58 | } 59 | let fromFile = archetypeName.endsWith(".md"); 60 | let sectionName = fromFile ? archetypeName.substring(0, archetypeName.length - 3) : archetypeName; 61 | 62 | vscode.window.showInputBox({ placeHolder: `Create "${archetypeName}" in "${sectionName}"` }).then((fileName) => { 63 | if (!fileName) { 64 | return; 65 | } 66 | 67 | let fullFileName = path.join(sectionName, fileName.replace(/ /g, "-")); 68 | if (fromFile) { 69 | if (!fullFileName.endsWith(".md")) { 70 | fullFileName += ".md"; 71 | } 72 | hugo.new(fullFileName).then((p) => { 73 | let indexFile = "file://" + p; 74 | vscode.window.showTextDocument(vscode.Uri.parse(indexFile)); 75 | }); 76 | } else { 77 | hugo.new(fullFileName, ["--kind", archetypeName]).then((p) => { 78 | let indexFile = "file://" + p + "/index.md"; 79 | vscode.window.showTextDocument(vscode.Uri.parse(indexFile)); 80 | }); 81 | } 82 | }); 83 | }); 84 | }); 85 | 86 | context.subscriptions.push(version); 87 | context.subscriptions.push(createContent); 88 | context.subscriptions.push(remoteVersion); 89 | context.subscriptions.push(fromArchetype); 90 | } 91 | 92 | export function deactivate(): void { } 93 | 94 | class Hugo { 95 | constructor(private projectRoot: string, private serverProcess?: cp.ChildProcess) { 96 | 97 | } 98 | 99 | public async runServer(): Promise { 100 | // TODO run server, config option; 101 | if (this.serverProcess) { 102 | return this; 103 | } 104 | let { process } = await this.run("server", ["--buildDrafts"]); 105 | return new Hugo(this.projectRoot, process); 106 | } 107 | 108 | public async isHugoFolder(): Promise { 109 | return await exists("config.toml") || exists("config.yaml") || exists("config.json"); 110 | } 111 | 112 | public async remoteVersion(): Promise { 113 | let response = await axios.default.get("https://github.com/gohugoio/hugo/releases/latest"); 114 | return path.basename(response.request.path); 115 | } 116 | 117 | public stopServer(): Hugo { 118 | if (!this.serverProcess) { 119 | return this; 120 | } 121 | this.serverProcess.kill("SIGTERM"); 122 | return new Hugo(this.projectRoot); 123 | } 124 | 125 | public async version(): Promise { 126 | let { stdout } = await this.spawn("version"); 127 | let matched = stdout.match(/v[0-9.]*/); 128 | if (matched) { 129 | return matched[0]; 130 | } 131 | throw new Error(`Version not found in ${stdout}`); 132 | } 133 | 134 | public async new(p: string, flag: string[] = []): Promise { 135 | this.spawn("new", flag.concat([p])); 136 | return this.projectRoot + "/content/" + p; 137 | } 138 | 139 | public sections(): string[] { 140 | let contentFolder = path.join(this.projectRoot, "content/"); 141 | return walk(contentFolder).map((item) => item.replace(contentFolder, "")); 142 | } 143 | 144 | public archetypes(): string[] { 145 | let archetypes = path.join(this.projectRoot, "archetypes/"); 146 | return walk(archetypes, false, false).map((item) => item.replace(archetypes, "")); 147 | } 148 | 149 | private async spawn(command: string = "", args: string[] = []): Promise<{ stdout: string; stderr: string; }> { 150 | let options: cp.ExecOptions = {}; 151 | if (this.projectRoot !== "") { 152 | options.cwd = this.projectRoot; 153 | } 154 | 155 | return await exec(["hugo", command].concat(args).join(" "), options); 156 | } 157 | 158 | private async run(command: string = "", args: string[] = []): Promise<{ process: cp.ChildProcess }> { 159 | let options: cp.ExecOptions = {}; 160 | if (this.projectRoot !== "") { 161 | options.cwd = this.projectRoot; 162 | } 163 | 164 | return await run(["hugo", command].concat(args).join(" "), options); 165 | } 166 | } 167 | 168 | function exec(command: string, options: cp.ExecOptions): Promise<{ stdout: string; stderr: string; }> { 169 | return new Promise<{ stdout: string; stderr: string; }>((resolve, reject) => { 170 | cp.exec(command, options, (error, stdout, stderr) => { 171 | if (error) { 172 | // todo enable debug 173 | vscode.window.showErrorMessage(stderr); 174 | reject({ error, stdout, stderr }); 175 | } 176 | resolve({ stdout, stderr }); 177 | }); 178 | }); 179 | } 180 | 181 | function run(command: string, options: cp.ExecOptions): Promise<{ process: cp.ChildProcess }> { 182 | return new Promise<{ process: cp.ChildProcess }>((resolve, reject) => { 183 | let process = cp.exec(command, options); 184 | process.on("error", reject); 185 | process.on("close", (code, signal) => { 186 | if (code !== 0) { 187 | reject(`Programm close with code ${code}, ${signal}`); 188 | } 189 | }); 190 | process.on("exit", (code, signal) => { 191 | if (code !== 0) { 192 | reject(`Programm exit with code ${code}, ${signal}`); 193 | } 194 | }); 195 | console.log(`Programm started, pid ${process.pid}`); 196 | resolve({ process }); 197 | }); 198 | } 199 | 200 | function exists(file: string): Promise { 201 | return new Promise((resolve, _reject) => { 202 | fs.exists(file, (value) => { 203 | resolve(value); 204 | }); 205 | }); 206 | } 207 | 208 | function walk(dirPath: string, recursive = true, isDirectory = true): string[] { 209 | let result: string[] = []; 210 | 211 | for (let p of fs.readdirSync(dirPath)) { 212 | let newPath = path.join(dirPath, p); 213 | if (!isDirectory || fs.lstatSync(newPath).isDirectory()) { 214 | result.push(newPath); 215 | if (recursive) { 216 | for (let d of walk(newPath)) { 217 | result.push(d); 218 | } 219 | } 220 | } 221 | } 222 | return result; 223 | } 224 | -------------------------------------------------------------------------------- /icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Layer 1 --------------------------------------------------------------------------------