package goncfiles import ( "fmt" "strings" ) // Visit is one ExApp opening: Working Folder for this request plus the Saved Default. type Visit struct { SavedDefault string WorkingRel string VisitRelative string FS Folder defaults DefaultPathStore root Root } // Open resolves the Working Folder for this visit. // initialFolderName is used when no Saved Default is stored yet (app-icon first launch). // visitRelative empty means app-icon launch (Saved Default, creating the initial folder empty if missing). // A Files-view folder is used only for this visit and does not change the Saved Default. // Missing or forbidden visit paths fail closed (no create, no fallback). func Open(root Root, defaults DefaultPathStore, initialFolderName, visitRelative string) (*Visit, error) { saved, err := defaults.GetDefault() if err != nil { return nil, err } if saved == "" { saved = initialFolderName } if CleanRel(saved) == "" { return nil, fmt.Errorf("invalid saved Working Folder path") } raw := strings.Trim(strings.ReplaceAll(visitRelative, "\\", "/"), "/") v := &Visit{ SavedDefault: saved, defaults: defaults, root: root, } if raw == "" { fs, err := root.EnsureFolder(saved) if err != nil { return nil, err } v.WorkingRel = saved v.FS = fs return v, nil } rel := CleanRel(raw) if rel == "" { return nil, fmt.Errorf("invalid Working Folder path") } v.VisitRelative = rel fs, err := root.OpenFolder(rel) if err != nil { return nil, fmt.Errorf("Working Folder %q: %w", rel, err) } v.WorkingRel = rel v.FS = fs return v, nil } // OpenLocal is the local-adapter convenience: files root + settings JSON. func OpenLocal(filesRoot, settingsPath, initialFolderName, visitRelative string) (*Visit, error) { return Open(Local{RootDir: filesRoot}, FileStore{Path: settingsPath}, initialFolderName, visitRelative) } // SetDefault persists a new Saved Default and ensures the folder exists. func (v *Visit) SetDefault(relative string) error { rel := CleanRel(relative) if rel == "" { return fmt.Errorf("invalid Saved Default path") } if _, err := v.root.EnsureFolder(rel); err != nil { return err } if err := v.defaults.SetDefault(rel); err != nil { return err } v.SavedDefault = rel return nil } // WorkingDir returns a local absolute path when using the local adapter; otherwise WorkingRel. func (v *Visit) WorkingDir() string { if p, ok := LocalPath(v.FS); ok { return p } return v.WorkingRel }