@@ -151,6 +151,7 @@ def noop(request: dict):
151151 "textDocument/didClose" : self .serve_onClose ,
152152 "textDocument/didChange" : self .serve_onChange ,
153153 "textDocument/codeAction" : self .serve_codeActions ,
154+ "textDocument/foldingRange" : self .serve_folding_range ,
154155 "initialized" : noop ,
155156 "workspace/didChangeWatchedFiles" : noop ,
156157 "workspace/didChangeConfiguration" : noop ,
@@ -226,6 +227,7 @@ def serve_initialize(self, request: dict):
226227 "renameProvider" : True ,
227228 "workspaceSymbolProvider" : True ,
228229 "textDocumentSync" : self .sync_type ,
230+ "foldingRangeProvider" : True ,
229231 }
230232 if self .use_signature_help :
231233 server_capabilities ["signatureHelpProvider" ] = {
@@ -1250,6 +1252,56 @@ def serve_codeActions(self, request: dict):
12501252 action ["diagnostics" ] = new_diags
12511253 return action_list
12521254
1255+ def serve_folding_range (self , request : dict ):
1256+ # Get parameters from request
1257+ params : dict = request ["params" ]
1258+ uri : str = params ["textDocument" ]["uri" ]
1259+ path = path_from_uri (uri )
1260+ # Find object
1261+ file_obj = self .workspace .get (path )
1262+ if file_obj is None :
1263+ return None
1264+ if file_obj .ast is None :
1265+ return None
1266+ else :
1267+ folding_start = file_obj .ast .folding_start
1268+ folding_end = file_obj .ast .folding_end
1269+ if (
1270+ folding_start is None
1271+ or folding_end is None
1272+ or len (folding_start ) != len (folding_end )
1273+ ):
1274+ return None
1275+ # Construct folding_rage list
1276+ folding_ranges = []
1277+ # First treating scope objects...
1278+ for scope in file_obj .ast .scope_list :
1279+ n_mlines = len (scope .mlines )
1280+ # ...with intermediate folding lines (if, select)...
1281+ if n_mlines > 0 :
1282+ self .add_range (folding_ranges , scope .sline - 1 , scope .mlines [0 ] - 2 )
1283+ for i in range (1 , n_mlines ):
1284+ self .add_range (
1285+ folding_ranges , scope .mlines [i - 1 ] - 1 , scope .mlines [i ] - 2
1286+ )
1287+ self .add_range (folding_ranges , scope .mlines [- 1 ] - 1 , scope .eline - 2 )
1288+ # ...and without
1289+ else :
1290+ self .add_range (folding_ranges , scope .sline - 1 , scope .eline - 2 )
1291+ # Then treat comment blocks
1292+ folds = len (folding_start )
1293+ for i in range (0 , folds ):
1294+ self .add_range (folding_ranges , folding_start [i ] - 1 , folding_end [i ] - 1 )
1295+
1296+ return folding_ranges
1297+
1298+ def add_range (self , folding_ranges : list , start : int , end : int ):
1299+ folding_range = {
1300+ "startLine" : start ,
1301+ "endLine" : end ,
1302+ }
1303+ folding_ranges .append (folding_range )
1304+
12531305 def send_diagnostics (self , uri : str ):
12541306 diag_results , diag_exp = self .get_diagnostics (uri )
12551307 if diag_results is not None :
@@ -1621,6 +1673,9 @@ def _load_config_file_general(self, config_dict: dict) -> None:
16211673 self .hover_signature = config_dict .get ("hover_signature" , self .hover_signature )
16221674 self .hover_language = config_dict .get ("hover_language" , self .hover_language )
16231675
1676+ # Folding range --------------------------------------------------------
1677+ self .folding_range = config_dict .get ("folding_range" , self .folding_range )
1678+
16241679 # Diagnostic options ---------------------------------------------------
16251680 self .max_line_length = config_dict .get ("max_line_length" , self .max_line_length )
16261681 self .max_comment_line_length = config_dict .get (
0 commit comments