diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index e232bec..ea6227b 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -315,14 +315,31 @@ should be on it, and the shell decides. ### Finishing A Word: -Tab finishes the **first** word of a line against the shell's own commands. One match goes in -with a space after it, because a word that can only be one thing is finished. Several are -folded into their longest common prefix and that goes in, which is the most that can be said -without guessing which was meant - and if that adds nothing, because what is typed is already -as far as they all agree, the matches are listed and the line put back underneath. +Tab finishes the word being typed. One match goes in with a space after it, because a word +that can only be one thing is finished. Several are folded into their longest common prefix +and that goes in, which is the most that can be said without guessing which was meant - and +if that adds nothing, because what is typed is already as far as they all agree, the matches +are listed and the line put back underneath. -Nothing typed and nothing matching both do nothing, quietly. Finishing an argument rather -than a command is not built yet. +**What it can be depends on where in the line it is.** The first word is a command or a +program; anything after it is a file. + +| Where | What is offered | +| -- | -- | +| The first word | the fifteen commands, and programs - under the name you would type, with the extension taken off | +| After it | anything on the disk, under its real name | +| Either, with a `/` in it | whatever is in the directory the word names | + +A directory answers with a separator on the end instead of a space, which says what it is and +lets the next part be typed straight away. + +**Programs are looked for in the three places the shell would look to run one**: where you +are, `/Apps` on the disk you are on, and `/Apps` on drive 0. Offering something the shell +would not find would be finishing a word into a thing that then does not work. A program that +is in two of those places is offered twice and so is never the only match, which costs it the +space after it - the shell is comparing names, not deciding which file it would have run. + +Nothing typed and nothing matching both do nothing, quietly. **This is the same wall the history was behind.** A shell that never sees a keystroke has no moment at which somebody has typed half a word - the terminal hands over finished lines - so diff --git a/Programs/CosmOS/Source/cosmos.asm b/Programs/CosmOS/Source/cosmos.asm index 3715b43..d4c5692 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -1538,7 +1538,7 @@ tabComplete: tabBack: SETD.1 TabWordAt LDA.1 - BRA tabIsFirst ; The start of the line is the start of the word, and of the line. + BRA tabAtLineStart ; The start of the line is the start of the word, and of the line. DECA CALL tabCharAt MVQA @@ -1551,10 +1551,19 @@ tabBack: STA.1 BRI tabBack +tabAtLineStart: + INIA 0x01 + SETD.1 TabFirst + STA.1 + BRI tabIsFirst + tabFoundStart: ; There is a space behind the word, so something may be in front of that space. Only a run - ; of spaces means this is still the first word; anything else is an argument, and finishing - ; one of those is not built yet. + ; of spaces means this is still the first word - and which word it is decides what the word + ; could BE: a command or a program at the front of a line, a file anywhere after it. + INIA 0x01 + SETD.1 TabFirst + STA.1 SETD.1 TabWordAt LDA.1 SETD.1 TabLeft @@ -1569,8 +1578,10 @@ tabFirstCheck: MVQA INIB 0x20 XOR - BNQ tabDone ; Not a space, so a word came before this one. - BRI tabFirstCheck + BRQ tabFirstCheck + RSTA + SETD.1 TabFirst + STA.1 ; A word came before this one, so this is an argument. tabIsFirst: ; How much of it is typed. Nothing at all is not a question anybody asked - it would offer @@ -1592,7 +1603,22 @@ tabIsFirst: SETD.1 TabBestLen STA.1 - CALL tabTryNames + ; A path in the word says which directory to look in, and narrows what is being matched to + ; the part after the last separator. + CALL tabSplit + + ; ---- What this word could be ---- + ; + ; The shell's own commands, only at the front of a line and only when no directory has been + ; named: nothing with a separator in it was ever going to be "dir". + ; + ; And on the disk: programs at the front of a line, since that is all a first word can + ; usefully be, and anything at all after it. + SETD.1 TabFirst + LDA.1 + SETD.1 TabPrograms + STA.1 + CALL tabRunSources SETD.1 TabCount LDA.1 @@ -1641,11 +1667,24 @@ tabPutDone: XOR BNQ tabAmbiguous - ; Only one thing it can be, so it is finished and a space says so. + ; Only one thing it can be, so it is finished and a space says so - unless it is a + ; directory, which answered with a separator on the end and is somewhere to carry on typing + ; rather than something to have finished. + SETD.3 TabBest + SETD.1 TabBestLen + LDA.1 + DECA + DPUA.3 + LDA.3 + INIB 0x2F + XOR + BRQ tabSaidDirectory + INIA 0x20 SETD.1 EditChar STA.1 CALL editPut +tabSaidDirectory: CALL editRedraw BRI tabDone @@ -1663,6 +1702,20 @@ tabAmbiguous: tabDone: BRI editKey +; Everywhere a candidate can come from, in the order they are tried. Run once to find the +; answer and again to show the matches, which is why it is a routine and not a run of code. +tabRunSources: + SETD.1 TabFirst + LDA.1 + BRA tabNoNames + SETD.1 TabDirLen + LDA.1 + BNA tabNoNames + CALL tabTryNames +tabNoNames: + CALL tabTryFiles + RET + ; A holds an offset into the line. Q is the character there. tabCharAt: SETD.1 EditBase @@ -1725,6 +1778,15 @@ tabOfferMatch: BRI tabOfferMatch tabOfferTake: + ; ---- Folded in, or shown ---- + ; + ; The same walk answers both questions, because they are the same question asked twice: + ; what matches. Listing used to be a second copy of the walk that knew only about the + ; shell's own words, so the files it should have been showing were never there. + SETD.1 TabShowing + LDA.1 + BNA tabOfferPrint + ; The first match is the answer. Every one after it cuts the answer back to where the two ; stop agreeing, which is all that can be said without guessing which was meant. SETD.1 TabCount @@ -1738,6 +1800,15 @@ tabOfferTake: BRI tabOfferSkip tabOfferFirst: CALL tabTake + BRI tabOfferSkip + +tabOfferPrint: + SETD.1 TabStart + LDD.0.1 + CALL printString + INIA 0x20 + OUTA 0x00 + OUTA 0x00 ; Two spaces between them, and A already holds one. tabOfferSkip: ; Past the end of this candidate, from wherever the comparison stopped. @@ -1813,6 +1884,355 @@ tabNarrowCut: tabNarrowDone: RET + +; ---- Splitting the word at its last separator ---- +; +; "Apps/Sn" is a directory to look in and a name to match, and everything downstream depends +; on getting that split right. What comes back is TabDir holding the directory part - empty +; when there is no separator, meaning where the machine already is - and TabWordAt and +; TabWordLen narrowed to the name part, so that matching and inserting go on working on the +; part of the word they were always about. +tabSplit: + RSTA + SETD.1 TabDirLen + STA.1 + + ; Backwards, so the LAST separator is the one found. + SETD.1 TabWordLen + LDA.1 + SETD.1 TabAt + STA.1 +tabSplitBack: + SETD.1 TabAt + LDA.1 + BRA tabSplitNone ; No separator anywhere in it. + DECA + STA.1 + SETD.1 TabWordAt + LDB.1 + CCF + ADD + MVQA + CALL tabCharAt + MVQA + INIB 0x2F + XOR + BNQ tabSplitBack + + ; Found one. The directory part is everything up to and including it, which is what makes + ; "/Source/" and "Source/" both say what they mean. + SETD.1 TabAt + LDA.1 + INCA + SETD.1 TabDirLen + STA.1 + + SETD.2 TabDir + RSTA + SETD.1 TabCopyAt + STA.1 +tabSplitCopy: + SETD.1 TabCopyAt + LDA.1 + SETD.1 TabDirLen + LDB.1 + CCF + SUB + BNC tabSplitCopied + SETD.1 TabWordAt + LDA.1 + SETD.1 TabCopyAt + LDB.1 + CCF + ADD + MVQA + CALL tabCharAt + MVQA + STA.2 + INCD.2 + SETD.1 TabCopyAt + LDA.1 + INCA + STA.1 + BRI tabSplitCopy +tabSplitCopied: + RSTA + STA.2 ; The zero that ends it. + + ; And the word being matched is what comes after the separator. + SETD.1 TabWordAt + LDA.1 + SETD.1 TabDirLen + LDB.1 + CCF + ADD + MVQA + SETD.1 TabWordAt + STA.1 + SETD.1 TabWordLen + LDA.1 + SETD.1 TabDirLen + LDB.1 + CCF + SUB + MVQA + SETD.1 TabWordLen + STA.1 + RET +tabSplitNone: + SETD.0 TabDir + RSTA + STA.0 + RET + +; ---- What is on the disk ---- +; +; Every entry of the directory the word names that begins with the rest of the word. A +; directory is offered with a separator after it, which says what it is and lets the next +; part be typed straight away - and, because the answer then ends in one, is also what stops +; a space being put after it. +; +; WHERE THE MACHINE IS COMES BACK. This walks somebody else's directory by standing in it, +; which is the only way to walk one here, so where they were and which drive they were on are +; put down first and restored whatever happens. +tabTryFiles: + SETD.0 DiskReady + LDA.0 + BRA tabFilesNone + + INA 0x24 + SETD.1 TabWasDrive + STA.1 + SETD.0 SbfsCwd + SETD.1 TabWasCwd + CALL sbfsCopyWord + + CALL tabWalkNamed + + ; ---- And the places a program is looked for ---- + ; + ; The first word of a line is a command or a program, and the shell looks for a program in + ; three places: where you are, the system's own place for them on the disk you are on, and + ; that same place on drive 0. Tab offers what the shell would find, or it would finish a + ; word into something that then would not run. + ; + ; ONLY WHEN NO DIRECTORY WAS NAMED. "Apps/Sn" means that directory and nowhere else. + SETD.1 TabFirst + LDA.1 + BRA tabFilesBack + SETD.1 TabDirLen + LDA.1 + BNA tabFilesBack + + CALL tabWalkApps + + ; And drive 0's, unless that is the drive we are already on - in which case it is the same + ; directory, and offering everything in it twice would mean nothing was ever the only + ; match. + SETD.1 TabWasDrive + LDA.1 + BRA tabFilesBack + RSTA + CALL sbfsUse + CALL tabWalkApps + BRI tabFilesBack + +; ---- Everything in a directory, offered ---- +; +; Two ways in, because there are two kinds of place to look: the one the word named, and the +; system's own place for programs. THE FIRST MUST NOT BE OVERWRITTEN BY THE SECOND - an +; earlier version wrote "/Apps" into TabDir, and since the whole walk runs a second time to +; list the matches, that second run looked in /Apps for a word which had named nowhere, and +; showed nothing at all. +; +; Where the machine stands is moved and put back by the caller, which is what makes calling +; either of these more than once safe. +tabWalkApps: + SETD.0 TabWasCwd + SETD.1 SbfsCwd + CALL sbfsCopyWord + SETD.0 AppsPath + BRI tabWalkTo + +tabWalkNamed: + SETD.0 TabWasCwd + SETD.1 SbfsCwd + CALL sbfsCopyWord + + SETD.1 TabDirLen + LDA.1 + BRA tabFilesHere ; No directory named, so it is this one. + + SETD.0 TabDir +tabWalkTo: + CALL sbfsWalk + BNQ tabWalkNothing ; No such path, and nothing to offer out of it. + + ; The root is not an entry, so it has no flags to ask - and it is the one place that can be + ; walked to without there being anything to have asked. + SETD.0 SbfsAt + LDA.0 + INCD.0 + LDB.0 + OR + BRQ tabFilesGo + SETD.0 SbfsFoundFlags + LDA.0 + INIB 0x02 + AND + BRQ tabWalkNothing ; Not a directory, so there is nothing in it. +tabFilesGo: + SETD.0 SbfsAt + SETD.1 SbfsCwd + CALL sbfsCopyWord + +tabFilesHere: + CALL sbfsFirst + BRI tabFilesCheck +tabFilesStep: + CALL sbfsNext +tabFilesCheck: + BNQ tabWalkNothing + CALL tabEntry + BRI tabFilesStep +tabWalkNothing: + RET + +tabFilesBack: + SETD.0 TabWasCwd + SETD.1 SbfsCwd + CALL sbfsCopyWord + SETD.1 TabWasDrive + LDA.1 + CALL sbfsUse +tabFilesNone: + RET + +; The entry the walk is standing on, offered under the name somebody would type for it. +tabEntry: + SETD.0 SbfsName + SETD.1 TabCandidate + CALL tabCopyName + + SETD.0 SbfsFoundFlags + LDA.0 + INIB 0x02 + AND + BRQ tabEntryFile ; The bit SET is what says directory - see dir, which asks the + ; same question the same way round. + + ; A directory, and the separator goes on the end of it. + SETD.3 TabCandidate + CALL tabEnd + INIA 0x2F + STA.3 + INCD.3 + RSTA + STA.3 + BRI tabEntryOffer + +tabEntryFile: + ; A file. When the first word of a line is being finished it can only usefully be a + ; program, and the name to type for one is the name without its extension - so anything + ; else is not offered at all rather than offered and useless. + SETD.1 TabPrograms + LDA.1 + BRA tabEntryOffer + CALL tabStripSbx + BNQ tabEntryDone + +tabEntryOffer: + SETD.3 TabCandidate + CALL tabOffer +tabEntryDone: + RET + +; DP0 names a string and DP1 where to put it. Copies up to what a name can be. +tabCopyName: + RSTB +tabCopyNext: + LDA.0 + BRA tabCopyDone + STA.1 + INCD.0 + INCD.1 + INCB + INIA 0d40 + CCF + SUB + BRQ tabCopyDone + BRI tabCopyNext +tabCopyDone: + RSTA + STA.1 + RET + +; DP3 names a string. Leaves DP3 on its zero. +tabEnd: + LDA.3 + BRA tabEndDone + INCD.3 + BRI tabEnd +tabEndDone: + RET + +; Takes ".sbx" off the end of TabCandidate. Q is zero if it was there, and one if it was not +; - which is how a file that is not a program is passed over. +tabStripSbx: + ; How long the name is, counted rather than measured from a pointer, because what is + ; wanted next is a NUMBER: four characters back from the end is only a place if there are + ; four of them to go back over. + SETD.0 TabCandidate + RSTB +tabStripCount: + LDA.0 + BRA tabStripCounted + INCD.0 + INCB + BRI tabStripCount +tabStripCounted: + ; The count is in B and wanted in A, and there is no instruction that moves one to the + ; other: adding it to nothing is how a value crosses from B to A on this machine. + RSTA + CCF + ADD + MVQA + INIB 0d4 + CCF + SUB + BRC tabStripNo ; Shorter than the extension, so it cannot end in it. + MVQA + SETD.3 TabCandidate + DPUA.3 ; Four from the end, which is where the extension would begin. + + SETD.0 SbxText +tabStripMatch: + LDA.0 + BRA tabStripYes + LDB.3 + XOR + BNQ tabStripNo + INCD.0 + INCD.3 + BRI tabStripMatch +tabStripYes: + ; It ended in the extension, so the name to type is what comes before it. DP3 was left on + ; the zero by the comparison, so four back is where the dot was. + INIA 0d4 + DPDA.3 + RSTA + STA.3 + RSTB + CCF + ADD ; Q is zero: it is a program. + RET +tabStripNo: + INIA 0x01 + RSTB + CCF + ADD ; Q is one: it is not. + RET + ; ---- The shell's own words ---- ; ; Fifteen strings packed end to end, each ending in the zero that says where the next one @@ -1842,7 +2262,13 @@ tabNamesDone: ; editor's idea of where things are hangs off those two registers. tabList: CALL newLine - CALL tabListNames + INIA 0x01 + SETD.1 TabShowing + STA.1 + CALL tabRunSources + RSTA + SETD.1 TabShowing + STA.1 CALL newLine CALL sayPrompt @@ -1858,82 +2284,6 @@ tabList: CALL editRedraw BRI editKey -tabListNames: - SETD.1 ShellNameCount - LDA.1 - SETD.1 TabLeft - STA.1 - SETD.3 ShellNames -tabListNext: - SETD.1 TabLeft - LDA.1 - BRA tabListDone - DECA - STA.1 - CALL tabShow - BRI tabListNext -tabListDone: - RET - -; DP3 names a candidate. Prints it if it begins with what was typed, and leaves DP3 past its -; zero either way, the same bargain tabOffer makes. -tabShow: - SETD.1 TabStart - STD.3.1 - SETD.1 TabWordLen - LDA.1 - SETD.1 TabSeen - STA.1 - RSTA - SETD.1 TabAt - STA.1 -tabShowMatch: - SETD.1 TabSeen - LDA.1 - BRA tabShowIt - DECA - STA.1 - LDA.3 - BRA tabShowSkip - SETD.1 TabHold - STA.1 - SETD.1 TabWordAt - LDA.1 - SETD.1 TabAt - LDB.1 - CCF - ADD - MVQA - CALL tabCharAt - MVQA - SETD.1 TabHold - LDB.1 - XOR - BNQ tabShowSkip - INCD.3 - SETD.1 TabAt - LDA.1 - INCA - STA.1 - BRI tabShowMatch - -tabShowIt: - SETD.1 TabStart - LDD.0.1 - CALL printString - INIA 0x20 - OUTA 0x00 - OUTA 0x00 ; Two spaces between them, and A already holds one. - -tabShowSkip: - LDA.3 - BRA tabShowPast - INCD.3 - BRI tabShowSkip -tabShowPast: - INCD.3 - RET - ; ---- A command that did not work ---- ; ; The one place a failure is recorded, so that the thing reading lines out of a file can @@ -6104,6 +6454,11 @@ MonitorName: ShellNameCount: 0d15 +SbxText: +".sbx" +AppsPath: +"/Apps" + ; Where the machine is, written out for the prompt, and where in the buffer it begins. ; Built from the end backwards, so it starts somewhere in the middle. CwdText: @@ -6457,6 +6812,30 @@ TabStart: ; The answer so far: the first match, cut back by every one after it to where they agree. TabBest: #Reserve 0d64 +; The word being matched, as somebody would type it: a name with its extension taken off, or +; a directory with a separator put on. +TabCandidate: + #Reserve 0d48 +; The part of the word up to and including its last separator, which is the directory to look +; in. Empty means where the machine already is. +TabDir: + #Reserve 0d64 +TabDirLen: + 0x00 +TabCopyAt: + 0x00 +TabFirst: + 0x00 +TabPrograms: + 0x00 +; Whether the walk is looking for the answer or showing what the answers were. +TabShowing: + 0x00 +; Where the machine was standing before a directory was walked on its behalf. +TabWasCwd: + 0x00 0x00 +TabWasDrive: + 0x00 ; ---- What the fault screen is saying ---- ; diff --git a/SplitBit Test Manual.md b/SplitBit Test Manual.md index b2dea2f..ddb0b93 100644 --- a/SplitBit Test Manual.md +++ b/SplitBit Test Manual.md @@ -79,7 +79,7 @@ from `make`, not from here. ### 1. Recorded output `Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares -everything it printed against a file in `Tests/expected`. 198 tests, of which 136 run, 35 +everything it printed against a file in `Tests/expected`. 199 tests, of which 137 run, 35 only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image given at all. diff --git a/Tests/expected/cosmosMonitor.out b/Tests/expected/cosmosMonitor.out index b521dd1..b29caa6 100644 --- a/Tests/expected/cosmosMonitor.out +++ b/Tests/expected/cosmosMonitor.out @@ -9,27 +9,27 @@ there is no such bank loaded, starting at 5000 * b program bank 00 -* d 4000 -4000 00 ? -4001 00 ? -4002 00 ? -4003 00 ? -4004 00 ? -4005 00 ? -4006 00 ? -4007 00 ? -* x 4000 -4000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -4010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -4020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -4030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +* d 5000 +5000 47 00 30 00 SETD.0 3000 +5004 72 10 SWI 10 +5006 47 00 30 44 SETD.0 3044 +500A 72 10 SWI 10 +500C 47 00 30 7A SETD.0 307A +5010 27 1F INIB 1F +5012 72 11 SWI 11 +5014 47 00 30 5D SETD.0 305D +* x 5000 +5000 47 00 30 00 72 10 47 00 30 44 72 10 47 00 30 7A G.0.r.G.0Dr.G.0z +5010 27 1F 72 11 47 00 30 5D 72 10 47 00 30 7A 72 10 '.r.G.0]r.G.0zr. +5020 47 00 30 65 72 10 20 72 12 00 00 00 00 00 00 00 G.0er. r........ +5030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ * b data bank 01 -* x 2000 -2000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -2010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -2020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -2030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +* x 3000 +3000 61 20 70 72 6F 67 72 61 6D 2C 20 6C 6F 61 64 65 a program, loade +3010 64 20 6F 66 66 20 61 20 64 69 73 6B 2C 20 72 75 d off a disk, ru +3020 6E 6E 69 6E 67 20 6F 6E 20 74 68 65 20 73 79 73 nning on the sys +3030 74 65 6D 20 74 68 61 74 20 6C 6F 61 64 65 64 20 tem that loaded * b 2 bank 02 * x 0 diff --git a/Tests/expected/cosmosTab.out b/Tests/expected/cosmosTab.out index 33a2965..4221db8 100644 --- a/Tests/expected/cosmosTab.out +++ b/Tests/expected/cosmosTab.out @@ -10,24 +10,10 @@ dir do drive delete I do not know: d > zzzx I do not know: zzzx -> echo here -here -> help  help  -dir list what is on the disk -load read a program off the disk -run [words] start what was loaded, and tell it those words - [words] look where you are and then in /Apps, and start that -cd [path] go to a directory, or to the root with nothing after it -mkdir make a directory -rmdir remove an empty one -do run the lines in a file, which must start with #! -echo [words] say them -clear empty the screen -delete take it off the disk -rename call it something else -monitor look at memory, change it, and jump into it -help this -exit stop, or leave the monitor if you are in it +> echo heecho hello.sbx re +hello.sbx re +> help  hel +I do not know: hel > exit halted Execution halted. diff --git a/Tests/expected/cosmosTabPath.out b/Tests/expected/cosmosTabPath.out new file mode 100644 index 0000000..16d889f --- /dev/null +++ b/Tests/expected/cosmosTabPath.out @@ -0,0 +1,18 @@ +CosmOS +> CrCrash zz +Crash opcode | service | bank | device | blind +finished +> SaSayzz +I do not know: Sayzz +> cd Apcd Apps/ +/Apps> echo where am I +where am I +/Apps> cd / +> echo Apps/Secho Apps/Say.sbx  +Apps/Say.sbx +> echo /Apps/Cecho /Apps/Copy.sbx  +/Apps/Copy.sbx +> exit +halted +Execution halted. +[exit 0] diff --git a/Tests/input/cosmosMonitor.in b/Tests/input/cosmosMonitor.in index f997a09..974475f 100644 --- a/Tests/input/cosmosMonitor.in +++ b/Tests/input/cosmosMonitor.in @@ -3,10 +3,10 @@ b nonsense b 9 load greet.sbx b program -d 4000 -x 4000 +d 5000 +x 5000 b data -x 2000 +x 3000 b 2 x 0 s 0 FF diff --git a/Tests/input/cosmosTabPath.in b/Tests/input/cosmosTabPath.in new file mode 100644 index 0000000..a0ca79f --- /dev/null +++ b/Tests/input/cosmosTabPath.in @@ -0,0 +1,8 @@ +Cr zz +Sa zz +cd Ap +echo where am I +cd / +echo Apps/S +echo /Apps/C +exit diff --git a/Tests/manifest b/Tests/manifest index dff4fcc..6dccc8b 100644 --- a/Tests/manifest +++ b/Tests/manifest @@ -389,6 +389,17 @@ cosmosHistory | CosmOS/Source/cosmos.asm | run | cosmosHis # The last line is the one that says it works on what is actually there rather than on what # was typed: two backspaces take "help" down to "he", and Tab finishes it again. cosmosTab | CosmOS/Source/cosmos.asm | run | cosmosTab.in | - | disks/cosmos.img +# And the half of it that reaches the disk. A program is offered under the name somebody +# would type - the extension taken off - because that is what a first word can usefully be; +# anywhere after the first word everything is offered as it really is. A directory answers +# with a separator rather than a space, which says what it is and lets the next part be +# typed straight away. +# +# A path in the word says where to look, and the shell looks in the three places it would +# look to RUN something: where you are, /Apps on the disk you are on, and /Apps on drive 0. +# Offering what the shell would not find would be finishing a word into something that then +# does not work. +cosmosTabPath | CosmOS/Source/cosmos.asm | run | cosmosTabPath.in | - | disks/cosmos.img # The same editing offered to a PROGRAM, through osReadLine. Edit reads its lines that way, # so a word typed with two letters the wrong way round is put right without starting the line # again - which is the whole of what A4 buys.