Skip to content

Commit

Permalink
Ensure prefix when logging without a trailing LF
Browse files Browse the repository at this point in the history
Fixes #467
  • Loading branch information
gustavohenke committed Aug 31, 2024
1 parent 950132d commit 1e882f1
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 18 deletions.
37 changes: 33 additions & 4 deletions src/logger.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,29 @@ describe('#log()', () => {
expect(values[1]).toEqual({ command: undefined, text: 'bar\nfoobaz\n' });
});

it('does not emit prefix if last call did not finish with a LF', () => {
it('does not emit prefix if previous call from same command did not finish with a LF', () => {
const { logger, spy } = createLogger({});
logger.log('foo', 'bar');
logger.log('foo', 'baz');
const command = new FakeCommand();
logger.log('foo', 'bar', command);
logger.log('foo', 'baz', command);

expect(spy.getValuesLength()).toBe(3);
expect(spy.getLastValue()).toEqual({ command: undefined, text: 'baz' });
expect(spy.getLastValue()).toEqual({ command, text: 'baz' });
});

it('emits LF and prefix if previous call is from different command and did not finish with a LF', () => {
const { logger, spy } = createLogger({});
const command1 = new FakeCommand();
logger.log('foo', 'bar', command1);

const command2 = new FakeCommand();
logger.log('foo', 'baz', command2);

const values = spy.getValues();
expect(values).toHaveLength(5);
expect(values).toContainEqual({ command: command1, text: '\n' });
expect(values).toContainEqual({ command: command2, text: 'foo' });
expect(values).toContainEqual({ command: command2, text: 'baz' });
});

it('does not emit prefix nor handle text if logger is in raw mode', () => {
Expand Down Expand Up @@ -267,6 +283,19 @@ describe('#logCommandEvent()', () => {
cmd,
);
});

it('prepends a LF if previous command write did not end with a LF', () => {
const { logger } = createLogger({});
const cmd = new FakeCommand('', undefined, 1);
logger.logCommandText('text', cmd);
logger.logCommandEvent('event', cmd);

expect(logger.log).toHaveBeenCalledWith(
chalk.reset('[1]') + ' ',
'\n' + chalk.reset('event') + '\n',
cmd,
);
});
});

describe('#logTable()', () => {
Expand Down
33 changes: 19 additions & 14 deletions src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ export class Logger {
private prefixLength = 0;

/**
* Last character emitted.
* Last character emitted, and from which command.
* If `undefined`, then nothing has been logged yet.
*/
private lastChar?: string;
private lastWrite?: { command: Command | undefined; char: string };

/**
* Observable that emits when there's been output logged.
Expand Down Expand Up @@ -160,7 +160,14 @@ export class Logger {
return;
}

this.logCommandText(chalk.reset(text) + '\n', command);
// Last write was from this command, but it didn't end with a line feed.
// Prepend one, otherwise the event's text will be concatenated to that write.
// A line feed is otherwise inserted anyway.
let prefix = '';
if (this.lastWrite?.command === command && this.lastWrite.char !== '\n') {
prefix = '\n';
}
this.logCommandText(prefix + chalk.reset(text) + '\n', command);
}

logCommandText(text: string, command: Command) {
Expand Down Expand Up @@ -254,24 +261,22 @@ export class Logger {
// #70 - replace some ANSI code that would impact clearing lines
text = text.replace(/\u2026/g, '...');

const lines = text.split('\n').map((line, index, lines) => {
// First line will write prefix only if we finished the last write with a LF.
// Last line won't write prefix because it should be empty.
if (index === 0 || index === lines.length - 1) {
return line;
}
return prefix + line;
});
// This write's interrupting another command, emit a line feed to start clean.
if (this.lastWrite && this.lastWrite.command !== command && this.lastWrite.char !== '\n') {
this.emit(this.lastWrite.command, '\n');
}

if (!this.lastChar || this.lastChar === '\n') {
// Clean lines should emit a prefix
if (!this.lastWrite || this.lastWrite.char === '\n') {
this.emit(command, prefix);
}

this.lastChar = text[text.length - 1];
this.emit(command, lines.join('\n'));
const textToWrite = text.replace(/\n(.)/g, `\n${prefix}$1`);
this.emit(command, textToWrite);
}

emit(command: Command | undefined, text: string) {
this.lastWrite = { command, char: text[text.length - 1] };
this.output.next({ command, text });
}
}

0 comments on commit 1e882f1

Please sign in to comment.