Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support hyperlinks in supported terminals #37

Merged
merged 21 commits into from
Apr 22, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9361477
Tweaking to support hyperlinks in supporting terminals
nicholaschiasson Sep 19, 2019
27865e2
Hyperlinkifying any link even if it doesn't wrap, and also padding wr…
nicholaschiasson Sep 20, 2019
0d2789c
Realizing I kind of misunderstood the task initially
nicholaschiasson Sep 20, 2019
c28e99f
Just throwin down some consts
nicholaschiasson Sep 20, 2019
1c628d2
Doing the coverage a small favour
nicholaschiasson Sep 20, 2019
a594fda
Update package.json
sindresorhus Sep 28, 2019
82e60c5
Undoing unnecessary change and making terminal-link a dev dependency
nicholaschiasson Oct 14, 2019
964d144
Merge branch 'support-hyperlinks' of https://github.com/nicholaschias…
nicholaschiasson Oct 14, 2019
c789282
Remove package-lock.json
nicholaschiasson Oct 14, 2019
89333aa
Update in accordance with @stroncium comments
nicholaschiasson Oct 22, 2019
6b4e742
Fixing resiliency with possible surrogate pairs
nicholaschiasson Apr 13, 2020
4a6bd4e
Following advice and allowing tests to fail in terminals not supporti…
nicholaschiasson Apr 13, 2020
20c9973
Merge branch 'master' into support-hyperlinks
nicholaschiasson Apr 13, 2020
ca423c3
Fixing bad merge
nicholaschiasson Apr 13, 2020
7a7eb43
Code complete, fix bugs, fix and clarify tests, full coverage
nicholaschiasson Apr 17, 2020
638b5cd
Removing dependency on terminal-link, as it make the tests fail in no…
nicholaschiasson Apr 17, 2020
9e3ea7b
Remove accidentally added .vscode directory
nicholaschiasson Apr 17, 2020
7dfd2ca
Renaming ESCAPE_TERMINATOR constant
nicholaschiasson Apr 17, 2020
35eee4e
Removing unnecessary cursor variable
nicholaschiasson Apr 17, 2020
2b6a0b4
Removing named regex capture groups to support node 8
nicholaschiasson Apr 17, 2020
165c956
Revert "Removing named regex capture groups to support node 8"
nicholaschiasson Apr 22, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const ESCAPES = new Set([

const END_CODE = 39;

const ANSI_ESCAPE_BELL = '\u0007';
const ANSI_ESCAPE_LINK = ']8;;';

const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`;

// Calculate the length of words split on ' ', ignoring
Expand All @@ -22,6 +25,7 @@ const wrapWord = (rows, word, columns) => {
const characters = [...word];

let isInsideEscape = false;
let isInsideLinkEscape = false;
let visible = stringWidth(stripAnsi(rows[rows.length - 1]));

for (const [index, character] of characters.entries()) {
Expand All @@ -36,12 +40,20 @@ const wrapWord = (rows, word, columns) => {

if (ESCAPES.has(character)) {
isInsideEscape = true;
} else if (isInsideEscape && character === 'm') {
isInsideEscape = false;
continue;
isInsideLinkEscape = word.slice(index).startsWith(`${character}${ANSI_ESCAPE_LINK}`);
nicholaschiasson marked this conversation as resolved.
Show resolved Hide resolved
}

if (isInsideEscape) {
/* istanbul ignore if: cannot enter on terminals not supporting hyperlinks */
nicholaschiasson marked this conversation as resolved.
Show resolved Hide resolved
if (isInsideLinkEscape) {
if (character === ANSI_ESCAPE_BELL) {
isInsideEscape = false;
isInsideLinkEscape = false;
}
} else if (character === 'm') {
nicholaschiasson marked this conversation as resolved.
Show resolved Hide resolved
isInsideEscape = false;
}

continue;
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"coveralls": "^3.0.3",
"has-ansi": "^3.0.0",
"nyc": "^14.1.1",
"terminal-link": "^2.0.0",
"xo": "^0.24.0"
}
}
19 changes: 19 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import test from 'ava';
import chalk from 'chalk';
import hasAnsi from 'has-ansi';
import stripAnsi from 'strip-ansi';
import terminalLink from 'terminal-link';
import wrapAnsi from '.';

chalk.enabled = true;
Expand Down Expand Up @@ -148,3 +149,21 @@ test('#27, does not remove spaces in line with ansi escapes when no trimming', t
t.is(wrapAnsi(chalk.bgGreen(` ${chalk.black('OK')} `), 100, {trim: false}), chalk.bgGreen(` ${chalk.black('OK')} `));
t.is(wrapAnsi(chalk.bgGreen(' hello '), 10, {hard: true, trim: false}), chalk.bgGreen(' hello '));
});

test('#35, wraps hyperlinks, preserving clickability in supporting terminals', t => {
const link = 'https://testlogin:testpassword@areallylongurlthatneedstogetwrapped.com/with_some/path?andparams=bogus&more=evenmorebogus#evensomehashparams=notdoinganything';
nicholaschiasson marked this conversation as resolved.
Show resolved Hide resolved
const input = `hi http://js.io ${terminalLink(link, link, {fallback: text => text})}`;
const expected = terminalLink.isSupported ?
'hi http://js.io\n\u001B]8;;https://testlogin:testpassword@areallylongurlthatneedstogetwrapped.com/with_some/path?andparams=bogus&more=evenmorebogus#evensomehashparams=notdoinganything\u0007https://testlogi\u001B[28m\n\u001B[8mn:testpassword@a\u001B[28m\n\u001B[8mreallylongurltha\u001B[28m\n\u001B[8mtneedstogetwrapp\u001B[28m\n\u001B[8med.com/with_some\u001B[28m\n\u001B[8m/path?andparams=\u001B[28m\n\u001B[8mbogus&more=evenm\u001B[28m\n\u001B[8morebogus#evensom\u001B[28m\n\u001B[8mehashparams=notd\u001B[28m\n\u001B[8moinganything\u001B]8;;\u0007' :
'hi http://js.io\nhttps://testlogi\nn:testpassword@a\nreallylongurltha\ntneedstogetwrapp\ned.com/with_some\n/path?andparams=\nbogus&more=evenm\norebogus#evensom\nehashparams=notd\noinganything';
t.is(wrapAnsi(input, 16, {hard: true}), expected);
});

test('#35, wraps coloured hyperlinks, preserving clickability in supporting terminals', t => {
const link = 'https://testlogin:testpassword@areallylongurlthatneedstogetwrapped.com/with_some/path?andparams=bogus&more=evenmorebogus#evensomehashparams=notdoinganything';
const input = `hi http://js.io ${terminalLink(chalk.bgGreen(link), link, {fallback: text => text})}`;
const expected = terminalLink.isSupported ?
`hi http://js.io\n\u001B]8;;https://testlogin:testpassword@areallylongurlthatneedstogetwrapped.com/with_some/path?andparams=bogus&more=evenmorebogus#evensomehashparams=notdoinganything\u0007${chalk.bgGreen('https://testlogi\nn:testpassword@a\nreallylongurltha\ntneedstogetwrapp\ned.com/with_some\n/path?andparams=\nbogus&more=evenm\norebogus#evensom\nehashparams=notd\noinganything')}\u001B]8;;\u0007` :
`hi http://js.io\n${chalk.bgGreen('https://testlogi\nn:testpassword@a\nreallylongurltha\ntneedstogetwrapp\ned.com/with_some\n/path?andparams=\nbogus&more=evenm\norebogus#evensom\nehashparams=notd\noinganything')}`;
t.is(wrapAnsi(input, 16, {hard: true}), expected);
});