Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | 22x 22x 22x 22x 22x 25x 25x 6x 6x 6x 6x 13x 13x 27x 27x 27x 27x 137x 18x 18x 137x 4x 27x 27x 27x 18x 18x 24x 24x 4x 14x 14x 11x 7x 4x 4x 4x 3x 3x 14x 14x 7x 7x 14x 14x 14x 12x 12x 12x 12x 12x 10x 3x 7x 5x 5x 1x 4x 2x 12x 19x 19x 26x 17x 8x 4x 4x 3x 1x 8x 9x 19x 23x | import { HighlightRuleComponent } from './HighlightRuleComponent.js';
export enum HIGHLIGHT_TYPES {
WholeLine,
WholeText,
PartialText,
}
// Define color mappings
const COLOR_MAPPING: { [key: string]: string } = {
r: 'var(--red)',
g: 'var(--green)',
b: 'var(--blue)',
c: 'var(--cyan)',
m: 'var(--magenta)',
y: 'var(--yellow)',
k: 'var(--black)',
w: 'var(--white)',
};
export class HighlightRule {
ruleComponents: HighlightRuleComponent[];
color?: string;
constructor(ruleComponents: HighlightRuleComponent[], color?: string) {
this.ruleComponents = ruleComponents;
this.color = color;
}
static parseAllRules(allRules: string, lineOffset: number, tokenContent: string) {
const highlightLines = this.splitByChar(allRules, ',');
const strArray = tokenContent.split('\n');
strArray.pop(); // removes the last empty string
return highlightLines
.map(ruleStr => HighlightRule.parseRule(ruleStr, lineOffset, strArray))
.filter(rule => rule) as HighlightRule[]; // discards invalid rules
}
// this function splits allRules by a splitter while ignoring the splitter if it is within quotes
static splitByChar(allRules: string, splitter: string) {
const highlightRules = [];
let isWithinQuote = false;
let currentPosition = 0;
for (let i = 0; i < allRules.length; i += 1) {
if (allRules.charAt(i) === splitter && !isWithinQuote) {
highlightRules.push(allRules.substring(currentPosition, i));
currentPosition = i + 1;
}
// Checks if the current character is not an unescaped quotation mark
if (allRules.charAt(i) === '\'' && (i === 0 || allRules.charAt(i - 1) !== '\\')) {
isWithinQuote = !isWithinQuote;
}
}
if (currentPosition !== allRules.length) {
highlightRules.push(allRules.substring(currentPosition));
}
return highlightRules;
}
static parseRule(ruleString: string, lineOffset: number, lines: string[]) {
// Split by @ (e.g "1[:]@blue" -> ["1[:]", "blue"])
const [rulePart, inputColor] = ruleString.split('@');
const components = this.splitByChar(rulePart, '-')
.map(compString => HighlightRuleComponent.parseRuleComponent(compString, lineOffset, lines));
if (components.some(c => !c)) {
// Not all components are properly parsed, which means
// the rule itself is not proper
return null;
}
const color: string = inputColor && COLOR_MAPPING[inputColor] ? COLOR_MAPPING[inputColor] : inputColor;
return new HighlightRule(components as HighlightRuleComponent[], color);
}
shouldApplyHighlight(lineNumber: number) {
const compares = this.ruleComponents.map(comp => comp.compareLine(lineNumber));
if (this.isLineRange()) {
const withinRangeStart = compares[0] <= 0;
const withinRangeEnd = compares[1] >= 0;
return withinRangeStart && withinRangeEnd;
}
const atLineNumber = compares[0] === 0;
return atLineNumber;
}
getHighlightType(lineNumber: number): {
highlightType: HIGHLIGHT_TYPES;
bounds: Array<[number, number]> | null;
color?: string;
}[] {
const results: {
highlightType: HIGHLIGHT_TYPES;
bounds: Array<[number, number]> | null;
color?: string;
}[] = [];
// Handle line range logic if this is a line range
if (this.isLineRange()) {
const lineRangeResults = this.handleLineRange(lineNumber);
results.push(...lineRangeResults);
}
// Now, handle rule components
const ruleComponentResults = this.handleRuleComponent(lineNumber);
results.push(...ruleComponentResults);
return results;
}
handleLineRange(lineNumber: number): {
highlightType: HIGHLIGHT_TYPES;
bounds: Array<[number, number]> | null;
color?: string;
}[] {
const results: {
highlightType: HIGHLIGHT_TYPES;
bounds: Array<[number, number]> | null;
color?: string;
}[] = [];
const [startRule, endRule] = this.ruleComponents;
const startLine = startRule.lineNumber;
const endLine = endRule.lineNumber;
if (lineNumber >= startLine && lineNumber <= endLine) {
// If any component is an unbounded slice, highlight the whole line
if (startRule.isUnboundedSlice() || endRule.isUnboundedSlice()) {
results.push({
highlightType: HIGHLIGHT_TYPES.WholeLine,
bounds: null,
color: this.color,
});
} else if (lineNumber === startLine || lineNumber === endLine) {
// Apply the rule component for the start or end line
const appliedRule = lineNumber === startLine ? startRule : endRule;
if (appliedRule.isSlice && appliedRule.bounds.length > 0) {
// If the rule has bounds, it's a PartialText highlight
results.push({
highlightType: HIGHLIGHT_TYPES.PartialText,
bounds: appliedRule.bounds,
color: this.color,
});
} else {
results.push({
highlightType: HIGHLIGHT_TYPES.WholeText,
bounds: null,
color: this.color,
});
}
} else {
// For lines within the range (not at the boundaries), apply WholeText
results.push({
highlightType: HIGHLIGHT_TYPES.WholeText,
bounds: null,
color: this.color,
});
}
}
return results;
}
handleRuleComponent(lineNumber: number): {
highlightType: HIGHLIGHT_TYPES;
bounds: Array<[number, number]> | null;
color?: string;
}[] {
const results: {
highlightType: HIGHLIGHT_TYPES;
bounds: Array<[number, number]> | null;
color?: string;
}[] = [];
// Iterate over all rule components to find matches for the current line
this.ruleComponents.forEach((ruleComponent) => {
if (ruleComponent.compareLine(lineNumber) === 0) {
if (ruleComponent.isSlice) {
let highlightType;
if (ruleComponent.isUnboundedSlice()) {
highlightType = HIGHLIGHT_TYPES.WholeLine;
} else if (ruleComponent.bounds.length > 0) {
highlightType = HIGHLIGHT_TYPES.PartialText;
} else {
highlightType = HIGHLIGHT_TYPES.WholeText;
}
results.push({
highlightType,
bounds: ruleComponent.isUnboundedSlice() ? null : ruleComponent.bounds,
color: this.color,
});
} else {
results.push({
highlightType: HIGHLIGHT_TYPES.WholeText,
bounds: null,
color: this.color,
});
}
}
});
return results;
}
isLineRange() {
return this.ruleComponents.length === 2;
}
}
|