TriOS-alt/zubehör/sphinx/spinx100225-ori/sphinx1/ed.spn

570 lines
16 KiB
Plaintext
Raw Blame History

{
Simple text editor
2009
March
5 started; basic screen drawing; cursor movement
6 InsertChar, InsertCR, DeleteLeft/Right
6 filename edit field
6 file load, save
June
9 Sphinxified
30 Page up/down, minor cursor movement improvement
2010
January
29 Bug: Was dropping last character when reading a file that didn't end with CR/LF. Fixed.
ENTER(CR) Carriage return
BKSP Delete to the left
DEL Delete to the right
?, ?, ?, ? Cursor movement
HOME Start of line
CTRL-HOME Start of file
END End of line
CTRL-END End of file
CTRL-O Open a file
CTRL-S Save to a file
CTRL-Q Quit to Sphinx
PGUP Page up
PGDN Page down
to do:
block select, cut/copy/paste, find/replace, undo/redo
}
obj
kb: "isxkb"
sxtv: "isxtv"
term: "tvtexted"
sd: "sxfile"
var
byte x[10]
pub Main | e
if e := \Try
if e > 0
sxtv.str( e )
else
sxtv.dec( e )
sxtv.out( 13 )
term.stop
sxtv.Enable
pub Try | i, key, refresh, blink, t, done
sxtv.Disable
term.start( sxtv.GetBasepin )
Init
Args
done~
blink~
t := cnt
repeat
refresh~
repeat while key := kb.key
refresh~~
blink~
case key
$20..$7f: InsertChar( key )
CR: InsertCR
BKSP: DeleteLeft
DEL: DeleteRight
LARROW: MoveCursorLeft
RARROW: MoveCursorRight
UARROW: MoveCursorUp( false )
DARROW: MoveCursorDown( false )
HOME: MoveToStartOfLine
CTRL+HOME: MoveToTop
END: MoveToEndOfLine
CTRL+END: MoveToBottom
CTRL+"o": FileOp( OPEN, FALSE )
CTRL+"s": FileOp( SAVE, FALSE )
CTRL+"q": FileOp( SAVE, FALSE )
done~~
PGUP: PageCursorUp
PGDN: PageCursorDown
other: refresh~
if cnt - t > 0
refresh~~
if refresh
RefreshScreen( blink ^= 1 )
t := cnt + clkfreq/10
until done
term.stop
sxtv.Enable
sd.Close
sd.Open( string("sphinx.bin"), "R" )
sd.Execute( 0 )
pri Args
if sd.Open( string("args.d8a"), "R" ) == 0
if sd.ReadByte
sd.ReadString( @filename, FILENAMEBUFFERSIZE-1 )
sd.Close
FileOp( OPEN, true )
sd.Close
con
VISIBLELINES = 13
VISIBLECOLUMNS = 40
con
CR = $0d
LARROW = $c0
RARROW = $c1
UARROW = $c2
DARROW = $c3
HOME = $c4
END = $c5
PGUP = $c6
PGDN = $c7
BKSP = $c8
DEL = $c9
ESC = $cb
CTRL = $0200
CTRL_ALT_DEL = $06c9
con
BUFFERSIZE = 20000
var
long nLines
long firstVisibleLine
long firstVisibleColumn
long bytesUsed
long cursorLine
long cursorColumn
long desiredColumn
long cp
long currentLineLength
long topPtr ' points to start of first visible line
pri InsertChar( ch ) | n
if cursorLine < nLines
if bytesUsed + 1 => BUFFERSIZE
return
else ' starting new line at end of file
if bytesUsed + 2 => BUFFERSIZE
return
buffer[bytesUsed++]~ ' terminating null for the new line
++nLines
n := bytesUsed - (cp - @buffer)
bytemove( cp+1, cp, n )
byte[cp] := ch
++bytesUsed
++currentLineLength
MoveCursorRight
pri InsertCR | n
if cursorLine < nLines
if bytesUsed + 1 => BUFFERSIZE
return
else ' starting new line at end of file
if bytesUsed + 2 => BUFFERSIZE
return
buffer[bytesUsed++]~ ' terminating null for the new line
++nLines
n := bytesUsed - (cp - @buffer)
bytemove( cp+1, cp, n )
byte[cp]~
++bytesUsed
++nLines
currentLineLength := cursorColumn
MoveCursorRight
pri DeleteLeft
if cursorLine or cursorColumn
MoveCursorLeft
DeleteRight
pri DeleteRight | n
if cursorLine == nLines ' can't delete if we're on the phantom line
return
if byte[cp] == 0 and cursorLine == nLines - 1 and cursorColumn
return ' can't delete if we're at the end of the last real line
' unless we're at the start (start = end => empty line
' which we can delete, making this line the new phantom line)
n := bytesUsed - (cp - @buffer) - 1
ifnot byte[cp]
--nLines
bytemove( cp, cp+1, n )
--bytesUsed
repeat while byte[--cp]
currentLineLength := strsize( ++cp )
cp += cursorColumn
AdjustVisibleColumn
pri MoveCursorLeft
if cursorColumn
desiredColumn := --cursorColumn
--cp
AdjustVisibleColumn
else
ifnot cursorLine
return
MoveCursorUp( true )
pri MoveCursorRight
if cursorColumn < currentLineLength
desiredColumn := ++cursorColumn
++cp
AdjustVisibleColumn
else
if cursorLine == nLines
return
MoveCursorDown( true )
pri MoveCursorDown( f )
' if f, also move cursor to start of line
if cursorLine == nLines
return
if ++cursorLine - firstVisibleLine => VISIBLELINES
++firstVisibleLine
repeat while byte[topPtr++]
MoveCpToNextLine
if f
cursorColumn~
desiredColumn~
elseif cursorLine < nLines
cursorColumn := currentLineLength <# desiredColumn
else
cursorColumn~
currentLineLength~
cp += cursorColumn
AdjustVisibleColumn
pri PageCursorDown
if firstVisibleLine + VISIBLELINES - 1 => nLines
return
repeat VISIBLELINES - 1
repeat while byte[topPtr++]
++firstVisibleLine
MoveCursorDown( false )
pri MoveCursorUp( f )
' if f, also move cursor to end of line
ifnot cursorLine
return
if --cursorLine < firstVisibleLine
--firstVisibleLine
repeat while byte[--topPtr]
repeat while byte[--topPtr]
++topPtr
MoveCpToPreviousLine
if f
cursorColumn := desiredColumn := currentLineLength
else
cursorColumn := currentLineLength <# desiredColumn
cp += cursorColumn
AdjustVisibleColumn
pri PageCursorUp | n
n := firstVisibleLine <# VISIBLELINES - 1
repeat n
repeat 2
repeat while byte[--topPtr]
++topPtr
--firstVisibleLine
MoveCursorUp( false )
pri MoveCpToNextLine
repeat while byte[cp++]
currentLineLength := strsize( cp )
pri MoveCpToPreviousLine
repeat while byte[--cp]
repeat while byte[--cp]
++cp
currentLineLength := strsize( cp )
pri MoveToStartOfLine
cp -= cursorColumn
cursorColumn~
desiredColumn~
AdjustVisibleColumn
pri MoveToEndOfLine
cp -= cursorColumn
cursorColumn := desiredColumn := currentLineLength
cp += currentLineLength
AdjustVisibleColumn
pri MoveToTop
cp := topPtr := @buffer[1]
currentLineLength := strsize( cp )
cursorLine~
cursorColumn~
desiredColumn~
firstVisibleLine~
firstVisibleColumn~
pri MoveToBottom ' cheesy implementation
MoveToTop
if nLines
repeat nLines-1
MoveCursorDown( false )
MoveToEndOfLine
pri AdjustVisibleColumn
firstVisibleColumn~
firstVisibleColumn #>= cursorColumn - VISIBLECOLUMNS + 1
var
byte buffer[BUFFERSIZE]
{ buffer contains nLines null-terminated strings, with sentinel nulls at the beginning and end:
+-+---------+-+--------+-+- ---------+-+-+
<20>0<EFBFBD> line0 0<> line1 0<> ... lineN-1 0<>0<EFBFBD>
+-+---------+-+--------+-+- ---------+-+-+
}
pri Init
nLines~
firstVisibleLine~
firstVisibleColumn~
bytesUsed := 2
buffer[0]~
buffer[1]~
cursorLine~
cursorColumn~
desiredColumn~
currentLineLength~
cp := topPtr := @buffer[1]
eolLength := 2
eol[0] := $0d
eol[1] := $0a
pri RefreshScreen( drawCursor ) | p, len, m, n, l, beyondEnd
p := topPtr
beyondEnd~
repeat l from 0 to VISIBLELINES-1
term.setXY( 0, l )
if firstVisibleLine + l => nLines
beyondEnd~~
len~
else
len := strsize( p )
if len > firstVisibleColumn
m := (len - firstVisibleColumn) <# VISIBLECOLUMNS
p += firstVisibleColumn
repeat m-1
term.out( byte[p++] )
term.printNoAdvance( byte[p++] )
term.setX( m )
n := VISIBLECOLUMNS - m
if n
repeat n-1
term.out( " " )
term.printNoAdvance( " " )
else
repeat VISIBLECOLUMNS-1
term.out( " " )
term.printNoAdvance( " " )
ifnot beyondEnd
repeat while byte[p++]
if drawCursor
term.setXY( cursorColumn-firstVisibleColumn, cursorLine-firstVisibleLine )
term.printNoAdvance( "_" )
con
#0, OPEN, SAVE ' File ops
' File errors
#1, FILE_TOO_BIG, CARD_FULL_MAYBE
FILENAMEBUFFERSIZE = 13 ' 8.3 + null
pri FileOp( op, t ) | e, i
if e := \_FileOp( op, t )
RefreshScreen( false ) ' cursor off
term.setXY( 0, VISIBLELINES-1 )
term.out( $0c ) ' set color
term.out( 1 )
repeat VISIBLECOLUMNS-1
term.out( " " )
term.printNoAdvance( " " )
term.setX( 0 )
case e
FILE_TOO_BIG: term.str( string("File too large") )
CARD_FULL_MAYBE: term.str( string("SD card full?") )
-13: term.str( string("Unable to mount SD card") )
other:
term.str( string("Error code ") )
term.dec( e )
kb.getkey
term.out( $0c ) ' set color
term.out( 0 )
pri _FileOp( op, t ) | r
case op
OPEN:
if t
ReadFile
elseif EditFilename
ReadFile
SAVE:
WriteFile
pri ReadFile | r, p, pEnd
sd.Close
if r := sd.Open( @filename, "R" ) <> 0
abort r
Init
r := sd.Read( @buffer[1], BUFFERSIZE-2 )
if r < 0
abort r
p := @buffer[1]
pEnd := @buffer[r+1]
repeat while p <> pEnd
if byte[p] == $0d or byte[p] == $0a ' change CR, LF, or CRLF
if byte[p] == $0d and byte[p+1] == $0a '
eolLength := 2 '
bytemove( p, p + 1, pEnd - p - 1 ) '
--pEnd '
else '
eolLength := 1 '
byte[p]~ ' to null
++nLines
++p
if byte[pEnd-1] ' if byte[pEnd-1] isn't null, that means that the file didn't
byte[pEnd++]~ ' end with CR, LF, or CRLF, so we have to fake it. (fixed 2010/01/29 mp)
++nLines
byte[pEnd]~ ' add final null
bytesUsed := pEnd + 1 - @buffer
currentLineLength := strsize( topPtr )
if r == BUFFERSIZE-2
abort FILE_TOO_BIG ' technically we don't know that it's too big at this point, but it's a good guess.
if r := sd.Close
abort r
pri WriteFile | p, len, r
ifnot EditFilename
return
sd.Close
if r := sd.Open( @filename, "W" )
abort r
p := @buffer[1]
repeat nLines
len := strsize( p )
r := sd.Write( p, len )
if r < 0
abort r
if r <> len ' Does this ever happen?
abort CARD_FULL_MAYBE
r := sd.Write( @eol, eolLength )
if r < 0
abort r
if r <> eolLength ' Does this ever happen?
abort CARD_FULL_MAYBE
p += len + 1
if (r := sd.Close) < 0
abort r
var
byte filename[FILENAMEBUFFERSIZE]
long filenameCursorColumn
long filenameLength
byte eolLength
byte eol[2]
con
EDITOFFSET = 10 ' filename edit field starts at column 10
pri EditFilename | t, key, blink, refresh
RefreshScreen( false ) ' cursor off
term.setXY( 0, VISIBLELINES-1 )
term.out( $0c ) ' set color
term.out( 2 )
repeat VISIBLECOLUMNS-1
term.out( " " )
term.printNoAdvance( " " )
term.setX( 0 )
term.str( string("Filename: ") )
filenameCursorColumn := filenameLength := strsize( @filename )
blink~
t := cnt
repeat
refresh~
repeat while key := kb.key
refresh~~
blink~
case key
$20..$7f: FilenameInsertChar( key )
CR:
term.out( $0c ) ' set color
term.out( 0 ) ' back to normal
return true
BKSP:
if filenameCursorColumn
filenameCursorColumn := (filenameCursorColumn - 1) #> 0
FilenameDeleteRight
DEL: FilenameDeleteRight
LARROW: filenameCursorColumn := (filenameCursorColumn - 1) #> 0
RARROW: filenameCursorColumn := (filenameCursorColumn + 1) <# filenameLength
ESC:
term.out( $0c ) ' set color
term.out( 0 ) ' back to normal
return false
other: refresh~
if cnt - t > 0
refresh~~
if refresh
RefreshFilename( blink ^= 1 )
t := cnt + clkfreq/10
pri RefreshFilename( drawCursor ) | i
term.setXY( EDITOFFSET, VISIBLELINES-1 )
repeat i from 0 to FILENAMEBUFFERSIZE-1
if drawCursor and i == filenameCursorColumn
term.out( "_" )
else
if i < filenameLength
term.out( filename[i] )
else
term.out( " " )
pri FilenameInsertChar( ch ) | n
if filenameLength => FILENAMEBUFFERSIZE-1
return
n := filenameLength - filenameCursorColumn + 1
bytemove( @filename[filenameCursorColumn+1], @filename[filenameCursorColumn], n )
++filenameLength
filename[filenameCursorColumn++] := ch
pri FilenameDeleteRight | n
ifnot filenameLength
return
ifnot n := filenameLength - filenameCursorColumn
return
bytemove( @filename[filenameCursorColumn], @filename[filenameCursorColumn+1], n )
--filenameLength
{{
Copyright (c) 2009 Michael Park
+------------------------------------------------------------------------------------------------------------------------------+
| TERMS OF USE: MIT License |
+------------------------------------------------------------------------------------------------------------------------------+
|Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation |
|files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, |
|modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
|is furnished to do so, subject to the following conditions: |
| |
|The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
| |
|THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
|ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
+------------------------------------------------------------------------------------------------------------------------------+
}}