11from __future__ import annotations
22
33import ast
4- from typing import TYPE_CHECKING , Any , List , Optional , cast
4+ import time
5+ from typing import TYPE_CHECKING , Any , List , Optional
56
7+ from robot .parsing .model .blocks import If , Keyword , TestCase
68from robotcode .core .logging import LoggingDescriptor
79from robotcode .core .lsp .types import FoldingRange
810
911from ...common .decorators import language_id
1012from ...common .text_document import TextDocument
11- from ..utils .async_ast import AsyncVisitor
13+ from ..utils .async_ast import Visitor
1214from .protocol_part import RobotLanguageServerProtocolPart
1315
1416if TYPE_CHECKING :
1719 )
1820
1921
20- class _Visitor (AsyncVisitor ):
22+ class _Visitor (Visitor ):
2123 def __init__ (self , parent : RobotFoldingRangeProtocolPart ) -> None :
2224 super ().__init__ ()
2325 self .parent = parent
@@ -33,72 +35,83 @@ def __init__(self, parent: RobotFoldingRangeProtocolPart) -> None:
3335 )
3436
3537 self .result : List [FoldingRange ] = []
38+ self .current_if : List [ast .AST ] = []
3639
37- async def visit (self , node : ast .AST ) -> None :
38- await super ().visit (node )
40+ def visit (self , node : ast .AST ) -> None :
41+ super ().visit (node )
3942
4043 @classmethod
41- async def find_from (cls , model : ast .AST , parent : RobotFoldingRangeProtocolPart ) -> Optional [List [FoldingRange ]]:
44+ def find_from (cls , model : ast .AST , parent : RobotFoldingRangeProtocolPart ) -> Optional [List [FoldingRange ]]:
4245 finder = cls (parent )
4346
44- await finder .visit (model )
47+ finder .visit (model )
4548
4649 return finder .result if finder .result else None
4750
48- def __append (self , node : ast .AST , kind : str ) -> None :
51+ def __append (self , start_node : ast .AST , kind : str , end_node : Optional [ast .AST ] = None ) -> None :
52+ if end_node is None :
53+ end_node = start_node
4954 if not self .line_folding_only :
5055 self .result .append (
5156 FoldingRange (
52- start_line = node .lineno - 1 ,
53- end_line = node .end_lineno - 1 if node .end_lineno is not None else node .lineno - 1 ,
54- start_character = node .col_offset if not self .line_folding_only else None ,
55- end_character = node .end_col_offset if not self .line_folding_only else None ,
57+ start_line = start_node .lineno - 1 ,
58+ end_line = end_node .end_lineno - 1 if end_node .end_lineno is not None else end_node .lineno - 1 ,
59+ start_character = start_node .col_offset if not self .line_folding_only else None ,
60+ end_character = end_node .end_col_offset if not self .line_folding_only else None ,
5661 kind = kind ,
5762 )
5863 )
5964 else :
6065 self .result .append (
6166 FoldingRange (
62- start_line = node .lineno - 1 ,
63- end_line = node .end_lineno - 1 if node .end_lineno is not None else node .lineno - 1 ,
67+ start_line = start_node .lineno - 1 ,
68+ end_line = end_node .end_lineno - 1 if end_node .end_lineno is not None else end_node .lineno - 1 ,
6469 kind = kind ,
6570 )
6671 )
6772
68- async def visit_Section (self , node : ast .AST ) -> None : # noqa: N802
73+ def visit_Section (self , node : ast .AST ) -> None : # noqa: N802
6974 self .__append (node , kind = "section" )
7075
71- await self .generic_visit (node )
76+ self .generic_visit (node )
7277
73- async def visit_CommentSection (self , node : ast .AST ) -> None : # noqa: N802
78+ def visit_CommentSection (self , node : ast .AST ) -> None : # noqa: N802
7479 self .__append (node , kind = "comment" )
75- await self .generic_visit (node )
80+ self .generic_visit (node )
7681
77- async def visit_TestCase (self , node : ast .AST ) -> None : # noqa: N802
78- from robot .parsing .model .blocks import TestCase
79-
80- if cast (TestCase , node ).name :
82+ def visit_TestCase (self , node : TestCase ) -> None : # noqa: N802
83+ if node .name :
8184 self .__append (node , kind = "testcase" )
82- await self .generic_visit (node )
83-
84- async def visit_Keyword (self , node : ast .AST ) -> None : # noqa: N802
85- from robot .parsing .model .blocks import Keyword
85+ self .generic_visit (node )
8686
87- if cast (Keyword , node ).name :
87+ def visit_Keyword (self , node : Keyword ) -> None : # noqa: N802
88+ if node .name :
8889 self .__append (node , kind = "keyword" )
89- await self .generic_visit (node )
90+ self .generic_visit (node )
9091
91- async def visit_ForLoop (self , node : ast .AST ) -> None : # noqa: N802, pragma: no cover
92+ def visit_ForLoop (self , node : ast .AST ) -> None : # noqa: N802
9293 self .__append (node , kind = "for_loop" )
93- await self .generic_visit (node )
94+ self .generic_visit (node )
9495
95- async def visit_For (self , node : ast .AST ) -> None : # noqa: N802
96+ def visit_For (self , node : ast .AST ) -> None : # noqa: N802
9697 self .__append (node , kind = "for" )
97- await self .generic_visit (node )
98+ self .generic_visit (node )
99+
100+ def visit_If (self , node : If ) -> None : # noqa: N802
101+ if node .orelse is not None and node .body [- 1 ]:
102+ self .__append (node , kind = "if" , end_node = node .body [- 1 ])
103+ elif node .orelse is None and node .type == "ELSE" :
104+ self .__append (node , kind = "if" , end_node = self .current_if [- 1 ] if self .current_if else None )
105+ else :
106+ self .__append (node , kind = "if" )
98107
99- async def visit_If (self , node : ast .AST ) -> None : # noqa: N802
100- self .__append (node , kind = "if" )
101- await self .generic_visit (node )
108+ if node .type == "IF" :
109+ self .current_if .append (node )
110+
111+ self .generic_visit (node )
112+
113+ if node .type == "IF" :
114+ self .current_if .remove (node )
102115
103116
104117class RobotFoldingRangeProtocolPart (RobotLanguageServerProtocolPart ):
@@ -112,4 +125,10 @@ def __init__(self, parent: RobotLanguageServerProtocol) -> None:
112125 @language_id ("robotframework" )
113126 @_logger .call
114127 async def collect (self , sender : Any , document : TextDocument ) -> Optional [List [FoldingRange ]]:
115- return await _Visitor .find_from (await self .parent .documents_cache .get_model (document , False ), self )
128+ start = time .monotonic ()
129+ try :
130+ return _Visitor .find_from (await self .parent .documents_cache .get_model (document , False ), self )
131+ finally :
132+ self ._logger .critical (
133+ lambda : f"Folding ranges collected in { (time .monotonic () - start ) * 1000 } ms" ,
134+ )
0 commit comments