[Fix] Created the safest navigate/load/open/please sir i want some more for a .kcl
file (#6867)
* fix: clear scene and bust cache if rust panics * Update onboarding following @jgomez720 * chore: hopefully made a safe navigate to kcl file to call executeAST without a race condition * chore: hopefully made a safe navigate to kcl file to call executeAST without a race condition * fix: clean up * fix: FUCK * fix: FUCK 2.0 * fix: oh boi * fix: oh boi * fix: idk man * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix: take main on this, do not need a single line from my testing code * fix: more PR cleanup from all of the testing code * fix: trying to clean up more, ope this has a lot of other code * fix: PR clean up * fix: trying to get a clean branch, I had multiple other branches in here ope * fix: more cleanup * fix: another one * fix: fixed the comment to be accurate * fix: removed confusing comment --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com> Co-authored-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -261,7 +261,14 @@ export const EngineStream = (props: {
|
||||
)
|
||||
.catch(trap)
|
||||
}
|
||||
}, [file?.path])
|
||||
/**
|
||||
* Watch file not file?.path. Watching the object allows us to send the same file.path back to back
|
||||
* and still trigger the executeCode() function. JS should not be doing a cache check on the file path
|
||||
* we should be putting the cache check in Rust.
|
||||
* e.g. We can call `navigate(/file/<>)` or `navigate(/file/<>/settings)` as much as we want and it will
|
||||
* trigger this workflow.
|
||||
*/
|
||||
}, [file])
|
||||
|
||||
const IDLE_TIME_MS = Number(streamIdleMode)
|
||||
|
||||
|
@ -4,12 +4,16 @@ import {
|
||||
joinRouterPaths,
|
||||
joinOSPaths,
|
||||
safeEncodeForRouterPaths,
|
||||
webSafePathSplit,
|
||||
getProjectDirectoryFromKCLFilePath,
|
||||
} from '@src/lib/paths'
|
||||
import {
|
||||
billingActor,
|
||||
systemIOActor,
|
||||
useSettings,
|
||||
useToken,
|
||||
kclManager,
|
||||
engineCommandManager,
|
||||
} from '@src/lib/singletons'
|
||||
import { BillingTransition } from '@src/machines/billingMachine'
|
||||
import {
|
||||
@ -29,6 +33,10 @@ import { useEffect } from 'react'
|
||||
import { submitAndAwaitTextToKclSystemIO } from '@src/lib/textToCad'
|
||||
import { reportRejection } from '@src/lib/trap'
|
||||
import { getUniqueProjectName } from '@src/lib/desktopFS'
|
||||
import { useLspContext } from '@src/components/LspProvider'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import makeUrlPathRelative from '@src/lib/makeUrlPathRelative'
|
||||
import { EXECUTE_AST_INTERRUPT_ERROR_MESSAGE } from '@src/lib/constants'
|
||||
|
||||
export function SystemIOMachineLogicListenerDesktop() {
|
||||
const requestedProjectName = useRequestedProjectName()
|
||||
@ -40,7 +48,73 @@ export function SystemIOMachineLogicListenerDesktop() {
|
||||
const requestedTextToCadGeneration = useRequestedTextToCadGeneration()
|
||||
const token = useToken()
|
||||
const folders = useFolders()
|
||||
const { onFileOpen, onFileClose } = useLspContext()
|
||||
const { pathname } = useLocation()
|
||||
|
||||
function safestNavigateToFile({
|
||||
requestedPath,
|
||||
requestedFilePathWithExtension,
|
||||
requestedProjectDirectory,
|
||||
}: {
|
||||
requestedPath: string
|
||||
requestedFilePathWithExtension: string | null
|
||||
requestedProjectDirectory: string | null
|
||||
}) {
|
||||
let filePathWithExtension = null
|
||||
let projectDirectory = null
|
||||
// assumes /file/<encodedURIComponent>
|
||||
// e.g '/file/%2Fhome%2Fkevin-nadro%2FDocuments%2Fzoo-modeling-app-projects%2Fbracket-1%2Fbracket.kcl'
|
||||
const [iAmABlankString, file, encodedURI] = webSafePathSplit(pathname)
|
||||
if (
|
||||
iAmABlankString === '' &&
|
||||
file === makeUrlPathRelative(PATHS.FILE) &&
|
||||
encodedURI
|
||||
) {
|
||||
filePathWithExtension = decodeURIComponent(encodedURI)
|
||||
const applicationProjectDirectory = settings.app.projectDirectory.current
|
||||
projectDirectory = getProjectDirectoryFromKCLFilePath(
|
||||
filePathWithExtension,
|
||||
applicationProjectDirectory
|
||||
)
|
||||
}
|
||||
|
||||
// Close current file in current project if it exists
|
||||
onFileClose(filePathWithExtension, projectDirectory)
|
||||
// Open the requested file in the requested project
|
||||
onFileOpen(requestedFilePathWithExtension, requestedProjectDirectory)
|
||||
|
||||
engineCommandManager.rejectAllModelingCommands(
|
||||
EXECUTE_AST_INTERRUPT_ERROR_MESSAGE
|
||||
)
|
||||
|
||||
/**
|
||||
* Check that both paths are truthy strings and if they do not match
|
||||
* then mark it is switchedFiles.
|
||||
* If they do not match but the origin is falsey we do not want to mark as
|
||||
* switchedFiles because checkIfSwitchedFilesShouldClear will trigger
|
||||
* clearSceneAndBustCache if there is a parse error!
|
||||
*
|
||||
* i.e. Only do switchedFiles check against two file paths, not null and a file path
|
||||
*/
|
||||
if (
|
||||
filePathWithExtension &&
|
||||
requestedFilePathWithExtension &&
|
||||
filePathWithExtension !== requestedFilePathWithExtension
|
||||
) {
|
||||
kclManager.switchedFiles = true
|
||||
}
|
||||
|
||||
kclManager.isExecuting = false
|
||||
navigate(requestedPath)
|
||||
}
|
||||
|
||||
/**
|
||||
* We watch objects because we want to be able to navigate to itself
|
||||
* if we used a string the useEffect would not change
|
||||
* e.g. context.projectName if this was a string we would not be able to
|
||||
* navigate to CoolProject N times in a row. If we wrap this in an object
|
||||
* the object is watched not the string value
|
||||
*/
|
||||
const useGlobalProjectNavigation = () => {
|
||||
useEffect(() => {
|
||||
if (!requestedProjectName.name) {
|
||||
@ -55,10 +129,21 @@ export function SystemIOMachineLogicListenerDesktop() {
|
||||
safeEncodeForRouterPaths(projectPathWithoutSpecificKCLFile),
|
||||
requestedProjectName.subRoute || ''
|
||||
)
|
||||
navigate(requestedPath)
|
||||
safestNavigateToFile({
|
||||
requestedPath,
|
||||
requestedFilePathWithExtension: null,
|
||||
requestedProjectDirectory: projectPathWithoutSpecificKCLFile,
|
||||
})
|
||||
}, [requestedProjectName])
|
||||
}
|
||||
|
||||
/**
|
||||
* We watch objects because we want to be able to navigate to itself
|
||||
* if we used a string the useEffect would not change
|
||||
* e.g. context.projectName if this was a string we would not be able to
|
||||
* navigate to coolFile.kcl N times in a row. If we wrap this in an object
|
||||
* the object is watched not the string value
|
||||
*/
|
||||
const useGlobalFileNavigation = () => {
|
||||
useEffect(() => {
|
||||
if (!requestedFileName.file || !requestedFileName.project) {
|
||||
@ -69,12 +154,20 @@ export function SystemIOMachineLogicListenerDesktop() {
|
||||
requestedFileName.project,
|
||||
requestedFileName.file
|
||||
)
|
||||
const projectPathWithoutSpecificKCLFile = joinOSPaths(
|
||||
projectDirectoryPath,
|
||||
requestedProjectName.name
|
||||
)
|
||||
const requestedPath = joinRouterPaths(
|
||||
PATHS.FILE,
|
||||
safeEncodeForRouterPaths(filePath),
|
||||
requestedFileName.subRoute || ''
|
||||
)
|
||||
navigate(requestedPath)
|
||||
safestNavigateToFile({
|
||||
requestedPath,
|
||||
requestedFilePathWithExtension: filePath,
|
||||
requestedProjectDirectory: projectPathWithoutSpecificKCLFile,
|
||||
})
|
||||
}, [requestedFileName])
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,27 @@ export function getStringAfterLastSeparator(path: string): string {
|
||||
return path.split(window.electron.sep).pop() || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* When you have '/home/kevin-nadro/Documents/zoo-modeling-app-projects/bracket-1/bracket.kcl'
|
||||
* and you need to get the projectDirectory from this string above.
|
||||
*
|
||||
* We replace the leading prefix which is the application project directory with
|
||||
* the empty string. Then it becomes //bracket-1/bracket.kcl
|
||||
* The first part of the path after the blank / will be the root project directory
|
||||
*
|
||||
*/
|
||||
export function getProjectDirectoryFromKCLFilePath(
|
||||
path: string,
|
||||
applicationProjectDirectory: string
|
||||
): string {
|
||||
const replacedPath = path.replace(applicationProjectDirectory, '')
|
||||
const [iAmABlankString, projectDirectory] = desktopSafePathSplit(replacedPath)
|
||||
if (iAmABlankString === '') {
|
||||
return projectDirectory
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this for only web related paths not paths in OS or on disk
|
||||
* e.g. document.location.pathname
|
||||
|
@ -84,6 +84,10 @@ export type SystemIOContext = {
|
||||
/** has the application gone through the initialization of systemIOMachine at least once.
|
||||
* this is required to prevent chokidar from spamming invalid events during initialization. */
|
||||
hasListedProjects: boolean
|
||||
/**
|
||||
* We watch objects because we want to be able to navigate to itself
|
||||
* if we used a string the useEffect would not change
|
||||
*/
|
||||
requestedProjectName: { name: string; subRoute?: string }
|
||||
requestedFileName: { project: string; file: string; subRoute?: string }
|
||||
canReadWriteProjectDirectory: { value: boolean; error: unknown }
|
||||
|
Reference in New Issue
Block a user