Change detection and tracking.

This commit is contained in:
Juha Ristolainen 2017-03-17 11:30:47 +00:00
parent 69f89cc4c4
commit cb048907f3
7 changed files with 181 additions and 49 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
out out
node_modules node_modules
.vscode-test/

View File

@ -11,14 +11,11 @@
"Other" "Other"
], ],
"activationEvents": [ "activationEvents": [
"onCommand:codestats.sayHello" "*"
], ],
"main": "./out/src/code-stats", "main": "./out/src/code-stats",
"contributes": { "contributes": {
"commands": [{ "commands": []
"command": "codestats.sayHello",
"title": "Code::Stats"
}]
}, },
"scripts": { "scripts": {
"vscode:prepublish": "tsc -p ./", "vscode:prepublish": "tsc -p ./",

View File

@ -1,34 +1,17 @@
"use strict"; "use strict";
// the module 'vscode' contains the VS Code extensibility API import { ExtensionContext } from "vscode";
// import the module and reference it with the alias vscode in your code below import { XpCounter } from "./xp-counter";
import * as vscode from "vscode";
// this method is called when your extension is activated export function activate(context: ExtensionContext): void {
// your extension is activated the very first time the command is executed console.log("Activating code-stats-vscode");
export function activate(context: vscode.ExtensionContext) {
// use the console to output diagnostic information (console.log) and errors (console.error) let controller: XpCounter = new XpCounter();
// this line of code will only be executed once when your extension is activated
console.log("Congratulations, your extension \"code-stats-vscode\" is now active!");
// the command has been defined in the package.json file // add to a list of disposables which are disposed when this extension is deactivated.
// now provide the implementation of the command with registerCommand context.subscriptions.push(controller);
// the commandId parameter must match the command field in package.json
let disposable: vscode.Disposable = vscode.commands.registerCommand("codestats.sayHello", () => {
var editor: vscode.TextEditor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
var selection: vscode.Selection = editor.selection;
var text: string = editor.document.getText(selection);
vscode.window.showInformationMessage("Selected characters: " + text.length);
});
context.subscriptions.push(disposable);
} }
// this method is called when your extension is deactivated // this method is called when your extension is deactivated
export function deactivate() { export function deactivate(): void {
} console.log("Deactivating code-stats-vscode");
}

28
src/pulse.ts Normal file
View File

@ -0,0 +1,28 @@
export class Pulse {
xps: Map < string, number > ;
constructor() {
console.log("Creating Pulse");
this.xps = new Map < string, number > ();
}
public getXP(language: string): number {
let xp: number = this.xps.get(language);
if (xp === null || xp === undefined) {
return 0;
} else {
return xp;
}
}
public addXP(language: string, amount: number): void {
let xp: number = this.getXP(language);
xp += amount;
this.xps.set(language, xp);
// console.log(`Added ${amount} of XP to ${language}, total is now ${xp}`);
}
}

20
src/utils.ts Normal file
View File

@ -0,0 +1,20 @@
// converted to ts from https://github.com/Nicd/code-stats-atom/blob/master/lib/utils.js
export function getISOTimestamp(date: Date): string {
const offset: number = -date.getTimezoneOffset();
const prefix: string = (offset >= 0) ? "+" : "-";
function pad(num: number): string {
const norm: number = Math.abs(Math.floor(num));
return ((norm < 10) ? "0" : "") + norm;
}
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
prefix + pad(offset / 60) +
pad(offset % 60);
}

72
src/xp-counter.ts Normal file
View File

@ -0,0 +1,72 @@
import { Disposable, workspace, window, StatusBarItem, TextDocument, StatusBarAlignment, TextDocumentChangeEvent, Range } from "vscode";
import { Pulse } from "./pulse";
export class XpCounter {
private combinedDisposable: Disposable;
private statusBarItem: StatusBarItem;
private pulse: Pulse;
private languages: Array<string> = ["typescript", "javascript"];
private changeCount: number = 0;
constructor() {
console.log(`Supported languages for Code::Stats are ${this.languages}`);
this.pulse = new Pulse();
if (!this.statusBarItem) {
this.statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
}
let subscriptions: Disposable[] = [];
workspace.onDidChangeTextDocument(this.onTextDocumentChanged, this, subscriptions);
this.combinedDisposable = Disposable.from(...subscriptions);
}
dispose(): void {
this.combinedDisposable.dispose();
this.statusBarItem.dispose();
}
private onTextDocumentChanged(event: TextDocumentChangeEvent): void {
let changeCount: number = 0;
for (let change of event.contentChanges) {
changeCount += this.determineChangeCount(change.range);
}
this.updateXpCount(event.document, changeCount);
}
private determineChangeCount(range: Range): number {
if (range === null || range === undefined ) {
return 0;
}
// console.log(`L${range.start.line}C${range.start.character} to L${range.end.line}C${range.end.character}`);
if (range.start.line === range.end.line) {
if (range.start.character === range.end.character) {
return 1;
} else {
console.log(`L${range.start.line}C${range.start.character} to L${range.end.line}C${range.end.character}`);
return range.end.character - range.start.character;
}
}
// todo detect multiline changes
return 1;
}
public updateXpCount(document: TextDocument, changeCount: number): void {
// only update xp if one of supported languages
if (this.isSupportedLanguage(document.languageId)) {
this.pulse.addXP(document.languageId, changeCount);
// this.statusBarItem.text = this.changeCount !== 1 ?
// ` C::S ${this.changeCount} Words` : "$(pencil) C::S 1 Word";
this.statusBarItem.text = `C::S $(pencil) ${this.pulse.getXP(document.languageId)}`;
this.statusBarItem.show();
} else {
this.statusBarItem.hide();
}
}
private isSupportedLanguage(language: string): boolean {
// todo: check supported languages
return true;
}
}

View File

@ -1,22 +1,53 @@
// import * as assert from "assert";
// Note: This example test is leveraging the Mocha test framework.
// Please refer to their documentation on https://mochajs.org/ for help.
//
// The module 'assert' provides assertion methods from node // tslint:disable-next-line:no-unused-variable
import * as assert from 'assert'; import * as vscode from "vscode";
// tslint:disable-next-line:no-unused-variable
import * as codestats from "../src/code-stats";
import { Pulse } from "../src/pulse";
// You can import and use all API from the 'vscode' module suite("code-stats-vscode extension tests", () => {
// as well as import your extension to test it test("Initialized Pulse is empty", () => {
import * as vscode from 'vscode'; let pulse: Pulse = new Pulse();
import * as myExtension from '../src/code-stats'; const language: string = "typescript";
// Defines a Mocha test suite to group tests of similar kind together let initialXP: number = pulse.getXP(language);
suite("Extension Tests", () => {
// Defines a Mocha unit test assert.equal(initialXP, 0);
test("Something 1", () => { });
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0)); test("Add XP to Pulse", () => {
let pulse: Pulse = new Pulse();
const language1: string = "typescript";
const language2: string = "javascript";
const language3: string = "coffeescript";
const addedXP: number = 1000;
let xp1: number = pulse.getXP(language1);
let xp2: number = pulse.getXP(language2);
let xp3: number = pulse.getXP(language3);
assert.equal(xp1, 0);
assert.equal(xp2, 0);
assert.equal(xp3, 0);
pulse.addXP(language1, addedXP);
xp1 = pulse.getXP(language1);
xp2 = pulse.getXP(language2);
xp3 = pulse.getXP(language3);
assert.equal(xp1, addedXP);
assert.equal(xp2, 0);
assert.equal(xp3, 0);
pulse.addXP(language1, addedXP);
pulse.addXP(language2, addedXP);
xp1 = pulse.getXP(language1);
xp2 = pulse.getXP(language2);
xp3 = pulse.getXP(language3);
assert.equal(xp1, 2 * addedXP);
assert.equal(xp2, addedXP);
assert.equal(xp3, 0);
}); });
}); });