66 "go/types"
77 "io/fs"
88 "path"
9+ "slices"
910 "time"
1011
1112 "github.com/goplus/builder/tools/spxls/internal/vfs"
@@ -175,21 +176,10 @@ func (s *Server) formatSpxDecls(snapshot *vfs.MapFS, spxFile string) ([]byte, er
175176 )
176177 for _ , decl := range astFile .Decls {
177178 // Skip the declaration if it appears after the error position.
178- if errorPos .IsValid () && errorPos <= decl .Pos () {
179+ if errorPos .IsValid () && decl .Pos () >= errorPos {
179180 continue
180181 }
181182
182- // Pre-process all comments within the declaration to exclude
183- // them from floating comments.
184- gopast .Inspect (decl , func (node gopast.Node ) bool {
185- cg , ok := node .(* gopast.CommentGroup )
186- if ! ok {
187- return true
188- }
189- processedComments [cg ] = struct {}{}
190- return true
191- })
192-
193183 switch decl := decl .(type ) {
194184 case * gopast.GenDecl :
195185 switch decl .Tok {
@@ -214,6 +204,23 @@ func (s *Server) formatSpxDecls(snapshot *vfs.MapFS, spxFile string) ([]byte, er
214204 default :
215205 otherDecls = append (otherDecls , decl )
216206 }
207+
208+ // Pre-process all comments within the declaration to exclude
209+ // them from floating comments.
210+ if doc := getDeclDoc (decl ); doc != nil {
211+ processedComments [doc ] = struct {}{}
212+ }
213+ startLine := compileResult .fset .Position (decl .Pos ()).Line
214+ endLine := compileResult .fset .Position (decl .End ()).Line
215+ for _ , cg := range astFile .Comments {
216+ if _ , ok := processedComments [cg ]; ok {
217+ continue
218+ }
219+ cgStartLine := compileResult .fset .Position (cg .Pos ()).Line
220+ if cgStartLine >= startLine && cgStartLine <= endLine {
221+ processedComments [cg ] = struct {}{}
222+ }
223+ }
217224 }
218225
219226 // Reorder declarations: imports -> types -> consts -> vars -> funcs -> others.
@@ -259,30 +266,51 @@ func (s *Server) formatSpxDecls(snapshot *vfs.MapFS, spxFile string) ([]byte, er
259266
260267 // Format the sorted declarations.
261268 formattedBuf := bytes .NewBuffer (make ([]byte , 0 , len (astFile .Code )))
269+ ensureTrailingNewlines := func (count int ) {
270+ if formattedBuf .Len () == 0 {
271+ return
272+ }
273+ for _ , b := range slices .Backward (formattedBuf .Bytes ()) {
274+ if b != '\n' {
275+ break
276+ }
277+ count --
278+ }
279+ for range count {
280+ formattedBuf .WriteByte ('\n' )
281+ }
282+ }
262283
263284 // Handle declarations and floating comments in order of their position.
264- var lastDeclEnd goptoken.Pos
265285 processDecl := func (decl gopast.Decl ) error {
266286 startPos := decl .Pos ()
267287 if doc := getDeclDoc (decl ); doc != nil {
268288 startPos = doc .Pos ()
269289 }
270290
271- if formattedBuf .Len () > 0 {
272- formattedBuf .WriteByte ('\n' )
291+ endPos := decl .End ()
292+ endLine := compileResult .fset .Position (endPos ).Line
293+ for _ , cg := range astFile .Comments {
294+ if compileResult .fset .Position (cg .Pos ()).Line != endLine {
295+ continue
296+ }
297+ if cg .Pos () > endPos {
298+ endPos = cg .End ()
299+ break
300+ }
273301 }
302+
303+ ensureTrailingNewlines (2 )
274304 if genDecl , ok := decl .(* gopast.GenDecl ); ok && genDecl .Tok == goptoken .VAR {
275305 if err := gopfmt .Node (formattedBuf , compileResult .fset , decl ); err != nil {
276306 return err
277307 }
278308 } else {
279309 start := compileResult .fset .Position (startPos ).Offset
280- end := compileResult .fset .Position (decl . End () ).Offset
310+ end := compileResult .fset .Position (endPos ).Offset
281311 formattedBuf .Write (astFile .Code [start :end ])
282312 }
283- formattedBuf .WriteByte ('\n' )
284-
285- lastDeclEnd = decl .End ()
313+ ensureTrailingNewlines (1 )
286314 return nil
287315 }
288316
@@ -294,10 +322,9 @@ func (s *Server) formatSpxDecls(snapshot *vfs.MapFS, spxFile string) ([]byte, er
294322 }
295323 processedComments [cg ] = struct {}{}
296324
297- if errorPos .IsValid () && errorPos <= cg .Pos () {
298- continue
299- }
300- if lastDeclEnd .IsValid () && cg .Pos () < lastDeclEnd {
325+ // Skip the comment if it appears after the error position or
326+ // shadow entry position.
327+ if errorPos .IsValid () && cg .Pos () >= errorPos {
301328 continue
302329 }
303330 if shadowEntryPos .IsValid () && cg .Pos () >= shadowEntryPos {
@@ -307,9 +334,6 @@ func (s *Server) formatSpxDecls(snapshot *vfs.MapFS, spxFile string) ([]byte, er
307334 // Process declarations that should come before this comment.
308335 for ; declIndex < len (sortedDecls ); declIndex ++ {
309336 decl := sortedDecls [declIndex ]
310- if errorPos .IsValid () && errorPos <= decl .Pos () {
311- continue
312- }
313337
314338 startPos := decl .Pos ()
315339 if doc := getDeclDoc (decl ); doc != nil {
@@ -325,35 +349,27 @@ func (s *Server) formatSpxDecls(snapshot *vfs.MapFS, spxFile string) ([]byte, er
325349 }
326350
327351 // Add the floating comment.
328- if formattedBuf .Len () > 0 {
329- formattedBuf .WriteByte ('\n' )
330- }
352+ ensureTrailingNewlines (2 )
331353 start := compileResult .fset .Position (cg .Pos ()).Offset
332354 end := compileResult .fset .Position (cg .End ()).Offset
333355 formattedBuf .Write (astFile .Code [start :end ])
334- formattedBuf . WriteByte ( '\n' )
356+ ensureTrailingNewlines ( 1 )
335357 }
336358
337359 // Process remaining declarations before shadow entry.
338360 for ; declIndex < len (sortedDecls ); declIndex ++ {
339- decl := sortedDecls [declIndex ]
340- if errorPos .IsValid () && errorPos <= decl .Pos () {
341- continue
342- }
343- if err := processDecl (decl ); err != nil {
361+ if err := processDecl (sortedDecls [declIndex ]); err != nil {
344362 return nil , err
345363 }
346364 }
347365
348366 // Add the shadow entry if it exists and not empty.
349367 if shadowEntryPos .IsValid () {
350- if formattedBuf .Len () > 0 {
351- formattedBuf .WriteByte ('\n' )
352- }
368+ ensureTrailingNewlines (2 )
353369 start := compileResult .fset .Position (shadowEntryPos ).Offset
354370 end := compileResult .fset .Position (astFile .ShadowEntry .End ()).Offset
355371 formattedBuf .Write (astFile .Code [start :end ])
356- formattedBuf . WriteByte ( '\n' )
372+ ensureTrailingNewlines ( 1 )
357373 }
358374
359375 formatted := formattedBuf .Bytes ()
0 commit comments