1- import {
2- Uri ,
3- Location ,
4- Range ,
5- WebviewPanel ,
6- workspace ,
7- window as Window ,
8- ViewColumn ,
9- Selection ,
10- TextEditorRevealType ,
11- ThemeColor ,
12- } from "vscode" ;
13- import { tryGetResolvableLocation , isLineColumnLoc } from "./pure/bqrs-utils" ;
14- import { DatabaseItem , DatabaseManager } from "./databases/local-databases" ;
15- import { ViewSourceFileMsg } from "./pure/interface-types" ;
16- import { Logger } from "./common" ;
17- import {
18- LineColumnLocation ,
19- WholeFileLocation ,
20- UrlValue ,
21- ResolvableLocationValue ,
22- } from "./pure/bqrs-cli-types" ;
1+ import { Uri , WebviewPanel } from "vscode" ;
232
243/**
254 * This module contains functions and types that are sharedd between
@@ -44,144 +23,3 @@ export function fileUriToWebviewUri(
4423) : string {
4524 return panel . webview . asWebviewUri ( fileUriOnDisk ) . toString ( ) ;
4625}
47-
48- /**
49- * Resolves the specified CodeQL location to a URI into the source archive.
50- * @param loc CodeQL location to resolve. Must have a non-empty value for `loc.file`.
51- * @param databaseItem Database in which to resolve the file location.
52- */
53- function resolveFivePartLocation (
54- loc : LineColumnLocation ,
55- databaseItem : DatabaseItem ,
56- ) : Location {
57- // `Range` is a half-open interval, and is zero-based. CodeQL locations are closed intervals, and
58- // are one-based. Adjust accordingly.
59- const range = new Range (
60- Math . max ( 0 , loc . startLine - 1 ) ,
61- Math . max ( 0 , loc . startColumn - 1 ) ,
62- Math . max ( 0 , loc . endLine - 1 ) ,
63- Math . max ( 1 , loc . endColumn ) ,
64- ) ;
65-
66- return new Location ( databaseItem . resolveSourceFile ( loc . uri ) , range ) ;
67- }
68-
69- /**
70- * Resolves the specified CodeQL filesystem resource location to a URI into the source archive.
71- * @param loc CodeQL location to resolve, corresponding to an entire filesystem resource. Must have a non-empty value for `loc.file`.
72- * @param databaseItem Database in which to resolve the filesystem resource location.
73- */
74- function resolveWholeFileLocation (
75- loc : WholeFileLocation ,
76- databaseItem : DatabaseItem ,
77- ) : Location {
78- // A location corresponding to the start of the file.
79- const range = new Range ( 0 , 0 , 0 , 0 ) ;
80- return new Location ( databaseItem . resolveSourceFile ( loc . uri ) , range ) ;
81- }
82-
83- /**
84- * Try to resolve the specified CodeQL location to a URI into the source archive. If no exact location
85- * can be resolved, returns `undefined`.
86- * @param loc CodeQL location to resolve
87- * @param databaseItem Database in which to resolve the file location.
88- */
89- export function tryResolveLocation (
90- loc : UrlValue | undefined ,
91- databaseItem : DatabaseItem ,
92- ) : Location | undefined {
93- const resolvableLoc = tryGetResolvableLocation ( loc ) ;
94- if ( ! resolvableLoc || typeof resolvableLoc === "string" ) {
95- return ;
96- } else if ( isLineColumnLoc ( resolvableLoc ) ) {
97- return resolveFivePartLocation ( resolvableLoc , databaseItem ) ;
98- } else {
99- return resolveWholeFileLocation ( resolvableLoc , databaseItem ) ;
100- }
101- }
102-
103- export async function showResolvableLocation (
104- loc : ResolvableLocationValue ,
105- databaseItem : DatabaseItem ,
106- ) : Promise < void > {
107- await showLocation ( tryResolveLocation ( loc , databaseItem ) ) ;
108- }
109-
110- export async function showLocation ( location ?: Location ) {
111- if ( ! location ) {
112- return ;
113- }
114-
115- const doc = await workspace . openTextDocument ( location . uri ) ;
116- const editorsWithDoc = Window . visibleTextEditors . filter (
117- ( e ) => e . document === doc ,
118- ) ;
119- const editor =
120- editorsWithDoc . length > 0
121- ? editorsWithDoc [ 0 ]
122- : await Window . showTextDocument ( doc , {
123- // avoid preview mode so editor is sticky and will be added to navigation and search histories.
124- preview : false ,
125- viewColumn : ViewColumn . One ,
126- } ) ;
127-
128- const range = location . range ;
129- // When highlighting the range, vscode's occurrence-match and bracket-match highlighting will
130- // trigger based on where we place the cursor/selection, and will compete for the user's attention.
131- // For reference:
132- // - Occurences are highlighted when the cursor is next to or inside a word or a whole word is selected.
133- // - Brackets are highlighted when the cursor is next to a bracket and there is an empty selection.
134- // - Multi-line selections explicitly highlight line-break characters, but multi-line decorators do not.
135- //
136- // For single-line ranges, select the whole range, mainly to disable bracket highlighting.
137- // For multi-line ranges, place the cursor at the beginning to avoid visual artifacts from selected line-breaks.
138- // Multi-line ranges are usually large enough to overshadow the noise from bracket highlighting.
139- const selectionEnd =
140- range . start . line === range . end . line ? range . end : range . start ;
141- editor . selection = new Selection ( range . start , selectionEnd ) ;
142- editor . revealRange ( range , TextEditorRevealType . InCenter ) ;
143- editor . setDecorations ( shownLocationDecoration , [ range ] ) ;
144- editor . setDecorations ( shownLocationLineDecoration , [ range ] ) ;
145- }
146-
147- const findMatchBackground = new ThemeColor ( "editor.findMatchBackground" ) ;
148- const findRangeHighlightBackground = new ThemeColor (
149- "editor.findRangeHighlightBackground" ,
150- ) ;
151-
152- export const shownLocationDecoration = Window . createTextEditorDecorationType ( {
153- backgroundColor : findMatchBackground ,
154- } ) ;
155-
156- export const shownLocationLineDecoration =
157- Window . createTextEditorDecorationType ( {
158- backgroundColor : findRangeHighlightBackground ,
159- isWholeLine : true ,
160- } ) ;
161-
162- export async function jumpToLocation (
163- msg : ViewSourceFileMsg ,
164- databaseManager : DatabaseManager ,
165- logger : Logger ,
166- ) {
167- const databaseItem = databaseManager . findDatabaseItem (
168- Uri . parse ( msg . databaseUri ) ,
169- ) ;
170- if ( databaseItem !== undefined ) {
171- try {
172- await showResolvableLocation ( msg . loc , databaseItem ) ;
173- } catch ( e ) {
174- if ( e instanceof Error ) {
175- if ( e . message . match ( / F i l e n o t f o u n d / ) ) {
176- void Window . showErrorMessage (
177- "Original file of this result is not in the database's source archive." ,
178- ) ;
179- } else {
180- void logger . log ( `Unable to handleMsgFromView: ${ e . message } ` ) ;
181- }
182- } else {
183- void logger . log ( `Unable to handleMsgFromView: ${ e } ` ) ;
184- }
185- }
186- }
187- }
0 commit comments