A program reading a line gets the editing too
osReadLine goes through the shell's editor now, so anything that asks the system for a line gets arrows, Home, End and Delete. The editor is a program, and a word typed with two letters the wrong way round can be put right without starting the line again. IT DOES NOT GET THE HISTORY, and that is the interesting half. Edit would otherwise fill the history with the text of somebody's document, and pressing Up in the middle of writing one would put "dir" into it. The history belongs to the thing whose lines are commands. Two entry points rather than a flag the caller sets first, so a caller cannot forget which it wanted. And the console is put back the way it was FOUND rather than the way the shell likes it. A program that had asked for key mode and then read a line through the system used to be handed back a console in line mode having asked for nothing of the sort. The status port reports all three things the control port can ask for, in the same order two bits along, so one shift turns what the console IS into what to write to make it that again. Which uncovered a real fault in the console. READING THE STATUS PORT WAS EATING A KEY: in line mode the poll consumed an arrow key and dropped it, so a program that looked and then asked for key mode - exactly what reading a line now does - found the first key it was reaching for already gone. A look must not consume what it cannot report, because the mode can change. It is held now and delivered as soon as something will take it. A blocking read still discards it, and must: that read IS the delivery, and a byte held there would be met again forever. Four recordings gained a program's echo, and cosmosEdit's went from "> : : : : > : : > 1: alpha" to a session you can read. VERIFIED THE SAME WAY AS BEFORE: with only the program side of the echo silenced, all 192 tests pass against the recordings as they were before this commit, so the echo is the whole of what changed. cosmosEditService is the new test and it checks both halves at once. Inside Edit, Left/Delete/Left puts "alpah" right. Up and Down do nothing there - were a program's line walking the shell's history, the next line would come out as the echo command from the top of the file instead of the word. And one press of Up back at the prompt finds the command typed before Edit was started, which is the proof that nothing the editor read went into the history at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
71f6e215f9
commit
4d976fc22a
@@ -331,8 +331,14 @@ The line holds 127 characters. It held 63 until the shell could edit one, which
|
|||||||
limit started to be felt: a copy between two disks with a directory on each is most of the
|
limit started to be felt: a copy between two disks with a directory on each is most of the
|
||||||
way there before anything has been said.
|
way there before anything has been said.
|
||||||
|
|
||||||
Everything else that reads a line - an application calling `osReadLine`, the editor - is
|
**An application reading a line through `osReadLine` gets the same editing**, which is the
|
||||||
unchanged and still gets a plain line with no editing in it.
|
point of the service being there: the editor is a program, and a word typed with two letters
|
||||||
|
the wrong way round can now be put right without starting the line again.
|
||||||
|
|
||||||
|
What a program does *not* get is the history. Up and Down do nothing while a program is
|
||||||
|
reading, and nothing it reads is kept. That is not meanness: the editor would otherwise fill
|
||||||
|
the history with the text of somebody's document, and pressing Up in the middle of writing
|
||||||
|
one would put `dir` into it. The history belongs to the thing whose lines are commands.
|
||||||
|
|
||||||
### Paths:
|
### Paths:
|
||||||
|
|
||||||
@@ -1017,7 +1023,7 @@ Those numbers are written down once, in `Programs/CosmOS/Source/services.asm`, w
|
|||||||
| Service | Does |
|
| Service | Does |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| osPrintString | DP0 names a string ending in a zero byte. Prints it. |
|
| osPrintString | DP0 names a string ending in a zero byte. Prints it. |
|
||||||
| osReadLine | DP0 names somewhere to put a line, B says how much room there is. Reads one from the console. Q comes back holding how long it was. |
|
| osReadLine | DP0 names somewhere to put a line, B says how much room there is. Reads one from the console, with the shell's own editing - arrows, Home, End, Delete - but not its history. Q comes back holding how long it was. The console is left in whatever mode it was found in. |
|
||||||
| osExit | Gives the machine back. Does not return. |
|
| osExit | Gives the machine back. Does not return. |
|
||||||
| osArgument | DP0 names somewhere to put whatever followed the run command, B says how much room there is. |
|
| osArgument | DP0 names somewhere to put whatever followed the run command, B says how much room there is. |
|
||||||
| osFileRead | DP0 names a file, DP1 says where to put it. Q is zero if it read, and DP3 comes back holding how many bytes there were. |
|
| osFileRead | DP0 names a file, DP1 says where to put it. Q is zero if it read, and DP3 comes back holding how many bytes there were. |
|
||||||
|
|||||||
@@ -434,6 +434,17 @@ shellReadRawTyped:
|
|||||||
; ConsoleEndOfInput is set if the console ran out instead of a line being finished, which is
|
; ConsoleEndOfInput is set if the console ran out instead of a line being finished, which is
|
||||||
; readLine's other promise and the one the shell uses to know when to stop.
|
; readLine's other promise and the one the shell uses to know when to stop.
|
||||||
;
|
;
|
||||||
|
; ---- Two doors, because the history is the SHELL'S ----
|
||||||
|
;
|
||||||
|
; editLine is what the shell reads through and keeps what it is given. editLinePlain is what
|
||||||
|
; a program reads through, and does not: Edit would otherwise fill the history with the text
|
||||||
|
; of somebody's document, and pressing Up in the middle of writing one would put "dir" in
|
||||||
|
; it. A program gets the editing, which is what it wanted; the history belongs to the thing
|
||||||
|
; whose lines are commands.
|
||||||
|
;
|
||||||
|
; Two entry points rather than a flag a caller sets first, because a caller cannot forget to
|
||||||
|
; do this one.
|
||||||
|
;
|
||||||
; ---- Why most keystrokes draw nothing but themselves ----
|
; ---- Why most keystrokes draw nothing but themselves ----
|
||||||
;
|
;
|
||||||
; A character typed at the END of a line needs no cursor moved: printing it is the whole of
|
; A character typed at the END of a line needs no cursor moved: printing it is the whole of
|
||||||
@@ -443,6 +454,14 @@ shellReadRawTyped:
|
|||||||
; transcript in the test suite with them. So the cheap path is the common one, and the line
|
; transcript in the test suite with them. So the cheap path is the common one, and the line
|
||||||
; is only reprinted when something happened in the middle of it.
|
; is only reprinted when something happened in the middle of it.
|
||||||
editLine:
|
editLine:
|
||||||
|
INIA 0x01
|
||||||
|
BRI editLineBegin
|
||||||
|
editLinePlain:
|
||||||
|
RSTA
|
||||||
|
editLineBegin:
|
||||||
|
SETD.1 EditKeepHistory
|
||||||
|
STA.1
|
||||||
|
|
||||||
SETD.1 EditBase
|
SETD.1 EditBase
|
||||||
STD.0.1
|
STD.0.1
|
||||||
SETD.1 EditRoom
|
SETD.1 EditRoom
|
||||||
@@ -477,8 +496,29 @@ editWidthKnown:
|
|||||||
SETD.1 EditWidth
|
SETD.1 EditWidth
|
||||||
STA.1
|
STA.1
|
||||||
|
|
||||||
; Key mode, with the cursor the shell keeps. Nothing echoes from here on: everything that
|
; ---- How the console was found, so it can be put back that way ----
|
||||||
; appears below is put there by this routine.
|
;
|
||||||
|
; Not "line mode with a cursor", which is only how the SHELL keeps it. A program that had
|
||||||
|
; asked for key mode and then read a line through the system would have been handed back a
|
||||||
|
; console in line mode, having asked for nothing of the sort.
|
||||||
|
;
|
||||||
|
; The status port reports every one of the three things the control port can ask for, and
|
||||||
|
; reports them in the same order two bits along - so one shift turns what the console IS
|
||||||
|
; into what to write to make it that again.
|
||||||
|
INA 0x01
|
||||||
|
RSTB
|
||||||
|
SHR
|
||||||
|
SHR
|
||||||
|
INIB 0d7
|
||||||
|
AND
|
||||||
|
MVQA
|
||||||
|
SETD.1 EditWasControl
|
||||||
|
STA.1
|
||||||
|
|
||||||
|
; Key mode with a cursor, and INTERRUPTS OFF whatever they were. Nothing echoes from here
|
||||||
|
; on: everything that appears below is put there by this routine. Interrupts are off
|
||||||
|
; because this is about to block on the data port, and the manual is explicit that a
|
||||||
|
; program does one or the other and not both.
|
||||||
INIA 0x05
|
INIA 0x05
|
||||||
OUTA 0x02
|
OUTA 0x02
|
||||||
|
|
||||||
@@ -746,6 +786,9 @@ editEnd:
|
|||||||
; makes the padding below matter: a long line replaced by a short one leaves the tail of the
|
; makes the padding below matter: a long line replaced by a short one leaves the tail of the
|
||||||
; long one behind unless something rubs it out.
|
; long one behind unless something rubs it out.
|
||||||
editUp:
|
editUp:
|
||||||
|
SETD.1 EditKeepHistory
|
||||||
|
LDA.1
|
||||||
|
BRA editKey ; A program's line has no history behind it.
|
||||||
SETD.1 HistoryPick
|
SETD.1 HistoryPick
|
||||||
LDA.1
|
LDA.1
|
||||||
BRA editKey ; Already at the oldest one kept.
|
BRA editKey ; Already at the oldest one kept.
|
||||||
@@ -769,6 +812,9 @@ editUpMoving:
|
|||||||
BRI editRecall
|
BRI editRecall
|
||||||
|
|
||||||
editDown:
|
editDown:
|
||||||
|
SETD.1 EditKeepHistory
|
||||||
|
LDA.1
|
||||||
|
BRA editKey ; A program's line has no history behind it.
|
||||||
SETD.1 HistoryPick
|
SETD.1 HistoryPick
|
||||||
LDA.1
|
LDA.1
|
||||||
SETD.1 HistoryCount
|
SETD.1 HistoryCount
|
||||||
@@ -829,12 +875,15 @@ editDoneEnd:
|
|||||||
|
|
||||||
; Kept before the buffer is handed over and while EditLength still says how long it is.
|
; Kept before the buffer is handed over and while EditLength still says how long it is.
|
||||||
; Only on this path: a console that ran out was not somebody finishing a line.
|
; Only on this path: a console that ran out was not somebody finishing a line.
|
||||||
|
SETD.1 EditKeepHistory
|
||||||
|
LDA.1
|
||||||
|
BRA editFinish
|
||||||
CALL historyAdd
|
CALL historyAdd
|
||||||
editFinish:
|
editFinish:
|
||||||
|
|
||||||
; Line mode, with the cursor still on: that is how boot left the console and how every
|
; And the console back exactly as it was found.
|
||||||
; program that knows nothing of any of this expects to find it.
|
SETD.1 EditWasControl
|
||||||
INIA 0x04
|
LDA.1
|
||||||
OUTA 0x02
|
OUTA 0x02
|
||||||
|
|
||||||
SETD.1 EditBase
|
SETD.1 EditBase
|
||||||
@@ -3239,7 +3288,7 @@ handlePrintString:
|
|||||||
RETI
|
RETI
|
||||||
|
|
||||||
handleReadLine:
|
handleReadLine:
|
||||||
CALL readLine
|
CALL editLinePlain
|
||||||
|
|
||||||
; readLine works out how long the line was, and it is already in Q where readLine left
|
; readLine works out how long the line was, and it is already in Q where readLine left
|
||||||
; it. SRET keeps Q and DP3 and puts everything else back, so the answer simply stands.
|
; it. SRET keeps Q and DP3 and puts everything else back, so the answer simply stands.
|
||||||
@@ -5629,6 +5678,14 @@ EditWalkColumn:
|
|||||||
EditWalkBack:
|
EditWalkBack:
|
||||||
0x00
|
0x00
|
||||||
|
|
||||||
|
; What the control port has to be written to put the console back how this routine found it.
|
||||||
|
EditWasControl:
|
||||||
|
0x00
|
||||||
|
|
||||||
|
; Whether the line being read is one to remember. The shell's are; a program's are not.
|
||||||
|
EditKeepHistory:
|
||||||
|
0x00
|
||||||
|
|
||||||
; How many characters of the line are on the screen, which is not always how many are in it:
|
; How many characters of the line are on the screen, which is not always how many are in it:
|
||||||
; between a line getting shorter and the screen being put right, the screen still has the
|
; between a line getting shorter and the screen being put right, the screen still has the
|
||||||
; old one on it. That gap is one character wide for a Delete and a whole line wide for a
|
; old one on it. That gap is one character wide for a Delete and a whole line wide for a
|
||||||
|
|||||||
+18
-1
@@ -602,8 +602,25 @@ static int consoleKeyFromInput(int mayWait) {
|
|||||||
// Nothing to hand over: either that sequence meant nothing here, or it meant a key
|
// Nothing to hand over: either that sequence meant nothing here, or it meant a key
|
||||||
// and line mode does not deliver keys. Both are the same answer to a caller - there
|
// and line mode does not deliver keys. Both are the same answer to a caller - there
|
||||||
// is still no byte - so a blocking read asks again and a poll says so and leaves.
|
// is still no byte - so a blocking read asks again and a poll says so and leaves.
|
||||||
if (got < 0 || (!consoleKeyMode && got >= CONSOLE_KEY_FIRST && got <= CONSOLE_KEY_LAST)) {
|
const int undeliverable =
|
||||||
|
!consoleKeyMode && got >= CONSOLE_KEY_FIRST && got <= CONSOLE_KEY_LAST;
|
||||||
|
if (got < 0 || undeliverable) {
|
||||||
if (!mayWait) {
|
if (!mayWait) {
|
||||||
|
// ---- A LOOK MUST NOT CONSUME WHAT IT CANNOT REPORT ----
|
||||||
|
//
|
||||||
|
// This is the status port asking, and either way it has no byte to report.
|
||||||
|
// But a key that line mode will not deliver is not the same as a key that is
|
||||||
|
// gone: THE MODE CAN CHANGE. A program that polls and then asks for key mode
|
||||||
|
// - which is exactly what the shell does before it reads a line - would find
|
||||||
|
// that the first key it was reaching for had been swallowed by the looking.
|
||||||
|
//
|
||||||
|
// So it is held rather than dropped, and delivered as soon as something is
|
||||||
|
// willing to take it. The blocking read below drops it instead, and must:
|
||||||
|
// that read IS the delivery, line mode genuinely has no use for the key, and
|
||||||
|
// a byte held there would be met again forever.
|
||||||
|
if (undeliverable) {
|
||||||
|
consoleHeldByte = got;
|
||||||
|
}
|
||||||
return CONSOLE_NOTHING_YET;
|
return CONSOLE_NOTHING_YET;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -309,6 +309,8 @@ Backspace is 0x08 and always has been. It is a different key from Delete and doe
|
|||||||
|
|
||||||
**These arrive in key mode only.** Line mode delivers characters, and a program in line mode is being handed a line that something else has already finished editing, so a key meaning "move the cursor left" arrived too late to mean anything. The console drops them there. This is what a terminal does too: it has always given a program in line mode backspace and line kill, and has never given it arrow keys.
|
**These arrive in key mode only.** Line mode delivers characters, and a program in line mode is being handed a line that something else has already finished editing, so a key meaning "move the cursor left" arrived too late to mean anything. The console drops them there. This is what a terminal does too: it has always given a program in line mode backspace and line kill, and has never given it arrow keys.
|
||||||
|
|
||||||
|
**But asking the status port in line mode does not throw one away.** A key line mode will not deliver is not the same as a key that is gone, because the mode can change: a program that looks at the status port and then asks for key mode - which is exactly what a system does before it reads a line - would otherwise find that the first key it was reaching for had been swallowed by the looking. So the console holds it and delivers it as soon as something is willing to take it. Reading the data port in line mode does discard it, and must: that read is the delivery, and a key held there would be met again forever.
|
||||||
|
|
||||||
**What a key means is not the console's business.** Where the cursor goes, what the line looks like afterwards and what was typed before are all decisions, and decisions belong to whatever is reading - which on this machine is usually CosmOS, whose shell edits its own line. The console says which key was pressed and stops there, exactly as the disk says what a drive is and says nothing about what should be on it.
|
**What a key means is not the console's business.** Where the cursor goes, what the line looks like afterwards and what was typed before are all decisions, and decisions belong to whatever is reading - which on this machine is usually CosmOS, whose shell edits its own line. The console says which key was pressed and stops there, exactly as the disk says what a drive is and says nothing about what should be on it.
|
||||||
|
|
||||||
### Reading Without Waiting:
|
### Reading Without Waiting:
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ from `make`, not from here.
|
|||||||
### 1. Recorded output
|
### 1. Recorded output
|
||||||
|
|
||||||
`Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares
|
`Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares
|
||||||
everything it printed against a file in `Tests/expected`. 191 tests, of which 129 run, 35
|
everything it printed against a file in `Tests/expected`. 192 tests, of which 130 run, 35
|
||||||
only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image
|
only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image
|
||||||
given at all.
|
given at all.
|
||||||
|
|
||||||
|
|||||||
@@ -3,22 +3,40 @@ CosmOS
|
|||||||
loaded, starting at 4000
|
loaded, starting at 4000
|
||||||
> run poem.txt
|
> run poem.txt
|
||||||
poem.txt, new file
|
poem.txt, new file
|
||||||
> : : : : > : : > 1: alpha
|
> a
|
||||||
|
: alpha
|
||||||
|
: beta
|
||||||
|
: gamma
|
||||||
|
: .
|
||||||
|
> i 2
|
||||||
|
: INSERTED
|
||||||
|
: .
|
||||||
|
> l
|
||||||
|
1: alpha
|
||||||
2: INSERTED
|
2: INSERTED
|
||||||
3: beta
|
3: beta
|
||||||
4: gamma
|
4: gamma
|
||||||
> : > > 1: CHANGED
|
> c 1
|
||||||
|
: CHANGED
|
||||||
|
> d 4
|
||||||
|
> l
|
||||||
|
1: CHANGED
|
||||||
2: INSERTED
|
2: INSERTED
|
||||||
3: beta
|
3: beta
|
||||||
> written, 22 bytes
|
> w
|
||||||
> finished
|
written, 22 bytes
|
||||||
|
> q
|
||||||
|
finished
|
||||||
> run poem.txt
|
> run poem.txt
|
||||||
poem.txt, 3 lines
|
poem.txt, 3 lines
|
||||||
> 1: CHANGED
|
> l
|
||||||
|
1: CHANGED
|
||||||
2: INSERTED
|
2: INSERTED
|
||||||
3: beta
|
3: beta
|
||||||
> there is no such line
|
> d 99
|
||||||
> finished
|
there is no such line
|
||||||
|
> q
|
||||||
|
finished
|
||||||
> exit
|
> exit
|
||||||
halted
|
halted
|
||||||
Execution halted.
|
Execution halted.
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
CosmOS
|
CosmOS
|
||||||
> Edit hello.asm
|
> Edit hello.asm
|
||||||
hello.asm, 31 lines
|
hello.asm, 31 lines
|
||||||
> finished
|
> q
|
||||||
|
finished
|
||||||
> Edit hello.asm
|
> Edit hello.asm
|
||||||
hello.asm, 31 lines
|
hello.asm, 31 lines
|
||||||
> finished
|
> q
|
||||||
|
finished
|
||||||
> Status
|
> Status
|
||||||
the last program left 0, which is: it did what it was asked
|
the last program left 0, which is: it did what it was asked
|
||||||
finished
|
finished
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
CosmOS
|
||||||
|
> echo remembered by the shell
|
||||||
|
remembered by the shell
|
||||||
|
> load Edit.sbx
|
||||||
|
loaded, starting at 4000
|
||||||
|
> run typed.txt
|
||||||
|
typed.txt, new file
|
||||||
|
> a
|
||||||
|
: alpah[9;3Halpa [9;3Halpha[9;8H
|
||||||
|
: second
|
||||||
|
: .
|
||||||
|
> l
|
||||||
|
1: alpha
|
||||||
|
2: second
|
||||||
|
> w
|
||||||
|
written, 13 bytes
|
||||||
|
> q
|
||||||
|
finished
|
||||||
|
> [19;3Hrun typed.txt[19;16H
|
||||||
|
typed.txt, 2 lines
|
||||||
|
> q
|
||||||
|
finished
|
||||||
|
> exit
|
||||||
|
halted
|
||||||
|
Execution halted.
|
||||||
|
[exit 0]
|
||||||
@@ -33,11 +33,13 @@ not a program
|
|||||||
loaded, starting at 4000
|
loaded, starting at 4000
|
||||||
> run
|
> run
|
||||||
a program, loaded off a disk, running on the system that loaded it
|
a program, loaded off a disk, running on the system that loaded it
|
||||||
what should I call you? hello, Anachronaut. that is all I do.
|
what should I call you? Anachronaut
|
||||||
|
hello, Anachronaut. that is all I do.
|
||||||
finished
|
finished
|
||||||
> run
|
> run
|
||||||
a program, loaded off a disk, running on the system that loaded it
|
a program, loaded off a disk, running on the system that loaded it
|
||||||
what should I call you? hello, Claude. that is all I do.
|
what should I call you? Claude
|
||||||
|
hello, Claude. that is all I do.
|
||||||
finished
|
finished
|
||||||
> exit
|
> exit
|
||||||
halted
|
halted
|
||||||
|
|||||||
@@ -7,8 +7,14 @@ Edit.sbx 2243
|
|||||||
loaded, starting at 4000
|
loaded, starting at 4000
|
||||||
> run note.txt
|
> run note.txt
|
||||||
note.txt, new file
|
note.txt, new file
|
||||||
> : : : > written, 67 bytes
|
> a
|
||||||
> finished
|
: a line written onto a disk with directories on it
|
||||||
|
: and a second one
|
||||||
|
: .
|
||||||
|
> w
|
||||||
|
written, 67 bytes
|
||||||
|
> q
|
||||||
|
finished
|
||||||
> dir
|
> dir
|
||||||
Folder <dir>
|
Folder <dir>
|
||||||
Edit.sbx 2243
|
Edit.sbx 2243
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
echo remembered by the shell
|
||||||
|
load Edit.sbx
|
||||||
|
run typed.txt
|
||||||
|
a
|
||||||
|
alpah‚†‚h
|
||||||
|
sec€�ond
|
||||||
|
.
|
||||||
|
l
|
||||||
|
w
|
||||||
|
q
|
||||||
|
€
|
||||||
|
q
|
||||||
|
exit
|
||||||
@@ -336,6 +336,16 @@ cosmosEditKeys | CosmOS/Source/cosmos.asm | run | cosmosEdi
|
|||||||
# the tail of the long one on the screen unless something covers it, and one space - which
|
# the tail of the long one on the screen unless something covers it, and one space - which
|
||||||
# is all a Delete ever needs - covers nothing.
|
# is all a Delete ever needs - covers nothing.
|
||||||
cosmosHistory | CosmOS/Source/cosmos.asm | run | cosmosHistory.in | - | disks/cosmos.img
|
cosmosHistory | CosmOS/Source/cosmos.asm | run | cosmosHistory.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.
|
||||||
|
#
|
||||||
|
# It also says what a program does NOT get. Up and Down do nothing while Edit is reading:
|
||||||
|
# were a program's line walking the shell's history, the second line here would come out as
|
||||||
|
# the echo command at the top instead of the word. And the last Up proves the reverse - that
|
||||||
|
# everything Edit read went nowhere near the history, since one press finds the line typed
|
||||||
|
# before Edit was started.
|
||||||
|
cosmosEditService | CosmOS/Source/cosmos.asm | run | cosmosEditService.in | - | disks/editor.img
|
||||||
# The shell taking things off a disk and calling them something else, which is the last of
|
# The shell taking things off a disk and calling them something else, which is the last of
|
||||||
# CosmOS's original four verbs to be built and the first time anything has changed a disk
|
# CosmOS's original four verbs to be built and the first time anything has changed a disk
|
||||||
# from the shell. Its own image, because it changes what is on it: a fixture named with a
|
# from the shell. Its own image, because it changes what is on it: a fixture named with a
|
||||||
|
|||||||
Reference in New Issue
Block a user