Header menu logo issie

FilesIO Module

Types

Type Description

FolderEntry

One folder as the project browser draws it.

LoadStatus

ProjectDirectory

What a directory looks like to Issie. The .dprj marker is not needed to load a project - loadAllComponentFiles reads the .dgm files and never opens it - but it is how a project is told from a folder that merely happens to have sheets in it, and how "would this new project be inside an existing one?" is answered.

Functions and values

Function or value Description

admitProjectFolder path

Full Usage: admitProjectFolder path

Parameters:
    path : string

Returns: bool

Ask for a folder chosen in the project browser to be made readable, and say whether it was. Every other read here goes through a channel confined to directories Issie already has a reason to trust, and a folder just picked out of the browser is not yet one of them. Main decides, by looking at the folder itself rather than taking the renderer's word: it admits one that holds sheets or a project marker. False therefore means "no project there", not "refused".

path : string
Returns: bool

askForExistingProjectPath defaultPath

Full Usage: askForExistingProjectPath defaultPath

Parameters:
    defaultPath : string option

Returns: string option

Ask the user to choose a project, with a dialog window. Return the chosen folder, or None if the user exits without choosing one. A project IS a directory, so that is what the dialog asks for. It used to ask for the .dprj inside one, which meant navigating into the project, past its sheets greyed out by the filter, to select a file that is empty, says nothing, and is named after the folder the user was already standing in - and whose directory was then all that was kept. Asking for the folder also lets a project whose marker was lost or renamed be opened, which the filter made impossible even though loading a project never reads it.

defaultPath : string option
Returns: string option

askForExistingSheetPaths defaultPath

Full Usage: askForExistingSheetPaths defaultPath

Parameters:
    defaultPath : string option

Returns: string list option

ask for existing sheet paths

defaultPath : string option
Returns: string list option

askForFolder title buttonLabel defaultPath

Full Usage: askForFolder title buttonLabel defaultPath

Parameters:
    title : string
    buttonLabel : string
    defaultPath : string option

Returns: string option

Ask the user to choose a folder, for a caller that knows what it wants one for. Return None if the user exits without choosing one.

title : string
buttonLabel : string
defaultPath : string option
Returns: string option

askForNewFile projectPath

Full Usage: askForNewFile projectPath

Parameters:
    projectPath : string

Returns: string option

Ask the user a new project path, with a dialog window. Return None if the user exits withouth selecting a path.

projectPath : string
Returns: string option

backupFileData path baseName

Full Usage: backupFileData path baseName

Parameters:
    path : string
    baseName : string

Returns: (int option * string) list

returns the list of backup files in descending chronological order.

path : string
baseName : string
Returns: (int option * string) list

baseName filePath

Full Usage: baseName filePath

Parameters:
    filePath : string

Returns: string
filePath : string
Returns: string

baseNameWithoutExtension

Full Usage: baseNameWithoutExtension

Returns: string -> string
Returns: string -> string

browseFolderForOpening path

Full Usage: browseFolderForOpening path

Parameters:
    path : string

Returns: Result<FolderEntry list, string>

Every immediate subdirectory of `path`, classified, for the browser to draw - or why the folder could not be listed. One level only: this lists a folder, it does not search a disk. A native folder picker draws every folder alike, so it cannot show which of them hold projects - which is the whole reason Issie draws this list itself. Deliberately NOT readSubdirectories and inspectFolder, which reach the operating system through the confined filesystem channel. The folder being browsed is by definition one the user has not opened yet, so every folder worth showing was refused: the dialog opened on the folder holding the last project and reported that the user's Documents did not exist. The browse channel in src/Main/Bridge.fs answers this one question without that confinement, and carries names and counts rather than the contents of anything.

path : string
Returns: Result<FolderEntry list, string>

checkMemoryContents projectPath comp

Full Usage: checkMemoryContents projectPath comp

Parameters:
Returns: Component

If the component is a RAM update its contents based on its initialiser

projectPath : string
comp : Component
Returns: Component

classifyFolder hasMarker sheetCount

Full Usage: classifyFolder hasMarker sheetCount

Parameters:
    hasMarker : bool
    sheetCount : int

Returns: ProjectDirectory

Which combination of marker and sheets means what. The one place that rule lives: inspectFolder reads a folder to answer it, and the project browser is handed the same two facts by main without either of them having to agree about the meaning separately.

hasMarker : bool
sheetCount : int
Returns: ProjectDirectory

copyFile sourcePath newPath

Full Usage: copyFile sourcePath newPath

Parameters:
    sourcePath : string
    newPath : string

copy a sheet from some source path to a destination path

sourcePath : string
newPath : string

copySheetWithNewIds sourcePath newPath

Full Usage: copySheetWithNewIds sourcePath newPath

Parameters:
    sourcePath : string
    newPath : string

Copy a sheet from some source path to a destination path, giving every component, port and connection in it a fresh uuid so that it cannot clash with the sheet it was copied from. Falls back to a plain file copy if the source cannot be parsed.

sourcePath : string
newPath : string

createEmptyDgmFile folderPath baseName

Full Usage: createEmptyDgmFile folderPath baseName

Parameters:
    folderPath : string
    baseName : string

Returns: Result<unit, string>

Create new empty diagram file. Automatically add the .dgm suffix.

folderPath : string
baseName : string
Returns: Result<unit, string>

dirName filePath

Full Usage: dirName filePath

Parameters:
    filePath : string

Returns: string
filePath : string
Returns: string

ensureDirectory dPath

Full Usage: ensureDirectory dPath

Parameters:
    dPath : string

dPath : string

exists filePath

Full Usage: exists filePath

Parameters:
    filePath : string

Returns: bool

False rather than an exception for a path main will not let Issie see. Every caller treats this as a question about whether to go on, and a throw here would turn a refusal into a crash - but it is logged, because "the file is not there" and "you may not look" are different problems.

filePath : string
Returns: bool

extName filePath

Full Usage: extName filePath

Parameters:
    filePath : string

Returns: string
filePath : string
Returns: string

fileExistsWithExtn extn folderPath baseName

Full Usage: fileExistsWithExtn extn folderPath baseName

Parameters:
    extn : string
    folderPath : string
    baseName : string

Returns: bool
extn : string
folderPath : string
baseName : string
Returns: bool

fileNameIsBad name

Full Usage: fileNameIsBad name

Parameters:
    name : char seq

Returns: bool
name : char seq
Returns: bool

filePathIsBad

Full Usage: filePathIsBad

Returns: string -> bool
Returns: string -> bool

getBaseNameNoExtension filePath

Full Usage: getBaseNameNoExtension filePath

Parameters:
    filePath : string

Returns: string
filePath : string
Returns: string

getCWD u

Full Usage: getCWD u

Parameters:
    u : unit

Returns: string
u : unit
Returns: string

getLatestCanvas state

Full Usage: getLatestCanvas state

Parameters:
Returns: Component list * Connection list

Interface function that can read old-style circuits (without wire vertices) as well as new circuits with vertices. Old circuits have an expansion parameter since new symbols are larger (in units) than old ones.

state : SavedInfo
Returns: Component list * Connection list

getLatestComp comp

Full Usage: getLatestComp comp

Parameters:
Returns: Component

Update from old component types to new In addition do some sanity checks The standard way to add functionality to an existing component is to create a new component type, keeping the old type. Then on reading sheets from disk both new and old will be correctly read. This function will be called on load and will convert from the old type to the new one so that the rest of issie need only process new types, but compatibility with saved old types remains.

comp : Component
Returns: Component

hasExtn extn fName

Full Usage: hasExtn extn fName

Parameters:
    extn : string
    fName : string

Returns: bool
extn : string
fName : string
Returns: bool

initialiseMem mem projectPath

Full Usage: initialiseMem mem projectPath

Parameters:
    mem : Memory1
    projectPath : string

Returns: Result<Memory1, string>

Return data for memory if it is linked to a ram. Return mem data if it is unlinked Error if the read fails ot the file parse fails.

mem : Memory1
projectPath : string
Returns: Result<Memory1, string>

inspectFolder path

Full Usage: inspectFolder path

Parameters:
    path : string

Returns: ProjectDirectory * int

What a directory is to Issie, and how many sheets are in it, from the one read of it. The count is free once the classification has looked at the file names anyway.

path : string
Returns: ProjectDirectory * int

inspectProjectDirectory path

Full Usage: inspectProjectDirectory path

Parameters:
    path : string

Returns: ProjectDirectory
path : string
Returns: ProjectDirectory

isDirectory filePath

Full Usage: isDirectory filePath

Parameters:
    filePath : string

Returns: bool

True when the path exists and is a directory. False for a file, and for a path that is not there at all, so it is safe to use as a filter before reading a directory's contents.

filePath : string
Returns: bool

isFilesystemRoot path

Full Usage: isFilesystemRoot path

Parameters:
    path : string

Returns: bool

True when a path has no parent to go up to - a drive root, or the root of a share. dirName returns such a path unchanged, which is what the browser's Up control asks.

path : string
Returns: bool

jsonStringToMem jsonString

Full Usage: jsonStringToMem jsonString

Parameters:
    jsonString : string

Returns: Result<Map<bigint, bigint>, string>
jsonString : string
Returns: Result<Map<bigint, bigint>, string>

latestBackupFileData path baseName

Full Usage: latestBackupFileData path baseName

Parameters:
    path : string
    baseName : string

Returns: (int * string) option

returns the sequence number and name of the most recent (highest sequence number) backup file

path : string
baseName : string
Returns: (int * string) option

loadAllComponentFiles folderPath

Full Usage: loadAllComponentFiles folderPath

Parameters:
    folderPath : string

Returns: Result<LoadStatus list, string>

load all files in folderpath. Return Ok list of LoadStatus or a single Error.

folderPath : string
Returns: Result<LoadStatus list, string>

magnifySheet magnification comp

Full Usage: magnifySheet magnification comp

Parameters:
Returns: LegacyComponent
magnification : float
comp : LegacyComponent
Returns: LegacyComponent

makeData aWidth dWidth makeFun

Full Usage: makeData aWidth dWidth makeFun

Parameters:
    aWidth : int
    dWidth : int
    makeFun : int -> int -> bigint

Returns: Map<bigint, bigint>
aWidth : int
dWidth : int
makeFun : int -> int -> bigint
Returns: Map<bigint, bigint>

makeFixedROM addr data mem

Full Usage: makeFixedROM addr data mem

Parameters:
    addr : int
    data : int
    mem : Memory1

Returns: Result<Map<bigint, bigint>, 'a>
addr : int
data : int
mem : Memory1
Returns: Result<Map<bigint, bigint>, 'a>

makeLoadedComponentFromCanvasData (arg1, arg2) filePath timeStamp waveInfo sheetInfo

Full Usage: makeLoadedComponentFromCanvasData (arg1, arg2) filePath timeStamp waveInfo sheetInfo

Parameters:
Returns: LoadedComponent * Component list

load a component from its canvas and other elements

arg0 : Component list
arg1 : Connection list
filePath : string
timeStamp : DateTime
waveInfo : SavedWaveInfo option
sheetInfo : SheetInfo option
Returns: LoadedComponent * Component list

mkdir folderPath

Full Usage: mkdir folderPath

Parameters:
    folderPath : string

folderPath : string

modifiedTimeMs filePath

Full Usage: modifiedTimeMs filePath

Parameters:
    filePath : string

Returns: float option

Modification time in milliseconds since the epoch, or None when the path is not there. Works on a directory as well as a file. NB a directory's time changes when an entry is added to it, removed from it or renamed - NOT when a file already in it is rewritten in place.

filePath : string
Returns: float option

openFolderInFileManager path onError

Full Usage: openFolderInFileManager path onError

Parameters:
    path : string
    onError : string -> unit

Show a directory in the platform's file manager. On Windows this launches explorer.exe rather than calling shell.openPath, because the folder window is created by the already-running explorer.exe, which has no right to take the foreground away from Issie - so shell.openPath opens it *behind* the app. A process launched by the foreground process does have that right and passes it on. Measured on Windows 11: through shell.openPath the window lands immediately below Issie and Issie keeps focus, through the spawn immediately above it and focused. Every other platform raises it already, and shell.openPath is the portable route there. onError is given a readable reason when the directory cannot be shown. On platforms other than Windows it is called asynchronously, since shell.openPath reports failure by resolving with a non-empty message rather than by rejecting - so saying nothing would make a failure look like success.

path : string
onError : string -> unit

openWriteDialogAndWriteMemory mem path

Full Usage: openWriteDialogAndWriteMemory mem path

Parameters:
Returns: string option
mem : Memory1
path : string
Returns: string option

pathJoin args

Full Usage: pathJoin args

Parameters:
    args : string array

Returns: string
args : string array
Returns: string

pathWithoutExtension filePath

Full Usage: pathWithoutExtension filePath

Parameters:
    filePath : string

Returns: string
filePath : string
Returns: string

projectMarkerPath projectPath

Full Usage: projectMarkerPath projectPath

Parameters:
    projectPath : string

Returns: string

The empty file that marks a directory as an Issie project, named after the directory.

projectPath : string
Returns: string

projectNameError name

Full Usage: projectNameError name

Parameters:
    name : string

Returns: string option

Why a project may not be called this, if it may not. One rule, in one place: the creation form asks it of every keystroke so that the user sees the objection while they can still act on it, and tryCreateFolder asks it as the last word. It used to be reachable only by breaking it, after the native dialog had been dismissed, in an error box that took the typing with it.

name : string
Returns: string option

readFile filePath

Full Usage: readFile filePath

Parameters:
    filePath : string

Returns: string
filePath : string
Returns: string

readFilesFromDirectory path

Full Usage: readFilesFromDirectory path

Parameters:
    path : string

Returns: string list

read file names from directory: returning [] on any error.

path : string
Returns: string list

readFilesFromDirectoryWithExtn path extn

Full Usage: readFilesFromDirectoryWithExtn path extn

Parameters:
    path : string
    extn : string

Returns: string list
path : string
extn : string
Returns: string list

readMemDefnLine addressWidth wordWidth lineNo s

Full Usage: readMemDefnLine addressWidth wordWidth lineNo s

Parameters:
    addressWidth : int
    wordWidth : int
    lineNo : int
    s : string

Returns: Result<(bigint * bigint * string option), string>

Parse one "address data" line of a .ram file, which may carry a comment. lineNo is the 1-based line number in the file, used only to say where an error is.

addressWidth : int
wordWidth : int
lineNo : int
s : string
Returns: Result<(bigint * bigint * string option), string>

readMemDefns addressWidth wordWidth fPath

Full Usage: readMemDefns addressWidth wordWidth fPath

Parameters:
    addressWidth : int
    wordWidth : int
    fPath : string

Returns: Result<(Map<bigint, bigint> * Map<bigint, string>), string>

The locations defined by a .ram file, and the comments written against them. Locations with no comment are absent from the second map.

addressWidth : int
wordWidth : int
fPath : string
Returns: Result<(Map<bigint, bigint> * Map<bigint, string>), string>

readMemLines addressWidth wordWidth lines

Full Usage: readMemLines addressWidth wordWidth lines

Parameters:
    addressWidth : int
    wordWidth : int
    lines : string array

Returns: Result<(bigint * bigint * string option) array, string>

Parse the lines of a .ram file, reporting the first bad line. lines must be the file's lines as they are, blanks included, so that reported line numbers match the file.

addressWidth : int
wordWidth : int
lines : string array
Returns: Result<(bigint * bigint * string option) array, string>

readSubdirectories folderPath

Full Usage: readSubdirectories folderPath

Parameters:
    folderPath : string

Returns: string list

The immediate subdirectories of a folder, as full paths. [] if it cannot be read. Deliberately not readdir: under .NET that is Directory.GetFiles, which lists files only, while node's readdirSync lists directories too. Anything looking for subfolders through readdir therefore works in the app and finds nothing under test - which is how this function came to exist. The directories come from the one readdir rather than from a stat of each entry, which is what this used to do: existsSync and lstatSync per name, paid on every FILE in the folder before discarding it. Listing C:\Windows\System32 took 244ms that way and takes 3ms this way - 4,885 entries, of which 4,687 were files answering a question nobody asked. Directory.GetDirectories never had the problem, so only the node side changes.

folderPath : string
Returns: string list

readdir folderPath

Full Usage: readdir folderPath

Parameters:
    folderPath : string

Returns: string array
folderPath : string
Returns: string array

removeAutoFile folderPath baseName

Full Usage: removeAutoFile folderPath baseName

Parameters:
    folderPath : string
    baseName : string

folderPath : string
baseName : string

removeExtn extn fName

Full Usage: removeExtn extn fName

Parameters:
    extn : string
    fName : string

Returns: string option
extn : string
fName : string
Returns: string option

removeFile folderPath baseName

Full Usage: removeFile folderPath baseName

Parameters:
    folderPath : string
    baseName : string

folderPath : string
baseName : string

removeFileWithExtn extn folderPath baseName

Full Usage: removeFileWithExtn extn folderPath baseName

Parameters:
    extn : string
    folderPath : string
    baseName : string

Asyncronously remove file. ignore if file does not exist

extn : string
folderPath : string
baseName : string

rename oldPath newPath

Full Usage: rename oldPath newPath

Parameters:
    oldPath : string
    newPath : string

oldPath : string
newPath : string

renameFile extn folderPath baseName newBaseName

Full Usage: renameFile extn folderPath baseName newBaseName

Parameters:
    extn : string
    folderPath : string
    baseName : string
    newBaseName : string

Returns: Result<unit, string>
extn : string
folderPath : string
baseName : string
newBaseName : string
Returns: Result<unit, string>

saveAllProjectFilesFromLoadedComponentsToDisk proj

Full Usage: saveAllProjectFilesFromLoadedComponentsToDisk proj

Parameters:
proj : Project

saveStateToFile folderPath baseName (arg3, arg4, arg5)

Full Usage: saveStateToFile folderPath baseName (arg3, arg4, arg5)

Parameters:
Returns: Result<unit, string>

Save state to normal file. Automatically add the .dgm suffix. This version will not correctly deal with bigint numbers. See svaStateToFileNew If serialisation fails the existing file is left untouched and an Error returned.

folderPath : string
baseName : string
arg2 : CanvasState
arg3 : SavedWaveInfo option
arg4 : SheetInfo option
Returns: Result<unit, string>

saveStateToFileExperimental folderPath baseName (arg3, arg4, arg5)

Full Usage: saveStateToFileExperimental folderPath baseName (arg3, arg4, arg5)

Parameters:
Returns: Result<unit, string>

Save state to file. Automatically add the .dgm suffix. This is the new version of the function that uses the new state format and copes with bigints However, it seems that it is not used??

folderPath : string
baseName : string
arg2 : CanvasState
arg3 : SavedWaveInfo option
arg4 : SheetInfo option
Returns: Result<unit, string>

splitMemDefnComment s

Full Usage: splitMemDefnComment s

Parameters:
    s : string

Returns: string * string option

Split a .ram file line into the part which defines a memory location and the comment written against it, if any. A comment runs from "//" to the end of the line.

s : string
Returns: string * string option

staticDir ()

Full Usage: staticDir ()

Parameters:
    () : unit

Returns: string

Absolute path to the static asset directory. This used to be worked out here, three ways: __static in development, a bare "./resources/static" relative to the working directory for production on Windows and Linux, and __dirname/../../static for production on macOS. All three land on the same place as the main process's process.resourcesPath, and __static in particular is a webpack substitution that expands to an expression over `path` and `process` - so it could not survive contextIsolation even in principle. Main resolves it once now and sends the answer; see Bridge.staticDirectory.

() : unit
Returns: string

staticFileDirectory

Full Usage: staticFileDirectory

Returns: string

absolute path to repo directory ./static NB this path is not fixed (even as relative path) between production and dev builds, so this must be used to access static assets. Empty under plain .NET - the tests - which have no Electron to ask and are given the directory they work on explicitly.

Returns: string

stripVertices conn

Full Usage: stripVertices conn

Parameters:
Returns: LegacyConnection
conn : LegacyConnection
Returns: LegacyConnection

tryCreateFolder path

Full Usage: tryCreateFolder path

Parameters:
    path : string

Returns: Result<unit, string>
path : string
Returns: Result<unit, string>

tryEnsureDirectory dPath

Full Usage: tryEnsureDirectory dPath

Parameters:
    dPath : string

Returns: Result<string, string>

Make a directory if it is not there, saying why if that could not be done. Creating a directory can genuinely fail - a read-only or full disk, a permissions policy - and the callers here are all able to carry on without it.

dPath : string
Returns: Result<string, string>

tryLoadComponentFromPath filePath

Full Usage: tryLoadComponentFromPath filePath

Parameters:
    filePath : string

Returns: Result<LoadedComponent, string>

Make a loadedComponent from the file read from filePath. Return the component, or an Error string.

filePath : string
Returns: Result<LoadedComponent, string>

tryReadFileSync fPath

Full Usage: tryReadFileSync fPath

Parameters:
    fPath : string

Returns: Result<string, string>
fPath : string
Returns: Result<string, string>

tryUserDataDirectory ()

Full Usage: tryUserDataDirectory ()

Parameters:
    () : unit

Returns: Result<string, string>

The per-user, writable Issie directory. Anything Issie writes for the user - demo working copies, component libraries the user makes or imports - belongs here and NOT beside the installation. On macOS the app bundle is signed and notarised, so writing inside it invalidates the signature and Gatekeeper can then refuse to launch it. On Windows the installation is usually under Program Files, which needs administrator rights to write. Both fail only for installed users, never in a development build, which is exactly the kind of bug that ships.

() : unit
Returns: Result<string, string>

tryUserDemosDirectory ()

Full Usage: tryUserDemosDirectory ()

Parameters:
    () : unit

Returns: Result<string, string>

Where a demo project is copied so that the user can edit it.

() : unit
Returns: Result<string, string>

tryUserLibrariesDirectory ()

Full Usage: tryUserLibrariesDirectory ()

Parameters:
    () : unit

Returns: Result<string, string>

Where libraries the user makes or imports live. The libraries shipped with Issie are NOT copied here: they stay read-only under the installation, and are found there directly.

() : unit
Returns: Result<string, string>

unlink folderPath

Full Usage: unlink folderPath

Parameters:
    folderPath : string

folderPath : string

writeFile path data

Full Usage: writeFile path data

Parameters:
    path : string
    data : string

Returns: Result<unit, string>

Write utf8 encoded data to file. Create file if it does not exist.

path : string
data : string
Returns: Result<unit, string>

writeMemDefns fPath mem

Full Usage: writeMemDefns fPath mem

Parameters:
Returns: Result<Result<unit, string>, string>
fPath : string
mem : Memory1
Returns: Result<Result<unit, string>, string>

Type something to start searching.