Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "Fix an issue where `rush list --detailed` did not print horizontal table separators.",
"type": "none",
"packageName": "@microsoft/rush"
}
],
"packageName": "@microsoft/rush",
"email": "iclanton@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "Fix `TerminalTable` rendering spurious border lines when separator characters are set to empty strings",
"type": "patch",
"packageName": "@rushstack/terminal"
}
],
"packageName": "@rushstack/terminal",
"email": "iclanton@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "Add borderColor and headingColor styling options to `TerminalTable`",
"type": "minor",
"packageName": "@rushstack/terminal"
}
],
"packageName": "@rushstack/terminal",
"email": "iclanton@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "Add borderColor and messageColor styling options to `PrintUtilities.printMessageInBox`",
"type": "minor",
"packageName": "@rushstack/terminal"
}
],
"packageName": "@rushstack/terminal",
"email": "iclanton@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "Add row separators between data rows in `TerminalTable`.",
"type": "patch",
"packageName": "@rushstack/terminal"
}
],
"packageName": "@rushstack/terminal",
"email": "iclanton@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "Add `TerminalTable.printToTerminal()` function.",
"type": "minor",
"packageName": "@rushstack/terminal"
}
],
"packageName": "@rushstack/terminal",
"email": "iclanton@users.noreply.github.com"
}
2 changes: 1 addition & 1 deletion common/config/rush/version-policies.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"policyName": "rush",
"definitionName": "lockStepVersion",
"version": "5.175.0",
"nextBump": "minor",
"nextBump": "patch",
"mainProject": "@microsoft/rush"
}
]
15 changes: 15 additions & 0 deletions common/reviews/api/terminal.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ export interface IPrefixProxyTerminalProviderOptionsBase {
terminalProvider: ITerminalProvider;
}

// @public
export interface IPrintMessageInBoxOptions {
borderColor?: (text: string) => string;
boxWidth?: number;
messageColor?: (text: string) => string;
}

// @beta
export interface IProblemCollector {
get problems(): ReadonlySet<IProblem>;
Expand Down Expand Up @@ -268,9 +275,11 @@ export interface ITerminalTableChars {
// @public
export interface ITerminalTableOptions {
borderCharacters?: Partial<ITerminalTableChars>;
borderColor?: (text: string) => string;
borderless?: boolean;
colWidths?: number[];
head?: string[];
headingColor?: (text: string) => string;
}

// @public
Expand Down Expand Up @@ -347,6 +356,10 @@ export class PrefixProxyTerminalProvider implements ITerminalProvider {
export class PrintUtilities {
static getConsoleWidth(): number | undefined;
// Warning: (ae-incompatible-release-tags) The symbol "printMessageInBox" is marked as @public, but its signature references "ITerminal" which is marked as @beta
static printMessageInBox(message: string, terminal: ITerminal, options?: IPrintMessageInBoxOptions): void;
// Warning: (ae-incompatible-release-tags) The symbol "printMessageInBox" is marked as @public, but its signature references "ITerminal" which is marked as @beta
//
// @deprecated (undocumented)
static printMessageInBox(message: string, terminal: ITerminal, boxWidth?: number): void;
static wrapWords(text: string, maxLineLength?: number, indent?: number): string;
static wrapWords(text: string, maxLineLength?: number, linePrefix?: string): string;
Expand Down Expand Up @@ -491,6 +504,8 @@ export class TerminalTable {
constructor(options?: ITerminalTableOptions);
// (undocumented)
getLines(): string[];
// Warning: (ae-incompatible-release-tags) The symbol "printToTerminal" is marked as @public, but its signature references "ITerminal" which is marked as @beta
printToTerminal(terminal: ITerminal): void;
push(...rows: string[][]): void;
toString(): string;
}
Expand Down
3 changes: 1 addition & 2 deletions libraries/rush-lib/src/cli/actions/ListAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@ export class ListAction extends BaseRushAction {
table.push(packageRow);
}

// eslint-disable-next-line no-console
console.log(table.toString());
table.printToTerminal(this.terminal);
}
}
85 changes: 77 additions & 8 deletions libraries/terminal/src/PrintUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,40 @@ import { Text } from '@rushstack/node-core-library';

import type { ITerminal } from './ITerminal';

/**
* Options for {@link PrintUtilities.(printMessageInBox:1)}.
*
* @public
*/
export interface IPrintMessageInBoxOptions {
/**
* The width of the box in characters. Defaults to half of the console width.
*/
boxWidth?: number;

/**
* A function to apply styling to the box border characters.
*
* @example
* ```typescript
* import { Colorize } from '@rushstack/terminal';
* PrintUtilities.printMessageInBox('Hello!', terminal, { borderColor: Colorize.cyan })
* ```
*/
borderColor?: (text: string) => string;

/**
* A function to apply styling to the message text inside the box.
*
* @example
* ```typescript
* import { Colorize } from '@rushstack/terminal';
* PrintUtilities.printMessageInBox('Hello!', terminal, { messageColor: Colorize.bold })
* ```
*/
messageColor?: (text: string) => string;
}

/**
* A sensible fallback column width for consoles.
*
Expand Down Expand Up @@ -186,14 +220,45 @@ export class PrintUtilities {
*
* @param message - The message to display.
* @param terminal - The terminal to write the message to.
* @param boxWidth - The width of the box, defaults to half of the console width.
* @param options - Controls the box width and optional styling for the border and message text.
* {@label WITH_OPTIONS}
*/
public static printMessageInBox(
message: string,
terminal: ITerminal,
options?: IPrintMessageInBoxOptions
): void;
/**
* @deprecated Use the {@link PrintUtilities.(printMessageInBox:1)} overload instead.
* Pass `boxWidth` via the {@link IPrintMessageInBoxOptions.boxWidth} property.
*/
public static printMessageInBox(message: string, terminal: ITerminal, boxWidth?: number): void {
if (!boxWidth) {
public static printMessageInBox(message: string, terminal: ITerminal, boxWidth?: number): void;
public static printMessageInBox(
message: string,
terminal: ITerminal,
optionsOrBoxWidth?: IPrintMessageInBoxOptions | number
): void {
let options: IPrintMessageInBoxOptions;
if (typeof optionsOrBoxWidth === 'number') {
options = {
boxWidth: optionsOrBoxWidth
};
} else {
options = optionsOrBoxWidth ?? {};
}

const { borderColor, messageColor, boxWidth: optionsBoxWidth } = options ?? {};
let boxWidth: number;
if (!optionsBoxWidth) {
const consoleWidth: number = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH;
boxWidth = Math.floor(consoleWidth / 2);
} else {
boxWidth = optionsBoxWidth;
}

const styleBorder = (s: string): string => borderColor?.(s) ?? s;
const styleMessage = (s: string): string => messageColor?.(s) ?? s;

const maxLineLength: number = boxWidth - 10;
const wrappedMessageLines: string[] = PrintUtilities.wrapWordsToLines(message, maxLineLength);
let longestLineLength: number = 0;
Expand All @@ -209,25 +274,29 @@ export class PrintUtilities {
// ═════════════
// Message
// ═════════════
const headerAndFooter: string = ` ${'═'.repeat(boxWidth)}`;
const headerAndFooter: string = ` ${styleBorder('═'.repeat(boxWidth))}`;
terminal.writeLine(headerAndFooter);
for (const line of wrappedMessageLines) {
terminal.writeLine(` ${line}`);
terminal.writeLine(` ${styleMessage(line)}`);
}

terminal.writeLine(headerAndFooter);
} else {
const verticalBorder: string = styleBorder('║');

// ╔═══════════╗
// ║ Message ║
// ╚═══════════╝
terminal.writeLine(` ╔${'═'.repeat(boxWidth - 2)}╗`);
terminal.writeLine(` ${styleBorder(`╔${'═'.repeat(boxWidth - 2)}╗`)}`);
for (const trimmedLine of trimmedLines) {
const padding: number = boxWidth - trimmedLine.length - 2;
const leftPadding: number = Math.floor(padding / 2);
const rightPadding: number = padding - leftPadding;
terminal.writeLine(` ║${' '.repeat(leftPadding)}${trimmedLine}${' '.repeat(rightPadding)}║`);
terminal.writeLine(
` ${verticalBorder}${' '.repeat(leftPadding)}${styleMessage(trimmedLine)}${' '.repeat(rightPadding)}${verticalBorder}`
);
}
terminal.writeLine(` ╚${'═'.repeat(boxWidth - 2)}╝`);
terminal.writeLine(` ${styleBorder(`╚${'═'.repeat(boxWidth - 2)}╝`)}`);
}
}
}
Loading