3434from ..config .model import RobotBaseProfile
3535from ..utils import get_robot_version
3636from ..utils .stubs import Languages
37- from .imports_manager import ImportsManager
37+ from .data_cache import CacheSection
38+ from .imports_manager import ImportsManager , NamespaceMetaData
3839from .library_doc import LibraryDoc
39- from .namespace import DocumentType , Namespace , NamespaceBuilder
40+ from .namespace import (
41+ DocumentType ,
42+ Namespace ,
43+ NamespaceBuilder ,
44+ NamespaceData ,
45+ )
4046from .project_index import ProjectIndex
4147from .workspace_config import (
4248 AnalysisDiagnosticModifiersConfig ,
@@ -409,6 +415,16 @@ def get_only_initialized_namespace(self, document: TextDocument) -> Optional[Nam
409415 def __get_namespace_for_document_type (
410416 self , document : TextDocument , document_type : Optional [DocumentType ]
411417 ) -> Namespace :
418+ source = str (document .uri .to_path ())
419+ imports_manager = self .get_imports_manager (document )
420+
421+ # --- Try disk cache (cold-start acceleration) ---
422+ if document .version is None :
423+ result = self ._try_load_cached_namespace (source , document , document_type , imports_manager )
424+ if result is not None :
425+ return result
426+
427+ # --- Cache miss: full build ---
412428 if document_type is not None and document_type == DocumentType .INIT :
413429 model = self .get_init_model (document )
414430 elif document_type is not None and document_type == DocumentType .RESOURCE :
@@ -418,14 +434,12 @@ def __get_namespace_for_document_type(
418434 else :
419435 model = self .get_model (document )
420436
421- imports_manager = self .get_imports_manager (document )
422-
423437 languages , workspace_languages = self .build_languages_from_model (document , model )
424438
425439 builder = NamespaceBuilder (
426440 imports_manager ,
427441 model ,
428- str ( document . uri . to_path ()) ,
442+ source ,
429443 document ,
430444 document_type ,
431445 languages ,
@@ -434,6 +448,9 @@ def __get_namespace_for_document_type(
434448
435449 result = builder .build ()
436450
451+ # Save to disk cache
452+ self ._save_namespace_to_cache (source , result , imports_manager )
453+
437454 # Update the folder-scoped reference index
438455 self .get_project_index (document ).update_file (result .source , result )
439456
@@ -446,6 +463,119 @@ def __get_namespace_for_document_type(
446463
447464 return result
448465
466+ def _try_load_cached_namespace (
467+ self ,
468+ source : str ,
469+ document : TextDocument ,
470+ document_type : Optional [DocumentType ],
471+ imports_manager : ImportsManager ,
472+ ) -> Optional [Namespace ]:
473+ """Attempt to load a Namespace from the disk cache.
474+
475+ Returns None on cache miss or validation failure.
476+ """
477+ data_cache = imports_manager .data_cache
478+
479+ # Check source file exists before attempting cache lookup
480+ if not Path (source ).exists ():
481+ return None
482+
483+ # Compute filepath_base from source path
484+ temp_filepath_base = NamespaceMetaData (
485+ meta_version = "" ,
486+ source = source ,
487+ source_mtime_ns = 0 ,
488+ config_fingerprint = "" ,
489+ ).filepath_base
490+
491+ meta_file = temp_filepath_base + ".meta"
492+ if not data_cache .cache_data_exists (CacheSection .NAMESPACE , meta_file ):
493+ return None
494+
495+ try :
496+ saved_meta = data_cache .read_cache_data (CacheSection .NAMESPACE , meta_file , NamespaceMetaData )
497+ except (SystemExit , KeyboardInterrupt ):
498+ raise
499+ except BaseException as e :
500+ ex = e
501+ self ._logger .debug (
502+ lambda : f"Failed to read namespace meta for { source } : { ex } " ,
503+ context_name = "import" ,
504+ )
505+ return None
506+
507+ if not imports_manager .validate_namespace_meta (saved_meta ):
508+ return None
509+
510+ # Meta is valid — load the full NamespaceData
511+ data_file = temp_filepath_base + ".data"
512+ try :
513+ namespace_data = data_cache .read_cache_data (CacheSection .NAMESPACE , data_file , NamespaceData )
514+ except (SystemExit , KeyboardInterrupt ):
515+ raise
516+ except BaseException as e :
517+ ex = e
518+ self ._logger .debug (
519+ lambda : f"Failed to read namespace data for { source } : { ex } " ,
520+ context_name = "import" ,
521+ )
522+ return None
523+
524+ # Reconstruct the Namespace from cached data.
525+ # Try to get the file's ResourceDoc from the RESOURCE disk cache first
526+ # (avoids parsing the model if already cached). Falls back to parsing.
527+ try :
528+ library_doc = imports_manager .get_resource_doc_from_document (document )
529+ result = Namespace .from_data (namespace_data , imports_manager , library_doc , document )
530+ except (SystemExit , KeyboardInterrupt ):
531+ raise
532+ except BaseException as e :
533+ ex = e
534+ self ._logger .debug (
535+ lambda : f"Failed to reconstruct namespace from cache for { source } : { ex } " ,
536+ context_name = "import" ,
537+ )
538+ return None
539+
540+ self ._logger .debug (
541+ lambda : f"Loaded namespace from disk cache for { source } " ,
542+ context_name = "import" ,
543+ )
544+
545+ # Update the folder-scoped reference index
546+ self .get_project_index (document ).update_file (result .source , result )
547+
548+ result .invalidated .add (self ._invalidate_namespace )
549+ self .__namespace_initialized (result )
550+
551+ return result
552+
553+ def _save_namespace_to_cache (
554+ self ,
555+ source : str ,
556+ namespace : Namespace ,
557+ imports_manager : ImportsManager ,
558+ ) -> None :
559+ """Save a Namespace to the disk cache."""
560+ try :
561+ meta = imports_manager .build_namespace_meta (source , namespace )
562+ data = namespace .to_data ()
563+
564+ data_cache = imports_manager .data_cache
565+ data_file = meta .filepath_base + ".data"
566+ meta_file = meta .filepath_base + ".meta"
567+
568+ data_cache .save_cache_data (CacheSection .NAMESPACE , data_file , data )
569+ data_cache .save_cache_data (CacheSection .NAMESPACE , meta_file , meta )
570+ except (SystemExit , KeyboardInterrupt ):
571+ raise
572+ except BaseException as e :
573+ ex = e
574+ self ._logger .debug (
575+ lambda : f"Failed to save namespace cache for { source } : { ex } " ,
576+ context_name = "import" ,
577+ )
578+
449579 def create_imports_manager (self , root_uri : Uri ) -> ImportsManager :
450580 cache_base_path = self .calc_cache_path (root_uri )
451581
0 commit comments