Skip to content

Commit 8268d68

Browse files
committed
Apply styling to RA predicate names
1 parent 70ec570 commit 8268d68

1 file changed

Lines changed: 73 additions & 24 deletions

File tree

extensions/ql-vscode/src/view/compare-performance/RAPrettyPrinter.tsx

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Fragment } from "react";
2+
import { styled } from "styled-components";
23

34
/**
45
* A set of names, for generating unambiguous abbreviations.
@@ -12,7 +13,7 @@ class NameSet {
1213
qnames
1314
.map((qname) => builder.visitQName(qname))
1415
.forEach((r, index) => {
15-
this.abbreviations.set(names[index], r.abbreviate());
16+
this.abbreviations.set(names[index], r.abbreviate(true));
1617
});
1718
}
1819

@@ -86,7 +87,7 @@ class TrieNode {
8687

8788
interface VisitResult {
8889
node: TrieNode;
89-
abbreviate: () => React.ReactNode;
90+
abbreviate: (isRoot?: boolean) => React.ReactNode;
9091
}
9192

9293
class TrieBuilder {
@@ -118,13 +119,21 @@ class TrieBuilder {
118119
}
119120
return {
120121
node: trieNode,
121-
abbreviate: () => {
122+
abbreviate: (isRoot = false) => {
122123
const result: React.ReactNode[] = [];
123124
if (prefix != null) {
124125
result.push(prefix.abbreviate());
125126
result.push("::");
126127
}
127-
result.push(qname.name);
128+
const { name } = qname;
129+
const hash = name.indexOf("#");
130+
if (hash !== -1 && isRoot) {
131+
const shortName = name.substring(0, hash);
132+
result.push(<IdentifierSpan>{shortName}</IdentifierSpan>);
133+
result.push(name.substring(hash));
134+
} else {
135+
result.push(isRoot ? <IdentifierSpan>{name}</IdentifierSpan> : name);
136+
}
128137
if (args != null) {
129138
result.push("<");
130139
if (trieNodeBeforeArgs.children.size === 1) {
@@ -148,33 +157,73 @@ class TrieBuilder {
148157
}
149158
}
150159

151-
const nameTokenRegex = /\b[^ ]+::[^ (]+\b/g;
160+
/**
161+
* Span enclosing an entire qualified name.
162+
*
163+
* Can be used to gray out uninteresting parts of the name, though this looks worse than expected.
164+
*/
165+
const QNameSpan = styled.span`
166+
/* color: var(--vscode-disabledForeground); */
167+
`;
168+
169+
/** Span enclosing the innermost identifier, e.g. the `foo` in `A::B<X>::foo#abc` */
170+
const IdentifierSpan = styled.span`
171+
font-weight: 600;
172+
`;
173+
174+
/** Span enclosing keywords such as `JOIN` and `WITH`. */
175+
const KeywordSpan = styled.span`
176+
font-weight: 500;
177+
`;
178+
179+
const nameTokenRegex = /\b[^ (]+\b/g;
180+
181+
function traverseMatches(
182+
text: string,
183+
regex: RegExp,
184+
callbacks: {
185+
onMatch: (match: RegExpMatchArray) => void;
186+
onText: (text: string) => void;
187+
},
188+
) {
189+
const matches = Array.from(text.matchAll(regex));
190+
let lastIndex = 0;
191+
for (const match of matches) {
192+
const before = text.substring(lastIndex, match.index);
193+
if (before !== "") {
194+
callbacks.onText(before);
195+
}
196+
callbacks.onMatch(match);
197+
lastIndex = match.index + match[0].length;
198+
}
199+
const after = text.substring(lastIndex);
200+
if (after !== "") {
201+
callbacks.onText(after);
202+
}
203+
}
152204

153205
export function abbreviateRASteps(steps: string[]): React.ReactNode[] {
154206
const nameTokens = steps.flatMap((step) =>
155207
Array.from(step.matchAll(nameTokenRegex)).map((tok) => tok[0]),
156208
);
157-
const nameSet = new NameSet(nameTokens);
209+
const nameSet = new NameSet(nameTokens.filter((name) => name.includes("::")));
158210
return steps.map((step, index) => {
159-
const matches = Array.from(step.matchAll(nameTokenRegex));
160211
const result: React.ReactNode[] = [];
161-
for (let i = 0; i < matches.length; i++) {
162-
const match = matches[i];
163-
const before = step.slice(
164-
i === 0 ? 0 : matches[i - 1].index + matches[i - 1][0].length,
165-
match.index,
166-
);
167-
result.push(before);
168-
result.push(nameSet.getAbbreviation(match[0]));
169-
}
170-
result.push(
171-
matches.length === 0
172-
? step
173-
: step.slice(
174-
matches[matches.length - 1].index +
175-
matches[matches.length - 1][0].length,
176-
),
177-
);
212+
traverseMatches(step, nameTokenRegex, {
213+
onMatch(match) {
214+
const text = match[0];
215+
if (text.includes("::")) {
216+
result.push(<QNameSpan>{nameSet.getAbbreviation(text)}</QNameSpan>);
217+
} else if (/[A-Z]+/.test(text)) {
218+
result.push(<KeywordSpan>{text}</KeywordSpan>);
219+
} else {
220+
result.push(match[0]);
221+
}
222+
},
223+
onText(text) {
224+
result.push(text);
225+
},
226+
});
178227
return <Fragment key={index}>{result}</Fragment>;
179228
});
180229
}

0 commit comments

Comments
 (0)