├── .gitignore ├── images ├── banner.jpg ├── icon.png ├── slowbug_demo.gif ├── pause_icon_dark.png ├── pause_icon_light.png ├── slow_icon_dark.png └── slow_icon_light.png ├── src ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts └── extension.ts ├── tsconfig.json ├── LICENSE ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | out 4 | .DS_Store 5 | *.vsix -------------------------------------------------------------------------------- /images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/banner.jpg -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/icon.png -------------------------------------------------------------------------------- /images/slowbug_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/slowbug_demo.gif -------------------------------------------------------------------------------- /images/pause_icon_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/pause_icon_dark.png -------------------------------------------------------------------------------- /images/pause_icon_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/pause_icon_light.png -------------------------------------------------------------------------------- /images/slow_icon_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/slow_icon_dark.png -------------------------------------------------------------------------------- /images/slow_icon_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postmalloc/slowbug/HEAD/images/slow_icon_light.png -------------------------------------------------------------------------------- /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.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Srimukh Sripada 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 | # slowbug 2 | 3 | 4 | Slowbug is a VS Code extension for debugging your code in slow-mo! 5 | 6 | ## What? 7 | The idea is simple. Make it possible to see how the control 8 | flows through the code. I noticed that often, I end up inserting 9 | too many breakpoints, and find it tedious to step through and 10 | understand the flow when working on a new codebase. Slowbug aims 11 | to solve that by executing the code slowly, at your preferred speed, 12 | line by line. 13 | 14 | Slowbug is agnostic to languages and debug adapters since it 15 | issues commands directly to the VS Code workbench. 16 | 17 | ## Usage 18 | 19 | 20 | You can install [Slowbug](https://marketplace.visualstudio.com/items?itemName=srimukh.slowbug) from VS Code Marketplace. 21 | 22 | Since Slowbug does not rely on any specific debuggers, it does not automatically 23 | generate a `launch.json` for you. Make sure you add `"stopOnEntry": true` 24 | property under your debugger in `launch.json` before you run Slowbug. 25 | 26 | To launch Slowbug, press the slowmo play button. Slowbug starts stepping through 27 | the code at a default pace of 800ms. The speed can be configured in 28 | `settings > Slowbug > stepDuration`. The pause button pauses the debugger. 29 | Resume it by pressing the slow-mo play button. Slowbug steps _into_ function calls. 30 | However, it only steps into your code, and ignores third-party libraries. 31 | 32 | The functionality right now is minimal. 33 | 34 | 35 | ## Upcoming features 36 | * Range selection 37 | Ability to select a code block and enable Slowbug only there. 38 | * Better controls 39 | 40 | 41 | ## Contributing 42 | You're welcome to add features and raise issues. 43 | 44 | ## License 45 | MIT License -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | /* Wrap the vanilla `setInterval` to handle 4 | clearing of all timers. Makes pause/resume experience 5 | more predictable. */ 6 | let setIntervalMod = (function(oldsetInterval){ 7 | const timers: NodeJS.Timeout[] = []; 8 | let f: any = function(a: () => any, b: number){ 9 | return timers[timers.length] = oldsetInterval(a,b); 10 | }; 11 | f.clearAll = function(){ 12 | let r; 13 | while(r = timers.pop()) { 14 | clearInterval( r ); 15 | } 16 | }; 17 | return f; 18 | })(setInterval); 19 | 20 | 21 | export function activate(context: vscode.ExtensionContext) { 22 | // Read the stepDuration from the settings 23 | let stepDuration = vscode.workspace.getConfiguration('slowbug').stepDuration; 24 | 25 | function stepFn() { 26 | vscode.commands.executeCommand("workbench.action.debug.stepInto"); 27 | } 28 | 29 | function startFn() { 30 | // Check if there is an active debug session. If not, start debugging 31 | // and start the timers 32 | if (vscode.debug.activeDebugSession == undefined) { 33 | stepDuration = vscode.workspace.getConfiguration('slowbug').stepDuration; 34 | vscode.commands.executeCommand("workbench.action.debug.start"); 35 | if (context.globalState.get('timerId') == undefined) { 36 | // Wait until the session is ready before you start the timer 37 | vscode.debug.onDidStartDebugSession(() => { 38 | setIntervalMod(stepFn, stepDuration); 39 | }); 40 | } 41 | } else { 42 | // If already debugging, just create a new timer 43 | setIntervalMod(stepFn, stepDuration); 44 | } 45 | } 46 | 47 | // Clear the timers on debug end 48 | vscode.debug.onDidTerminateDebugSession(() => { 49 | setIntervalMod.clearAll(); 50 | }); 51 | 52 | // Fn to pause the debugger and clear the current timer 53 | function pauseFn() { 54 | vscode.commands.executeCommand("workbench.action.debug.pause"); 55 | process.nextTick(() => setIntervalMod.clearAll()); 56 | } 57 | 58 | const startCmd = vscode.commands.registerCommand('extension.slowbug-start', startFn); 59 | const pauseCmd = vscode.commands.registerCommand('extension.slowbug-pause', pauseFn); 60 | 61 | context.subscriptions.push(startCmd, pauseCmd); 62 | } 63 | 64 | export function deactivate() { } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slowbug", 3 | "publisher": "srimukh", 4 | "displayName": "Slowbug - Debug your code in slow-mo!", 5 | "description": "Slowbug is a VS Code extension for debugging your code in slow-mo.", 6 | "version": "1.0.7", 7 | "icon": "images/icon.png", 8 | "engines": { 9 | "vscode": "^1.52.0" 10 | }, 11 | "categories": [ 12 | "Debuggers", 13 | "Other" 14 | ], 15 | "keywords": [ 16 | "debug", 17 | "controls", 18 | "visualization", 19 | "slow" 20 | ], 21 | "activationEvents": [ 22 | "onCommand:extension.slowbug-start", 23 | "onCommand:extension.slowbug-pause" 24 | ], 25 | "main": "./out/extension.js", 26 | "contributes": { 27 | "commands": [ 28 | { 29 | "command": "extension.slowbug-start", 30 | "title": "Start Slowbug", 31 | "category": "Slowbug", 32 | "icon": { 33 | "dark": "images/slow_icon_dark.png", 34 | "light": "images/slow_icon_light.png" 35 | } 36 | }, 37 | { 38 | "command": "extension.slowbug-pause", 39 | "title": "Pause Slowbug", 40 | "category": "Slowbug", 41 | "icon": { 42 | "dark": "images/pause_icon_dark.png", 43 | "light": "images/pause_icon_light.png" 44 | } 45 | } 46 | ], 47 | "menus": { 48 | "editor/title": [ 49 | { 50 | "when": "true", 51 | "command": "extension.slowbug-start", 52 | "group": "navigation@420" 53 | }, 54 | { 55 | "when": "true", 56 | "command": "extension.slowbug-pause", 57 | "group": "navigation@421" 58 | } 59 | ] 60 | }, 61 | "configuration": { 62 | "title": "Slowbug", 63 | "properties": { 64 | "slowbug.stepDuration": { 65 | "type": "integer", 66 | "default": 800, 67 | "description": "Duration of each step (in milliseconds)" 68 | } 69 | } 70 | } 71 | }, 72 | "scripts": { 73 | "vscode:prepublish": "npm run compile", 74 | "compile": "tsc -p ./", 75 | "watch": "tsc -watch -p ./", 76 | "pretest": "npm run compile && npm run lint", 77 | "lint": "eslint src --ext ts", 78 | "test": "node ./out/test/runTest.js" 79 | }, 80 | "devDependencies": { 81 | "@types/glob": "^7.1.3", 82 | "@types/mocha": "^8.0.4", 83 | "@types/node": "^12.11.7", 84 | "@types/vscode": "^1.52.0", 85 | "@typescript-eslint/eslint-plugin": "^4.9.0", 86 | "@typescript-eslint/parser": "^4.9.0", 87 | "eslint": "^7.15.0", 88 | "glob": "^7.1.6", 89 | "mocha": "^8.1.3", 90 | "typescript": "^4.1.2", 91 | "vscode-test": "^1.4.1" 92 | }, 93 | "repository": "https://github.com/postmalloc/slowbug.git" 94 | } 95 | --------------------------------------------------------------------------------