@@ -7,6 +7,7 @@ import { graphToDot } from "../control-flow/render";
7
7
import { simplifyCFG , trimFor } from "../control-flow/graph-ops" ;
8
8
import { newCFGBuilder , type Language } from "../control-flow/cfg" ;
9
9
import { mergeNodeAttrs } from "../control-flow/cfg-defs" ;
10
+ import { OverviewViewProvider } from "./overview-view" ;
10
11
11
12
let graphviz : Graphviz ;
12
13
interface SupportedLanguage {
@@ -110,12 +111,43 @@ function getCurrentCode(): {
110
111
return { code, languageId, language } ;
111
112
}
112
113
114
+ type Settings = { flatSwitch ?: boolean ; simplify ?: boolean } ;
115
+ function loadSettings ( ) : Settings {
116
+ const config = vscode . workspace . getConfiguration ( "functionGraphOverview" ) ;
117
+ return {
118
+ flatSwitch : config . get ( "flatSwitch" ) ,
119
+ simplify : config . get ( "simplify" ) ,
120
+ } ;
121
+ }
122
+
123
+ function getFunctionAtPosition (
124
+ tree : Parser . Tree ,
125
+ position : vscode . Position ,
126
+ language : Language ,
127
+ ) : Parser . SyntaxNode | null {
128
+ let syntax : SyntaxNode | null = tree . rootNode . descendantForPosition ( {
129
+ row : position . line ,
130
+ column : position . character ,
131
+ } ) ;
132
+
133
+ while ( syntax ) {
134
+ if ( functionNodeTypes [ language ] . includes ( syntax . type ) ) {
135
+ break ;
136
+ }
137
+ syntax = syntax . parent ;
138
+ }
139
+ return syntax ;
140
+ }
113
141
// This method is called when your extension is activated
114
142
// Your extension is activated the very first time the command is executed
115
143
export async function activate ( context : vscode . ExtensionContext ) {
116
144
graphviz = await Graphviz . load ( ) ;
145
+ const helloWorldSvg = graphviz . dot ( "digraph G { Hello -> World }" ) ;
117
146
118
- const provider = new OverviewViewProvider ( context . extensionUri ) ;
147
+ const provider = new OverviewViewProvider (
148
+ context . extensionUri ,
149
+ helloWorldSvg ,
150
+ ) ;
119
151
120
152
context . subscriptions . push (
121
153
vscode . window . registerWebviewViewProvider (
@@ -136,6 +168,11 @@ export async function activate(context: vscode.ExtensionContext) {
136
168
( event : vscode . TextEditorSelectionChangeEvent ) : void => {
137
169
const editor = event . textEditor ;
138
170
const position = editor . selection . active ;
171
+ // const offset = editor.document.offsetAt(position);
172
+
173
+ console . log (
174
+ `Cursor position changed: Line ${ position . line + 1 } , Column ${ position . character + 1 } ` ,
175
+ ) ;
139
176
140
177
const { code, languageId, language } = getCurrentCode ( ) ?? { } ;
141
178
if ( ! code || ! languageId || ! language ) {
@@ -144,62 +181,28 @@ export async function activate(context: vscode.ExtensionContext) {
144
181
145
182
const tree = parsers [ language ] . parse ( code ) ;
146
183
147
- console . log (
148
- `Cursor position changed: Line ${ position . line + 1 } , Column ${ position . character + 1 } ` ,
149
- ) ;
150
- let node : SyntaxNode | null = tree . rootNode . descendantForPosition ( {
151
- row : position . line ,
152
- column : position . character ,
153
- } ) ;
184
+ const functionSyntax = getFunctionAtPosition ( tree , position , language ) ;
185
+
186
+ if ( ! functionSyntax ) return ;
154
187
155
- while ( node ) {
156
- if ( functionNodeTypes [ language ] . includes ( node . type ) ) {
157
- break ;
158
- }
159
- node = node . parent ;
188
+ console . log ( functionSyntax ) ;
189
+ const nameSyntax = functionSyntax . childForFieldName ( "name" ) ;
190
+ if ( nameSyntax ) {
191
+ console . log ( "Currently in" , nameSyntax . text ) ;
160
192
}
161
193
162
- if ( node ) {
163
- console . log ( node ) ;
164
- const nameNode = node . childForFieldName ( "name" ) ;
165
- if ( nameNode ) {
166
- const name = editor . document . getText (
167
- new vscode . Range (
168
- new vscode . Position (
169
- nameNode . startPosition . row ,
170
- nameNode . startPosition . column ,
171
- ) ,
172
- new vscode . Position (
173
- nameNode . endPosition . row ,
174
- nameNode . endPosition . column ,
175
- ) ,
176
- ) ,
177
- ) ;
178
- console . log ( "Currently in" , name ) ;
179
- }
180
- const flatSwitch = Boolean (
181
- vscode . workspace
182
- . getConfiguration ( "functionGraphOverview" )
183
- . get ( "flatSwitch" ) ,
184
- ) ;
185
- const language = idToLanguage ( languageId ) ;
186
- if ( ! language ) {
187
- return ;
188
- }
189
- const builder = newCFGBuilder ( language , { flatSwitch } ) ;
190
- let cfg = builder . buildCFG ( node ) ;
191
- cfg = trimFor ( cfg ) ;
192
- if (
193
- vscode . workspace
194
- . getConfiguration ( "functionGraphOverview" )
195
- . get ( "simplify" )
196
- ) {
197
- cfg = simplifyCFG ( cfg , mergeNodeAttrs ) ;
198
- }
199
- const dot = graphToDot ( cfg ) ;
200
- const svg = graphviz . dot ( dot ) ;
201
- provider . setSVG ( svg ) ;
194
+ const { flatSwitch, simplify } = loadSettings ( ) ;
195
+ const builder = newCFGBuilder ( language , { flatSwitch } ) ;
196
+ let cfg = builder . buildCFG ( functionSyntax ) ;
197
+ cfg = trimFor ( cfg ) ;
198
+ if ( simplify ) {
199
+ cfg = simplifyCFG ( cfg , mergeNodeAttrs ) ;
202
200
}
201
+
202
+ const dot = graphToDot ( cfg ) ;
203
+ const svg = graphviz . dot ( dot ) ;
204
+
205
+ provider . setSVG ( svg ) ;
203
206
} ,
204
207
) ;
205
208
@@ -210,96 +213,3 @@ export async function activate(context: vscode.ExtensionContext) {
210
213
export function deactivate ( ) { }
211
214
212
215
//------------------------------------------------
213
-
214
- class OverviewViewProvider implements vscode . WebviewViewProvider {
215
- public static readonly viewType = "functionGraphOverview.overview" ;
216
-
217
- private _view ?: vscode . WebviewView ;
218
-
219
- constructor ( private readonly _extensionUri : vscode . Uri ) { }
220
-
221
- public setSVG ( svg : string ) {
222
- if ( this . _view ) {
223
- this . _view . webview . postMessage ( { type : "svgImage" , svg } ) ;
224
- }
225
- }
226
-
227
- resolveWebviewView (
228
- webviewView : vscode . WebviewView ,
229
- _context : vscode . WebviewViewResolveContext ,
230
- _token : vscode . CancellationToken ,
231
- ) : Thenable < void > | void {
232
- this . _view = webviewView ;
233
-
234
- webviewView . webview . options = {
235
- // Allow scripts in the webview
236
- enableScripts : true ,
237
-
238
- localResourceRoots : [ this . _extensionUri ] ,
239
- } ;
240
-
241
- webviewView . webview . html = this . _getHtmlForWebview ( webviewView . webview ) ;
242
- }
243
- private _getHtmlForWebview ( webview : vscode . Webview ) : string {
244
- // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview.
245
- const scriptUri = webview . asWebviewUri (
246
- vscode . Uri . joinPath ( this . _extensionUri , "webview-content" , "main.js" ) ,
247
- ) ;
248
-
249
- // Do the same for the stylesheet.
250
- const styleResetUri = webview . asWebviewUri (
251
- vscode . Uri . joinPath ( this . _extensionUri , "webview-content" , "reset.css" ) ,
252
- ) ;
253
- const styleVSCodeUri = webview . asWebviewUri (
254
- vscode . Uri . joinPath ( this . _extensionUri , "webview-content" , "vscode.css" ) ,
255
- ) ;
256
- const styleMainUri = webview . asWebviewUri (
257
- vscode . Uri . joinPath ( this . _extensionUri , "webview-content" , "main.css" ) ,
258
- ) ;
259
-
260
- // Use a nonce to only allow a specific script to be run.
261
- const nonce = getNonce ( ) ;
262
-
263
- const svg = graphviz . dot ( "digraph G { Hello -> World }" ) ;
264
- return `<!DOCTYPE html>
265
- <html lang="en">
266
- <head>
267
- <meta charset="UTF-8">
268
-
269
- <!--
270
- Use a content security policy to only allow loading styles from our extension directory,
271
- and only allow scripts that have a specific nonce.
272
- (See the 'webview-sample' extension sample for img-src content security policy examples)
273
- -->
274
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${ webview . cspSource } ; script-src 'nonce-${ nonce } ';">
275
-
276
- <link href="${ styleResetUri } " rel="stylesheet">
277
- <link href="${ styleVSCodeUri } " rel="stylesheet">
278
- <link href="${ styleMainUri } " rel="stylesheet">
279
-
280
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
281
- <title>Overview</title>
282
- <style>
283
-
284
- </style>
285
- </head>
286
- <body>
287
- <div id="overview">
288
- ${ svg }
289
- </div>
290
-
291
- <script nonce="${ nonce } " src="${ scriptUri } "></script>
292
- </body>
293
- </html>` ;
294
- }
295
- }
296
-
297
- function getNonce ( ) {
298
- let text = "" ;
299
- const possible =
300
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ;
301
- for ( let i = 0 ; i < 32 ; i ++ ) {
302
- text += possible . charAt ( Math . floor ( Math . random ( ) * possible . length ) ) ;
303
- }
304
- return text ;
305
- }
0 commit comments