Skip to content

Commit cd3dbb3

Browse files
committed
Improves performance of blame annotations
1 parent a2a6096 commit cd3dbb3

File tree

5 files changed

+39
-32
lines changed

5 files changed

+39
-32
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
99
- Adds *Checkout Commit (via Terminal)* command (`gitlens.terminalCheckoutCommit`) to commit node(s) of the *GitLens* explorer — closes [#463](https://github.com/eamodio/vscode-gitlens/issues/463)
1010

1111
### Changed
12+
- Improves performance of blame annotation rendering
1213
- Changes commit search by sha to jump directly to the commit (if one is found), rather than having to click through to the commit
1314
- Updates settings descriptions to better support the new settings editor in vscode
1415
- Changes *Rebase to Commit (via Terminal)* command (`gitlens.terminalRebaseCommit`) to apply to all commit node(s) of the *GitLens* explorer

src/annotations/annotations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ export class Annotations {
288288

289289
if (width >= 0) {
290290
// Add the width of the template string (without tokens)
291-
width += Strings.width(Strings.interpolate(format, undefined));
291+
width += Strings.getWidth(Strings.interpolate(format, undefined));
292292
// If we have some width, add a bit of padding
293293
if (width > 0) {
294294
width += 3;

src/annotations/gutterBlameAnnotationProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
6868
before: {
6969
...gutter.renderOptions!.before,
7070
contentText: GlyphChars.Space.repeat(
71-
Strings.width(gutter.renderOptions!.before!.contentText!)
71+
Strings.getWidth(gutter.renderOptions!.before!.contentText!)
7272
)
7373
}
7474
};

src/git/formatters/formatter.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,37 +52,39 @@ export abstract class Formatter<TItem = any, TOptions extends IFormatOptions = I
5252

5353
let max = options.truncateTo;
5454

55-
const width = Strings.width(s);
5655
if (max === undefined) {
5756
if (this.collapsableWhitespace === 0) return s;
5857

58+
const width = Strings.getWidth(s);
59+
5960
// If we have left over whitespace make sure it gets re-added
6061
const diff = this.collapsableWhitespace - width;
6162
this.collapsableWhitespace = 0;
6263

6364
if (diff <= 0) return s;
6465
if (options.truncateTo === undefined) return s;
65-
return Strings.padLeft(s, diff);
66+
return Strings.padLeft(s, diff, undefined, width);
6667
}
6768

6869
max += this.collapsableWhitespace;
6970
this.collapsableWhitespace = 0;
7071

72+
const width = Strings.getWidth(s);
7173
const diff = max - width;
7274
if (diff > 0) {
7375
if (options.collapseWhitespace) {
7476
this.collapsableWhitespace = diff;
7577
}
7678

77-
if (options.padDirection === 'left') return Strings.padLeft(s, max);
79+
if (options.padDirection === 'left') return Strings.padLeft(s, max, undefined, width);
7880

7981
if (options.collapseWhitespace) {
8082
max -= diff;
8183
}
82-
return Strings.padRight(s, max);
84+
return Strings.padRight(s, max, undefined, width);
8385
}
8486

85-
if (diff < 0) return Strings.truncate(s, max);
87+
if (diff < 0) return Strings.truncate(s, max, undefined, width);
8688

8789
return s;
8890
}

src/system/string.ts

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,37 +74,37 @@ export namespace Strings {
7474
return `${before === 0 ? '' : padding.repeat(before)}${s}${after === 0 ? '' : padding.repeat(after)}`;
7575
}
7676

77-
export function padLeft(s: string, padTo: number, padding: string = '\u00a0') {
78-
const diff = padTo - width(s);
77+
export function padLeft(s: string, padTo: number, padding: string = '\u00a0', width?: number) {
78+
const diff = padTo - (width || getWidth(s));
7979
return diff <= 0 ? s : padding.repeat(diff) + s;
8080
}
8181

82-
export function padLeftOrTruncate(s: string, max: number, padding?: string) {
83-
const len = width(s);
84-
if (len < max) return padLeft(s, max, padding);
85-
if (len > max) return truncate(s, max);
82+
export function padLeftOrTruncate(s: string, max: number, padding?: string, width?: number) {
83+
width = width || getWidth(s);
84+
if (width < max) return padLeft(s, max, padding, width);
85+
if (width > max) return truncate(s, max, undefined, width);
8686
return s;
8787
}
8888

89-
export function padRight(s: string, padTo: number, padding: string = '\u00a0') {
90-
const diff = padTo - width(s);
89+
export function padRight(s: string, padTo: number, padding: string = '\u00a0', width?: number) {
90+
const diff = padTo - (width || getWidth(s));
9191
return diff <= 0 ? s : s + padding.repeat(diff);
9292
}
9393

94-
export function padOrTruncate(s: string, max: number, padding?: string) {
94+
export function padOrTruncate(s: string, max: number, padding?: string, width?: number) {
9595
const left = max < 0;
9696
max = Math.abs(max);
9797

98-
const len = width(s);
99-
if (len < max) return left ? padLeft(s, max, padding) : padRight(s, max, padding);
100-
if (len > max) return truncate(s, max);
98+
width = width || getWidth(s);
99+
if (width < max) return left ? padLeft(s, max, padding, width) : padRight(s, max, padding, width);
100+
if (width > max) return truncate(s, max, undefined, width);
101101
return s;
102102
}
103103

104-
export function padRightOrTruncate(s: string, max: number, padding?: string) {
105-
const len = width(s);
106-
if (len < max) return padRight(s, max, padding);
107-
if (len > max) return truncate(s, max);
104+
export function padRightOrTruncate(s: string, max: number, padding?: string, width?: number) {
105+
width = width || getWidth(s);
106+
if (width < max) return padRight(s, max, padding, width);
107+
if (width > max) return truncate(s, max);
108108
return s;
109109
}
110110

@@ -122,18 +122,18 @@ export namespace Strings {
122122
.digest(encoding);
123123
}
124124

125-
export function truncate(s: string, truncateTo: number, ellipsis: string = '\u2026') {
125+
export function truncate(s: string, truncateTo: number, ellipsis: string = '\u2026', width?: number) {
126126
if (!s) return s;
127127

128-
const len = width(s);
129-
if (len <= truncateTo) return s;
130-
if (len === s.length) return `${s.substring(0, truncateTo - 1)}${ellipsis}`;
128+
width = width || getWidth(s);
129+
if (width <= truncateTo) return s;
130+
if (width === s.length) return `${s.substring(0, truncateTo - 1)}${ellipsis}`;
131131

132132
// Skip ahead to start as far as we can by assuming all the double-width characters won't be truncated
133-
let chars = Math.floor(truncateTo / (len / s.length));
134-
let count = width(s.substring(0, chars));
133+
let chars = Math.floor(truncateTo / (width / s.length));
134+
let count = getWidth(s.substring(0, chars));
135135
while (count < truncateTo) {
136-
count += width(s[chars++]);
136+
count += getWidth(s[chars++]);
137137
}
138138

139139
if (count >= truncateTo) {
@@ -144,9 +144,13 @@ export namespace Strings {
144144
}
145145

146146
const ansiRegex = /[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))/g;
147+
const containsNonAsciiRegex = /[^\x20-\x7F\u00a0\u2026]/;
147148

148-
export function width(s: string): number {
149-
if (!s || s.length === 0) return 0;
149+
export function getWidth(s: string): number {
150+
if (s == null || s.length === 0) return 0;
151+
152+
// Shortcut to avoid needless string `RegExp`s, replacements, and allocations
153+
if (!containsNonAsciiRegex.test(s)) return s.length;
150154

151155
s = s.replace(ansiRegex, '');
152156

0 commit comments

Comments
 (0)