github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/drivers/cga/cga.go (about)

     1  package cga
     2  
     3  import (
     4  	"strconv"
     5  )
     6  
     7  var (
     8  	parser  = ansiParser{}
     9  	backend = cgabackend{}
    10  )
    11  
    12  func WriteString(s string) {
    13  	for i := range s {
    14  		WriteByte(s[i])
    15  	}
    16  }
    17  
    18  func setCursorColumn(n int) {
    19  	pos := getbackend().GetPos()
    20  	pos = (pos/80)*80 + n - 1
    21  	getbackend().SetPos(pos)
    22  }
    23  
    24  func setCursorHome() {
    25  	getbackend().SetPos(0)
    26  }
    27  
    28  func eraseLine(method EraseMethod) {
    29  	backend := getbackend()
    30  	pos := backend.GetPos()
    31  	switch method {
    32  	case EraseMethod_Line:
    33  		end := (pos/80 + 1) * 80
    34  		for i := pos; i < end; i++ {
    35  			backend.WritePos(i, ' ')
    36  		}
    37  
    38  	case EraseMethod_All:
    39  		for i := 0; i < 25*80; i++ {
    40  			backend.WritePos(i, ' ')
    41  		}
    42  
    43  	default:
    44  		panic("unsupported erase line method")
    45  	}
    46  }
    47  
    48  func writeCSI(action byte, params []string) {
    49  	// fmt.Fprintf(os.Stderr, "action:%c, params:%v\n", action, params)
    50  	switch action {
    51  	// set cursor column
    52  	case 'G':
    53  		if len(params) == 0 {
    54  			setCursorColumn(1)
    55  		} else {
    56  			n, _ := strconv.Atoi(params[0])
    57  			setCursorColumn(n)
    58  		}
    59  	// erase line
    60  	case 'K':
    61  		if len(params) == 0 {
    62  			eraseLine(EraseMethod_Line)
    63  		} else {
    64  			//n, _ := strconv.Atoi(params[0])
    65  			eraseLine(EraseMethod_Unknown)
    66  		}
    67  
    68  	// Erase screen - note; this action *looks* like it ought
    69  	// to be just <ESC>[J - which is 'erase from current line to
    70  	// bottom of screen', but I actually want it to mimic <ESC>[2J
    71  	// which is 'erase screen and return to top'
    72  	//
    73  	// Hopefully nobody ever uses my fork if they expect that functionality
    74  	case 'J':
    75  		eraseLine(EraseMethod_All)
    76  		setCursorHome()
    77  
    78  	default:
    79  		// ignore
    80  	}
    81  }
    82  
    83  func WriteByte(ch byte) {
    84  	switch parser.step(ch) {
    85  	case errNormalChar:
    86  		backend := getbackend()
    87  
    88  		switch ch {
    89  		case '\n', '\r', '\b':
    90  			backend.WriteByte(ch)
    91  		case '\t':
    92  			for i := 0; i < 4; i++ {
    93  				backend.WriteByte(' ')
    94  			}
    95  		default:
    96  			if ch >= 32 && ch <= 127 {
    97  				backend.WriteByte(ch)
    98  			} else {
    99  				backend.WriteByte('?')
   100  			}
   101  		}
   102  
   103  		// do normal char
   104  	case errCSIDone:
   105  		// do csi
   106  		writeCSI(parser.Action(), parser.Params())
   107  		parser.Reset()
   108  	case errInvalidChar:
   109  		parser.Reset()
   110  	default:
   111  		getbackend().WriteByte(ch)
   112  		// ignore
   113  	}
   114  }