diff --git a/package.json b/package.json index 73cd1d4..8404f3d 100644 --- a/package.json +++ b/package.json @@ -1,60 +1,76 @@ { - "name": "ddb50", - "displayName": "CS50 Duck Debugger", - "description": "Provide everyone with their own virtual duck in VS Code. Introduce students to rubber duck debugging, a technique that involves talking to a rubber duck (or any inanimate, or even animate object) about a bug in their code.", - "icon": "images/ddb50.png", - "version": "1.0.6", - "publisher": "CS50", - "repository": "https://github.com/cs50/ddb50.vsix", - "engines": { - "vscode": "^1.59.0" - }, - "categories": [ - "Education" - ], - "activationEvents": [ - "onView:ddb50.debugView" - ], - "main": "./out/extension.js", - "contributes": { - "views": { - "ddb50": [ - { - "id": "ddb50.debugView", - "name": "CS50 Duck Debugger", - "type": "webview" - } - ] + "name": "ddb50", + "displayName": "CS50 Duck Debugger", + "description": "Provide everyone with their own virtual duck in VS Code. Introduce students to rubber duck debugging, a technique that involves talking to a rubber duck (or any inanimate, or even animate object) about a bug in their code.", + "icon": "images/ddb50.png", + "version": "1.1.0", + "publisher": "CS50", + "repository": "https://github.com/cs50/ddb50.vsix", + "engines": { + "vscode": "^1.59.0" }, - "viewsContainers": { - "activitybar": [ - { - "id": "ddb50", - "title": "CS50 Duck Debugger", - "icon": "resources/ddb.svg" + "categories": [ + "Education" + ], + "activationEvents": [ + "onView:ddb50.debugView" + ], + "main": "./out/extension.js", + "contributes": { + "commands": [ + { + "command": "ddb50.clearMessages", + "title": "Clear Messages", + "icon": "$(extensions-refresh)" + } + ], + "views": { + "ddb50": [ + { + "id": "ddb50.debugView", + "name": "CS50 Duck Debugger", + "type": "webview" + } + ] + }, + "viewsContainers": { + "activitybar": [ + { + "id": "ddb50", + "title": "CS50 Duck Debugger", + "icon": "resources/ddb.svg" + } + ] + }, + "menus": { + "view/title": [ + { + "command": "ddb50.clearMessages", + "group": "navigation", + "when": "view == ddb50.debugView" + } + ] } - ] + }, + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./", + "watch": "tsc -watch -p ./", + "pretest": "npm run compile && npm run lint", + "lint": "eslint src --ext ts", + "test": "node ./out/test/runTest.js" + }, + "devDependencies": { + "@types/glob": "^7.1.3", + "@types/mocha": "^8.2.2", + "@types/node": "14.x", + "@types/vscode": "^1.59.0", + "@typescript-eslint/eslint-plugin": "^4.26.0", + "@typescript-eslint/parser": "^4.26.0", + "eslint": "^7.27.0", + "glob": "^7.1.7", + "mocha": "^10.0.0", + "typescript": "^4.4.2", + "vscode-test": "^1.5.2" } - }, - "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./", - "watch": "tsc -watch -p ./", - "pretest": "npm run compile && npm run lint", - "lint": "eslint src --ext ts", - "test": "node ./out/test/runTest.js" - }, - "devDependencies": { - "@types/glob": "^7.1.3", - "@types/mocha": "^8.2.2", - "@types/node": "14.x", - "@types/vscode": "^1.59.0", - "@typescript-eslint/eslint-plugin": "^4.26.0", - "@typescript-eslint/parser": "^4.26.0", - "eslint": "^7.27.0", - "glob": "^7.1.7", - "mocha": "^10.0.0", - "typescript": "^4.4.2", - "vscode-test": "^1.5.2" - } } diff --git a/src/extension.ts b/src/extension.ts index d6a851c..55065e9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,52 +1,61 @@ import * as vscode from 'vscode'; export function activate(context: vscode.ExtensionContext) { - const provider = new DDBViewProvider(context.extensionUri); - context.subscriptions.push( - vscode.window.registerWebviewViewProvider(DDBViewProvider.viewId, provider)); + const provider = new DDBViewProvider(context.extensionUri); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider(DDBViewProvider.viewId, provider)); + + // Command: Clear Messages in the ddb50 chat window + context.subscriptions.push( + vscode.commands.registerCommand('ddb50.clearMessages', () => { + provider.webViewGlobal?.webview.postMessage({ command: 'clearMessages' }); + }) + ); } class DDBViewProvider implements vscode.WebviewViewProvider { - public static readonly viewId = 'ddb50.debugView'; + public static readonly viewId = 'ddb50.debugView'; + public webViewGlobal: vscode.WebviewView | undefined; - constructor( - private readonly _extensionUri: vscode.Uri, - ) {} + constructor( + private readonly _extensionUri: vscode.Uri, + ) { } - public resolveWebviewView( - webviewView: vscode.WebviewView, - _context: vscode.WebviewViewResolveContext, - _token: vscode.CancellationToken, - ) { - webviewView.webview.options = { - enableScripts: true, - localResourceRoots: [this._extensionUri] - }; - webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); - } + public resolveWebviewView( + webviewView: vscode.WebviewView, + _context: vscode.WebviewViewResolveContext, + _token: vscode.CancellationToken, + ) { + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [this._extensionUri] + }; + webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); + this.webViewGlobal = webviewView; + } - private _getHtmlForWebview(webview: vscode.Webview) { - const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'static', 'ddb.js')); - const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'static', 'style.css')); - return ` - - - - - - - - ddb50 - - -
-
-
-
- - - `; - } + private _getHtmlForWebview(webview: vscode.Webview) { + const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'static', 'ddb.js')); + const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'static', 'style.css')); + return ` + + + + + + + + ddb50 + + +
+
+
+
+ + + `; + } } -export function deactivate() {} +export function deactivate() { } diff --git a/static/ddb.js b/static/ddb.js index 8a353cf..8734044 100644 --- a/static/ddb.js +++ b/static/ddb.js @@ -2,6 +2,15 @@ let firstMsg = true; document.addEventListener('DOMContentLoaded', () => { + window.addEventListener('message', event => { + const message = event.data; + switch (message.command) { + case 'clearMessages': + clearMessages(); + break; + } + }); + // Preserve chat for a single session if (localStorage.getItem('msgHistory') === null) { localStorage.setItem('msgHistory', JSON.stringify([])); @@ -21,10 +30,10 @@ document.addEventListener('DOMContentLoaded', () => { textarea.focus(); textarea.addEventListener('keypress', (event) => { if (event.key === 'Enter' && event.target.value) { - addMessage({text: event.target.value}); - event.preventDefault(); - reply(event.target.value); - event.target.value = ''; + addMessage({text: event.target.value}); + event.preventDefault(); + reply(event.target.value); + event.target.value = ''; } }); }); @@ -65,6 +74,10 @@ function addMessage({text, fromDuck}, saveMsg=true) { } } +function clearMessages() { + document.querySelector('#ddbChatText').innerHTML = ''; + localStorage.setItem('msgHistory', JSON.stringify([])); + } function reply(prevMsg) { let reply = "quack ".repeat(1 + getRandomInt(3)).trim();