ctrl+c, ctrl+d, start of a buffer lib
This commit is contained in:
parent
ddb5f375d7
commit
9376ed14f9
|
@ -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
|
|
@ -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"
|
Loading…
Reference in New Issue