@@ -32,6 +32,85 @@ export async function activate(context: ExtensionContext) {
3232 let restartTimestamps : number [ ] = [ ] ;
3333 let restartTimer : NodeJS . Timeout | undefined ;
3434 let startPromise : Promise < void > | undefined ;
35+ const syncedVisibleDocuments = new Set < string > ( ) ;
36+
37+ const isVisibleDocument = ( document : TextDocument ) => {
38+ return window . visibleTextEditors . some ( editor => editor . document . uri . toString ( ) === document . uri . toString ( ) ) ;
39+ } ;
40+
41+ const isSyncCandidate = ( document : TextDocument ) => {
42+ return document . uri . scheme === 'file' && document . languageId === 'nattlua' ;
43+ } ;
44+
45+ const sendDidOpen = ( document : TextDocument ) => {
46+ if ( ! client || ! client . isRunning ( ) ) {
47+ return ;
48+ }
49+
50+ const uri = document . uri . toString ( ) ;
51+ client . sendNotification ( 'textDocument/didOpen' , {
52+ textDocument : {
53+ uri,
54+ languageId : document . languageId ,
55+ version : document . version ,
56+ text : document . getText ( ) ,
57+ } ,
58+ } ) ;
59+ syncedVisibleDocuments . add ( uri ) ;
60+ } ;
61+
62+ const sendDidClose = ( document : TextDocument ) => {
63+ if ( ! client || ! client . isRunning ( ) ) {
64+ return ;
65+ }
66+
67+ const uri = document . uri . toString ( ) ;
68+ client . sendNotification ( 'textDocument/didClose' , {
69+ textDocument : { uri } ,
70+ } ) ;
71+ syncedVisibleDocuments . delete ( uri ) ;
72+ } ;
73+
74+ const reconcileVisibleDocumentSync = ( ) => {
75+ if ( ! client || ! client . isRunning ( ) ) {
76+ return ;
77+ }
78+
79+ const visibleDocuments = window . visibleTextEditors
80+ . map ( editor => editor . document )
81+ . filter ( isSyncCandidate ) ;
82+ const nextVisibleUris = new Set ( visibleDocuments . map ( document => document . uri . toString ( ) ) ) ;
83+
84+ for ( const document of visibleDocuments ) {
85+ const uri = document . uri . toString ( ) ;
86+ if ( ! syncedVisibleDocuments . has ( uri ) ) {
87+ sendDidOpen ( document ) ;
88+ }
89+ }
90+
91+ for ( const uri of Array . from ( syncedVisibleDocuments ) ) {
92+ if ( ! nextVisibleUris . has ( uri ) ) {
93+ const document = workspace . textDocuments . find ( document => document . uri . toString ( ) === uri ) ;
94+ if ( document && isSyncCandidate ( document ) ) {
95+ sendDidClose ( document ) ;
96+ } else {
97+ syncedVisibleDocuments . delete ( uri ) ;
98+ }
99+ }
100+ }
101+ } ;
102+
103+ const sendVisibleEditors = ( ) => {
104+ if ( ! client || ! client . isRunning ( ) ) {
105+ return ;
106+ }
107+
108+ const uris = window . visibleTextEditors
109+ . filter ( editor => editor . document . uri . scheme === 'file' && editor . document . languageId === 'nattlua' )
110+ . map ( editor => editor . document . uri . toString ( ) ) ;
111+
112+ client . sendNotification ( 'nattlua/visibleEditors' , { uris } ) ;
113+ } ;
35114
36115 const executable = resolveVariables ( config . get < string > ( "executable" ) || "nattlua" ) ;
37116 const workingDirectory = resolveVariables ( config . get < string > ( "workingDirectory" ) || "${workspaceFolder}" ) ;
@@ -88,6 +167,8 @@ export async function activate(context: ExtensionContext) {
88167 try {
89168 await client . start ( ) ;
90169 clientOutput . appendLine ( `NattLua server started successfully (${ reason } )` ) ;
170+ reconcileVisibleDocumentSync ( ) ;
171+ sendVisibleEditors ( ) ;
91172 } catch ( err : any ) {
92173 const message = err ?. message || String ( err ) ;
93174 clientOutput . appendLine ( `NattLua failed to start (${ reason } ): ${ message } ` ) ;
@@ -103,7 +184,7 @@ export async function activate(context: ExtensionContext) {
103184 const errorHandler : ErrorHandler = {
104185 error : ( error , message , count ) => {
105186 LSPOutput . appendLine ( `LSP Error: ${ message } (${ count } ) - ${ error . message } ` ) ;
106- if ( count <= 3 ) return { action : ErrorAction . Continue } ;
187+ if ( ( count ?? 0 ) <= 3 ) return { action : ErrorAction . Continue } ;
107188 return { action : ErrorAction . Shutdown } ;
108189 } ,
109190 closed : ( ) => {
@@ -118,6 +199,41 @@ export async function activate(context: ExtensionContext) {
118199 synchronize : {
119200 configurationSection : "nattlua" ,
120201 } ,
202+ middleware : {
203+ didOpen : ( document , next ) => {
204+ const visible = isVisibleDocument ( document ) ;
205+
206+ if ( ! visible ) {
207+ return Promise . resolve ( ) ;
208+ }
209+
210+ syncedVisibleDocuments . add ( document . uri . toString ( ) ) ;
211+ return next ( document ) ;
212+ } ,
213+ didChange : ( event , next ) => {
214+ if ( ! syncedVisibleDocuments . has ( event . document . uri . toString ( ) ) ) {
215+ return Promise . resolve ( ) ;
216+ }
217+
218+ return next ( event ) ;
219+ } ,
220+ didSave : ( document , next ) => {
221+ if ( ! syncedVisibleDocuments . has ( document . uri . toString ( ) ) ) {
222+ return Promise . resolve ( ) ;
223+ }
224+
225+ return next ( document ) ;
226+ } ,
227+ didClose : ( document , next ) => {
228+ const uri = document . uri . toString ( ) ;
229+ if ( ! syncedVisibleDocuments . has ( uri ) ) {
230+ return Promise . resolve ( ) ;
231+ }
232+
233+ syncedVisibleDocuments . delete ( uri ) ;
234+ return next ( document ) ;
235+ } ,
236+ } ,
121237 errorHandler : errorHandler ,
122238 } ;
123239
@@ -241,10 +357,20 @@ export async function activate(context: ExtensionContext) {
241357 } ,
242358 } ) ;
243359
360+ context . subscriptions . push ( window . onDidChangeVisibleTextEditors ( ( ) => {
361+ reconcileVisibleDocumentSync ( ) ;
362+ sendVisibleEditors ( ) ;
363+ } ) ) ;
364+
365+ context . subscriptions . push ( window . onDidChangeActiveTextEditor ( ( ) => {
366+ reconcileVisibleDocumentSync ( ) ;
367+ sendVisibleEditors ( ) ;
368+ } ) ) ;
369+
244370 await startClient ( "initial start" ) ;
245371}
246372
247- export async function deactivate ( ) : Promise < void > | undefined {
373+ export async function deactivate ( ) : Promise < void | undefined > {
248374 if ( ! client ) {
249375 return undefined ;
250376 }
0 commit comments