Skip to content

Commit

Permalink
feat: support for output outside the workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
uctakeoff committed Jul 31, 2024
1 parent bc8273c commit c45cf92
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 34 deletions.
1 change: 0 additions & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
.VSCodeCounter/**
out/test/**
src/**
.gitignore
vsc-extension-quickstart.md
**/tsconfig.json
**/tslint.json
Expand Down
Binary file added src.zip
Binary file not shown.
37 changes: 18 additions & 19 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as path from 'path';
import { Count } from './LineCounter';
import { LanguageConf, LineCounterTable } from './LineCounterTable';
import Gitignore from './Gitignore';
import { buildUri, createTextDecoder, currentWorkspaceFolder, dirUri, makeDirectories, parseUriOrFile, readJsonFile, readUtf8Files, showTextPreview, writeTextFile } from './vscode-utils';
import { buildUri, createTextDecoder, currentWorkspaceFolder, dirUri, makeDirectories, readJsonFile, readUtf8Files, showTextPreview, writeTextFile } from './vscode-utils';
import { internalDefinitions } from './internalDefinitions';

const EXTENSION_ID = 'uctakeoff.vscode-counter';
Expand Down Expand Up @@ -119,10 +119,9 @@ class CodeCounterController {
// create a combined disposable from both event subscriptions
this.disposable = vscode.Disposable.from(...subscriptions);

currentWorkspaceFolder().then((workFolder) => {
vscode.workspace.fs.stat(buildUri(workFolder.uri, this.conf.outputDirectory, REALTIME_COUNTER_FILE))
.then(() => this.toggleVisible(), log);
});
currentWorkspaceFolder()
.then((workFolder) => vscode.workspace.fs.stat(buildUri(workFolder.uri, this.conf.outputDirectory, REALTIME_COUNTER_FILE)))
.then(() => this.toggleVisible(), log);
}
dispose() {
this.statusBarItem?.dispose();
Expand Down Expand Up @@ -259,9 +258,9 @@ class CodeCounterController {
.filter(d => ((d[1] & vscode.FileType.Directory) != 0) && regex.test(d[0]))
.map(d => d[0])
.sort()
.map(d => buildUri(outputDir, d));
.map(d => vscode.Uri.joinPath(outputDir, d));

const outSubdir = buildUri(outputDir, toLocalDateString(date, ['-', '_', '-']));
const outSubdir = vscode.Uri.joinPath(outputDir, toLocalDateString(date, ['-', '_', '-']));
await outputResults(date, targetUri, results, outSubdir, histories[histories.length - 1], this.conf);

if (histories.length >= this.conf.history) {
Expand Down Expand Up @@ -423,7 +422,7 @@ const collectLanguageConfigurations = (langs: Map<string, LanguageConf>): Promis
const langExt = append(langs, l.id, l);
if (l.configuration) {
const confUrl = vscode.Uri.file(path.join(ex.extensionPath, l.configuration));
const langConf = await readJsonFile<VscodeLanguageConfiguration>(confUrl, undefined, {});
const langConf = await readJsonFile<VscodeLanguageConfiguration>(confUrl, {});
// log(`"${confUrl.fsPath}" :${l.id}\n aliases:${l.aliases}\n extensions:${l.extensions}\n filenames:${l.filenames}`, l);
if (langConf.comments) {
if (langConf.comments.lineComment) {
Expand Down Expand Up @@ -470,7 +469,7 @@ const saveLanguageConfigurations = async (langs: { [key: string]: LanguageConf }
}
case "use languageConfUri":{
const workFolder = await currentWorkspaceFolder();
await writeTextFile(parseUriOrFile(conf.languageConfUri, workFolder.uri), JSON.stringify(langs), {recursive: true});
await writeTextFile(buildUri(workFolder.uri, conf.languageConfUri), JSON.stringify(langs), {recursive: true});
break;
}
default: break;
Expand All @@ -486,10 +485,10 @@ const loadLanguageConfigurations = async (conf: Config): Promise<{ [key: string]
case "output directory":
const workFolder = await currentWorkspaceFolder();
const outputDir = buildUri(workFolder.uri, conf.outputDirectory);
return await readJsonFile<{ [key: string]: Partial<LanguageConf> }>(outputDir, 'languages.json', {});
return await readJsonFile<{ [key: string]: Partial<LanguageConf> }>(vscode.Uri.joinPath(outputDir, 'languages.json'), {});
case "use languageConfUri":{
const workFolder = await currentWorkspaceFolder();
return await readJsonFile<{ [key: string]: Partial<LanguageConf> }>(parseUriOrFile(conf.languageConfUri, workFolder.uri), undefined, {});
return await readJsonFile<{ [key: string]: Partial<LanguageConf> }>(buildUri(workFolder.uri, conf.languageConfUri), {});
}
default: break;
}
Expand All @@ -509,15 +508,15 @@ const previewFiles = new Map<string, string>([
]);
const outputResults = async (date: Date, targetDirUri: vscode.Uri, results: Result[], outputDir: vscode.Uri, prevOutputDir: vscode.Uri | undefined, conf: Config) => {
await makeDirectories(outputDir);
writeTextFile(buildUri(outputDir, `results.json`), resultsToJson(results));
writeTextFile(vscode.Uri.joinPath(outputDir, `results.json`), resultsToJson(results));

const resultTable = new ResultFormatter(targetDirUri, results, conf);
log(`OutputDir : ${outputDir}, count ${results.length} files`);

const diffs: Result[] = [];
if (prevOutputDir) {
try {
const prevResults = await readJsonFile<{ [uri: string]: Count & { language: string } }>(prevOutputDir, 'results.json', {});
const prevResults = await readJsonFile<{ [uri: string]: Count & { language: string } }>(vscode.Uri.joinPath(prevOutputDir, 'results.json'), {});
log(`Previous OutputDir : ${prevOutputDir}, count ${Object.keys(prevResults).length} files`);
results.forEach(r => {
const p = prevResults[r.uri.toString()];
Expand All @@ -542,12 +541,12 @@ const outputResults = async (date: Date, targetDirUri: vscode.Uri, results: Resu
const diffTable = new ResultFormatter(targetDirUri, diffs, conf);

if (conf.outputAsText) {
await writeTextFile(buildUri(outputDir, 'results.txt'), resultTable.toTextLines(date));
await writeTextFile(buildUri(outputDir, 'diff.txt'), diffTable.toTextLines(date));
await writeTextFile(vscode.Uri.joinPath(outputDir, 'results.txt'), resultTable.toTextLines(date));
await writeTextFile(vscode.Uri.joinPath(outputDir, 'diff.txt'), diffTable.toTextLines(date));
}
if (conf.outputAsCSV) {
await writeTextFile(buildUri(outputDir, 'results.csv'), resultTable.toCSVLines());
await writeTextFile(buildUri(outputDir, 'diff.csv'), diffTable.toCSVLines());
await writeTextFile(vscode.Uri.joinPath(outputDir, 'results.csv'), resultTable.toCSVLines());
await writeTextFile(vscode.Uri.joinPath(outputDir, 'diff.csv'), diffTable.toCSVLines());
}
if (conf.outputAsMarkdown) {
const mds = [
Expand All @@ -557,12 +556,12 @@ const outputResults = async (date: Date, targetDirUri: vscode.Uri, results: Resu
{ title: 'Diff Details', path: 'diff-details.md', table: diffTable, detail: true },
];
await Promise.all(mds.map(({ title, path, table, detail }, index) => {
return writeTextFile(buildUri(outputDir, path), table.toMarkdown(date, title, detail, mds.map((f, i) => [f.title, i === index ? undefined : f.path])));
return writeTextFile(vscode.Uri.joinPath(outputDir, path), table.toMarkdown(date, title, detail, mds.map((f, i) => [f.title, i === index ? undefined : f.path])));
}));
}
const previewFile = previewFiles.get(conf.outputPreviewType);
if (previewFile) {
showTextPreview(buildUri(outputDir, previewFile));
showTextPreview(vscode.Uri.joinPath(outputDir, previewFile));
}
}

Expand Down
23 changes: 23 additions & 0 deletions src/test/runTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as path from 'path';

import { runTests } from 'vscode-test';

async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../');

// The path to test runner
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index');

// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.error('Failed to run tests');
process.exit(1);
}
}

main();
18 changes: 18 additions & 0 deletions src/test/suite/Gitignore.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as assert from 'assert';
import * as mocha from 'mocha'; //①

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
import Gitignore from '../../Gitignore';

mocha.describe('Extension Test Suite', () => { //①
before(() => {
vscode.window.showInformationMessage('Start all tests.');
});

it('Sample test', () => { //①
const g = new Gitignore(`**/logs`);
assert.ok(g.includes('logs/debug.log'));
});
});
15 changes: 15 additions & 0 deletions src/test/suite/extension.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as assert from 'assert';

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../extension';

suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');

test('Sample test', () => {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});
37 changes: 37 additions & 0 deletions src/test/suite/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as path from 'path';
import * as Mocha from 'mocha';
import * as glob from 'glob';

export function run(): Promise<void> {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
});
// mocha.useColors(true);

const testsRoot = path.resolve(__dirname, '..');

return new Promise((c, e) => {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}

// Add files to the test suite
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));

try {
// Run the mocha test
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
e(err);
}
});
});
}
29 changes: 15 additions & 14 deletions src/vscode-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ export const currentWorkspaceFolder = async () => {
throw Error('workspace not open.');
}

export const buildUri = (uri: vscode.Uri, ...names: string[]) => uri.with({ path: `${uri.path}/${names.join('/')}` });
export const dirUri = (uri: vscode.Uri) => uri.with({ path: path.dirname(uri.path) });
export const parseUriOrFile = (uriOrFileath: string, baseUri?: vscode.Uri) => {
const u = vscode.Uri.parse(uriOrFileath);
// log(uriOrFileath, u.toString(), path.isAbsolute(uriOrFileath), baseUri?.toString(), buildUri(baseUri??u, uriOrFileath).fsPath, (!baseUri || path.isAbsolute(uriOrFileath)));
return uriOrFileath.startsWith(u.scheme + ':/') ? u
: (!baseUri || path.isAbsolute(uriOrFileath)) ? vscode.Uri.file(uriOrFileath)
: buildUri(baseUri, uriOrFileath);
export const buildUri = (uri: vscode.Uri, ...uriOrPaths: string[]) => {
return uriOrPaths.reduce((baseUri, uriOrPath) => {
const u = vscode.Uri.parse(uriOrPath);
// log('buildUri', uriOrPath, u.toString(), path.isAbsolute(uriOrPath), baseUri?.toString(), vscode.Uri.joinPath(baseUri??u, uriOrPath).fsPath, (!baseUri || path.isAbsolute(uriOrPath)));
return uriOrPath.startsWith(u.scheme + ':/') ? u
: (!baseUri || path.isAbsolute(uriOrPath)) ? vscode.Uri.file(uriOrPath)
: vscode.Uri.joinPath(baseUri, uriOrPath);
}, uri);
}
export const dirUri = (uri: vscode.Uri) => uri.with({ path: path.dirname(uri.path) });

const decoderU8 = new TextDecoder('utf8');
const encoderU8 = new TextEncoder();

Expand Down Expand Up @@ -80,15 +82,14 @@ const vscodeEncodingTable = new Map<string, string>([

export const createTextDecoder = (vscodeTextEncoding: string) => new TextDecoder(vscodeEncodingTable.get(vscodeTextEncoding) || vscodeTextEncoding);

export const readUtf8File = async (baseUri: vscode.Uri, path?: string): Promise<{ uri: vscode.Uri, data: string, error?: any }> => {
const uri = path ? buildUri(baseUri, path) : baseUri;
export const readUtf8File = async (uri: vscode.Uri): Promise<{ uri: vscode.Uri, data: string, error?: any }> => {
try {
const bin = await vscode.workspace.fs.readFile(uri);
// log(`read ${uri} : ${bin.length}B`);
const data = decoderU8.decode(bin);
return {uri, data};
} catch (error: any) {
log(`readUtf8File(${baseUri}, ${path}) failed. : ${error}`);
log(`readUtf8File(${uri}) failed. : ${error}`);
return { uri, data: '', error };
}
}
Expand All @@ -111,14 +112,14 @@ export const checkJsonType = <T extends boolean | number | string | Array<any> |
return defaultValue;
}

export const readJsonFile = async <T extends boolean | number | string | Array<any> | { [key: string]: any }>(baseUri: vscode.Uri, path: string | undefined, defaultValue: T): Promise<T> => {
export const readJsonFile = async <T extends boolean | number | string | Array<any> | { [key: string]: any }>(uri: vscode.Uri, defaultValue: T): Promise<T> => {
try {
const text = await readUtf8File(baseUri, path);
const text = await readUtf8File(uri);
if (text.error) return defaultValue;
const json = JSONC.parse(text.data);
return checkJsonType(json, defaultValue);
} catch (e: any) {
log(`readJsonFile(${baseUri}, ${path}) failed. : ${e}`);
log(`readJsonFile(${uri}) failed. : ${e}`);
}
return defaultValue;
}
Expand Down

0 comments on commit c45cf92

Please sign in to comment.