Improve vt100 support to make vim work

This commit is contained in:
Terence Boldt 2021-11-25 06:49:46 +00:00
parent 453a644a0b
commit 485332d0e9
10 changed files with 342 additions and 134 deletions

View File

@ -37,8 +37,15 @@ ClearKeyboard = $c010
Home = $fc58
Wait = $fca8
PromptChar = $33
Read80Col = $c01f
TextPage1 = $c054
TextPage2 = $c055
htab = $24
vtab = $25
BasL = $28
htab80 = $057b
BasCalc = $fbc1
ESC = $9b
@ -56,6 +63,9 @@ DumpOutput:
bcs checkInput
cmp #$00
beq endOutput
pha
jsr InvertChar
pla
cmp #'H'
beq setColumn
cmp #'V'
@ -65,8 +75,11 @@ DumpOutput:
cmp #'T'
beq setTop
cmp #'B'
beq setBottom
beq setBottom
cmp #'U'
beq moveUp
jsr PrintChar
jsr InvertChar
jmp DumpOutput
checkInput:
bit Keyboard ;check for keypress
@ -80,25 +93,35 @@ endOutput:
rts
clearScreen:
jsr Home
jsr InvertChar
jmp DumpOutput
setColumn:
jsr GetByte
sta htab
sta $057B
sta htab80
jsr InvertChar
jmp DumpOutput
setRow:
jsr GetByte
sta vtab
jsr $fbc1 ; bascalc
sta $28 ;basl
jsr BasCalc
jsr InvertChar
jmp DumpOutput
setTop:
jsr GetByte
sta $22
jsr InvertChar
jmp DumpOutput
setBottom:
jsr GetByte
sta $23
jsr InvertChar
jmp DumpOutput
moveUp:
dec vtab
lda vtab
jsr BasCalc
jsr InvertChar
jmp DumpOutput
SendByte:
@ -148,9 +171,26 @@ finishRead:
end:
rts
InvertChar:
lda htab80 ;get horizontal location / 2
lsr
tay
lda TextPage2
bcc invert
lda TextPage1
invert:
lda (BasL),y
eor #$80
sta (BasL),y
lda TextPage1
screen40:
rts
HelpCommand:
.byte "a2help",$00
PromptCommand:
.byte "a2prompt",$00
OldPromptChar:
.byte "]"
DrawCursor:
.byte $80

Binary file not shown.

View File

@ -41,8 +41,15 @@ Current file: Shell.asm
000000r 1 Home = $fc58
000000r 1 Wait = $fca8
000000r 1 PromptChar = $33
000000r 1 Read80Col = $c01f
000000r 1 TextPage1 = $c054
000000r 1 TextPage2 = $c055
000000r 1
000000r 1 htab = $24
000000r 1 vtab = $25
000000r 1 BasL = $28
000000r 1 htab80 = $057b
000000r 1 BasCalc = $fbc1
000000r 1
000000r 1 ESC = $9b
000000r 1
@ -51,114 +58,147 @@ Current file: Shell.asm
002000 1 20 00 C3 jsr $c300 ; force 80 columns
002003 1 2C 10 C0 bit ClearKeyboard
002006 1 A9 09 lda #ShellCommand
002008 1 20 74 20 jsr SendByte
002008 1 20 9A 20 jsr SendByte
00200B 1 20 0F 20 jsr DumpOutput
00200E 1 60 rts
00200F 1
00200F 1 DumpOutput:
00200F 1 20 92 20 jsr GetByte
002012 1 B0 1E bcs checkInput
00200F 1 20 B8 20 jsr GetByte
002012 1 B0 2A bcs checkInput
002014 1 C9 00 cmp #$00
002016 1 F0 2D beq endOutput
002018 1 C9 48 cmp #'H'
00201A 1 F0 30 beq setColumn
00201C 1 C9 56 cmp #'V'
00201E 1 F0 37 beq setRow
002020 1 C9 43 cmp #'C'
002022 1 F0 22 beq clearScreen
002024 1 C9 54 cmp #'T'
002026 1 F0 3C beq setTop
002028 1 C9 42 cmp #'B'
00202A 1 F0 40 beq setBottom
00202C 1 20 ED FD jsr PrintChar
00202F 1 4C 0F 20 jmp DumpOutput
002032 1 checkInput:
002032 1 2C 00 C0 bit Keyboard ;check for keypress
002035 1 10 D8 bpl DumpOutput ;keep dumping output if no keypress
002037 1 AD 00 C0 lda Keyboard ;send keypress to RPi
00203A 1 29 7F and #$7f
00203C 1 20 74 20 jsr SendByte
00203F 1 2C 10 C0 bit ClearKeyboard
002042 1 4C 0F 20 jmp DumpOutput
002045 1 endOutput:
002045 1 60 rts
002046 1 clearScreen:
002046 1 20 58 FC jsr Home
002049 1 4C 0F 20 jmp DumpOutput
00204C 1 setColumn:
00204C 1 20 92 20 jsr GetByte
00204F 1 85 24 sta htab
002051 1 8D 7B 05 sta $057B
002054 1 4C 0F 20 jmp DumpOutput
002057 1 setRow:
002057 1 20 92 20 jsr GetByte
00205A 1 85 25 sta vtab
00205C 1 20 C1 FB jsr $fbc1 ; bascalc
00205F 1 85 28 sta $28 ;basl
002061 1 4C 0F 20 jmp DumpOutput
002064 1 setTop:
002064 1 20 92 20 jsr GetByte
002067 1 85 22 sta $22
002069 1 4C 0F 20 jmp DumpOutput
00206C 1 setBottom:
00206C 1 20 92 20 jsr GetByte
00206F 1 85 23 sta $23
002071 1 4C 0F 20 jmp DumpOutput
002074 1
002074 1 SendByte:
002074 1 48 pha
002075 1 waitWrite:
002075 1 AD FB C0 lda InputFlags
002078 1 2A rol
002079 1 2A rol
00207A 1 B0 F9 bcs waitWrite
00207C 1 68 pla
00207D 1 8D FD C0 sta OutputByte
002080 1 A9 1E lda #$1e ; set bit 0 low to indicate write started
002082 1 8D F7 C0 sta OutputFlags
002085 1 finishWrite:
002085 1 AD FB C0 lda InputFlags
002088 1 2A rol
002089 1 2A rol
00208A 1 90 F9 bcc finishWrite
00208C 1 A9 1F lda #$1f
00208E 1 8D F7 C0 sta OutputFlags
002091 1 60 rts
002092 1
002092 1 GetByte:
002092 1 A9 1D lda #$1d ;set read flag low
002094 1 8D F7 C0 sta OutputFlags
002097 1 waitRead:
002097 1 AD FB C0 lda InputFlags
00209A 1 2A rol
00209B 1 90 0C bcc readByte
00209D 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read
0020A0 1 10 F5 bpl waitRead
0020A2 1 A9 1F lda #$1f ;set all flags high and exit
0020A4 1 8D F7 C0 sta OutputFlags
0020A7 1 38 sec ;failure
0020A8 1 60 rts
0020A9 1 readByte:
0020A9 1 AD FE C0 lda InputByte
0020AC 1 48 pha
0020AD 1 A9 1F lda #$1f ;set all flags high
0020AF 1 8D F7 C0 sta OutputFlags
0020B2 1 finishRead:
0020B2 1 AD FB C0 lda InputFlags
0020B5 1 2A rol
0020B6 1 90 FA bcc finishRead
0020B8 1 68 pla
0020B9 1 18 clc ;success
0020BA 1 end:
0020BA 1 60 rts
0020BB 1
0020BB 1 HelpCommand:
0020BB 1 61 32 68 65 .byte "a2help",$00
0020BF 1 6C 70 00
0020C2 1 PromptCommand:
0020C2 1 61 32 70 72 .byte "a2prompt",$00
0020C6 1 6F 6D 70 74
0020CA 1 00
0020CB 1 OldPromptChar:
0020CB 1 5D .byte "]"
0020CC 1
002016 1 F0 39 beq endOutput
002018 1 48 pha
002019 1 20 E1 20 jsr InvertChar
00201C 1 68 pla
00201D 1 C9 48 cmp #'H'
00201F 1 F0 3A beq setColumn
002021 1 C9 56 cmp #'V'
002023 1 F0 44 beq setRow
002025 1 C9 43 cmp #'C'
002027 1 F0 29 beq clearScreen
002029 1 C9 54 cmp #'T'
00202B 1 F0 4A beq setTop
00202D 1 C9 42 cmp #'B'
00202F 1 F0 51 beq setBottom
002031 1 C9 55 cmp #'U'
002033 1 F0 58 beq moveUp
002035 1 20 ED FD jsr PrintChar
002038 1 20 E1 20 jsr InvertChar
00203B 1 4C 0F 20 jmp DumpOutput
00203E 1 checkInput:
00203E 1 2C 00 C0 bit Keyboard ;check for keypress
002041 1 10 CC bpl DumpOutput ;keep dumping output if no keypress
002043 1 AD 00 C0 lda Keyboard ;send keypress to RPi
002046 1 29 7F and #$7f
002048 1 20 9A 20 jsr SendByte
00204B 1 2C 10 C0 bit ClearKeyboard
00204E 1 4C 0F 20 jmp DumpOutput
002051 1 endOutput:
002051 1 60 rts
002052 1 clearScreen:
002052 1 20 58 FC jsr Home
002055 1 20 E1 20 jsr InvertChar
002058 1 4C 0F 20 jmp DumpOutput
00205B 1 setColumn:
00205B 1 20 B8 20 jsr GetByte
00205E 1 85 24 sta htab
002060 1 8D 7B 05 sta htab80
002063 1 20 E1 20 jsr InvertChar
002066 1 4C 0F 20 jmp DumpOutput
002069 1 setRow:
002069 1 20 B8 20 jsr GetByte
00206C 1 85 25 sta vtab
00206E 1 20 C1 FB jsr BasCalc
002071 1 20 E1 20 jsr InvertChar
002074 1 4C 0F 20 jmp DumpOutput
002077 1 setTop:
002077 1 20 B8 20 jsr GetByte
00207A 1 85 22 sta $22
00207C 1 20 E1 20 jsr InvertChar
00207F 1 4C 0F 20 jmp DumpOutput
002082 1 setBottom:
002082 1 20 B8 20 jsr GetByte
002085 1 85 23 sta $23
002087 1 20 E1 20 jsr InvertChar
00208A 1 4C 0F 20 jmp DumpOutput
00208D 1 moveUp:
00208D 1 C6 25 dec vtab
00208F 1 A5 25 lda vtab
002091 1 20 C1 FB jsr BasCalc
002094 1 20 E1 20 jsr InvertChar
002097 1 4C 0F 20 jmp DumpOutput
00209A 1
00209A 1 SendByte:
00209A 1 48 pha
00209B 1 waitWrite:
00209B 1 AD FB C0 lda InputFlags
00209E 1 2A rol
00209F 1 2A rol
0020A0 1 B0 F9 bcs waitWrite
0020A2 1 68 pla
0020A3 1 8D FD C0 sta OutputByte
0020A6 1 A9 1E lda #$1e ; set bit 0 low to indicate write started
0020A8 1 8D F7 C0 sta OutputFlags
0020AB 1 finishWrite:
0020AB 1 AD FB C0 lda InputFlags
0020AE 1 2A rol
0020AF 1 2A rol
0020B0 1 90 F9 bcc finishWrite
0020B2 1 A9 1F lda #$1f
0020B4 1 8D F7 C0 sta OutputFlags
0020B7 1 60 rts
0020B8 1
0020B8 1 GetByte:
0020B8 1 A9 1D lda #$1d ;set read flag low
0020BA 1 8D F7 C0 sta OutputFlags
0020BD 1 waitRead:
0020BD 1 AD FB C0 lda InputFlags
0020C0 1 2A rol
0020C1 1 90 0C bcc readByte
0020C3 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read
0020C6 1 10 F5 bpl waitRead
0020C8 1 A9 1F lda #$1f ;set all flags high and exit
0020CA 1 8D F7 C0 sta OutputFlags
0020CD 1 38 sec ;failure
0020CE 1 60 rts
0020CF 1 readByte:
0020CF 1 AD FE C0 lda InputByte
0020D2 1 48 pha
0020D3 1 A9 1F lda #$1f ;set all flags high
0020D5 1 8D F7 C0 sta OutputFlags
0020D8 1 finishRead:
0020D8 1 AD FB C0 lda InputFlags
0020DB 1 2A rol
0020DC 1 90 FA bcc finishRead
0020DE 1 68 pla
0020DF 1 18 clc ;success
0020E0 1 end:
0020E0 1 60 rts
0020E1 1
0020E1 1 InvertChar:
0020E1 1 AD 7B 05 lda htab80 ;get horizontal location / 2
0020E4 1 4A lsr
0020E5 1 A8 tay
0020E6 1 AD 55 C0 lda TextPage2
0020E9 1 90 03 bcc invert
0020EB 1 AD 54 C0 lda TextPage1
0020EE 1 invert:
0020EE 1 B1 28 lda (BasL),y
0020F0 1 49 80 eor #$80
0020F2 1 91 28 sta (BasL),y
0020F4 1 AD 54 C0 lda TextPage1
0020F7 1 screen40:
0020F7 1 60 rts
0020F8 1
0020F8 1 HelpCommand:
0020F8 1 61 32 68 65 .byte "a2help",$00
0020FC 1 6C 70 00
0020FF 1 PromptCommand:
0020FF 1 61 32 70 72 .byte "a2prompt",$00
002103 1 6F 6D 70 74
002107 1 00
002108 1 OldPromptChar:
002108 1 5D .byte "]"
002109 1 DrawCursor:
002109 1 80 .byte $80
002109 1

Binary file not shown.

View File

@ -19,4 +19,5 @@ type A2Io interface {
ReadString() (string, error)
ReadBlock(buffer []byte) error
SendCharacter(character byte)
ReadCharacter() (string, error)
}

View File

@ -318,3 +318,8 @@ func (a2 A2Gpio) WriteBuffer(buffer []byte) error {
func (a2 A2Gpio) SendCharacter(character byte) {
sendCharacter(a2, character)
}
// ReadCharacter is a pass-through to vt100 implementation
func (a2 A2Gpio) ReadCharacter() (string, error) {
return readCharacter(a2)
}

View File

@ -105,3 +105,8 @@ func (mockIo MockIo) ReadBlock(buffer []byte) error {
func (mockIo MockIo) SendCharacter(character byte) {
sendCharacter(mockIo, character)
}
// ReadCharacter is a pass-through to vt100 implementation
func (mockIo MockIo) ReadCharacter() (string, error) {
return readCharacter(mockIo)
}

View File

@ -82,3 +82,8 @@ func (userIo UserIo) ReadBlock(buffer []byte) error {
func (userIo UserIo) SendCharacter(character byte) {
sendCharacter(userIo, character)
}
// ReadCharacter is a pass-through to vt100 implementation
func (userIo UserIo) ReadCharacter() (string, error) {
return readCharacter(userIo)
}

View File

@ -12,22 +12,50 @@ import (
)
var escapeSequence string
var operatingSystemSequence bool
var htab, vtab, savedHtab, savedVtab int
var applicationMode bool
var windowTop int
var windowBottom = 22
var windowBottom = 23
func sendCharacter(comm A2Io, b byte) {
if b == 0x1b {
escapeSequence = "^["
return
}
if b == 13 {
fmt.Printf("CR\n")
comm.WriteByte('H')
comm.WriteByte(0)
return
}
if b > 13 && b < 32 {
fmt.Printf("Control code: %02X\n", b)
return
}
if len(escapeSequence) == 0 {
fmt.Printf("%c", b)
}
if len(escapeSequence) > 0 {
escapeSequence += string(b)
if escapeSequence == "^[]" {
fmt.Printf("Start operating system sequence\n")
operatingSystemSequence = true
return
}
if operatingSystemSequence {
if b == 0x07 {
fmt.Printf("Operating system sequence: %s\n", escapeSequence)
operatingSystemSequence = false
escapeSequence = ""
}
return
}
// save cursor
if escapeSequence == "^[7" {
savedHtab = htab
savedVtab = vtab
fmt.Printf("Save Cursor (%d, %d): %s\n", htab, vtab, escapeSequence)
escapeSequence = ""
}
// restore cursor
@ -38,6 +66,7 @@ func sendCharacter(comm A2Io, b byte) {
comm.WriteByte(byte(htab))
comm.WriteByte('V')
comm.WriteByte(byte(vtab))
fmt.Printf("Restore Cursor (%d, %d): %s\n", htab, vtab, escapeSequence)
escapeSequence = ""
}
if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') {
@ -48,10 +77,14 @@ func sendCharacter(comm A2Io, b byte) {
fmt.Sscanf(escapeSequence, "^[[%d;%d%s", &vtab, &htab, &ignore)
htab--
vtab--
if htab < 0 {
htab = 0
}
comm.WriteByte('H')
comm.WriteByte(byte(htab))
comm.WriteByte('V')
comm.WriteByte(byte(vtab))
fmt.Printf("Set Cursor (%d, %d): %s\n", htab, vtab, escapeSequence)
escapeSequence = ""
case 'r':
fmt.Sscanf(escapeSequence, "^[[%d;%dr", &windowTop, &windowBottom)
@ -61,13 +94,68 @@ func sendCharacter(comm A2Io, b byte) {
comm.WriteByte(byte(windowTop))
comm.WriteByte('B')
comm.WriteByte(byte(windowBottom))
fmt.Printf("Set Window (%d, %d): %s\n", windowTop, windowBottom, escapeSequence)
escapeSequence = ""
case 'A':
if escapeSequence == "^[[A" || escapeSequence == "^[A" {
vtab--
comm.WriteByte('U')
fmt.Printf("Up: %s\n", escapeSequence)
} else {
var up int
fmt.Sscanf(escapeSequence, "^[[%dA", &up)
vtab -= up
for i := 0; i < up; i++ {
comm.WriteByte('U')
}
fmt.Printf("Up (%d): %s\n", up, escapeSequence)
}
escapeSequence = ""
case 'B':
if escapeSequence == "^[(B" || escapeSequence == "^[)B" || escapeSequence == "^[B" {
escapeSequence = ""
} else if escapeSequence == "^[[B" {
vtab++
comm.WriteByte(0x0a)
fmt.Printf("Down: %s\n", escapeSequence)
} else {
var down int
fmt.Sscanf(escapeSequence, "^[[%dB", &down)
vtab += down
for i := 0; i < down; i++ {
comm.WriteByte(0x0a)
}
fmt.Printf("Down (%d): %s\n", down, escapeSequence)
}
escapeSequence = ""
case 'C':
var right int
fmt.Sscanf(escapeSequence, "^[[%dC", &right)
htab -= right
for i := 0; i < right; i++ {
if escapeSequence == "^[[C" || escapeSequence == "^[C" {
htab++
comm.WriteByte(0x1c)
fmt.Printf("Right: %s\n", escapeSequence)
} else {
var right int
fmt.Sscanf(escapeSequence, "^[[%dC", &right)
htab += right
for i := 0; i < right; i++ {
comm.WriteByte(0x1c)
}
fmt.Printf("Right (%d): %s\n", right, escapeSequence)
}
escapeSequence = ""
case 'D':
if escapeSequence == "^[[D" || escapeSequence == "^[D" {
htab--
comm.WriteByte(0x08)
fmt.Printf("Left: %s\n", escapeSequence)
} else {
var left int
fmt.Sscanf(escapeSequence, "^[[%dD", &left)
htab -= left
for i := 0; i < left; i++ {
comm.WriteByte(0x08)
}
fmt.Printf("Left (%d): %s\n", left, escapeSequence)
}
escapeSequence = ""
}
@ -76,6 +164,7 @@ func sendCharacter(comm A2Io, b byte) {
case "^[[?1h":
applicationMode = true
comm.WriteByte(0x0c) // ^L clears the screen
fmt.Printf("Start application mode: %s\n", escapeSequence)
escapeSequence = ""
case "^[[?1l":
applicationMode = false
@ -84,54 +173,64 @@ func sendCharacter(comm A2Io, b byte) {
comm.WriteByte('B')
comm.WriteByte(0x18)
comm.WriteByte(0x0c) // ^L clears the screen
fmt.Printf("End application mode: %s\n", escapeSequence)
escapeSequence = ""
// Tab to home position
case "^[[H", "^[[;H", "^[[f", "^[[;f":
htab = 0
vtab = 0
comm.WriteByte(0x19) // ^Y moves to home position
fmt.Printf("Home: %s\n", escapeSequence)
escapeSequence = ""
// Clear screen
case "^[[2J", "^[[c":
htab = 0
vtab = 0
comm.WriteByte(0x0c) // ^L clears the screen
fmt.Printf("Clear screen: %s\n", escapeSequence)
escapeSequence = ""
// Move down one line
case "^[E":
comm.WriteByte(0x0A) // ^J moves cursor down
fmt.Printf("Move down: %s\n", escapeSequence)
escapeSequence = ""
case "^[D":
comm.WriteByte(0x17) // ^W scrolls up
fmt.Printf("Scroll up: %s\n", escapeSequence)
escapeSequence = ""
// Clear line to the right
case "^[[K", "^[[0K":
comm.WriteByte(0x1d) // ^] clears to end of line
fmt.Printf("Clear line right: %s\n", escapeSequence)
escapeSequence = ""
case "^[M":
comm.WriteByte(0x16) // ^V scrolls down
fmt.Printf("Scroll down: %s\n", escapeSequence)
escapeSequence = ""
// Clear screen below cursor
case "^[[J":
comm.WriteByte(0x0b) // ^K clears to end of screen
fmt.Printf("Clear below cursor: %s\n", escapeSequence)
escapeSequence = ""
case "^[[7m":
comm.WriteByte(0x0f) // ^O inverse video
fmt.Printf("Inverse: %s\n", escapeSequence)
escapeSequence = ""
case "^[[m", "^[[0m":
comm.WriteByte(0x0e) // ^N normal video
//comm.WriteByte(0x0e) // ^N normal video
fmt.Printf("Normal: %s\n", escapeSequence)
escapeSequence = ""
}
if len(escapeSequence) > 0 {
fmt.Printf("\nUnhandled escape sequence: %s\n", escapeSequence)
fmt.Printf("Unhandled escape sequence: %s\n", escapeSequence)
}
escapeSequence = ""
return
}
return
}
fmt.Print(string(b))
//fmt.Print(string(b))
htabIncrement := 0
switch b {
// convert LF to CR for Apple II compatiblity
@ -158,7 +257,7 @@ func sendCharacter(comm A2Io, b byte) {
default:
htabIncrement = 1
}
if !applicationMode || htab < 78 {
if !applicationMode || htab < 79 {
updateTabs(comm)
b |= 0x80
htab += htabIncrement
@ -171,6 +270,26 @@ func sendCharacter(comm A2Io, b byte) {
}
}
func readCharacter(comm A2Io) (string, error) {
b, err := comm.ReadByte()
var s = string(b)
if err == nil {
switch b {
case 0x0b: // up
s = "\033[A"
case 0x0a: // down
s = "\033[B"
case 0x15: // right
s = "\033[C"
case 0x08: // left
s = "\033[D"
case 0x0d: // return
s = string(byte(0x0a))
}
}
return s, err
}
func updateTabs(comm A2Io) {
if htab >= 80 {
htab = 0

View File

@ -158,22 +158,15 @@ func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, use
inputComplete <- true
return
default:
b, err := comm.ReadByte()
s, err := comm.ReadCharacter()
if err == nil {
if b == 0x03 {
stdin.Close()
userCancelled <- true
return
}
if b == 0x0d {
b = 0x0a
}
if b == 0x0b {
b = 'k'
}
fmt.Printf("%c", b)
io.WriteString(stdin, string(b))
// if b == 0x03 {
// stdin.Close()
// userCancelled <- true
// return
// }
//fmt.Printf("%s", s)
io.WriteString(stdin, string(s))
}
}
}