cz-cli icon indicating copy to clipboard operation
cz-cli copied to clipboard

Inconsistent spacing around emojis when displayed in terminal

Open meredithmurfin opened this issue 3 years ago • 2 comments

Issue

When I use Emojis in my .cz-config.js file to customize my commit messages, I see inconsistent spacing around specific Emojis. This is happening in both my VS Code terminal and my Mac OS terminal. I originally had issues with Emojis displaying correctly in VS Code files (you can see that issue here), but I believe this spacing issue stems from commitizen since it's happening outside of my VS Code.

Check out my .cz-config.js file at the end of this issue so that you can see how the Emojis are being used for my commit messages. You will see that after every Emoji I have just 1 space between the Emoji and the next text.

No space shown after ⚙️ :gear: and ♻️ :recycle: Emojis: Screen Shot 2021-03-20 at 5 12 07 PM

No space shown after ⬇️ :arrow_down: and 🛠️ :hammer_and_wrench: Emojis: Screen Shot 2021-03-20 at 5 13 22 PM

No space shown after ✔️ :heavy_check_mark:, ✏️ :pencil2:, and ⬆️ :arrow_up: Emojis: Screen Shot 2021-03-20 at 5 16 35 PM

No space shown after 🏷️ :label: Emoji: Screen Shot 2021-03-20 at 5 17 53 PM

No space shown after 🖥️ :desktop_computer: Emoji: Screen Shot 2021-03-20 at 5 19 04 PM

The issue IS resolved when 2 spaces are added after Emojis, but I feel like this is a hacky fix and shouldn't be necessary

Project Information

This occurs in multiple projects. Each project I use this same setup:

  • VS Code version 1.54.3
  • package.json devDependencies:
    • "@commitlint/cli": "^12.0.1"
    • "@commitlint/config-conventional": "^12.0.1"
    • "commitizen": "^4.2.3"
    • "cz-customizable": "^6.3.0"
  • This config is also in my package.json:
    "config": {
        "commitizen": {
            "path": "./node_modules/cz-customizable"
        }
    },
    
  • My .commitlintrc.js: module.exports = { extends: ['@commitlint/config-conventional'] };
My .cz-config.js
module.exports = {
    types: [
        {
            value: 'chore',
            name: 'chore:      ⚙️ Build process or supporting tool changes',
        },
        {
            value: 'ci',
            name: 'ci:         🚀 CI-related changes',
        },
        {
            value: 'docs',
            name: 'docs:       📚 Documentation updates',
        },
        {
            value: 'feat',
            name: 'feat:       ⭐ Adds functionality',
        },
        {
            value: 'fix',
            name: 'fix:        🐞 Fixes a bug',
        },
        {
            value: 'perf',
            name: 'perf:       ⚡️ Changes that improve performance',
        },
        {
            value: 'refactor',
            name: 'refactor:   ♻️ Neither fixes a bug nor adds functionality',
        },
        {
            value: 'release',
            name: 'release:    🔖 Releases a new version',
        },
        {
            value: 'setup',
            name: 'setup:      🎉 Initial setup',
        },
        {
            value: 'style',
            name: 'style:      🎨 Adds or updates styles',
        },
        {
            value: 'test',
            name: 'test:       🧪 Adds or updates tests',
        },
        {
            value: 'ux',
            name: 'ux:         🚸 Changes that improve user experience',
        },
    ],
    scopes: [
        {
            value: 'wip',
            name: 'wip:    🚧 WIP',
        },
        {
            value: 'review',
            name: 'review: 💯 Code review changes',
        },
    ],
    allowTicketNumber: false,
    scopeOverrides: {
        chore: [
            {
                value: 'add-dep',
                name: 'add-dep:    ➕ Adds dependencies',
            },
            {
                value: 'analytics',
                name: 'analytics:  📈 Adds or updates analytics',
            },
            {
                value: 'config',
                name: 'config:     🛠️ Adds or updates configuration files',
            },
            {
                value: 'downgrade',
                name: 'downgrade:  ⬇️ Downgrades dependencies',
            },
            {
                value: 'errors',
                name: 'errors:     🥅 Changes that improve error handling',
            },
            {
                value: 'ignore',
                name: 'ignore:     🙈 Adds or updates .*ignore files',
            },
            {
                value: 'merge',
                name: 'merge:      🔀 Merge branches',
            },
            {
                value: 'pin-dep',
                name: 'pin-dep:    📌 Pins dependencies to specific versions',
            },
            {
                value: 'rem-dep',
                name: 'rem-dep:    ➖ Removes dependencies',
            },
            {
                value: 'scripts',
                name: 'scripts:    📜 Adds or updates development scripts',
            },
            {
                value: 'security',
                name: 'security:   🔒 Security-related changes',
            },
            {
                value: 'upgrade',
                name: 'upgrade:    ⬆️ Upgrades dependencies',
            },
        ],
        docs: [
            {
                value: 'config',
                name: 'config: 🛠️ Adds or updates configuration documentation',
            },
            {
                value: 'logs',
                name: 'logs:   🔊 Adds or updates logs',
            },
            {
                value: 'meta',
                name: 'meta:   📖 Adds or updates metadata',
            },
        ],
        fix: [
            {
                value: 'downgrade',
                name: 'downgrade:  ⬇️ Downgrades dependencies',
            },
            {
                value: 'merge',
                name: 'merge:      🔀 Merge branches',
            },
            {
                value: 'quick',
                name: 'quick:      🚑 Temporarily resolves a critical bug',
            },
            {
                value: 'revert',
                name: 'revert:     🦔 Rolls back to a previous version',
            },
            {
                value: 'style',
                name: 'style:      🎨 Fixes styles',
            },
            {
                value: 'test',
                name: 'test:       ✔️ Fixes tests',
            },
            {
                value: 'typo',
                name: 'typo:       ✏️ Fixes typos',
            },
            {
                value: 'upgrade',
                name: 'upgrade:    ⬆️ Upgrades dependencies',
            },
            {
                value: 'warn',
                name: 'warn:       🚨 Fixes compiler and/or 👕 linter warnings',
            },
        ],
        refactor: [
            {
                value: 'abstract',
                name:
                    'abstract:   〰️ Changes that simplify code through abstraction',
            },
            {
                value: 'move',
                name: 'move:       🚚 Moves files',
            },
            {
                value: 'prune',
                name: 'prune:      🔥 Removes code and/or files',
            },
            {
                value: 'read',
                name: 'read:       💡 Changes that improve code readability',
            },
            {
                value: 'rename',
                name: 'rename:     🏷️ Renames files',
            },
            {
                value: 'reuse',
                name:
                    'reuse:      ➰ Changes that implement or improve code reuse',
            },
        ],
        setup: [
            {
                value: 'config',
                name: 'config: 🛠️ Adds or updates configuration files',
            },
            {
                value: 'docs',
                name: 'docs:   📚 Documentation updates',
            },
            {
                value: 'init',
                name: 'init:   💃 Initial commit',
            },
            {
                value: 'move',
                name: 'move:   🚚 Moves files',
            },
            {
                value: 'prune',
                name: 'prune:  🔥 Removes code and/or files',
            },
            {
                value: 'rename',
                name: 'rename: 🏷️ Renames files',
            },
        ],
        test: [
            {
                value: 'e2e',
                name: 'e2e:    🎢 Adds or updates end-to-end tests',
            },
            {
                value: 'perf',
                name: 'perf:   ⚡️ Adds or updates performance tests',
            },
            {
                value: 'unit',
                name: 'unit:   🚦 Adds or updates unit tests',
            },
        ],
        ux: [
            {
                value: 'access',
                name: 'access:     ♿️ Changes that improve user accessibility',
            },
            {
                value: 'alt-text',
                name: 'alt-text:   💬 Adds or updates alternative text',
            },
            {
                value: 'android',
                name: 'android:    🤖 Android-specific changes',
            },
            {
                value: 'animation',
                name:
                    'animation:  ✨ Adds or updates animations and transitions',
            },
            {
                value: 'ios',
                name: 'ios:        📱 iOS-specific changes',
            },
            {
                value: 'linux',
                name: 'linux:      🐧 Linux-specific changes',
            },
            {
                value: 'osx',
                name: 'osx:        🍎 OSX-specific changes',
            },
            {
                value: 'responsive',
                name:
                    'responsive: 📲 Changes that affect overall responsive design',
            },
            {
                value: 'style',
                name: 'style:      🎨 Adds or updates styles',
            },
            {
                value: 'ui',
                name: 'ui:         🖥️ General UI-related changes',
            },
            {
                value: 'windows',
                name: 'windows:    🏁 Windows-specific changes',
            },
        ],
    },
    messages: {
        type: "Select the type of change that you're committing:",
        scope: 'Select the scope of this change (optional):',
        customScope: 'Denote the scope of this change:',
        subject: 'Write a short description describing this change:\n',
        confirmCommit:
            'Are you sure you want to proceed with the commit above?',
    },
    allowCustomScopes: true,
    skipQuestions: ['body', 'breaking', 'footer'],
    subjectLimit: 100,
};

meredithmurfin avatar Mar 20 '21 21:03 meredithmurfin

FYI: I'm facing the same issue on macOS when writing to the console using simple console.log. What I hit was that I need to add two spaces after 🆚 and ✅ to display a single space, but not for ✳️ or 🆗.

So on one hand I don't think it is a cz-cli issue, because had the same situation in a totally unrelated setup.

So far the common thing is that we are both using macOS, so it may be a macOS issue...

Update: Really looks like it is a terminal + Unicode specification issue, as Unicode marked some emojis single width, and terminals tend to respect that, but the indicated widths changed over time, so each terminal software may have slightly different view while most terminals at the same time give Emoji rendering to the OS to handle and most OS-es have defined all emojis look to be double width. So long story short, the terminal believes the specification, which is in itself inconsistent and has different versions, while the OS simply renders the double width emoji image regardless of how much space the terminal SW left out for it resulting in the look on the images in the issue opening description.

Best solution would be for all Terminal apps to decide to render all emojis as double width. It'd be far better than the current situation...

More info: https://github.com/unicode-rs/unicode-width/issues/4

Conclusion: probably out of scope for cz-cli.

BenceSzalai avatar Sep 05 '23 21:09 BenceSzalai

I believe this is an issue of xterm.js not handling Variation Selector-16, described here https://github.com/microsoft/vscode/issues/118905#issuecomment-1836842947

It is not a surprise that you also see this issue outside of xterm.js, only 7 of 23 terminals that I have tested with ucs-detect support all VS-16 sequences. Terminal.app does not support VS-16 sequences, but iTerm2 and kitty for MacOS do, so you might compare with those instead.

jquast avatar Dec 01 '23 22:12 jquast