Ver código fonte

Closes #146 - Attempts to deal with emoji in gutter

Adds ability to automagically set the width of the gutter annotations
main
Eric Amodio 7 anos atrás
pai
commit
70071448d6
7 arquivos alterados com 137 adições e 51 exclusões
  1. +5
    -4
      CHANGELOG.md
  2. +0
    -27
      package-lock.json
  3. +0
    -1
      package.json
  4. +18
    -3
      src/annotations/annotations.ts
  5. +2
    -2
      src/annotations/gutterBlameAnnotationProvider.ts
  6. +1
    -1
      src/git/formatters/formatter.ts
  7. +111
    -13
      src/system/string.ts

+ 5
- 4
CHANGELOG.md Ver arquivo

@ -6,17 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [Unreleased]
## [5.1.1-beta]
## [5.2.0-beta]
### Added
- Adds new `Changed Files` node to the `Repository Status` node of the `GitLens` custom view's `Repository View` (enabled via `"gitlens.insiders": true`) -- closes [#139](https://github.com/eamodio/vscode-gitlens/issues/139)
- Provides a file-based view of all the changed files in the working tree and/or files in commits that haven't yet been pushed upstream
- Adds new `Changed Files` node to the `Repository Status` node of the `GitLens` custom view's `Repository View` -- closes [#139](https://github.com/eamodio/vscode-gitlens/issues/139)
- Provides a file-based view of all the changed files in the working tree (enabled via `"gitlens.insiders": true`) and/or files in commits that haven't yet been pushed upstream
- Adds `gitlens.gitExplorer.enabled` setting to specify whether or not to show the `GitLens` custom view - closes [#144](https://github.com/eamodio/vscode-gitlens/issues/144)
### Changed
- Chnages the default of the `gitlens.gitExplorer.commitFormat` setting to add parentheses around the commit id
- Changes the default of the `gitlens.gitExplorer.commitFormat` setting to add parentheses around the commit id
- Removes many menu items from `editor/title` & `editor/title/context` by default -- can be re-enabled via the `gitlens.advanced.menus` setting
### Fixed
- Fixes [#146](https://github.com/eamodio/vscode-gitlens/issues/146) - Blame gutter annotation issue when commit contains emoji
- Fixes an issue when running `Open File in Remote` with a multi-line selection wasn't properly opening the selection in GitLab -- thanks to [PR #145](https://github.com/eamodio/vscode-gitlens/pull/145) by Amanda Cameron ([@AmandaCameron](https://github.com/AmandaCameron))!
- Fixes an issue where the `gitlens.advanced.menus` setting wasn't controlling all the menu items properly

+ 0
- 27
package-lock.json Ver arquivo

@ -47,11 +47,6 @@
"json-stable-stringify": "1.0.1"
}
},
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
@ -1336,11 +1331,6 @@
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
@ -2334,15 +2324,6 @@
"integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=",
"dev": true
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "2.0.0",
"strip-ansi": "4.0.0"
}
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
@ -2358,14 +2339,6 @@
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
"dev": true
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "3.0.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",

+ 0
- 1
package.json Ver arquivo

@ -1921,7 +1921,6 @@
"lodash.once": "4.1.1",
"moment": "2.18.1",
"spawn-rx": "2.0.11",
"string-width": "2.1.1",
"tmp": "0.0.33"
},
"devDependencies": {

+ 18
- 3
src/annotations/annotations.ts Ver arquivo

@ -1,4 +1,4 @@
import { Dates, Strings } from '../system';
import { Dates, Objects, Strings } from '../system';
import { DecorationInstanceRenderOptions, DecorationOptions, MarkdownString, ThemableDecorationRenderOptions } from 'vscode';
import { DiffWithCommand, OpenCommitInRemoteCommand, ShowQuickCommitDetailsCommand } from '../commands';
import { IThemeConfig, themeDefaults } from '../configuration';
@ -133,9 +133,23 @@ export class Annotations {
} as DecorationOptions;
}
static gutterRenderOptions(cfgTheme: IThemeConfig, heatmap: IHeatmapConfig): IRenderOptions {
static gutterRenderOptions(cfgTheme: IThemeConfig, heatmap: IHeatmapConfig, options: ICommitFormatOptions): IRenderOptions {
const cfgFileTheme = cfgTheme.annotations.file.gutter;
// Try to get the width of the string, if there is a cap
let width = 4; // Start with a padding
for (const token of Objects.values<Strings.ITokenOptions | undefined>(options.tokenOptions)) {
if (token === undefined) continue;
// If any token is uncapped, kick out and set no max
if (token.truncateTo == null) {
width = 0;
break;
}
width += token.truncateTo;
}
let borderStyle = undefined;
let borderWidth = undefined;
if (heatmap.enabled) {
@ -152,7 +166,8 @@ export class Annotations {
borderStyle: borderStyle,
borderWidth: borderWidth,
height: '100%',
margin: '0 26px -1px 0'
margin: '0 26px -1px 0',
width: (width > 4) ? `${width}ch` : undefined
},
dark: {
backgroundColor: cfgFileTheme.dark.backgroundColor || undefined,

+ 2
- 2
src/annotations/gutterBlameAnnotationProvider.ts Ver arquivo

@ -34,7 +34,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
const now = Date.now();
const offset = this.uri.offset;
const renderOptions = Annotations.gutterRenderOptions(this._config.theme, cfg.heatmap);
const renderOptions = Annotations.gutterRenderOptions(this._config.theme, cfg.heatmap, options);
const separateLines = this._config.theme.annotations.file.gutter.separateLines;
const decorations: DecorationOptions[] = [];
@ -58,7 +58,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
...gutter.renderOptions,
before: {
...gutter.renderOptions!.before,
contentText: GlyphChars.Space.repeat(Strings.getWidth(gutter.renderOptions!.before!.contentText!))
contentText: GlyphChars.Space.repeat(Strings.width(gutter.renderOptions!.before!.contentText!))
}
};

+ 1
- 1
src/git/formatters/formatter.ts Ver arquivo

@ -51,7 +51,7 @@ export abstract class Formatter
let max = options.truncateTo;
const width = Strings.getWidth(s);
const width = Strings.width(s);
if (max === undefined) {
if (this.collapsableWhitespace === 0) return s;

+ 111
- 13
src/system/string.ts Ver arquivo

@ -1,16 +1,11 @@
'use strict';
const _escapeRegExp = require('lodash.escaperegexp');
const stringWidth = require('string-width');
export namespace Strings {
export function escapeRegExp(s: string): string {
return _escapeRegExp(s);
}
export function getWidth(s: string): number {
return stringWidth(s);
}
const TokenRegex = /\$\{([^|]*?)(?:\|(\d+)(\-|\?)?)?\}/g;
const TokenSanitizeRegex = /\$\{(\w*?)(?:\W|\d)*?\}/g;
@ -68,19 +63,19 @@ export namespace Strings {
}
export function padLeft(s: string, padTo: number, padding: string = '\u00a0') {
const diff = padTo - getWidth(s);
const diff = padTo - width(s);
return (diff <= 0) ? s : '\u00a0'.repeat(diff) + s;
}
export function padLeftOrTruncate(s: string, max: number, padding?: string) {
const len = getWidth(s);
const len = width(s);
if (len < max) return padLeft(s, max, padding);
if (len > max) return truncate(s, max);
return s;
}
export function padRight(s: string, padTo: number, padding: string = '\u00a0') {
const diff = padTo - getWidth(s);
const diff = padTo - width(s);
return (diff <= 0) ? s : s + '\u00a0'.repeat(diff);
}
@ -88,14 +83,14 @@ export namespace Strings {
const left = max < 0;
max = Math.abs(max);
const len = getWidth(s);
const len = width(s);
if (len < max) return left ? padLeft(s, max, padding) : padRight(s, max, padding);
if (len > max) return truncate(s, max);
return s;
}
export function padRightOrTruncate(s: string, max: number, padding?: string) {
const len = getWidth(s);
const len = width(s);
if (len < max) return padRight(s, max, padding);
if (len > max) return truncate(s, max);
return s;
@ -112,15 +107,15 @@ export namespace Strings {
export function truncate(s: string, truncateTo: number, ellipsis: string = '\u2026') {
if (!s) return s;
const len = getWidth(s);
const len = width(s);
if (len <= truncateTo) return s;
if (len === s.length) return `${s.substring(0, truncateTo - 1)}${ellipsis}`;
// Skip ahead to start as far as we can by assuming all the double-width characters won't be truncated
let chars = Math.floor(truncateTo / (len / s.length));
let count = getWidth(s.substring(0, chars));
let count = width(s.substring(0, chars));
while (count < truncateTo) {
count += getWidth(s[chars++]);
count += width(s[chars++]);
}
if (count >= truncateTo) {
@ -129,4 +124,107 @@ export namespace Strings {
return `${s.substring(0, chars)}${ellipsis}`;
}
const ansiRegex = /[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))/g;
export function width(s: string): number {
if (!s || s.length === 0) return 0;
s = s.replace(ansiRegex, '');
let count = 0;
let emoji = 0;
let joiners = 0;
const graphemes = [...s];
for (let i = 0; i < graphemes.length; i++) {
const code = graphemes[i].codePointAt(0)!;
// Ignore control characters
if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) continue;
// Ignore combining characters
if (code >= 0x300 && code <= 0x36F) continue;
// https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji
if (
(code >= 0x1F600 && code <= 0x1F64F) || // Emoticons
(code >= 0x1F300 && code <= 0x1F5FF) || // Misc Symbols and Pictographs
(code >= 0x1F680 && code <= 0x1F6FF) || // Transport and Map
(code >= 0x2600 && code <= 0x26FF) || // Misc symbols
(code >= 0x2700 && code <= 0x27BF) || // Dingbats
(code >= 0xFE00 && code <= 0xFE0F) || // Variation Selectors
(code >= 0x1F900 && code <= 0x1F9FF) || // Supplemental Symbols and Pictographs
(code >= 65024 && code <= 65039) || // Variation selector
(code >= 8400 && code <= 8447) // Combining Diacritical Marks for Symbols
) {
if (code >= 0x1F3FB && code <= 0x1F3FF) continue; // emoji modifier fitzpatrick type
emoji++;
count += 2;
continue;
}
// Ignore zero-width joiners '\u200d'
if (code === 8205) {
joiners++;
count -= 2;
continue;
}
// Surrogates
if (code > 0xFFFF) {
i++;
}
count += isFullwidthCodePoint(code) ? 2 : 1;
}
const offset = emoji - joiners;
if (offset > 1) {
count += offset - 1;
}
return count;
}
function isFullwidthCodePoint(cp: number) {
// code points are derived from:
// http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt
if (
cp >= 0x1100 && (
cp <= 0x115f || // Hangul Jamo
cp === 0x2329 || // LEFT-POINTING ANGLE BRACKET
cp === 0x232a || // RIGHT-POINTING ANGLE BRACKET
// CJK Radicals Supplement .. Enclosed CJK Letters and Months
(0x2e80 <= cp && cp <= 0x3247 && cp !== 0x303f) ||
// Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
(0x3250 <= cp && cp <= 0x4dbf) ||
// CJK Unified Ideographs .. Yi Radicals
(0x4e00 <= cp && cp <= 0xa4c6) ||
// Hangul Jamo Extended-A
(0xa960 <= cp && cp <= 0xa97c) ||
// Hangul Syllables
(0xac00 <= cp && cp <= 0xd7a3) ||
// CJK Compatibility Ideographs
(0xf900 <= cp && cp <= 0xfaff) ||
// Vertical Forms
(0xfe10 <= cp && cp <= 0xfe19) ||
// CJK Compatibility Forms .. Small Form Variants
(0xfe30 <= cp && cp <= 0xfe6b) ||
// Halfwidth and Fullwidth Forms
(0xff01 <= cp && cp <= 0xff60) ||
(0xffe0 <= cp && cp <= 0xffe6) ||
// Kana Supplement
(0x1b000 <= cp && cp <= 0x1b001) ||
// Enclosed Ideographic Supplement
(0x1f200 <= cp && cp <= 0x1f251) ||
// CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
(0x20000 <= cp && cp <= 0x3fffd)
)
) {
return true;
}
return false;
}
}

Carregando…
Cancelar
Salvar