@@ -8,13 +8,28 @@ import {
88} from "vscode-languageclient/node"
99
1010let client : LanguageClient | undefined
11+ let log : Pick <
12+ vscode . LogOutputChannel ,
13+ "trace" | "debug" | "info" | "warn" | "error" | "show"
14+ >
1115
1216export async function activate ( context : vscode . ExtensionContext ) {
13- console . log ( "Squawk activate" )
17+ log = vscode . window . createOutputChannel ( "Squawk Client" , {
18+ log : true ,
19+ } )
1420
15- const serverVersionCommand = vscode . commands . registerCommand (
16- "squawk.serverVersion" ,
17- ( ) => {
21+ log . info ( "Squawk activate" )
22+
23+ const syntaxTreeProvider = new SyntaxTreeProvider ( context )
24+ context . subscriptions . push (
25+ vscode . workspace . registerTextDocumentContentProvider (
26+ "squawk-syntax-tree" ,
27+ syntaxTreeProvider ,
28+ ) ,
29+ )
30+
31+ context . subscriptions . push (
32+ vscode . commands . registerCommand ( "squawk.serverVersion" , ( ) => {
1833 try {
1934 const serverPath = getSquawkPath ( context )
2035 const stdout = execFileSync ( serverPath . path , [ "--version" ] , {
@@ -28,17 +43,20 @@ export async function activate(context: vscode.ExtensionContext) {
2843 } catch ( error ) {
2944 vscode . window . showErrorMessage ( `Failed to get server version: ${ error } ` )
3045 }
31- } ,
46+ } ) ,
3247 )
33- context . subscriptions . push ( serverVersionCommand )
3448
35- const showLogsCommand = vscode . commands . registerCommand (
36- "squawk.showLogs" ,
37- ( ) => {
49+ context . subscriptions . push (
50+ vscode . commands . registerCommand ( "squawk.showLogs" , ( ) => {
3851 client ?. outputChannel ?. show ( )
39- } ,
52+ } ) ,
53+ )
54+
55+ context . subscriptions . push (
56+ vscode . commands . registerCommand ( "squawk.showClientLogs" , ( ) => {
57+ log . show ( )
58+ } ) ,
4059 )
41- context . subscriptions . push ( showLogsCommand )
4260
4361 const statusBarItem = vscode . window . createStatusBarItem (
4462 vscode . StatusBarAlignment . Right ,
@@ -57,13 +75,21 @@ export async function deactivate() {
5775 await client ?. stop ( )
5876}
5977
78+ function isSqlDocument ( document : vscode . TextDocument ) : boolean {
79+ return document . languageId === "sql" || document . languageId === "postgres"
80+ }
81+
82+ function isSqlEditor ( editor : vscode . TextEditor ) : boolean {
83+ return isSqlDocument ( editor . document )
84+ }
85+
6086function getSquawkPath ( context : vscode . ExtensionContext ) : vscode . Uri {
6187 const ext = process . platform === "win32" ? ".exe" : ""
6288 return vscode . Uri . joinPath ( context . extensionUri , "server" , `squawk${ ext } ` )
6389}
6490
6591async function startServer ( context : vscode . ExtensionContext ) {
66- console . log ( "starting squawk server ")
92+ log . info ( "Starting Squawk Language Server... ")
6793
6894 const squawkPath = getSquawkPath ( context )
6995 const hasBinary = await vscode . workspace . fs . stat ( squawkPath ) . then (
@@ -72,11 +98,11 @@ async function startServer(context: vscode.ExtensionContext) {
7298 )
7399 if ( ! hasBinary ) {
74100 const errorMsg = `Squawk binary not found at: ${ squawkPath . path } `
75- console . error ( errorMsg )
101+ log . error ( `ERROR: ${ errorMsg } ` )
76102 vscode . window . showErrorMessage ( errorMsg )
77103 return
78104 }
79- console . log ( `Found Squawk binary at: ${ squawkPath } ` )
105+ log . info ( `Found Squawk binary at: ${ squawkPath . path } ` )
80106
81107 const serverExecutable : Executable = {
82108 command : squawkPath . path ,
@@ -94,5 +120,79 @@ async function startServer(context: vscode.ExtensionContext) {
94120 clientOptions ,
95121 )
96122
123+ log . info ( "Language client created, starting..." )
97124 client . start ( )
125+ log . info ( "Language client started" )
126+ }
127+
128+ // Based on rust-analyzer's SyntaxTree support:
129+ // https://github.com/rust-lang/rust-analyzer/blob/c0eaff7dd1fdfffed4e5706780e79967760d1d9b/editors/code/src/commands.ts#L432-L510
130+ class SyntaxTreeProvider implements vscode . TextDocumentContentProvider {
131+ _eventEmitter = new vscode . EventEmitter < vscode . Uri > ( )
132+ _activeEditor : vscode . TextEditor | undefined
133+ // TODO: for now we only show syntax highlighting when someone has
134+ // rust-analyzer installed which ships with the rast grammar
135+ _uri = vscode . Uri . parse ( "squawk-syntax-tree://syntaxtree/tree.rast" )
136+
137+ constructor ( context : vscode . ExtensionContext ) {
138+ context . subscriptions . push (
139+ vscode . window . onDidChangeActiveTextEditor ( ( editor ) => {
140+ this . _onDidChangeActiveTextEditor ( editor )
141+ } ) ,
142+ )
143+ context . subscriptions . push (
144+ vscode . workspace . onDidChangeTextDocument ( ( event ) => {
145+ this . _onDidChangeTextDocument ( event . document )
146+ } ) ,
147+ )
148+ context . subscriptions . push (
149+ vscode . commands . registerCommand ( "squawk.showSyntaxTree" , async ( ) => {
150+ const doc = await vscode . workspace . openTextDocument ( this . _uri )
151+ await vscode . window . showTextDocument ( doc , vscode . ViewColumn . Beside )
152+ } ) ,
153+ )
154+
155+ // initial kick off to make sure we have the editor set
156+ this . _onDidChangeActiveTextEditor ( vscode . window . activeTextEditor )
157+ }
158+
159+ onDidChange = this . _eventEmitter . event
160+
161+ _onDidChangeActiveTextEditor ( editor : vscode . TextEditor | undefined ) {
162+ if ( editor && isSqlEditor ( editor ) ) {
163+ this . _activeEditor = editor
164+ this . _eventEmitter . fire ( this . _uri )
165+ }
166+ }
167+
168+ _onDidChangeTextDocument ( document : vscode . TextDocument ) {
169+ if (
170+ isSqlDocument ( document ) &&
171+ this . _activeEditor &&
172+ document === this . _activeEditor . document
173+ ) {
174+ this . _eventEmitter . fire ( this . _uri )
175+ }
176+ }
177+
178+ async provideTextDocumentContent ( _uri : vscode . Uri ) : Promise < string > {
179+ try {
180+ const document = this . _activeEditor ?. document
181+ if ( ! document ) {
182+ return "Error: no active editor found"
183+ }
184+ const text = document . getText ( )
185+ const uri = document . uri . toString ( )
186+ log . info ( `Requesting syntax tree for: ${ uri } ` )
187+ const response = await client ?. sendRequest ( "squawk/syntaxTree" , {
188+ textDocument : { uri } ,
189+ text,
190+ } )
191+ log . info ( "Syntax tree received" )
192+ return response as string
193+ } catch ( error ) {
194+ log . error ( `Failed to get syntax tree: ${ error } ` )
195+ return `Error: Failed to get syntax tree: ${ error } `
196+ }
197+ }
98198}
0 commit comments