core-components: add tests for LogLine highlighting + fix and refactor
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -14,8 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChunkModifiers } from './AnsiProcessor';
|
||||
import { findSearchResults, getModifierClasses } from './LogLine';
|
||||
import { AnsiLine, ChunkModifiers } from './AnsiProcessor';
|
||||
import {
|
||||
calculateHighlightedChunks,
|
||||
findSearchResults,
|
||||
getModifierClasses,
|
||||
} from './LogLine';
|
||||
|
||||
describe('getModifierClasses', () => {
|
||||
const classes = {
|
||||
@@ -110,3 +114,243 @@ describe('findSearchResults', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateHighlightedChunks', () => {
|
||||
it('should pass through chunks if there are no results', () => {
|
||||
const chunks = [{ text: 'Foo', modifiers: {} }];
|
||||
const line = new AnsiLine(0, chunks);
|
||||
expect(calculateHighlightedChunks(line, 'bar')).toBe(chunks);
|
||||
});
|
||||
|
||||
it('should highlight one result from plain text', () => {
|
||||
const line = new AnsiLine(0, [{ text: 'FooBarBaz', modifiers: {} }]);
|
||||
expect(calculateHighlightedChunks(line, 'foo')).toEqual([
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BarBaz',
|
||||
modifiers: {},
|
||||
},
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'bar')).toEqual([
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
},
|
||||
{
|
||||
text: 'Bar',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Baz',
|
||||
modifiers: {},
|
||||
},
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'baz')).toEqual([
|
||||
{
|
||||
text: 'FooBar',
|
||||
modifiers: {},
|
||||
},
|
||||
{
|
||||
text: 'Baz',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should highlight multiple results from plain text', () => {
|
||||
const line = new AnsiLine(0, [
|
||||
{ text: 'FooBarBazBazBarFoo', modifiers: {} },
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'foo')).toEqual([
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BarBazBazBar',
|
||||
modifiers: {},
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'bar')).toEqual([
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
},
|
||||
{
|
||||
text: 'Bar',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BazBaz',
|
||||
modifiers: {},
|
||||
},
|
||||
{
|
||||
text: 'Bar',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
},
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'baz')).toEqual([
|
||||
{
|
||||
text: 'FooBar',
|
||||
modifiers: {},
|
||||
},
|
||||
{
|
||||
text: 'Baz',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Baz',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BarFoo',
|
||||
modifiers: {},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should forward modifiers to result', () => {
|
||||
const line = new AnsiLine(0, [
|
||||
{ text: 'FooBarBazBazBarFoo', modifiers: { bold: true } },
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'foo')).toEqual([
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { bold: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BarBazBazBar',
|
||||
modifiers: { bold: true },
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { bold: true },
|
||||
highlight: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should highlight full chunks', () => {
|
||||
const line = new AnsiLine(0, [
|
||||
{ text: 'Foo', modifiers: { bold: true } },
|
||||
{ text: 'BarBaz', modifiers: { bold: true } },
|
||||
{ text: 'BazBar', modifiers: { italic: true } },
|
||||
{ text: 'Foo', modifiers: { italic: true } },
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'foo')).toEqual([
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { bold: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BarBaz',
|
||||
modifiers: { bold: true },
|
||||
},
|
||||
{
|
||||
text: 'BazBar',
|
||||
modifiers: { italic: true },
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { italic: true },
|
||||
highlight: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should highlight partial chunks', () => {
|
||||
const line = new AnsiLine(0, [
|
||||
{ text: 'Fo', modifiers: { bold: true } },
|
||||
{ text: 'oFooFo', modifiers: {} },
|
||||
{ text: 'oBarBaz', modifiers: { italic: true } },
|
||||
{ text: 'Foo', modifiers: { foreground: 'blue' } },
|
||||
{ text: 'FooFoo', modifiers: { italic: true } },
|
||||
{ text: 'F', modifiers: { bold: true } },
|
||||
{ text: 'o', modifiers: {} },
|
||||
{ text: 'o', modifiers: { bold: true } },
|
||||
]);
|
||||
expect(calculateHighlightedChunks(line, 'foo')).toEqual([
|
||||
{
|
||||
text: 'Fo',
|
||||
modifiers: { bold: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'o',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Fo',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'o',
|
||||
modifiers: { italic: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'BarBaz',
|
||||
modifiers: { italic: true },
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { foreground: 'blue' },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { italic: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'Foo',
|
||||
modifiers: { italic: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'F',
|
||||
modifiers: { bold: true },
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'o',
|
||||
modifiers: {},
|
||||
highlight: true,
|
||||
},
|
||||
{
|
||||
text: 'o',
|
||||
modifiers: { bold: true },
|
||||
highlight: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,45 +82,54 @@ export function calculateHighlightedChunks(
|
||||
|
||||
const chunks = new Array<HighlightAnsiChunk>();
|
||||
|
||||
let chunkOffset = 0;
|
||||
let lineOffset = 0;
|
||||
let nextResult = results.shift();
|
||||
for (const chunk of line.chunks) {
|
||||
const { text, modifiers } = chunk;
|
||||
if (!nextResult || chunkOffset + text.length < nextResult.start) {
|
||||
if (!nextResult || lineOffset + text.length < nextResult.start) {
|
||||
chunks.push(chunk);
|
||||
chunkOffset += text.length;
|
||||
lineOffset += text.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
let localOffset = 0;
|
||||
while (nextResult) {
|
||||
let localStart = nextResult.start - chunkOffset;
|
||||
if (localStart < 0) {
|
||||
localStart = 0;
|
||||
const localStart = Math.max(nextResult.start - lineOffset, 0);
|
||||
if (localStart > text.length) {
|
||||
break; // The next result is not in this chunk
|
||||
}
|
||||
const localEnd = nextResult.end - chunkOffset;
|
||||
const beforeMatch = text.slice(localOffset, localStart);
|
||||
const match = text.slice(localStart, localEnd);
|
||||
|
||||
if (beforeMatch) {
|
||||
chunks.push({ text: beforeMatch, modifiers });
|
||||
const localEnd = Math.min(nextResult.end - lineOffset, text.length);
|
||||
|
||||
const hasTextBeforeResult = localStart > localOffset;
|
||||
if (hasTextBeforeResult) {
|
||||
chunks.push({ text: text.slice(localOffset, localStart), modifiers });
|
||||
}
|
||||
const hasResultText = localEnd > localStart;
|
||||
if (hasResultText) {
|
||||
chunks.push({
|
||||
modifiers,
|
||||
highlight: true,
|
||||
text: text.slice(localStart, localEnd),
|
||||
});
|
||||
}
|
||||
chunks.push({ text: match, modifiers, highlight: true });
|
||||
|
||||
localOffset = localStart + match.length;
|
||||
localOffset = localEnd;
|
||||
|
||||
if (match.length === searchText.length) {
|
||||
const foundCompleteResult = nextResult.end - lineOffset === localEnd;
|
||||
if (foundCompleteResult) {
|
||||
nextResult = results.shift();
|
||||
} else {
|
||||
break;
|
||||
break; // The rest of the result is in the following chunks
|
||||
}
|
||||
}
|
||||
|
||||
if (localOffset < text.length) {
|
||||
const hasTextAfterResult = localOffset < text.length;
|
||||
if (hasTextAfterResult) {
|
||||
chunks.push({ text: text.slice(localOffset), modifiers });
|
||||
}
|
||||
|
||||
chunkOffset += text.length;
|
||||
lineOffset += text.length;
|
||||
}
|
||||
|
||||
return chunks;
|
||||
|
||||
Reference in New Issue
Block a user