ctrl+c, ctrl+d, start of a buffer lib

This commit is contained in:
Art 2022-12-28 23:55:34 +01:00
parent ddb5f375d7
commit 9376ed14f9
Signed by: prod2
GPG Key ID: F3BB5A97A70A8DDE
2 changed files with 148 additions and 0 deletions

134
termBuffer/buffer.nim Normal file
View File

@ -0,0 +1,134 @@
import unicode
import escapeSequences
type
Buffer* = ref object
# AS IS ON SCREEN VALUES
stdout: File # usually you want to put stdout here
displayed: seq[Cell]
displayX, displayY: int # where the cursor is on display
positionX, positionY: int # where the buffer's top left corner is
# SIMULATED VALUES
buffered: seq[Cell]
# cursor position
bufferX, bufferY: int # where the cursor is, in buffer
width, height: int
# current style we're writing with
cursorAttributes: seq[uint8]
ForegroundColors* = enum
fcBlack = 30, fcRed, fcGreen, fcYellow, fcBlue,
fcMagenta, fcCyan, fcLightGray,
fcDefault = 39,
fcDarkGray = 90, fcLightRed, fcLightGreen,
fcLightYellow, fcLightBlue, fcLightMagenta,
fcLightCyan, fcWhite
BackgroundColors* = enum
bcBlack, bcRed, bcGreen, bcYellow, bcBlue,
bcMagenta, bcCyan, bcLightGray,
bcDefault = 49,
bcDarkGray = 100, bcLightRed, bcLightGreen,
bcLightYellow, bcLightBlue, bcLightMagenta,
bcLightCyan, bcWhite
FontStyle* = enum
# these two are the most widely supported
fsReset = 0,
fsBold = 1,
fsUnderlined = 4,
Cell = object
attributes: seq[uint8]
text: Rune
func getCursorPos*(buf: Buffer): (int, int) =
(buf.bufferX, buf.bufferY)
proc setCursorPos*(buf: Buffer, x, y: int) =
if x < 0 or y < 0 or x >= buf.width or y >= buf.height:
raise newException(ValueError, "Provided x or y out of bounds for SetCursorPos.")
buf.bufferX = x
buf.bufferY = y
func getCursorXPos*(buf: Buffer): int =
buf.bufferX
proc setCursorXPos*(buf: Buffer, x: int) =
if x < 0 or x >= buf.width:
raise newException(ValueError, "Provided x is out of bounds.")
buf.bufferX = x
proc setAttributes*(buf: Buffer, attributes: seq[uint8]) =
buf.cursorAttributes = attributes
proc addAttribute*(buf: Buffer, attribute: uint8) =
buf.cursorAttributes.add(attribute)
proc clearAttributes*(buf: Buffer) =
buf.cursorAttributes = @[]
proc clear*(buf: Buffer) =
for i in 0..buf.buffered.high():
buf.buffered[i] = Cell(text: Rune(0))
buf.bufferX = 0
buf.bufferY = 0
template lineStart(buf: Buffer, line: int): int =
# returns where line <line> starts
buf.width * line
template lineEnd(buf: Buffer, line: int): int =
buf.lineStart(line + 1) - 1
proc clearLine*(buf: Buffer) =
for i in buf.lineStart(buf.bufferY)..buf.lineEnd(buf.bufferY):
buf.buffered[i] = Cell(text: Rune(0))
buf.bufferX = 0
proc write*(buf: Buffer, text: string) =
# convert text to characters
let runes = text.toRunes()
# if it would go out of the screen, crash
if buf.bufferX + runes.len() >= buf.width:
raise newException(ValueError, "Text too long, would overflow the buffer.")
let fromPos = buf.lineStart(buf.bufferY) + buf.bufferX
let toPos = fromPos + runes.high()
for i in fromPos..toPos:
buf.buffered[i] = Cell(text: runes[i-fromPos], attributes: buf.cursorAttributes)
proc redraw*(buf: Buffer) =
var toPrint = ""
# save cursor state
let oldDisplayX = buf.displayX
let oldDisplayY = buf.displayY
# go over display and buffer to find any differences
for i in 0..buf.buffered.high():
let cellBuffer = buf.buffered[i]
let cellDisplay = buf.displayed[i]
# TODO continue here :)
# finish
toPrint &= escCursorPos(oldDisplayX, oldDisplayY)
buf.stdout.write(toPrint)
func getSize*(buf: Buffer): (int, int) =
(buf.width, buf.height)
proc resize*(buf: Buffer, newX, newY: int) =
raise newException(Defect, "Not implemented")
func getPosition*(buf: Buffer): (int, int) =
(buf.positionX, buf.positionY)
proc setPosition*(buf: Buffer, x, y: int) =
buf.positionX = x
buf.positionY = y

View File

@ -0,0 +1,14 @@
# list of functions to generate escape sequences
import strformat
import strutils
func escCursorPos*(x, y: int): string =
&"\e[{x+1};{y+1}H"
func escAttributes*(attributes: seq[uint8]): string =
let joined = attributes.join(";")
&"\e[{joined}m"
func escEraseCharacters*(n: int): string =
&"\e[{n}X"