Display query text in "virtual" (readonly) file
This commit is contained in:
@@ -12,7 +12,9 @@ import {
|
||||
env,
|
||||
window,
|
||||
QuickPickItem,
|
||||
Range
|
||||
Range,
|
||||
workspace,
|
||||
ProviderResult
|
||||
} from 'vscode';
|
||||
import { LanguageClient } from 'vscode-languageclient';
|
||||
import * as os from 'os';
|
||||
@@ -78,6 +80,7 @@ import { CodeQlStatusBarHandler } from './status-bar';
|
||||
import { Credentials } from './authentication';
|
||||
import { RemoteQueriesManager } from './remote-queries/remote-queries-manager';
|
||||
import { RemoteQuery } from './remote-queries/remote-query';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
@@ -773,6 +776,8 @@ async function activateWithInstalledDistribution(
|
||||
void logger.log('Initializing remote queries interface.');
|
||||
const rqm = new RemoteQueriesManager(ctx, logger, cliServer);
|
||||
|
||||
registerTextProvider();
|
||||
|
||||
// The "runRemoteQuery" command is internal-only.
|
||||
ctx.subscriptions.push(
|
||||
commandRunnerWithProgress('codeQL.runRemoteQuery', async (
|
||||
@@ -980,3 +985,20 @@ async function initializeLogging(ctx: ExtensionContext): Promise<void> {
|
||||
}
|
||||
|
||||
const checkForUpdatesCommand = 'codeQL.checkForUpdatesToCLI';
|
||||
|
||||
/**
|
||||
* This text provider lets us open readonly files in the editor.
|
||||
*
|
||||
* TODO: Consolidate this with the 'codeql' text provider in query-history.ts.
|
||||
*/
|
||||
function registerTextProvider() {
|
||||
workspace.registerTextDocumentContentProvider('remote-query', {
|
||||
provideTextDocumentContent(
|
||||
uri: Uri
|
||||
): ProviderResult<string> {
|
||||
const params = new URLSearchParams(uri.query);
|
||||
|
||||
return params.get('queryText');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -181,6 +181,11 @@ export interface OpenFileMsg {
|
||||
filePath: string;
|
||||
}
|
||||
|
||||
export interface OpenVirtualFileMsg {
|
||||
t: 'openVirtualFile';
|
||||
queryText: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message from the results view to toggle the display of
|
||||
* query diagnostics.
|
||||
@@ -369,7 +374,8 @@ export interface ParsedResultSets {
|
||||
export type FromRemoteQueriesMessage =
|
||||
| RemoteQueryLoadedMessage
|
||||
| RemoteQueryErrorMessage
|
||||
| OpenFileMsg;
|
||||
| OpenFileMsg
|
||||
| OpenVirtualFileMsg;
|
||||
|
||||
export type ToRemoteQueriesMessage =
|
||||
| SetRemoteQueryResultMessage;
|
||||
|
||||
@@ -32,7 +32,7 @@ export type QueryHistoryItemOptions = {
|
||||
isQuickQuery?: boolean;
|
||||
};
|
||||
|
||||
const SHOW_QUERY_TEXT_MSG = `\
|
||||
export const SHOW_QUERY_TEXT_MSG = `\
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// This is the text of the entire query file when it was executed for this query //
|
||||
// run. The text or dependent libraries may have changed since then. //
|
||||
|
||||
@@ -21,6 +21,8 @@ import { RemoteQuery } from './remote-query';
|
||||
import { RemoteQueryResult as RemoteQueryResultViewModel } from './shared/remote-query-result';
|
||||
import { AnalysisResult as AnalysisResultViewModel } from './shared/remote-query-result';
|
||||
import { showAndLogWarningMessage } from '../helpers';
|
||||
import { URLSearchParams } from 'url';
|
||||
import { SHOW_QUERY_TEXT_MSG } from '../query-history';
|
||||
|
||||
export class RemoteQueriesInterfaceManager {
|
||||
private panel: WebviewPanel | undefined;
|
||||
@@ -65,7 +67,7 @@ export class RemoteQueriesInterfaceManager {
|
||||
queryTitle: query.queryName,
|
||||
queryFileName: queryFileName,
|
||||
queryFilePath: query.queryFilePath,
|
||||
queryTextTmpFilePath: query.queryTextTmpFilePath,
|
||||
queryText: query.queryText,
|
||||
totalRepositoryCount: query.repositories.length,
|
||||
affectedRepositoryCount: affectedRepositories.length,
|
||||
totalResultCount: totalResultCount,
|
||||
@@ -142,6 +144,22 @@ export class RemoteQueriesInterfaceManager {
|
||||
}
|
||||
}
|
||||
|
||||
private async openVirtualFile(text: string) {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
queryText: encodeURIComponent(SHOW_QUERY_TEXT_MSG + text)
|
||||
});
|
||||
const uri = Uri.parse(
|
||||
`remote-query:query-text.ql?${params.toString()}`,
|
||||
true
|
||||
);
|
||||
const doc = await workspace.openTextDocument(uri);
|
||||
await Window.showTextDocument(doc, { preview: false });
|
||||
} catch (error) {
|
||||
void showAndLogWarningMessage('Could not open query text');
|
||||
}
|
||||
}
|
||||
|
||||
private async handleMsgFromView(
|
||||
msg: FromRemoteQueriesMessage
|
||||
): Promise<void> {
|
||||
@@ -159,6 +177,9 @@ export class RemoteQueriesInterfaceManager {
|
||||
case 'openFile':
|
||||
await this.openFile(msg.filePath);
|
||||
break;
|
||||
case 'openVirtualFile':
|
||||
await this.openVirtualFile(msg.queryText);
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Repository } from './repository';
|
||||
export interface RemoteQuery {
|
||||
queryName: string;
|
||||
queryFilePath: string;
|
||||
queryTextTmpFilePath: string;
|
||||
queryText: string;
|
||||
controllerRepository: Repository;
|
||||
repositories: Repository[];
|
||||
executionStartTime: Date;
|
||||
|
||||
@@ -467,26 +467,12 @@ async function buildRemoteQueryEntity(
|
||||
return { owner: owner, name: repo };
|
||||
});
|
||||
|
||||
// Get the query text from query file and save it in a temporary .ql file.
|
||||
const queryTextTmpFilePath = path.join(tmpDir.name, `tmp-${queryName}`);
|
||||
const queryText = await fs.readFile(queryFilePath, 'utf8');
|
||||
await fs.writeFile(
|
||||
queryTextTmpFilePath, `\
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// This is the text of the entire query file when it was executed for this query //
|
||||
// run. The text or dependent libraries may have changed since then. //
|
||||
// //
|
||||
// To make changes to the query and the dependent libraries, save this file in a //
|
||||
// suitable, permanent location. //
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
${queryText}`
|
||||
);
|
||||
|
||||
return {
|
||||
queryName,
|
||||
queryFilePath,
|
||||
queryTextTmpFilePath,
|
||||
queryText,
|
||||
controllerRepository: {
|
||||
owner: controllerRepoOwner,
|
||||
name: controllerRepoName,
|
||||
|
||||
@@ -2,7 +2,7 @@ export interface RemoteQueryResult {
|
||||
queryTitle: string;
|
||||
queryFileName: string;
|
||||
queryFilePath: string;
|
||||
queryTextTmpFilePath: string;
|
||||
queryText: string;
|
||||
totalRepositoryCount: number;
|
||||
affectedRepositoryCount: number;
|
||||
totalResultCount: number;
|
||||
|
||||
@@ -13,7 +13,7 @@ const emptyQueryResult: RemoteQueryResult = {
|
||||
queryTitle: '',
|
||||
queryFileName: '',
|
||||
queryFilePath: '',
|
||||
queryTextTmpFilePath: '',
|
||||
queryText: '',
|
||||
totalRepositoryCount: 0,
|
||||
affectedRepositoryCount: 0,
|
||||
totalResultCount: 0,
|
||||
@@ -40,13 +40,6 @@ const AnalysisResultItem = (props: AnalysisResult) => (
|
||||
</span>
|
||||
);
|
||||
|
||||
function openFile(filePath: string): void {
|
||||
vscode.postMessage({
|
||||
t: 'openFile',
|
||||
filePath
|
||||
});
|
||||
}
|
||||
|
||||
export function RemoteQueries(): JSX.Element {
|
||||
const [queryResult, setQueryResult] = useState<RemoteQueryResult>(emptyQueryResult);
|
||||
|
||||
@@ -74,11 +67,17 @@ export function RemoteQueries(): JSX.Element {
|
||||
|
||||
try {
|
||||
const openQueryFile = () => {
|
||||
openFile(queryResult.queryFilePath);
|
||||
vscode.postMessage({
|
||||
t: 'openFile',
|
||||
filePath: queryResult.queryFilePath
|
||||
});
|
||||
};
|
||||
|
||||
const openQueryTextTmpFile = () => {
|
||||
openFile(queryResult.queryTextTmpFilePath);
|
||||
vscode.postMessage({
|
||||
t: 'openVirtualFile',
|
||||
queryText: queryResult.queryText
|
||||
});
|
||||
};
|
||||
|
||||
return <div className="vscode-codeql__remote-queries-view">
|
||||
|
||||
Reference in New Issue
Block a user