@@ -7,12 +7,12 @@ use colored::Colorize;
77use  crossbeam:: channel as  crossbeam_channel; 
88use  salsa:: plumbing:: ZalsaDatabase ; 
99
10- use  red_knot_python_semantic:: { ProgramSettings ,   SearchPathSettings } ; 
10+ use  red_knot_python_semantic:: SitePackages ; 
1111use  red_knot_server:: run_server; 
1212use  red_knot_workspace:: db:: RootDatabase ; 
13- use  red_knot_workspace:: site_packages:: VirtualEnvironment ; 
1413use  red_knot_workspace:: watch; 
1514use  red_knot_workspace:: watch:: WorkspaceWatcher ; 
15+ use  red_knot_workspace:: workspace:: settings:: Configuration ; 
1616use  red_knot_workspace:: workspace:: WorkspaceMetadata ; 
1717use  ruff_db:: system:: { OsSystem ,  System ,  SystemPath ,  SystemPathBuf } ; 
1818use  target_version:: TargetVersion ; 
@@ -65,15 +65,14 @@ to resolve type information for the project's third-party dependencies.",
6565        value_name = "PATH" ,  
6666        help = "Additional path to use as a module-resolution source (can be passed multiple times)"  
6767    ) ]  
68-     extra_search_path :  Vec < SystemPathBuf > , 
68+     extra_search_path :  Option < Vec < SystemPathBuf > > , 
6969
7070    #[ arg(  
7171        long,  
7272        help = "Python version to assume when resolving types" ,  
73-         default_value_t = TargetVersion :: default ( ) ,  
74-         value_name="VERSION" )  
75-     ]  
76-     target_version :  TargetVersion , 
73+         value_name = "VERSION"  
74+     ) ]  
75+     target_version :  Option < TargetVersion > , 
7776
7877    #[ clap( flatten) ]  
7978    verbosity :  Verbosity , 
@@ -86,6 +85,36 @@ to resolve type information for the project's third-party dependencies.",
8685    watch :  bool , 
8786} 
8887
88+ impl  Args  { 
89+     fn  to_configuration ( & self ,  cli_cwd :  & SystemPath )  -> Configuration  { 
90+         let  mut  configuration = Configuration :: default ( ) ; 
91+ 
92+         if  let  Some ( target_version)  = self . target_version  { 
93+             configuration. target_version  = Some ( target_version. into ( ) ) ; 
94+         } 
95+ 
96+         if  let  Some ( venv_path)  = & self . venv_path  { 
97+             configuration. search_paths . site_packages  = Some ( SitePackages :: Derived  { 
98+                 venv_path :  SystemPath :: absolute ( venv_path,  cli_cwd) , 
99+             } ) ; 
100+         } 
101+ 
102+         if  let  Some ( custom_typeshed_dir)  = & self . custom_typeshed_dir  { 
103+             configuration. search_paths . custom_typeshed  =
104+                 Some ( SystemPath :: absolute ( custom_typeshed_dir,  cli_cwd) ) ; 
105+         } 
106+ 
107+         if  let  Some ( extra_search_paths)  = & self . extra_search_path  { 
108+             configuration. search_paths . extra_paths  = extra_search_paths
109+                 . iter ( ) 
110+                 . map ( |path| Some ( SystemPath :: absolute ( path,  cli_cwd) ) ) 
111+                 . collect ( ) ; 
112+         } 
113+ 
114+         configuration
115+     } 
116+ } 
117+ 
89118#[ derive( Debug ,  clap:: Subcommand ) ]  
90119pub  enum  Command  { 
91120    /// Start the language server 
@@ -115,22 +144,13 @@ pub fn main() -> ExitStatus {
115144} 
116145
117146fn  run ( )  -> anyhow:: Result < ExitStatus >  { 
118-     let  Args  { 
119-         command, 
120-         current_directory, 
121-         custom_typeshed_dir, 
122-         extra_search_path :  extra_paths, 
123-         venv_path, 
124-         target_version, 
125-         verbosity, 
126-         watch, 
127-     }  = Args :: parse_from ( std:: env:: args ( ) . collect :: < Vec < _ > > ( ) ) ; 
128- 
129-     if  matches ! ( command,  Some ( Command :: Server ) )  { 
147+     let  args = Args :: parse_from ( std:: env:: args ( ) . collect :: < Vec < _ > > ( ) ) ; 
148+ 
149+     if  matches ! ( args. command,  Some ( Command :: Server ) )  { 
130150        return  run_server ( ) . map ( |( ) | ExitStatus :: Success ) ; 
131151    } 
132152
133-     let  verbosity = verbosity. level ( ) ; 
153+     let  verbosity = args . verbosity . level ( ) ; 
134154    countme:: enable ( verbosity. is_trace ( ) ) ; 
135155    let  _guard = setup_tracing ( verbosity) ?; 
136156
@@ -146,10 +166,12 @@ fn run() -> anyhow::Result<ExitStatus> {
146166            } ) ?
147167    } ; 
148168
149-     let  cwd = current_directory
169+     let  cwd = args
170+         . current_directory 
171+         . as_ref ( ) 
150172        . map ( |cwd| { 
151173            if  cwd. as_std_path ( ) . is_dir ( )  { 
152-                 Ok ( SystemPath :: absolute ( & cwd,  & cli_base_path) ) 
174+                 Ok ( SystemPath :: absolute ( cwd,  & cli_base_path) ) 
153175            }  else  { 
154176                Err ( anyhow ! ( 
155177                    "Provided current-directory path '{cwd}' is not a directory." 
@@ -160,33 +182,18 @@ fn run() -> anyhow::Result<ExitStatus> {
160182        . unwrap_or_else ( || cli_base_path. clone ( ) ) ; 
161183
162184    let  system = OsSystem :: new ( cwd. clone ( ) ) ; 
163-     let  workspace_metadata = WorkspaceMetadata :: from_path ( system. current_directory ( ) ,  & system) ?; 
164- 
165-     // TODO: Verify the remaining search path settings eagerly. 
166-     let  site_packages = venv_path
167-         . map ( |path| { 
168-             VirtualEnvironment :: new ( path,  & OsSystem :: new ( cli_base_path) ) 
169-                 . and_then ( |venv| venv. site_packages_directories ( & system) ) 
170-         } ) 
171-         . transpose ( ) ?
172-         . unwrap_or_default ( ) ; 
173- 
174-     // TODO: Respect the settings from the workspace metadata. when resolving the program settings. 
175-     let  program_settings = ProgramSettings  { 
176-         target_version :  target_version. into ( ) , 
177-         search_paths :  SearchPathSettings  { 
178-             extra_paths, 
179-             src_root :  workspace_metadata. root ( ) . to_path_buf ( ) , 
180-             custom_typeshed :  custom_typeshed_dir, 
181-             site_packages, 
182-         } , 
183-     } ; 
185+     let  cli_configuration = args. to_configuration ( & cwd) ; 
186+     let  workspace_metadata = WorkspaceMetadata :: from_path ( 
187+         system. current_directory ( ) , 
188+         & system, 
189+         Some ( cli_configuration. clone ( ) ) , 
190+     ) ?; 
184191
185192    // TODO: Use the `program_settings` to compute the key for the database's persistent 
186193    //   cache and load the cache if it exists. 
187-     let  mut  db = RootDatabase :: new ( workspace_metadata,  program_settings ,   system) ?; 
194+     let  mut  db = RootDatabase :: new ( workspace_metadata,  system) ?; 
188195
189-     let  ( main_loop,  main_loop_cancellation_token)  = MainLoop :: new ( ) ; 
196+     let  ( main_loop,  main_loop_cancellation_token)  = MainLoop :: new ( cli_configuration ) ; 
190197
191198    // Listen to Ctrl+C and abort the watch mode. 
192199    let  main_loop_cancellation_token = Mutex :: new ( Some ( main_loop_cancellation_token) ) ; 
@@ -198,7 +205,7 @@ fn run() -> anyhow::Result<ExitStatus> {
198205        } 
199206    } ) ?; 
200207
201-     let  exit_status = if  watch { 
208+     let  exit_status = if  args . watch  { 
202209        main_loop. watch ( & mut  db) ?
203210    }  else  { 
204211        main_loop. run ( & mut  db) 
@@ -238,17 +245,20 @@ struct MainLoop {
238245
239246    /// The file system watcher, if running in watch mode. 
240247watcher :  Option < WorkspaceWatcher > , 
248+ 
249+     cli_configuration :  Configuration , 
241250} 
242251
243252impl  MainLoop  { 
244-     fn  new ( )  -> ( Self ,  MainLoopCancellationToken )  { 
253+     fn  new ( cli_configuration :   Configuration )  -> ( Self ,  MainLoopCancellationToken )  { 
245254        let  ( sender,  receiver)  = crossbeam_channel:: bounded ( 10 ) ; 
246255
247256        ( 
248257            Self  { 
249258                sender :  sender. clone ( ) , 
250259                receiver, 
251260                watcher :  None , 
261+                 cli_configuration, 
252262            } , 
253263            MainLoopCancellationToken  {  sender } , 
254264        ) 
@@ -331,7 +341,7 @@ impl MainLoop {
331341                MainLoopMessage :: ApplyChanges ( changes)  => { 
332342                    revision += 1 ; 
333343                    // Automatically cancels any pending queries and waits for them to complete. 
334-                     db. apply_changes ( changes) ; 
344+                     db. apply_changes ( changes,   Some ( & self . cli_configuration ) ) ; 
335345                    if  let  Some ( watcher)  = self . watcher . as_mut ( )  { 
336346                        watcher. update ( db) ; 
337347                    } 
0 commit comments