Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ab933fc
Add 'show next/previous alert' commands
asgerf Oct 5, 2022
2949fc3
Replace 'expanded' with a Set<number>
asgerf Oct 5, 2022
bb61b5e
Replace the expansion index with the result key
asgerf Oct 5, 2022
3c4682e
Ensure nodes are expanded
asgerf Oct 5, 2022
20dea5e
Also show selection in raw result view
asgerf Oct 5, 2022
125f638
Make raw result view respond to navigation events
asgerf Oct 5, 2022
88bfd19
Switch commands to up/down/left/right semantics
asgerf Oct 6, 2022
0f6100c
Bugfix in getPathNode
asgerf Oct 7, 2022
5a69465
Rename command IDs.
asgerf Oct 7, 2022
f759eed
Remove unsed parts of result-keys.ts
asgerf Oct 7, 2022
4871728
Added change note
asgerf Oct 10, 2022
d08e005
When stepping up or down, collapse the previous node
asgerf Oct 11, 2022
45b6288
Reveal panel on navigate, to prevent webview destruction
asgerf Oct 19, 2022
0e3679d
Scroll selected item into view
asgerf Oct 19, 2022
ecc07a5
Update extensions/ql-vscode/CHANGELOG.md
asgerf Oct 21, 2022
cbf15e6
Update extensions/ql-vscode/src/view/results/alert-table.tsx
asgerf Oct 21, 2022
53bb9d7
Title-case command names, like other commands
asgerf Oct 21, 2022
65777b5
Use null-aware accessors in getResult
asgerf Oct 21, 2022
d4a58a6
Consistently check for undefined rather than nullish
asgerf Oct 21, 2022
e1a56dd
Update a new more nullish checks
asgerf Oct 21, 2022
bdf7208
Mention keyboard navigation in README
asgerf Oct 21, 2022
9cb4b9d
Update extensions/ql-vscode/package.json
asgerf Oct 24, 2022
0acf9f7
Fix bad suggestion merge in package.json
asgerf Oct 24, 2022
ead1fb4
Merge branch 'main' into asgerf/navigate-alerts
asgerf Oct 24, 2022
b480f8f
Fix incorrect merge resolution in changelog
asgerf Oct 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,14 @@
"command": "codeQLQueryResults.previousPathStep",
"title": "CodeQL: Show Previous Step on Path"
},
{
"command": "codeQLQueryResults.nextAlert",
"title": "CodeQL: Show Next Alert"
},
{
"command": "codeQLQueryResults.previousAlert",
"title": "CodeQL: Show Previous Alert"
},
{
"command": "codeQL.restartQueryServer",
"title": "CodeQL: Restart Query Server"
Expand Down
16 changes: 16 additions & 0 deletions extensions/ql-vscode/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
this.navigatePathStep.bind(this, -1)
)
);
this.push(
commandRunner(
'codeQLQueryResults.nextAlert',
this.navigateAlert.bind(this, 1)
Comment thread
aeisenberg marked this conversation as resolved.
Outdated
)
);
this.push(
commandRunner(
'codeQLQueryResults.previousAlert',
this.navigateAlert.bind(this, -1)
)
);

this.push(
this.databaseManager.onDidChangeDatabaseItem(({ kind }) => {
Expand All @@ -173,6 +185,10 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
await this.postMessage({ t: 'navigatePath', direction });
}

async navigateAlert(direction: number): Promise<void> {
await this.postMessage({ t: 'navigateAlert', direction });
}

protected getPanelConfig(): WebviewPanelConfig {
return {
viewId: 'resultsView',
Expand Down
11 changes: 10 additions & 1 deletion extensions/ql-vscode/src/pure/interface-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,22 @@ export interface ShowInterpretedPageMsg {
queryPath: string;
}

/** Advance to the next or previous path no in the path viewer */
/** Advance to the next or previous path step in the path viewer */
export interface NavigatePathMsg {
t: 'navigatePath';

/** 1 for next, -1 for previous */
direction: number;
}

/** Advance to the next or previous alert in the path viewer */
export interface NavigateAlertMsg {
t: 'navigateAlert';

/** 1 for next, -1 for previous */
direction: number;
}

/**
* A message indicating that the results view should untoggle the
* "Show results in Problems view" checkbox.
Expand All @@ -165,6 +173,7 @@ export type IntoResultsViewMsg =
| SetStateMsg
| ShowInterpretedPageMsg
| NavigatePathMsg
| NavigateAlertMsg
| UntoggleShowProblemsMsg;

/**
Expand Down
37 changes: 30 additions & 7 deletions extensions/ql-vscode/src/pure/result-keys.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,48 @@
import * as sarif from 'sarif';

/**
* Identifies a result, a path, or one of the nodes on a path.
*/
interface ResultKeyBase {
resultIndex: number;
pathIndex?: number;
pathNodeIndex?: number;
}

/**
* Identifies one of the results in a result set by its index in the result list.
*/
export interface Result {
export interface Result extends ResultKeyBase {
resultIndex: number;
pathIndex?: undefined;
pathNodeIndex?: undefined;
}

/**
* Identifies one of the paths associated with a result.
*/
export interface Path extends Result {
export interface Path extends ResultKeyBase {
pathIndex: number;
pathNodeIndex?: undefined;
}

/**
* Identifies one of the nodes in a path.
*/
export interface PathNode extends Path {
export interface PathNode extends ResultKeyBase {
pathIndex: number;
pathNodeIndex: number;
}

export type ResultKey = Result | Path | PathNode;

/** Alias for `undefined` but more readable in some cases */
export const none: PathNode | undefined = undefined;

/**
* Looks up a specific result in a result set.
*/
export function getResult(sarif: sarif.Log, key: Result): sarif.Result | undefined {
export function getResult(sarif: sarif.Log, key: Result | Path | PathNode): sarif.Result | undefined {
Comment thread
aeisenberg marked this conversation as resolved.
if (sarif.runs.length === 0) return undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: The body of this function can be replaced with this:

  return sarif.runs?.[0]?.results?.[key.resultIndex];

It's really outside the scope of this PR, but it's a minor readability improvement if you want to add it.

if (sarif.runs[0].results === undefined) return undefined;
const results = sarif.runs[0].results;
Expand All @@ -37,7 +52,7 @@ export function getResult(sarif: sarif.Log, key: Result): sarif.Result | undefin
/**
* Looks up a specific path in a result set.
*/
export function getPath(sarif: sarif.Log, key: Path): sarif.ThreadFlow | undefined {
export function getPath(sarif: sarif.Log, key: Path | PathNode): sarif.ThreadFlow | undefined {
Comment thread
aeisenberg marked this conversation as resolved.
const result = getResult(sarif, key);
if (result === undefined) return undefined;
let index = -1;
Expand All @@ -64,7 +79,7 @@ export function getPathNode(sarif: sarif.Log, key: PathNode): sarif.Location | u
/**
* Returns true if the two keys are both `undefined` or contain the same set of indices.
*/
export function equals(key1: PathNode | undefined, key2: PathNode | undefined): boolean {
export function equals(key1: Partial<PathNode> | undefined, key2: Partial<PathNode> | undefined): boolean {
Comment thread
aeisenberg marked this conversation as resolved.
Outdated
if (key1 === key2) return true;
if (key1 === undefined || key2 === undefined) return false;
return key1.resultIndex === key2.resultIndex && key1.pathIndex === key2.pathIndex && key1.pathNodeIndex === key2.pathNodeIndex;
Expand All @@ -73,7 +88,7 @@ export function equals(key1: PathNode | undefined, key2: PathNode | undefined):
/**
* Returns true if the two keys contain the same set of indices and neither are `undefined`.
*/
export function equalsNotUndefined(key1: PathNode | undefined, key2: PathNode | undefined): boolean {
export function equalsNotUndefined(key1: Partial<PathNode> | undefined, key2: Partial<PathNode> | undefined): boolean {
if (key1 === undefined || key2 === undefined) return false;
return key1.resultIndex === key2.resultIndex && key1.pathIndex === key2.pathIndex && key1.pathNodeIndex === key2.pathNodeIndex;
}
Expand All @@ -93,3 +108,11 @@ export function getAllPaths(result: sarif.Result): sarif.ThreadFlow[] {
}
return paths;
}

/**
* Creates a unique string representation of the given key, suitable for use
* as the key in a map or set.
*/
export function keyToString(key: ResultKey) {
return key.resultIndex + '-' + (key.pathIndex ?? '') + '-' + (key.pathNodeIndex ?? '');
}
7 changes: 5 additions & 2 deletions extensions/ql-vscode/src/view/results/RawTableRow.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import * as React from 'react';
import { ResultRow } from '../../pure/bqrs-cli-types';
import { zebraStripe } from './result-table-utils';
import { selectableZebraStripe } from './result-table-utils';
import RawTableValue from './RawTableValue';

interface Props {
rowIndex: number;
row: ResultRow;
databaseUri: string;
className?: string;
isSelected?: boolean;
onSelected?: (row: number, column: number) => void;
}

export default function RawTableRow(props: Props) {
return (
<tr key={props.rowIndex} {...zebraStripe(props.rowIndex, props.className || '')}>
<tr key={props.rowIndex} {...selectableZebraStripe(props.isSelected ?? false, props.rowIndex, props.className || '')}>
<td key={-1}>{props.rowIndex + 1}</td>

{props.row.map((value, columnIndex) => (
<td key={columnIndex}>
<RawTableValue
value={value}
databaseUri={props.databaseUri}
onSelected={() => props.onSelected?.(props.rowIndex, columnIndex)}
/>
</td>
))}
Expand Down
3 changes: 2 additions & 1 deletion extensions/ql-vscode/src/view/results/RawTableValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CellValue } from '../../pure/bqrs-cli-types';
interface Props {
value: CellValue;
databaseUri: string;
onSelected?: () => void;
}

export default function RawTableValue(props: Props): JSX.Element {
Expand All @@ -18,5 +19,5 @@ export default function RawTableValue(props: Props): JSX.Element {
return <span>{renderLocation(undefined, rawValue.toString())}</span>;
}

return renderLocation(rawValue.url, rawValue.label, props.databaseUri);
return renderLocation(rawValue.url, rawValue.label, props.databaseUri, undefined, props.onSelected);
}
Loading