Skip to content

Commit 27a8636

Browse files
authored
Deal with non-printable characters when rendering raw results (#1203)
1 parent 92a9993 commit 27a8636

3 files changed

Lines changed: 36 additions & 30 deletions

File tree

extensions/ql-vscode/src/remote-queries/view/RawResultsTable.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Box, Link } from '@primer/react';
33
import { CellValue, RawResultSet, ResultSetSchema } from '../../pure/bqrs-cli-types';
44
import { useState } from 'react';
55
import TextButton from './TextButton';
6+
import { convertNonPrintableChars } from '../../text-utils';
67

78
const numOfResultsInContractedMode = 5;
89

@@ -34,11 +35,11 @@ const Cell = ({
3435
case 'string':
3536
case 'number':
3637
case 'boolean':
37-
return <span>{value.toString()}</span>;
38+
return <span>{convertNonPrintableChars(value.toString())}</span>;
3839
case 'object':
3940
// TODO: This will be converted to a proper link once there
4041
// is support for populating link URLs.
41-
return <Link>{value.label}</Link>;
42+
return <Link>{convertNonPrintableChars(value.label)}</Link>;
4243
}
4344
};
4445

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const CONTROL_CODE = '\u001F'.codePointAt(0)!;
2+
const CONTROL_LABEL = '\u2400'.codePointAt(0)!;
3+
4+
/**
5+
* Converts the given text so that any non-printable characters are replaced.
6+
* @param label The text to convert.
7+
* @returns The converted text.
8+
*/
9+
export function convertNonPrintableChars(label: string | undefined) {
10+
// If the label was empty, use a placeholder instead, so the link is still clickable.
11+
if (!label) {
12+
return '[empty string]';
13+
} else if (label.match(/^\s+$/)) {
14+
return `[whitespace: "${label}"]`;
15+
} else {
16+
/**
17+
* If the label contains certain non-printable characters, loop through each
18+
* character and replace it with the cooresponding unicode control label.
19+
*/
20+
const convertedLabelArray: any[] = [];
21+
for (let i = 0; i < label.length; i++) {
22+
const labelCheck = label.codePointAt(i)!;
23+
if (labelCheck <= CONTROL_CODE) {
24+
convertedLabelArray[i] = String.fromCodePoint(labelCheck + CONTROL_LABEL);
25+
} else {
26+
convertedLabelArray[i] = label.charAt(i);
27+
}
28+
}
29+
return convertedLabelArray.join('');
30+
}
31+
}

extensions/ql-vscode/src/view/result-table-utils.tsx

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { RawResultsSortState, QueryMetadata, SortDirection } from '../pure/inter
55
import { assertNever } from '../pure/helpers-pure';
66
import { ResultSet } from '../pure/interface-types';
77
import { vscode } from './vscode-api';
8+
import { convertNonPrintableChars } from '../text-utils';
89

910
export interface ResultTableProps {
1011
resultSet: ResultSet;
@@ -37,9 +38,6 @@ export const oddRowClassName = 'vscode-codeql__result-table-row--odd';
3738
export const pathRowClassName = 'vscode-codeql__result-table-row--path';
3839
export const selectedRowClassName = 'vscode-codeql__result-table-row--selected';
3940

40-
const CONTROL_CODE = '\u001F'.codePointAt(0)!;
41-
const CONTROL_LABEL = '\u2400'.codePointAt(0)!;
42-
4341
export function jumpToLocationHandler(
4442
loc: ResolvableLocationValue,
4543
databaseUri: string,
@@ -70,30 +68,6 @@ export function openFile(filePath: string): void {
7068
});
7169
}
7270

73-
function convertedNonprintableChars(label: string) {
74-
// If the label was empty, use a placeholder instead, so the link is still clickable.
75-
if (!label) {
76-
return '[empty string]';
77-
} else if (label.match(/^\s+$/)) {
78-
return `[whitespace: "${label}"]`;
79-
} else {
80-
/**
81-
* If the label contains certain non-printable characters, loop through each
82-
* character and replace it with the cooresponding unicode control label.
83-
*/
84-
const convertedLabelArray: any[] = [];
85-
for (let i = 0; i < label.length; i++) {
86-
const labelCheck = label.codePointAt(i)!;
87-
if (labelCheck <= CONTROL_CODE) {
88-
convertedLabelArray[i] = String.fromCodePoint(labelCheck + CONTROL_LABEL);
89-
} else {
90-
convertedLabelArray[i] = label.charAt(i);
91-
}
92-
}
93-
return convertedLabelArray.join('');
94-
}
95-
}
96-
9771
/**
9872
* Render a location as a link which when clicked displays the original location.
9973
*/
@@ -105,7 +79,7 @@ export function renderLocation(
10579
callback?: () => void
10680
): JSX.Element {
10781

108-
const displayLabel = convertedNonprintableChars(label!);
82+
const displayLabel = convertNonPrintableChars(label!);
10983

11084
if (loc === undefined) {
11185
return <span>{displayLabel}</span>;

0 commit comments

Comments
 (0)