├── .gitignore ├── .vscodeignore ├── README.md ├── images ├── runner.png └── screenshot.gif ├── package.json ├── renovate.json ├── src └── extension.ts ├── tsconfig.json └── typings ├── fs-extra └── fs-extra.d.ts ├── json-rpc2.d.ts ├── node └── node.d.ts └── vscode-typings.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | 5 | # Icon must end with two \r 6 | Icon 7 | 8 | 9 | # Thumbnails 10 | ._* 11 | 12 | # Files that might appear in the root of a volume 13 | .DocumentRevisions-V100 14 | .fseventsd 15 | .Spotlight-V100 16 | .TemporaryItems 17 | .Trashes 18 | .VolumeIcon.icns 19 | 20 | # Directories potentially created on remote AFP share 21 | .AppleDB 22 | .AppleDesktop 23 | Network Trash Folder 24 | Temporary Items 25 | .apdisk 26 | node_modules 27 | out 28 | .vscode 29 | *.vsix 30 | 31 | # Compiled typescript 32 | src/extension.js 33 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | src/**/* 2 | typings/**/* 3 | .vscode/**/* 4 | tsconfig.json 5 | .gitignore 6 | node_modules/fs-extra 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Runner 2 | 3 | Run various scripts. 4 | 5 | ![](https://raw.githubusercontent.com/mattn/vscode-runner/master/images/screenshot.gif) 6 | 7 | ## Usage 8 | 9 | Type CTRL-SHIFT-R on script files. 10 | 11 | ## Configuration 12 | 13 | Add entry into `runner.languageMap`, keys should be known type on Visual Studio Code. 14 | `runner.extensionMap` matches end of the name of file. 15 | 16 | ```json 17 | { 18 | "runner.languageMap": { 19 | "foo": "/usr/bin/bar" 20 | }, 21 | "runner.extensionMap": { 22 | "foo": "/usr/bin/bar" 23 | }, 24 | "runner.shebangMap": { 25 | "^#!\\s*/usr/bin/python2": "python", 26 | "^#!\\s*/usr/bin/env python": "python", 27 | "^#!\\s*/usr/bin/python3": "python3", 28 | "^#!\\s*/usr/bin/env python3": "python3" 29 | } 30 | } 31 | ``` 32 | 33 | If want to clear previous output, set `"runner.clearPreviousOutput": true`. 34 | want to ignore shebang line, set "runner.ignoreShebang": true`. 35 | 36 | Type CTRL-SHIFT-T to stop the process. 37 | 38 | ## License 39 | 40 | MIT 41 | 42 | ## Author 43 | 44 | Yasuhiro Matsumoto (a.k.a mattn) 45 | -------------------------------------------------------------------------------- /images/runner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/vscode-runner/167fc6f0a82b7516f7937409a5626ee4502bedda/images/runner.png -------------------------------------------------------------------------------- /images/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/vscode-runner/167fc6f0a82b7516f7937409a5626ee4502bedda/images/screenshot.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Runner", 3 | "version": "0.1.16", 4 | "publisher": "mattn", 5 | "description": "Run various scripts.", 6 | "author": { 7 | "name": "Yasuhiro Matsumoto (a.k.a mattn)" 8 | }, 9 | "icon": "images/runner.png", 10 | "categories": [ 11 | "Other", 12 | "Languages" 13 | ], 14 | "license": "MIT", 15 | "private": true, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/mattn/vscode-runner" 19 | }, 20 | "scripts": { 21 | "vscode:prepublish": "node ./node_modules/vscode/bin/compile", 22 | "compile": "node ./node_modules/vscode/bin/compile -watch -p ./" 23 | }, 24 | "dependencies": {}, 25 | "devDependencies": { 26 | "typescript": "1.8.10", 27 | "vscode": "0.11.18" 28 | }, 29 | "engines": { 30 | "vscode": "0.10.x" 31 | }, 32 | "main": "./out/extension", 33 | "extensionDependencies": [], 34 | "activationEvents": [ 35 | "onCommand:extension.runner.start" 36 | ], 37 | "contributes": { 38 | "commands": [ 39 | { 40 | "command": "extension.runner", 41 | "title": "Run", 42 | "description": "Run this file" 43 | } 44 | ], 45 | "keybindings": [ 46 | { 47 | "key": "Ctrl+Shift+r", 48 | "command": "extension.runner.start", 49 | "when": "editorTextFocus" 50 | }, 51 | { 52 | "key": "Ctrl+Shift+t", 53 | "command": "extension.runner.stop" 54 | } 55 | ], 56 | "configuration": { 57 | "type": "object", 58 | "title": "Runner configuration", 59 | "properties": { 60 | "runner.ignoreShebang": { 61 | "type": "boolean", 62 | "default": false, 63 | "description": "Ignore shebang line" 64 | }, 65 | "runner.clearPreviousOutput": { 66 | "type": "boolean", 67 | "default": true, 68 | "description": "Clear Previous Outputs" 69 | }, 70 | "runner.extensionMap": { 71 | "type": "object", 72 | "default": {}, 73 | "description": "Specify file extension as key, specify execuable as value" 74 | }, 75 | "runner.languageMap": { 76 | "type": "object", 77 | "default": {}, 78 | "description": "Specify language name as key, specify execuable as value" 79 | }, 80 | "runner.shebangMap": { 81 | "type": "object", 82 | "default": {}, 83 | "description": "Specify replacement of shebang line" 84 | } 85 | } 86 | } 87 | }, 88 | "readmeFilename": "README.md", 89 | "bugs": { 90 | "url": "https://github.com/mattn/vscode-runner/issues" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import vscode = require('vscode'); 4 | import cp = require('child_process'); 5 | import path = require('path'); 6 | 7 | const win32 = process.platform === 'win32'; 8 | 9 | const defaultExtensionMap = { 10 | coffee: 'coffee' 11 | } 12 | 13 | const defaultLanguageMap = { 14 | bat: '', 15 | clojure: 'clj', 16 | crystal: 'crystal', 17 | go: 'go run', 18 | javascript: 'node', 19 | lua: 'lua', 20 | perl6: 'perl6', 21 | perl: 'perl', 22 | php: 'php', 23 | powershell: 'powershell -noninteractive -noprofile -c -', 24 | python: 'python -u', 25 | r: 'Rscript', 26 | ruby: 'ruby', 27 | shell: 'bash', 28 | typescript: 'tsc' 29 | }; 30 | 31 | function getActionFromFileName(fileName: string): string { 32 | if (!fileName) return null; 33 | var extensionMap = {}; 34 | var userExtensionMap = vscode.workspace.getConfiguration('runner')['extensionMap'] || {}; 35 | for (var key in defaultExtensionMap) { extensionMap[key] = defaultExtensionMap[key]; } 36 | for (var key in userExtensionMap) { extensionMap[key] = userExtensionMap[key]; } 37 | var ids = Object.keys(extensionMap).sort(); 38 | for (var id in ids) { 39 | var ext = ids[id]; 40 | if (fileName.match((ext.match(/^\b/) ? '' : '\\b') + ext + '$')) { 41 | return extensionMap[ext]; 42 | } 43 | } 44 | return null; 45 | } 46 | 47 | function getActionFromShebang(): string { 48 | var ignoreShebang = vscode.workspace.getConfiguration('runner')['ignoreShebang'] || false; 49 | if (ignoreShebang) return null; 50 | var firstLine = vscode.window.activeTextEditor.document.lineAt(0).text; 51 | if (firstLine.match(/^#!\s*(.*)\s*$/)) { 52 | var cmd = RegExp.$1; 53 | var shebangMap = vscode.workspace.getConfiguration('runner')['shebangMap'] || {}; 54 | for (var key in shebangMap) { 55 | try { 56 | if (new RegExp(key).test(firstLine)) return shebangMap[key]; 57 | } catch(e) { } 58 | } 59 | return cmd; 60 | } 61 | return null; 62 | } 63 | 64 | function getActionFromLanguageId(languageId: string): string { 65 | var languageMap = {}; 66 | var userLanguageMap = vscode.workspace.getConfiguration('runner')['languageMap'] || {}; 67 | for (var key in defaultLanguageMap) { languageMap[key] = defaultLanguageMap[key]; } 68 | for (var key in userLanguageMap) { languageMap[key] = userLanguageMap[key]; } 69 | return languageMap[languageId]; 70 | } 71 | 72 | export function activate(ctx: vscode.ExtensionContext): void { 73 | var currentProcess : cp.ChildProcess; 74 | 75 | ctx.subscriptions.push(vscode.commands.registerCommand('extension.runner.stop', () => { 76 | if (currentProcess != null) { 77 | if (win32) 78 | cp.spawn('taskkill', ['/pid', currentProcess.pid.toString(), '/f', '/t']); 79 | else 80 | currentProcess.kill(); 81 | } 82 | })); 83 | ctx.subscriptions.push(vscode.commands.registerCommand('extension.runner.start', () => { 84 | var document = vscode.window.activeTextEditor.document; 85 | var fileName = document.fileName; 86 | var languageId = document.languageId; 87 | 88 | var action = getActionFromShebang(); 89 | if (action == null) action = getActionFromLanguageId(languageId); 90 | if (action == null) action = getActionFromFileName(fileName); 91 | if (action == null) { 92 | vscode.window.showErrorMessage('Not found action for ' + languageId); 93 | return; 94 | } 95 | var cwd = vscode.workspace.rootPath; 96 | if(cwd != null) 97 | fileName = path.relative(cwd, fileName); 98 | fileName = win32 ? fileName : fileName.replace(/ /g, '\\ '); 99 | var fromInput = document.isDirty || document.isUntitled; 100 | 101 | fileName = '\"' + fileName + '\"' 102 | if (action.indexOf('$(file)') != -1) { 103 | action = action.replace(/\$\(file\)/g, fileName); 104 | } else if (!fromInput) { 105 | action += ' ' + fileName; 106 | } 107 | 108 | var output = vscode.window.createOutputChannel('Runner: ' + action + ' ' + fileName); 109 | output.show(vscode.ViewColumn.Two); 110 | setTimeout(() => { 111 | vscode.window.showTextDocument(document) 112 | },50) 113 | // TODO parse line and spawn command without shells. because it's not 114 | // possible to get an error code of execute on windows. 115 | var sh = win32 ? 'cmd' : '/bin/sh'; 116 | var args = win32 ? ['/s', '/c', action] : ['-c', action]; 117 | var opts = { cwd: cwd, detached: false }; 118 | if (win32) opts['windowsVerbatimArguments'] = true; 119 | var child = cp.spawn(sh, args, opts); 120 | currentProcess = child; 121 | 122 | var clearPreviousOutput = vscode.workspace.getConfiguration('runner')['clearPreviousOutput'] && true; 123 | if(clearPreviousOutput) 124 | output.clear() 125 | child.stderr.on('data', (data) => { 126 | output.append(data.toString()); 127 | }); 128 | child.stdout.on('data', (data) => { 129 | output.append(data.toString()); 130 | }); 131 | child.on('close', (code, signal) => { 132 | if (signal) 133 | output.appendLine('Exited with signal ' + signal) 134 | else if (code) 135 | output.appendLine('Exited with status ' + code) 136 | currentProcess = null; 137 | }); 138 | if (fromInput) { 139 | child.stdin.write(document.getText()); 140 | } 141 | child.stdin.end(); 142 | })); 143 | } 144 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "outDir": "out", 5 | "sourceMap": true, 6 | "target": "es5", 7 | "noLib": true 8 | }, 9 | "exclude": [ 10 | "node_modules" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /typings/fs-extra/fs-extra.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for fs-extra 2 | // Project: https://github.com/jprichardson/node-fs-extra 3 | // Definitions by: midknight41 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | // Imported from: https://github.com/soywiz/typescript-node-definitions/fs-extra.d.ts 7 | 8 | /// 9 | 10 | declare module "fs-extra" { 11 | import stream = require("stream"); 12 | 13 | export interface Stats { 14 | isFile(): boolean; 15 | isDirectory(): boolean; 16 | isBlockDevice(): boolean; 17 | isCharacterDevice(): boolean; 18 | isSymbolicLink(): boolean; 19 | isFIFO(): boolean; 20 | isSocket(): boolean; 21 | dev: number; 22 | ino: number; 23 | mode: number; 24 | nlink: number; 25 | uid: number; 26 | gid: number; 27 | rdev: number; 28 | size: number; 29 | blksize: number; 30 | blocks: number; 31 | atime: Date; 32 | mtime: Date; 33 | ctime: Date; 34 | } 35 | 36 | export interface FSWatcher { 37 | close(): void; 38 | } 39 | 40 | export class ReadStream extends stream.Readable { } 41 | export class WriteStream extends stream.Writable { } 42 | 43 | //extended methods 44 | export function copy(src: string, dest: string, callback?: (err: Error) => void): void; 45 | export function copy(src: string, dest: string, filter: (src: string) => boolean, callback?: (err: Error) => void): void; 46 | 47 | export function copySync(src: string, dest: string): void; 48 | export function copySync(src: string, dest: string, filter: (src: string) => boolean): void; 49 | 50 | export function createFile(file: string, callback?: (err: Error) => void): void; 51 | export function createFileSync(file: string): void; 52 | 53 | export function mkdirs(dir: string, callback?: (err: Error) => void): void; 54 | export function mkdirp(dir: string, callback?: (err: Error) => void): void; 55 | export function mkdirs(dir: string, options?: MkdirOptions, callback?: (err: Error) => void): void; 56 | export function mkdirp(dir: string, options?: MkdirOptions, callback?: (err: Error) => void): void; 57 | export function mkdirsSync(dir: string, options?: MkdirOptions): void; 58 | export function mkdirpSync(dir: string, options?: MkdirOptions): void; 59 | 60 | export function outputFile(file: string, data: any, callback?: (err: Error) => void): void; 61 | export function outputFileSync(file: string, data: any): void; 62 | 63 | export function outputJson(file: string, data: any, callback?: (err: Error) => void): void; 64 | export function outputJSON(file: string, data: any, callback?: (err: Error) => void): void; 65 | export function outputJsonSync(file: string, data: any): void; 66 | export function outputJSONSync(file: string, data: any): void; 67 | 68 | export function readJson(file: string, callback?: (err: Error) => void): void; 69 | export function readJson(file: string, options?: OpenOptions, callback?: (err: Error) => void): void; 70 | export function readJSON(file: string, callback?: (err: Error) => void): void; 71 | export function readJSON(file: string, options?: OpenOptions, callback?: (err: Error) => void): void; 72 | 73 | export function readJsonSync(file: string, options?: OpenOptions): void; 74 | export function readJSONSync(file: string, options?: OpenOptions): void; 75 | 76 | export function remove(dir: string, callback?: (err: Error) => void): void; 77 | export function removeSync(dir: string): void; 78 | // export function delete(dir: string, callback?: (err: Error) => void): void; 79 | // export function deleteSync(dir: string): void; 80 | 81 | export function writeJson(file: string, object: any, callback?: (err: Error) => void): void; 82 | export function writeJson(file: string, object: any, options?: OpenOptions, callback?: (err: Error) => void): void; 83 | export function writeJSON(file: string, object: any, callback?: (err: Error) => void): void; 84 | export function writeJSON(file: string, object: any, options?: OpenOptions, callback?: (err: Error) => void): void; 85 | 86 | export function writeJsonSync(file: string, object: any, options?: OpenOptions): void; 87 | export function writeJSONSync(file: string, object: any, options?: OpenOptions): void; 88 | 89 | export function rename(oldPath: string, newPath: string, callback?: (err: Error) => void): void; 90 | export function renameSync(oldPath: string, newPath: string): void; 91 | export function truncate(fd: number, len: number, callback?: (err: Error) => void): void; 92 | export function truncateSync(fd: number, len: number): void; 93 | export function chown(path: string, uid: number, gid: number, callback?: (err: Error) => void): void; 94 | export function chownSync(path: string, uid: number, gid: number): void; 95 | export function fchown(fd: number, uid: number, gid: number, callback?: (err: Error) => void): void; 96 | export function fchownSync(fd: number, uid: number, gid: number): void; 97 | export function lchown(path: string, uid: number, gid: number, callback?: (err: Error) => void): void; 98 | export function lchownSync(path: string, uid: number, gid: number): void; 99 | export function chmod(path: string, mode: number, callback?: (err: Error) => void): void; 100 | export function chmod(path: string, mode: string, callback?: (err: Error) => void): void; 101 | export function chmodSync(path: string, mode: number): void; 102 | export function chmodSync(path: string, mode: string): void; 103 | export function fchmod(fd: number, mode: number, callback?: (err: Error) => void): void; 104 | export function fchmod(fd: number, mode: string, callback?: (err: Error) => void): void; 105 | export function fchmodSync(fd: number, mode: number): void; 106 | export function fchmodSync(fd: number, mode: string): void; 107 | export function lchmod(path: string, mode: string, callback?: (err: Error) => void): void; 108 | export function lchmod(path: string, mode: number, callback?: (err: Error) => void): void; 109 | export function lchmodSync(path: string, mode: number): void; 110 | export function lchmodSync(path: string, mode: string): void; 111 | export function stat(path: string, callback?: (err: Error, stats: Stats) => void): void; 112 | export function lstat(path: string, callback?: (err: Error, stats: Stats) => void): void; 113 | export function fstat(fd: number, callback?: (err: Error, stats: Stats) => void): void; 114 | export function statSync(path: string): Stats; 115 | export function lstatSync(path: string): Stats; 116 | export function fstatSync(fd: number): Stats; 117 | export function link(srcpath: string, dstpath: string, callback?: (err: Error) => void): void; 118 | export function linkSync(srcpath: string, dstpath: string): void; 119 | export function symlink(srcpath: string, dstpath: string, type?: string, callback?: (err: Error) => void): void; 120 | export function symlinkSync(srcpath: string, dstpath: string, type?: string): void; 121 | export function readlink(path: string, callback?: (err: Error, linkString: string) => void): void; 122 | export function realpath(path: string, callback?: (err: Error, resolvedPath: string) => void): void; 123 | export function realpath(path: string, cache: string, callback: (err: Error, resolvedPath: string) => void): void; 124 | export function realpathSync(path: string, cache?: boolean): string; 125 | export function unlink(path: string, callback?: (err: Error) => void): void; 126 | export function unlinkSync(path: string): void; 127 | export function rmdir(path: string, callback?: (err: Error) => void): void; 128 | export function rmdirSync(path: string): void; 129 | export function mkdir(path: string, mode?: number, callback?: (err: Error) => void): void; 130 | export function mkdir(path: string, mode?: string, callback?: (err: Error) => void): void; 131 | export function mkdirSync(path: string, mode?: number): void; 132 | export function mkdirSync(path: string, mode?: string): void; 133 | export function readdir(path: string, callback?: (err: Error, files: string[]) => void ): void; 134 | export function readdirSync(path: string): string[]; 135 | export function close(fd: number, callback?: (err: Error) => void): void; 136 | export function closeSync(fd: number): void; 137 | export function open(path: string, flags: string, mode?: string, callback?: (err: Error, fs: number) => void): void; 138 | export function openSync(path: string, flags: string, mode?: string): number; 139 | export function utimes(path: string, atime: number, mtime: number, callback?: (err: Error) => void): void; 140 | export function utimesSync(path: string, atime: number, mtime: number): void; 141 | export function futimes(fd: number, atime: number, mtime: number, callback?: (err: Error) => void): void; 142 | export function futimesSync(fd: number, atime: number, mtime: number): void; 143 | export function fsync(fd: number, callback?: (err: Error) => void): void; 144 | export function fsyncSync(fd: number): void; 145 | export function write(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error, written: number, buffer: NodeBuffer) => void): void; 146 | export function writeSync(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number): number; 147 | export function read(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error, bytesRead: number, buffer: NodeBuffer) => void ): void; 148 | export function readSync(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number): number; 149 | export function readFile(filename: string, encoding: string, callback: (err: Error, data: string) => void ): void; 150 | export function readFile(filename: string, options: OpenOptions, callback: (err: Error, data: string) => void ): void; 151 | export function readFile(filename: string, callback: (err: Error, data: NodeBuffer) => void ): void; 152 | export function readFileSync(filename: string): NodeBuffer; 153 | export function readFileSync(filename: string, encoding: string): string; 154 | export function readFileSync(filename: string, options: OpenOptions): string; 155 | export function writeFile(filename: string, data: any, encoding?: string, callback?: (err: Error) => void): void; 156 | export function writeFile(filename: string, data: any, options?: OpenOptions, callback?: (err: Error) => void): void; 157 | export function writeFileSync(filename: string, data: any, encoding?: string): void; 158 | export function writeFileSync(filename: string, data: any, option?: OpenOptions): void; 159 | export function appendFile(filename: string, data: any, encoding?: string, callback?: (err: Error) => void): void; 160 | export function appendFile(filename: string, data: any,option?: OpenOptions, callback?: (err: Error) => void): void; 161 | export function appendFileSync(filename: string, data: any, encoding?: string): void; 162 | export function appendFileSync(filename: string, data: any, option?: OpenOptions): void; 163 | export function watchFile(filename: string, listener: { curr: Stats; prev: Stats; }): void; 164 | export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: { curr: Stats; prev: Stats; }): void; 165 | export function unwatchFile(filename: string, listener?: Stats): void; 166 | export function watch(filename: string, options?: { persistent?: boolean; }, listener?: (event: string, filename: string) => any): FSWatcher; 167 | export function exists(path: string, callback?: (exists: boolean) => void ): void; 168 | export function existsSync(path: string): boolean; 169 | export function ensureDir(path: string, cb: (err: Error) => void): void; 170 | 171 | export interface OpenOptions { 172 | encoding?: string; 173 | flag?: string; 174 | } 175 | 176 | export interface MkdirOptions { 177 | fs?: any; 178 | mode?: number; 179 | } 180 | 181 | export interface ReadStreamOptions { 182 | flags?: string; 183 | encoding?: string; 184 | fd?: number; 185 | mode?: number; 186 | bufferSize?: number; 187 | } 188 | export interface WriteStreamOptions { 189 | flags?: string; 190 | encoding?: string; 191 | string?: string; 192 | } 193 | export function createReadStream(path: string, options?: ReadStreamOptions): ReadStream; 194 | export function createWriteStream(path: string, options?: WriteStreamOptions): WriteStream; 195 | } 196 | -------------------------------------------------------------------------------- /typings/json-rpc2.d.ts: -------------------------------------------------------------------------------- 1 | declare module "json-rpc2" { 2 | export interface RPCConnection { 3 | call(command: string, args: any[], callback: (err: Error, result:T) => void): void; 4 | } 5 | 6 | export class Client { 7 | static $create(port: number, addr: string): Client; 8 | connectSocket(callback: (err: Error, conn: RPCConnection) => void): void; 9 | } 10 | } -------------------------------------------------------------------------------- /typings/node/node.d.ts: -------------------------------------------------------------------------------- 1 | /// -------------------------------------------------------------------------------- /typings/vscode-typings.d.ts: -------------------------------------------------------------------------------- 1 | /// --------------------------------------------------------------------------------