Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Quillstack Output

TestsLatest VersionDownloadsPHP VersionStyleCICodeFactorQuality GateCoverageMaintainabilityReliabilitySecurityLicense

The library responsible for console output in CLI commands, colouring text with HTML-like tags.

Why this exists

A command-line tool needs two things from its output: colour where a person is watching, and no colour where the output is being piped into a file or read by another program. Getting the second one wrong fills logs with escape codes.

This does both, in one class with three methods, and it is what quillstack/cli writes through. It exists separately from the console because writing coloured text is not the same job as parsing arguments, and plenty of scripts want the first without the second.

Requirements

  • PHP 8.1 or newer

Installation

composer require quillstack/output

Usage

useQuillstack\Output\Output;
$output = newOutput();
$output->writeln('Everything <green>works</green>');
$output->writeln('Something <red>went wrong</red>');

Or through the helpers, which are there as soon as the package is installed:

writeln('Everything <green>works</green>');
write('No line ending here');

format() returns the text instead of writing it:

$line = $output->format('<yellow>Careful</yellow>');

Colours

A colour is opened with <name> and closed with </name>. A colour left open is closed at the end of the text, so the terminal is never left painted. Tags naming no colour are left exactly as they were, so text which merely looks like markup survives untouched.

TagTag
<black><dark-grey>
<red><light-red>
<green><light-green>
<brown><yellow>
<blue><light-blue>
<purple><light-purple>
<cyan><light-cyan>
<light-grey><white>

Colours of your own go to the constructor, written as ANSI codes:

useQuillstack\Output\Colors;
useQuillstack\Output\Output;
$output = newOutput(newColors(['brand' => '1;35']));
$output->writeln('<brand>Quillstack</brand>');

Output which is not a terminal

Escape codes only make sense on a terminal. Piped somewhere else they are noise, so an undecorated output drops them and writes the text alone:

$output = newOutput(decorated: stream_isatty(STDOUT));

Benchmark

Measured with quillstack/benchmark on a thousand lines of tagged text turned into escape codes. Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/output0.6.0
symfony/consolev7.4.17
Per lineRelativeInstalled
quillstack/output1.92 µs76 kB
symfony/console6.19 µs3.2×952 kB

league/climate is not in the table: it writes as it formats rather than handing back a string, so there is nothing to measure the same way. It is 704 kB.

Symfony's formatter is doing considerably more. It parses nested tags, supports 256-colour and true-colour output, href links, custom styles registered by name, and it wraps text to the terminal width. This matches a fixed set of tags and replaces them.

At two microseconds a line, a command printing a thousand lines spends two milliseconds here and six on Symfony's — and if you are printing a thousand lines to a terminal, the terminal is the slow part.

Tests

composer test

Coverage needs phpdbg:

composer test:coverage

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

About

The library responsible for console output in CLI commands.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages