Skip to content

Commit 704d7ae

Browse files
authored
Merge pull request #90 from darkriszty/feature/small-perf-improvements
Small perf improvements
2 parents 33743cd + 6c1f9b2 commit 704d7ae

12 files changed

Lines changed: 617 additions & 40 deletions

File tree

.github/workflows/benchmark.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Performance Benchmarks
2+
3+
on:
4+
# Run on pushes to main branches and feature branches with 'perf' in name
5+
push:
6+
branches: [ master, 'feature/*perf*' ]
7+
8+
# Allow manual triggering
9+
workflow_dispatch:
10+
inputs:
11+
reason:
12+
description: 'Reason for running benchmark'
13+
required: false
14+
default: 'Manual benchmark run'
15+
16+
# Run on release
17+
release:
18+
types: [published]
19+
20+
jobs:
21+
benchmark:
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
28+
- name: Use Node.js LTS
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: 'lts/*'
32+
33+
- name: Install dependencies
34+
run: npm ci
35+
36+
- name: Run benchmark
37+
run: |
38+
echo "Starting benchmark run..."
39+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
40+
echo "Reason: ${{ github.event.inputs.reason }}"
41+
fi
42+
xvfb-run -a npm run benchmark

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
out
22
node_modules
33
.vscode-test
4-
*.vsix
4+
*.vsix
5+
benchmark-results-*.json

.vscode/launch.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@
2323
],
2424
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
2525
"preLaunchTask": "compileAndCopyTestResources"
26+
},
27+
{
28+
"name": "Launch Benchmarks",
29+
"type": "extensionHost",
30+
"request": "launch",
31+
"runtimeExecutable": "${execPath}",
32+
"args": [
33+
"--disable-extensions",
34+
"--extensionDevelopmentPath=${workspaceRoot}",
35+
"--extensionTestsPath=${workspaceRoot}/out/test/systemTests/benchmarkRunner.js"
36+
],
37+
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
38+
"preLaunchTask": "compileAndCopyTestResources"
2639
}
2740
]
2841
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[![OVSX](https://img.shields.io/open-vsx/v/darkriszty/markdown-table-prettify?color=success&label=Open%20VSX)](https://open-vsx.org/extension/darkriszty/markdown-table-prettify)
66
[![Docker image](https://img.shields.io/docker/v/darkriszty/prettify-md?color=success&label=Docker)](https://hub.docker.com/r/darkriszty/prettify-md/tags?page=1&ordering=last_updated)
77
[![NPM package](https://img.shields.io/npm/v/markdown-table-prettify?color=success)](https://www.npmjs.com/package/markdown-table-prettify)
8+
[![Benchmarks](https://github.com/darkriszty/MarkdownTablePrettify-VSCodeExt/actions/workflows/benchmark.yml/badge.svg)](https://github.com/darkriszty/MarkdownTablePrettify-VSCodeExt/actions/workflows/benchmark.yml)
89

910
Makes tables more readable for humans. Compatible with the Markdown writer plugin's table formatter feature in Atom.
1011

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"compile": "tsc -p ./",
7979
"pretest": "npm run compile",
8080
"test": "npx gulp copy-systemTest-resources && node ./out/test/index.js",
81+
"benchmark": "npm run compile && npx gulp copy-systemTest-resources && node ./out/test/systemTests/benchmarkTestRunner.js",
8182
"prettify-md": "node ./out/cli/index.js",
8283
"check-md": "node ./out/cli/index.js --check"
8384
},

src/extension/extension.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
'use strict';
22
import * as vscode from 'vscode';
3-
import { getSupportLanguageIds, getDocumentRangePrettyfier, getDocumentPrettyfier, getDocumentPrettyfierCommand } from './prettyfierFactory';
3+
import { getSupportLanguageIds, getDocumentRangePrettyfier, getDocumentPrettyfier, getDocumentPrettyfierCommand, invalidateCache } from './prettyfierFactory';
44

55
// This method is called when the extension is activated.
66
// The extension is activated the very first time the command is executed.
77
export function activate(context: vscode.ExtensionContext): void {
88

9+
// Invalidate cache when configuration changes
10+
context.subscriptions.push(
11+
vscode.workspace.onDidChangeConfiguration(event => {
12+
if (event.affectsConfiguration("markdownTablePrettify")) {
13+
invalidateCache();
14+
}
15+
})
16+
);
17+
918
const supportedLanguageIds = getSupportLanguageIds();
1019
for (let language of supportedLanguageIds) {
1120
context.subscriptions.push(

src/extension/prettyfierFactory.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ import { SingleTablePrettyfier } from '../prettyfiers/singleTablePrettyfier';
2424
import { TableStringWriter } from "../writers/tableStringWriter";
2525
import { ValuePaddingProvider } from '../writers/valuePaddingProvider';
2626

27+
let cachedMultiTablePrettyfier: MultiTablePrettyfier | null = null;
28+
29+
export function invalidateCache() {
30+
cachedMultiTablePrettyfier = null;
31+
}
32+
2733
export function getSupportLanguageIds() {
2834
return [ "markdown", ...getConfigurationValue<Array<string>>("extendedLanguages", []) ];
2935
}
@@ -41,15 +47,21 @@ export function getDocumentPrettyfierCommand(): TableDocumentPrettyfierCommand {
4147
}
4248

4349
function getMultiTablePrettyfier(): MultiTablePrettyfier {
50+
if (cachedMultiTablePrettyfier) {
51+
return cachedMultiTablePrettyfier;
52+
}
53+
4454
const loggers = getLoggers();
4555
const sizeLimitCheker = getSizeLimitChecker(loggers);
4656
const columnPadding: number = getConfigurationValue<number>("columnPadding", 0);
4757

48-
return new MultiTablePrettyfier(
58+
cachedMultiTablePrettyfier = new MultiTablePrettyfier(
4959
new TableFinder(new TableValidator(new SelectionInterpreter(true))),
5060
getSingleTablePrettyfier(loggers, sizeLimitCheker, columnPadding),
5161
sizeLimitCheker
5262
);
63+
64+
return cachedMultiTablePrettyfier;
5365
}
5466

5567
function getSingleTablePrettyfier(loggers: ILogger[], sizeLimitCheker: ConfigSizeLimitChecker, columnPadding: number): SingleTablePrettyfier {

src/padCalculation/padCalculatorSelector.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,41 @@ import * as CenterAlignment from "./center";
66
import { Alignment } from "../models/alignment";
77

88
export class PadCalculatorSelector {
9-
public select(table: Table, column: number) : BasePadCalculator {
9+
private static readonly leftFirstColumn = new LeftAlignment.FirstColumnPadCalculator();
10+
private static readonly leftMiddleColumn = new LeftAlignment.MiddleColumnPadCalculator();
11+
private static readonly leftLastColumn = new LeftAlignment.LastColumnPadCalculator();
12+
13+
private static readonly centerFirstColumn = new CenterAlignment.FirstColumnPadCalculator();
14+
private static readonly centerMiddleColumn = new CenterAlignment.MiddleColumnPadCalculator();
15+
private static readonly centerLastColumn = new CenterAlignment.LastColumnPadCalculator();
16+
17+
private static readonly rightFirstColumn = new RightAlignment.FirstColumnPadCalculator();
18+
private static readonly rightMiddleColumn = new RightAlignment.MiddleColumnPadCalculator();
19+
private static readonly rightLastColumn = new RightAlignment.LastColumnPadCalculator();
20+
21+
public select(table: Table, column: number) : BasePadCalculator {
1022
switch (table.alignments[column]) {
1123
case Alignment.Center: return this.centerAlignmentPadCalculator(table, column);
1224
case Alignment.Right: return this.rightAlignmentPadCalculator(table, column);
1325
default: return this.leftAlignmentPadCalculator(table, column);
1426
}
1527
}
1628

17-
private leftAlignmentPadCalculator(table: Table, column: number) : BasePadCalculator {
18-
if (column == 0) return new LeftAlignment.FirstColumnPadCalculator();
19-
if (column == table.columnCount - 1) return new LeftAlignment.LastColumnPadCalculator();
20-
return new LeftAlignment.MiddleColumnPadCalculator();
29+
private leftAlignmentPadCalculator(table: Table, column: number) : BasePadCalculator {
30+
if (column == 0) return PadCalculatorSelector.leftFirstColumn;
31+
if (column == table.columnCount - 1) return PadCalculatorSelector.leftLastColumn;
32+
return PadCalculatorSelector.leftMiddleColumn;
2133
}
2234

23-
private centerAlignmentPadCalculator(table: Table, column: number) : BasePadCalculator {
24-
if (column == 0) return new CenterAlignment.FirstColumnPadCalculator();
25-
if (column == table.columnCount - 1) return new CenterAlignment.LastColumnPadCalculator();
26-
return new CenterAlignment.MiddleColumnPadCalculator();
35+
private centerAlignmentPadCalculator(table: Table, column: number) : BasePadCalculator {
36+
if (column == 0) return PadCalculatorSelector.centerFirstColumn;
37+
if (column == table.columnCount - 1) return PadCalculatorSelector.centerLastColumn;
38+
return PadCalculatorSelector.centerMiddleColumn;
2739
}
2840

29-
private rightAlignmentPadCalculator(table: Table, column: number) : BasePadCalculator {
30-
if (column == 0) return new RightAlignment.FirstColumnPadCalculator();
31-
if (column == table.columnCount - 1) return new RightAlignment.LastColumnPadCalculator();
32-
return new RightAlignment.MiddleColumnPadCalculator();
41+
private rightAlignmentPadCalculator(table: Table, column: number) : BasePadCalculator {
42+
if (column == 0) return PadCalculatorSelector.rightFirstColumn;
43+
if (column == table.columnCount - 1) return PadCalculatorSelector.rightLastColumn;
44+
return PadCalculatorSelector.rightMiddleColumn;
3345
}
3446
}
Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import { Alignment } from "../../models/alignment";
22
import { IAlignmentMarker, LeftAlignmentMarker, RightAlignmentMarker, CenterAlignmentMarker, NotSetAlignmentMarker } from ".";
33

4-
54
export class AlignmentMarkerStrategy {
6-
constructor(private _markerChar: string) { }
5+
private readonly _leftMarker: IAlignmentMarker;
6+
private readonly _rightMarker: IAlignmentMarker;
7+
private readonly _centerMarker: IAlignmentMarker;
8+
private readonly _notSetMarker: IAlignmentMarker;
9+
10+
constructor(private _markerChar: string) {
11+
this._leftMarker = new LeftAlignmentMarker(this._markerChar);
12+
this._rightMarker = new RightAlignmentMarker(this._markerChar);
13+
this._centerMarker = new CenterAlignmentMarker(this._markerChar);
14+
this._notSetMarker = new NotSetAlignmentMarker();
15+
}
716

817
public markerFor(alignment: Alignment): IAlignmentMarker {
918
switch (alignment) {
10-
case Alignment.Left: return new LeftAlignmentMarker(this._markerChar);
11-
case Alignment.Right: return new RightAlignmentMarker(this._markerChar);
12-
case Alignment.Center: return new CenterAlignmentMarker(this._markerChar);
13-
default: return new NotSetAlignmentMarker();
19+
case Alignment.Left: return this._leftMarker;
20+
case Alignment.Right: return this._rightMarker;
21+
case Alignment.Center: return this._centerMarker;
22+
default: return this._notSetMarker;
1423
}
1524
}
1625
}

src/writers/tableStringWriter.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,36 @@ export class TableStringWriter {
1414
if (table.rows == null) throw new Error("Table rows can't be null.");
1515
if (table.columnCount == 0) throw new Error("Table must have at least one column.");
1616

17-
let buffer = "";
18-
buffer += this.writeRowViewModel(table.header, table, true);
19-
buffer += this.writeRowViewModel(table.separator, table, table.rowCount > 0);
20-
buffer += this.writeRows(table);
17+
const buffer: string[] = [];
18+
buffer.push(this.writeRowViewModel(table.header, table, true));
19+
buffer.push(this.writeRowViewModel(table.separator, table, table.rowCount > 0));
20+
buffer.push(this.writeRows(table));
2121

22-
return buffer;
22+
return buffer.join('');
2323
}
2424

2525
private writeRows(table: TableViewModel): string {
26-
let buffer = "";
26+
const buffer: string[] = [];
2727
for (let row = 0; row < table.rowCount; row++) {
28-
buffer += this.writeRowViewModel(table.rows[row], table, row != table.rowCount - 1);
28+
buffer.push(this.writeRowViewModel(table.rows[row], table, row != table.rowCount - 1));
2929
}
30-
return buffer;
30+
return buffer.join('');
3131
}
3232

3333
private writeRowViewModel(row: RowViewModel, table: TableViewModel, addEndOfLine: boolean): string {
34-
let buffer = "";
35-
buffer += table.leftPad;
36-
buffer += this.getLeftBorderIfNeeded(table);
34+
const buffer: string[] = [];
35+
buffer.push(table.leftPad);
36+
buffer.push(this.getLeftBorderIfNeeded(table));
3737
for (let col = 0; col < table.columnCount; col++) {
38-
buffer += this._valuePaddingProvider.getLeftPadding();
39-
buffer += row.getValueAt(col);
40-
buffer += this._valuePaddingProvider.getRightPadding(table, col);
41-
buffer += this.getSeparatorIfNeeded(table, col);
38+
buffer.push(this._valuePaddingProvider.getLeftPadding());
39+
buffer.push(row.getValueAt(col));
40+
buffer.push(this._valuePaddingProvider.getRightPadding(table, col));
41+
buffer.push(this.getSeparatorIfNeeded(table, col));
4242
}
43-
buffer += this.getRightBorderIfNeeded(table);
43+
buffer.push(this.getRightBorderIfNeeded(table));
4444
if (addEndOfLine)
45-
buffer += row.EOL;
46-
return buffer;
45+
buffer.push(row.EOL);
46+
return buffer.join('');
4747
}
4848

4949
private getSeparatorIfNeeded(table: TableViewModel, currentColumn: number): string {

0 commit comments

Comments
 (0)