fix project list showing projects of double clicked files (#2441)

* make sure there is at least one kcl file in the dir to show in list

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* open the correct file not assuming main.kcl

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add file path tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update settings paths

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* new images

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-05-21 18:14:49 -07:00
committed by GitHub
parent 63159c1cb8
commit ec7b733a0d
29 changed files with 238 additions and 59 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

49
src-tauri/Cargo.lock generated
View File

@ -212,6 +212,15 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.4" version = "0.7.4"
@ -1207,6 +1216,17 @@ dependencies = [
"syn 2.0.65", "syn 2.0.65",
] ]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
]
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.17" version = "0.99.17"
@ -1258,6 +1278,17 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "displaydoc"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
]
[[package]] [[package]]
name = "dlib" name = "dlib"
version = "0.5.2" version = "0.5.2"
@ -2579,7 +2610,7 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"winnow 0.5.40", "winnow 0.5.40",
"zip", "zip 1.3.0",
] ]
[[package]] [[package]]
@ -5471,7 +5502,7 @@ dependencies = [
"tokio", "tokio",
"url", "url",
"windows-sys 0.52.0", "windows-sys 0.52.0",
"zip", "zip 0.6.6",
] ]
[[package]] [[package]]
@ -7123,6 +7154,20 @@ dependencies = [
"zstd", "zstd",
] ]
[[package]]
name = "zip"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f4a27345eb6f7aa7bd015ba7eb4175fa4e1b462a29874b779e0bbcf96c6ac7"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
"indexmap 2.2.6",
"thiserror",
]
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.11.2+zstd.1.5.2" version = "0.11.2+zstd.1.5.2"

View File

@ -121,11 +121,8 @@ async fn write_app_settings_file(app: tauri::AppHandle, configuration: Configura
Ok(()) Ok(())
} }
async fn get_project_settings_file_path( async fn get_project_settings_file_path(project_path: &str) -> Result<PathBuf, InvokeError> {
app_settings: Configuration, let project_dir = std::path::Path::new(project_path);
project_name: &str,
) -> Result<PathBuf, InvokeError> {
let project_dir = app_settings.settings.project.directory.join(project_name);
if !project_dir.exists() { if !project_dir.exists() {
tokio::fs::create_dir_all(&project_dir) tokio::fs::create_dir_all(&project_dir)
@ -137,11 +134,8 @@ async fn get_project_settings_file_path(
} }
#[tauri::command] #[tauri::command]
async fn read_project_settings_file( async fn read_project_settings_file(project_path: &str) -> Result<ProjectConfiguration, InvokeError> {
app_settings: Configuration, let settings_path = get_project_settings_file_path(project_path).await?;
project_name: &str,
) -> Result<ProjectConfiguration, InvokeError> {
let settings_path = get_project_settings_file_path(app_settings, project_name).await?;
// Check if this file exists. // Check if this file exists.
if !settings_path.exists() { if !settings_path.exists() {
@ -159,11 +153,10 @@ async fn read_project_settings_file(
#[tauri::command] #[tauri::command]
async fn write_project_settings_file( async fn write_project_settings_file(
app_settings: Configuration, project_path: &str,
project_name: &str,
configuration: ProjectConfiguration, configuration: ProjectConfiguration,
) -> Result<(), InvokeError> { ) -> Result<(), InvokeError> {
let settings_path = get_project_settings_file_path(app_settings, project_name).await?; let settings_path = get_project_settings_file_path(project_path).await?;
let contents = toml::to_string_pretty(&configuration).map_err(|e| InvokeError::from_anyhow(e.into()))?; let contents = toml::to_string_pretty(&configuration).map_err(|e| InvokeError::from_anyhow(e.into()))?;
tokio::fs::write(settings_path, contents.as_bytes()) tokio::fs::write(settings_path, contents.as_bytes())
.await .await

View File

@ -22,8 +22,7 @@ import {
LspWorker, LspWorker,
} from 'editor/plugins/lsp/types' } from 'editor/plugins/lsp/types'
import { wasmUrl } from 'lang/wasm' import { wasmUrl } from 'lang/wasm'
import { PROJECT_ENTRYPOINT } from 'lib/constants'
const DEFAULT_FILE_NAME: string = 'main.kcl'
function getWorkspaceFolders(): LSP.WorkspaceFolder[] { function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
return [] return []
@ -137,7 +136,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (isKclLspServerReady && !TEST && kclLspClient) { if (isKclLspServerReady && !TEST && kclLspClient) {
// Set up the lsp plugin. // Set up the lsp plugin.
const lsp = kclLanguage({ const lsp = kclLanguage({
documentUri: `file:///${DEFAULT_FILE_NAME}`, documentUri: `file:///${PROJECT_ENTRYPOINT}`,
workspaceFolders: getWorkspaceFolders(), workspaceFolders: getWorkspaceFolders(),
client: kclLspClient, client: kclLspClient,
}) })
@ -211,7 +210,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (isCopilotLspServerReady && !TEST && copilotLspClient) { if (isCopilotLspServerReady && !TEST && copilotLspClient) {
// Set up the lsp plugin. // Set up the lsp plugin.
const lsp = copilotPlugin({ const lsp = copilotPlugin({
documentUri: `file:///${DEFAULT_FILE_NAME}`, documentUri: `file:///${PROJECT_ENTRYPOINT}`,
workspaceFolders: getWorkspaceFolders(), workspaceFolders: getWorkspaceFolders(),
client: copilotLspClient, client: copilotLspClient,
allowHTMLContent: true, allowHTMLContent: true,
@ -236,7 +235,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
redirect: boolean redirect: boolean
) => { ) => {
const currentFilePath = projectBasename( const currentFilePath = projectBasename(
file?.path || DEFAULT_FILE_NAME, file?.path || PROJECT_ENTRYPOINT,
projectPath || '' projectPath || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {
@ -267,7 +266,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (file) { if (file) {
// Send that the file was opened. // Send that the file was opened.
const filename = projectBasename( const filename = projectBasename(
file?.path || DEFAULT_FILE_NAME, file?.path || PROJECT_ENTRYPOINT,
project?.path || '' project?.path || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {
@ -285,7 +284,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const onFileOpen = (filePath: string | null, projectPath: string | null) => { const onFileOpen = (filePath: string | null, projectPath: string | null) => {
const currentFilePath = projectBasename( const currentFilePath = projectBasename(
filePath || DEFAULT_FILE_NAME, filePath || PROJECT_ENTRYPOINT,
projectPath || '' projectPath || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {
@ -302,7 +301,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const onFileClose = (filePath: string | null, projectPath: string | null) => { const onFileClose = (filePath: string | null, projectPath: string | null) => {
const currentFilePath = projectBasename( const currentFilePath = projectBasename(
filePath || DEFAULT_FILE_NAME, filePath || PROJECT_ENTRYPOINT,
projectPath || '' projectPath || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {

View File

@ -119,7 +119,7 @@ function ProjectCard({
<> <>
<Link <Link
className="relative z-0 flex flex-col h-full gap-2 p-1 !no-underline !text-chalkboard-110 dark:!text-chalkboard-10" className="relative z-0 flex flex-col h-full gap-2 p-1 !no-underline !text-chalkboard-110 dark:!text-chalkboard-10"
to={`${paths.FILE}/${encodeURIComponent(project.path)}`} to={`${paths.FILE}/${encodeURIComponent(project.default_file)}`}
data-testid="project-link" data-testid="project-link"
> >
<div className="flex-1">{project.name?.replace(FILE_EXT, '')}</div> <div className="flex-1">{project.name?.replace(FILE_EXT, '')}</div>

View File

@ -24,6 +24,7 @@ const projectWellFormed = {
}, },
kcl_file_count: 1, kcl_file_count: 1,
directory_count: 0, directory_count: 0,
default_file: '/some/path/Simple Box/main.kcl',
} satisfies Project } satisfies Project
describe('ProjectSidebarMenu tests', () => { describe('ProjectSidebarMenu tests', () => {

View File

@ -172,7 +172,7 @@ export const SettingsAuthProviderBase = ({
}, },
'Execute AST': () => kclManager.executeCode(true), 'Execute AST': () => kclManager.executeCode(true),
persistSettings: (context) => persistSettings: (context) =>
saveSettings(context, loadedProject?.project?.name), saveSettings(context, loadedProject?.project?.path),
}, },
} }
) )

View File

@ -38,8 +38,8 @@ export const settingsLoader: LoaderFunction = async ({
configuration configuration
) )
if (projectPathData) { if (projectPathData) {
const { project_name } = projectPathData const { project_path } = projectPathData
const { settings: s } = await loadAndValidateSettings(project_name) const { settings: s } = await loadAndValidateSettings(project_path)
settings = s settings = s
} }
} }
@ -118,6 +118,7 @@ export const fileLoader: LoaderFunction = async ({
children: [], children: [],
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file: project_path,
}, },
file: { file: {
name: current_file_name, name: current_file_name,

View File

@ -147,7 +147,7 @@ export interface AppSettings {
} }
export async function loadAndValidateSettings( export async function loadAndValidateSettings(
projectName?: string projectPath?: string
): Promise<AppSettings> { ): Promise<AppSettings> {
const settings = createSettings() const settings = createSettings()
const inTauri = isTauri() const inTauri = isTauri()
@ -166,9 +166,9 @@ export async function loadAndValidateSettings(
setSettingsAtLevel(settings, 'user', appSettingsPayload) setSettingsAtLevel(settings, 'user', appSettingsPayload)
// Load the project settings if they exist // Load the project settings if they exist
if (projectName) { if (projectPath) {
const projectSettings = inTauri const projectSettings = inTauri
? await readProjectSettingsFile(appSettings, projectName) ? await readProjectSettingsFile(projectPath)
: readLocalStorageProjectSettingsFile() : readLocalStorageProjectSettingsFile()
const projectSettingsPayload = const projectSettingsPayload =
@ -182,7 +182,7 @@ export async function loadAndValidateSettings(
export async function saveSettings( export async function saveSettings(
allSettings: typeof settings, allSettings: typeof settings,
projectName?: string projectPath?: string
) { ) {
// Make sure we have wasm initialized. // Make sure we have wasm initialized.
await initPromise await initPromise
@ -204,7 +204,7 @@ export async function saveSettings(
) )
} }
if (!projectName) { if (!projectPath) {
// If we're not saving project settings, we're done. // If we're not saving project settings, we're done.
return return
} }
@ -217,7 +217,7 @@ export async function saveSettings(
// Write the project settings. // Write the project settings.
if (inTauri) { if (inTauri) {
await writeProjectSettingsFile(appSettings, projectName, projectSettings) await writeProjectSettingsFile(projectPath, projectSettings)
} else { } else {
localStorage.setItem( localStorage.setItem(
localStorageProjectSettingsPath(), localStorageProjectSettingsPath(),

View File

@ -143,24 +143,20 @@ export async function writeAppSettingsFile(
// Read project settings file. // Read project settings file.
export async function readProjectSettingsFile( export async function readProjectSettingsFile(
appSettings: Configuration, projectPath: string
projectName: string
): Promise<ProjectConfiguration> { ): Promise<ProjectConfiguration> {
return await invoke<ProjectConfiguration>('read_project_settings_file', { return await invoke<ProjectConfiguration>('read_project_settings_file', {
appSettings, projectPath,
projectName,
}) })
} }
// Write project settings file. // Write project settings file.
export async function writeProjectSettingsFile( export async function writeProjectSettingsFile(
appSettings: Configuration, projectPath: string,
projectName: string,
settings: ProjectConfiguration settings: ProjectConfiguration
): Promise<void> { ): Promise<void> {
return await invoke('write_project_settings_file', { return await invoke('write_project_settings_file', {
appSettings, projectPath,
projectName,
configuration: settings, configuration: settings,
}) })
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -1,5 +1,6 @@
//! Types for interacting with files in projects. //! Types for interacting with files in projects.
#[cfg(not(target_arch = "wasm32"))]
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
@ -7,7 +8,7 @@ use parse_display::{Display, FromStr};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::settings::types::{Configuration, DEFAULT_PROJECT_KCL_FILE}; use crate::settings::types::Configuration;
/// State management for the application. /// State management for the application.
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)] #[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)]
@ -48,7 +49,7 @@ impl ProjectState {
.map_err(|e| anyhow::anyhow!("Error loading project from path {}: {:?}", source_path.display(), e))?; .map_err(|e| anyhow::anyhow!("Error loading project from path {}: {:?}", source_path.display(), e))?;
// Check if we have a main.kcl file in the project. // Check if we have a main.kcl file in the project.
let project_file = source_path.join(DEFAULT_PROJECT_KCL_FILE); let project_file = source_path.join(crate::settings::types::DEFAULT_PROJECT_KCL_FILE);
if !project_file.exists() { if !project_file.exists() {
// Create the default file in the project. // Create the default file in the project.
@ -247,6 +248,8 @@ pub struct Project {
#[serde(default)] #[serde(default)]
#[ts(type = "number")] #[ts(type = "number")]
pub directory_count: u64, pub directory_count: u64,
/// The default file to open on load.
pub default_file: String,
} }
impl Project { impl Project {
@ -266,12 +269,13 @@ impl Project {
} }
let file = crate::settings::utils::walk_dir(&path).await?; let file = crate::settings::utils::walk_dir(&path).await?;
let metadata = std::fs::metadata(path).ok().map(|m| m.into()); let metadata = std::fs::metadata(&path).ok().map(|m| m.into());
let mut project = Self { let mut project = Self {
file, file: file.clone(),
metadata, metadata,
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file: get_default_kcl_file_for_dir(path, file).await?,
}; };
project.populate_kcl_file_count()?; project.populate_kcl_file_count()?;
project.populate_directory_count()?; project.populate_directory_count()?;
@ -309,6 +313,40 @@ impl Project {
} }
} }
/// Get the default KCL file for a directory.
/// This determines what the default file to open is.
#[cfg(not(target_arch = "wasm32"))]
#[async_recursion::async_recursion]
pub async fn get_default_kcl_file_for_dir<P>(dir: P, file: FileEntry) -> Result<String>
where
P: AsRef<Path> + Send,
{
// Make sure the dir is a directory.
if !dir.as_ref().is_dir() {
return Err(anyhow::anyhow!("Path `{}` is not a directory", dir.as_ref().display()));
}
let default_file = dir.as_ref().join(crate::settings::types::DEFAULT_PROJECT_KCL_FILE);
if !default_file.exists() {
// Find a kcl file in the directory.
if let Some(children) = file.children {
for entry in children.iter() {
if entry.name.ends_with(".kcl") {
return Ok(dir.as_ref().join(&entry.name).display().to_string());
} else if entry.children.is_some() {
// Recursively find a kcl file in the directory.
return get_default_kcl_file_for_dir(entry.path.clone(), entry.clone()).await;
}
}
}
// If we didn't find a kcl file, create one.
tokio::fs::write(&default_file, vec![]).await?;
}
Ok(default_file.display().to_string())
}
/// Information about a file or directory. /// Information about a file or directory.
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)] #[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)]
#[ts(export)] #[ts(export)]
@ -588,4 +626,100 @@ mod tests {
} }
); );
} }
#[test]
fn test_project_route_from_route_non_main_file() {
let mut configuration = crate::settings::types::Configuration::default();
configuration.settings.project.directory =
std::path::PathBuf::from("/Users/macinatormax/Documents/kittycad-modeling-projects");
let route = "/Users/macinatormax/Documents/kittycad-modeling-projects/assembly/thing.kcl";
let state = super::ProjectRoute::from_route(&configuration, route).unwrap();
assert_eq!(
state,
super::ProjectRoute {
project_name: Some("assembly".to_string()),
project_path: "/Users/macinatormax/Documents/kittycad-modeling-projects/assembly".to_string(),
current_file_name: Some("thing.kcl".to_string()),
current_file_path: Some(
"/Users/macinatormax/Documents/kittycad-modeling-projects/assembly/thing.kcl".to_string()
),
}
);
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_non_exist() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(default_file, dir.join("main.kcl").display().to_string());
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_main_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("main.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(default_file, dir.join("main.kcl").display().to_string());
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_thing_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("thing.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(default_file, dir.join("thing.kcl").display().to_string());
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_nested_main_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::create_dir_all(dir.join("assembly")).unwrap();
std::fs::write(dir.join("assembly").join("main.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(
default_file,
dir.join("assembly").join("main.kcl").display().to_string()
);
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_nested_thing_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::create_dir_all(dir.join("assembly")).unwrap();
std::fs::write(dir.join("assembly").join("thing.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(
default_file,
dir.join("assembly").join("thing.kcl").display().to_string()
);
std::fs::remove_dir_all(dir).unwrap();
}
} }

View File

@ -109,6 +109,7 @@ impl Configuration {
// Because we just created it and it's empty. // Because we just created it and it's empty.
children: None, children: None,
}, },
default_file: project_file.to_string_lossy().to_string(),
metadata: Some(tokio::fs::metadata(&project_dir).await?.into()), metadata: Some(tokio::fs::metadata(&project_dir).await?.into()),
kcl_file_count: 1, kcl_file_count: 1,
directory_count: 0, directory_count: 0,
@ -130,7 +131,13 @@ impl Configuration {
continue; continue;
} }
projects.push(self.get_project_info(&e.path().display().to_string()).await?); // Make sure the project has at least one kcl file in it.
let project = self.get_project_info(&e.path().display().to_string()).await?;
if project.kcl_file_count == 0 {
continue;
}
projects.push(project);
} }
Ok(projects) Ok(projects)
@ -150,11 +157,14 @@ impl Configuration {
return Err(anyhow::anyhow!("Project path is not a directory: {}", project_path)); return Err(anyhow::anyhow!("Project path is not a directory: {}", project_path));
} }
let walked = crate::settings::utils::walk_dir(project_dir).await?;
let mut project = crate::settings::types::file::Project { let mut project = crate::settings::types::file::Project {
file: crate::settings::utils::walk_dir(project_dir).await?, file: walked.clone(),
metadata: Some(tokio::fs::metadata(&project_dir).await?.into()), metadata: Some(tokio::fs::metadata(&project_dir).await?.into()),
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file: crate::settings::types::file::get_default_kcl_file_for_dir(project_dir, walked).await?,
}; };
// Populate the number of KCL files in the project. // Populate the number of KCL files in the project.

View File

@ -33,6 +33,16 @@ pub async fn walk_dir<P>(dir: P) -> Result<FileEntry>
where where
P: AsRef<Path> + Send, P: AsRef<Path> + Send,
{ {
// Make sure the path is a directory.
if !dir.as_ref().is_dir() {
return Err(anyhow::anyhow!("Path `{}` is not a directory", dir.as_ref().display()));
}
// Make sure the directory exists.
if !dir.as_ref().exists() {
return Err(anyhow::anyhow!("Directory `{}` does not exist", dir.as_ref().display()));
}
let mut entry = FileEntry { let mut entry = FileEntry {
name: dir name: dir
.as_ref() .as_ref()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View File

@ -77,16 +77,6 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
) )
.await?; .await?;
// Enter edit mode.
// We can't get control points of an existing sketch without being in edit mode.
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::EditModeEnter { target: sketch_id },
)
.await?;
Ok((ctx, program, sketch_id)) Ok((ctx, program, sketch_id))
} }