44//! Django, Python, and the filesystem for facts, then writes changed facts to
55//! the `Project` input. Pure semantic derivation stays in tracked queries.
66
7+ use camino:: Utf8PathBuf ;
8+ use salsa:: Setter ;
9+
710use crate :: db:: Db as ProjectDb ;
811use crate :: environment:: templatetag_candidate_paths;
9- use crate :: project :: Project ;
12+ use crate :: resolve :: SearchPaths ;
1013use crate :: resolve:: model_modules;
1114use crate :: resolve:: templatetag_modules;
1215use crate :: settings:: settings_source_files;
@@ -18,33 +21,32 @@ use crate::settings::settings_source_files;
1821/// into the `Project` input, then lets tracked semantic queries handle editor
1922/// file contents and downstream derivations.
2023pub fn refresh_external_data ( db : & mut dyn ProjectDb ) {
21- let Some ( project ) = db . project ( ) else {
24+ let Some ( refresh ) = compute_refresh ( db ) else {
2225 return ;
2326 } ;
24-
25- project. refresh_source_roots ( db) ;
26- refresh_python_modules ( db, project) ;
27+ apply_refresh ( db, refresh) ;
2728}
2829
29- fn refresh_python_modules ( db : & mut dyn ProjectDb , project : Project ) {
30- // The LSP currently has no watched-file stream for dependency roots. Treat
31- // an explicit refresh as the freshness boundary for module discovery and
32- // currently discovered Python files.
33- let roots: Vec < _ > = project
34- . search_paths ( db)
35- . iter ( )
36- . filter_map ( |search_path| db. files ( ) . root ( db, search_path. path ( ) ) )
37- . collect ( ) ;
30+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
31+ pub struct RefreshData {
32+ search_paths : SearchPaths ,
33+ file_paths : Vec < Utf8PathBuf > ,
34+ }
3835
39- for root in roots {
40- db. bump_file_root_revision ( root) ;
41- }
36+ pub fn compute_refresh ( db : & dyn ProjectDb ) -> Option < RefreshData > {
37+ let project = db. project ( ) ?;
38+ let search_paths = SearchPaths :: from_project_settings (
39+ db. file_system ( ) ,
40+ project. root ( db) ,
41+ project. interpreter ( db) ,
42+ project. pythonpath ( db) ,
43+ ) ;
4244
43- for file in settings_source_files ( db, project) {
44- db. bump_file_revision ( file) ;
45- }
45+ let mut file_paths: Vec < _ > = settings_source_files ( db, project)
46+ . into_iter ( )
47+ . map ( |file| file. path ( db) . to_path_buf ( ) )
48+ . collect ( ) ;
4649
47- let mut file_paths = Vec :: new ( ) ;
4850 file_paths. extend (
4951 model_modules ( db, project)
5052 . iter ( )
@@ -61,6 +63,39 @@ fn refresh_python_modules(db: &mut dyn ProjectDb, project: Project) {
6163 file_paths. sort ( ) ;
6264 file_paths. dedup ( ) ;
6365
66+ Some ( RefreshData {
67+ search_paths,
68+ file_paths,
69+ } )
70+ }
71+
72+ pub fn apply_refresh ( db : & mut dyn ProjectDb , refresh : RefreshData ) {
73+ let Some ( project) = db. project ( ) else {
74+ return ;
75+ } ;
76+ let RefreshData {
77+ search_paths,
78+ file_paths,
79+ } = refresh;
80+
81+ search_paths. register_roots ( db) ;
82+ if project. search_paths ( db) != & search_paths {
83+ project. set_search_paths ( db) . to ( search_paths) ;
84+ }
85+
86+ // The LSP currently has no watched-file stream for dependency roots. Treat
87+ // an explicit refresh as the freshness boundary for module discovery and
88+ // currently discovered Python files.
89+ let roots: Vec < _ > = project
90+ . search_paths ( db)
91+ . iter ( )
92+ . filter_map ( |search_path| db. files ( ) . root ( db, search_path. path ( ) ) )
93+ . collect ( ) ;
94+
95+ for root in roots {
96+ db. bump_file_root_revision ( root) ;
97+ }
98+
6499 for path in file_paths {
65100 let file = db. get_or_create_file ( & path) ;
66101 db. bump_file_revision ( file) ;
0 commit comments