
' ANSI Interpreter in Liquid BASIC

w=80
h=25

CONST ESC=27
CONST SGR_RESET=0
CONST SGR_BOLD=1
CONST SGR_UNDERLINE=4
CONST SGR_BLINK=5
CONST SGR_REVERSE=7
CONST SGR_NO_UNDERLINE=24
CONST SGR_NO_BLINK=25
CONST SGR_NO_REVERSE=27
CONST SGR_FORE_BLACK=30
CONST SGR_FORE_RED=31
CONST SGR_FORE_GREEN=32
CONST SGR_FORE_YELLOW=33
CONST SGR_FORE_BLUE=34
CONST SGR_FORE_MAGENTA=35
CONST SGR_FORE_CYAN=36
CONST SGR_FORE_WHITE=37
CONST SGR_FORE_DEFAULT=39
CONST SGR_BACK_BLACK=40
CONST SGR_BACK_RED=41
CONST SGR_BACK_GREEN=42
CONST SGR_BACK_YELLOW=43
CONST SGR_BACK_BLUE=44
CONST SGR_BACK_MAGENTA=45
CONST SGR_BACK_CYAN=46
CONST SGR_BACK_WHITE=47
CONST SGR_BACK_DEFAULT=49

FUNCTION InterpretAnsi(ansiText$)
    SHARE w,h

    CLEAR TILEMAP
    SWAP TILES 0,32

    DIM params$(10)

    CursorVisible=FALSE
    CursorX=1
    CursorY=1
    ForeColor=7
    BackColor=0
    IsBold=0
    IsUnderline=0
    IsBlink=0
    IsReverse=0

    i=1
    WHILE i<=LEN(ansiText$)
        currentChar$=MID$(ansiText$,i,1)

        IF currentChar$=CHR$(ESC) THEN
            i=i+1
            IF MID$(ansiText$,i,1)="[" THEN
                state$=""
                paramCount=0
                i=i+1
                b=0

                ' Regular Expression for escape sequences: \033\[[0-9;]*[A-Za-z]

                DO
                    currentChar$=MID$(ansiText$,i,1)
                    IF currentChar$>="0" AND currentChar$<="9" THEN
                        state$=state$+currentChar$
                        b=1
                    ELSE IF currentChar$=";" THEN
                        paramCount=paramCount+1
                        params$(paramCount)=state$
                        state$=""
                    ELSE
                        IF b THEN
                            paramCount=paramCount+1
                            params$(paramCount)=state$
                        END IF
                        EXIT DO
                    END IF
                    i=i+1
                LOOP

                SELECT CASE currentChar$
                    CASE "m"
                        IF paramCount=0 THEN
                            ForeColor=7
                            BackColor=0
                            IsBold=0
                            IsUnderline=0
                            IsBlink=0
                            IsReverse=0
                        END IF
                        FOR j=1 TO paramCount
                            ansiCode=VAL(params$(j))
                            IF (ansiCode>=90 AND ansiCode<=97) OR (ansiCode>=100 AND ansiCode<=107) THEN
                                ansiCode=ansiCode-60
                                IsBold=8
                            END IF
                            SELECT CASE ansiCode
                                CASE SGR_RESET
                                    ForeColor=7
                                    BackColor=0
                                    IsBold=0
                                    IsUnderline=0
                                    IsBlink=0
                                    IsReverse=0
                                CASE SGR_BOLD
                                    IsBold=8
                                CASE SGR_UNDERLINE
                                    IsUnderline=1
                                CASE SGR_BLINK
                                    IsBlink=1
                                CASE SGR_REVERSE
                                    IF IsReversed=0 THEN
                                        SWAP ForeColor,BackColor
                                        IsBold=0
                                        IsReversed=1
                                    END IF
                                CASE SGR_NO_UNDERLINE
                                    IsUnderline=0
                                CASE SGR_NO_BLINK
                                    IsBlink=0
                                CASE SGR_NO_REVERSE
                                    IF IsReversed=1 THEN
                                        SWAP ForeColor,BackColor
                                        IsBold=0
                                        IsReversed=0
                                    END IF
                                CASE SGR_FORE_BLACK
                                    ForeColor=0
                                CASE SGR_FORE_RED
                                    ForeColor=4
                                CASE SGR_FORE_GREEN
                                    ForeColor=2
                                CASE SGR_FORE_YELLOW
                                    ForeColor=6
                                CASE SGR_FORE_BLUE
                                    ForeColor=1
                                CASE SGR_FORE_MAGENTA
                                    ForeColor=5
                                CASE SGR_FORE_CYAN
                                    ForeColor=3
                                CASE SGR_FORE_WHITE
                                    ForeColor=7
                                CASE SGR_FORE_DEFAULT
                                    ForeColor=7
                                CASE SGR_BACK_BLACK
                                    BackColor=0
                                CASE SGR_BACK_RED
                                    BackColor=4
                                CASE SGR_BACK_GREEN
                                    BackColor=2
                                CASE SGR_BACK_YELLOW
                                    BackColor=6
                                CASE SGR_BACK_BLUE
                                    BackColor=1
                                CASE SGR_BACK_MAGENTA
                                    BackColor=5
                                CASE SGR_BACK_CYAN
                                    BackColor=3
                                CASE SGR_BACK_WHITE
                                    BackColor=7
                                CASE SGR_BACK_DEFAULT
                                    BackColor=0
                                CASE 38 ' 8-bit color
                                    IF VAL(params$(2))=5 THEN
                                        ForeColor=VAL(params$(3))
                                        IsBold=0
                                        EXIT FOR
                                    ELSE
                                        ASSERT 1=0
                                    END IF
                                CASE 48 ' 8-bit color
                                    IF VAL(params$(2))=5 THEN
                                        BackColor=VAL(params$(3))
                                        EXIT FOR
                                    END IF
                                CASE ELSE
                                    ASSERT 1=0
                            END SELECT
                        NEXT j
                    CASE "H","f"
                        IF paramCount=0 THEN
                            CursorX=1
                            CursorY=1
                        ELSE IF paramCount=1 THEN
                            CursorX=1
                            CursorY=VAL(params$(1))
                        ELSE IF paramCount=2 THEN
                            CursorX=VAL(params$(2))
                            CursorY=VAL(params$(1))
                        ELSE
                            ASSERT 1=0
                        END IF
                    CASE "A"
                        IF paramCount=0 THEN
                            CursorY=CursorY-1
                        ELSE IF paramCount=1 THEN
                            CursorY=CursorY-VAL(params$(1))
                        ELSE
                            ASSERT 1=0
                        END IF
                    CASE "B"
                        IF paramCount=0 THEN
                            CursorY=CursorY+1
                        ELSE IF paramCount=1 THEN
                            CursorY=CursorY+VAL(params$(1))
                        ELSE
                            ASSERT 1=0
                        END IF
                    CASE "C"
                        IF paramCount=0 THEN
                            CursorX=CursorX+1
                        ELSE IF paramCount=1 THEN
                            CursorX=CursorX+VAL(params$(1))
                        ELSE
                            ASSERT 1=0
                        END IF
                    CASE "D"
                        IF paramCount=0 THEN
                            CursorX=CursorX-1
                        ELSE IF paramCount=1 THEN
                            CursorX=CursorX-VAL(params$(1))
                        ELSE
                            ASSERT 1=0
                        END IF
                    CASE "J"
                        IF paramCount=1 THEN
                            SELECT CASE VAL(params$(1))
                                CASE 0
                                    ASSERT 1=0
                                CASE 1
                                    ASSERT 1=0
                                CASE 2
                                    CLEAR TILEMAP
                                    SWAP TILES 0,32
                                    CursorX=1
                                    CursorY=1
                                CASE ELSE
                                    ASSERT 1=0
                            END SELECT
                        ELSE
                            ASSERT 1=0
                        END IF
                    CASE "s"
                        SavedCursorX=CursorX
                        SavedCursorY=CursorY
                    CASE "u"
                        CursorX=SavedCursorX
                        CursorY=SavedCursorY
                    CASE "?25h"
                        CursorVisible=TRUE
                    CASE "?25l"
                        CursorVisible=FALSE
                    CASE ELSE
                        PRINT "Unknown escape code: "+currentChar$
                        END
                END SELECT
            END IF
        ELSE IF currentChar$=CHR$(13) THEN
            CursorX=1
            CursorY=CursorY+1
            IF CursorY > h THEN
                SCROLL TILEMAP UP 1
                SWAP TILES 0,32
                CursorY=h
            END IF
        ELSE
            ch=ASC(currentChar$)
            IF ch>=32 AND ch<=255 THEN
                INK CLUT("ansi",ForeColor+IsBold)
                HIGHLIGHT CLUT("ansi",BackColor)
                PUT TILE CursorX-1,CursorY-1,ch
            END IF
            CursorX=CursorX+1
            'if CursorX > w then
            '    CursorX=w
            'end if
            IF CursorX > w THEN
                CursorX=1
                CursorY=CursorY+1
                IF CursorY > h THEN
                    SCROLL TILEMAP UP 1
                    SWAP TILES 0,32
                    CursorY=h
                END IF
            END IF

            PAUSE
        END IF

        IF CursorVisible THEN
            CURSOR SHOW
        ELSE
            CURSOR HIDE
        END IF

        CursorX=CLAMP(CursorX,1,w)
        CursorY=CLAMP(CursorY,1,h)

        i=i+1
    WEND
END FUNCTION

' Main program

CLEAR ALL
TILESET 1 NEW "msdos"
TILEMAP 1 NEW w,h,1
TARGET TILEMAP 1
SPRITE 1 BIND TILEMAP 1 SHOW FIT

DO
    f$=FILE.OPEN$(CURDIR$,".ans","ANSI files (*.ans)|*.ans|All files (*.*)|*.*")
    IF f$="" THEN END

    ansiText$=""

    OPEN f$ FOR INPUT AS #1
    WHILE NOT EOF(1)
        'LINE INPUT #1,line$
        INPUT #1,line$
        ansiText$=ansiText$+line$+CHR$(13)
    WEND
    CLOSE #1

    ' Interpret and print the ANSI text to the console
    CALL InterpretAnsi(ansiText$)
    GETKEY a$
LOOP UNTIL a$=CHR$(27)

