added getcursor pos, undone forced fullscreen
This commit is contained in:
parent
4e1ee4d089
commit
a013c34fc4
16
editor.nim
16
editor.nim
|
@ -1,12 +1,11 @@
|
||||||
import unicode
|
import unicode
|
||||||
import strutils
|
import strutils
|
||||||
import terminal
|
|
||||||
import strformat
|
import strformat
|
||||||
import posix
|
import posix
|
||||||
|
|
||||||
import termBuffer/buffer
|
import terminalUtils/buffer
|
||||||
|
import terminalUtils/terminalGetInfo
|
||||||
import keycodes
|
import terminalUtils/keycodes
|
||||||
|
|
||||||
type
|
type
|
||||||
EditorState* = ref object
|
EditorState* = ref object
|
||||||
|
@ -44,7 +43,6 @@ proc newEditor*(prompt: string = "> ", multiline: bool = true): EditorState =
|
||||||
result.prompt = prompt
|
result.prompt = prompt
|
||||||
result.maxRowsGoal = if multiline: 0 else: 1
|
result.maxRowsGoal = if multiline: 0 else: 1
|
||||||
result.buffer.add("")
|
result.buffer.add("")
|
||||||
result.screenBuffer = newBuffer(0, 0, terminalWidth(), terminalHeight(), stdout)
|
|
||||||
editors.add(result)
|
editors.add(result)
|
||||||
|
|
||||||
proc destroyEditor*(oldEditor: EditorState) =
|
proc destroyEditor*(oldEditor: EditorState) =
|
||||||
|
@ -63,13 +61,11 @@ proc render(ed: EditorState) =
|
||||||
template cline(ed: EditorState): var string =
|
template cline(ed: EditorState): var string =
|
||||||
ed.buffer[ed.y]
|
ed.buffer[ed.y]
|
||||||
|
|
||||||
proc print*(ed: EditorState, text: string) =
|
|
||||||
ed.screenBuffer.print(text)
|
|
||||||
ed.screenBuffer.redraw()
|
|
||||||
|
|
||||||
proc read*(ed: EditorState): (EditorResult, string) =
|
proc read*(ed: EditorState): (EditorResult, string) =
|
||||||
|
|
||||||
var editorResult = erError
|
var editorResult = erError
|
||||||
|
let (_, cursorY) = termGetCursorPos(stdout)
|
||||||
|
ed.screenBuffer = newBuffer(0, cursorY, termGetWidth(), termGetHeight() - cursorY, stdout)
|
||||||
|
|
||||||
ed.render()
|
ed.render()
|
||||||
while true:
|
while true:
|
||||||
|
@ -126,8 +122,10 @@ proc read*(ed: EditorState): (EditorResult, string) =
|
||||||
result = (editorResult, ed.buffer.join("\n"))
|
result = (editorResult, ed.buffer.join("\n"))
|
||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
|
stdout.write("\n")
|
||||||
ed.history.add(ed.buffer)
|
ed.history.add(ed.buffer)
|
||||||
ed.buffer = @[""]
|
ed.buffer = @[""]
|
||||||
ed.y = 0
|
ed.y = 0
|
||||||
ed.x = 0
|
ed.x = 0
|
||||||
|
ed.screenBuffer = nil
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import editor
|
import editor
|
||||||
|
|
||||||
let e = newEditor("> ", false)
|
let e = newEditor(">>> ", false)
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
let (res, text) = e.read()
|
let (res, text) = e.read()
|
||||||
if res in {erCtrlC, erCtrlD} or text == "quit":
|
if res in {erCtrlC, erCtrlD} or text == "quit":
|
||||||
e.print("")
|
|
||||||
break
|
break
|
||||||
e.print(text)
|
if text.len() > 0:
|
||||||
|
echo text
|
|
@ -1,14 +0,0 @@
|
||||||
# list of functions to generate escape sequences
|
|
||||||
|
|
||||||
import strformat
|
|
||||||
import strutils
|
|
||||||
|
|
||||||
func escCursorPos*(x, y: int): string =
|
|
||||||
&"\e[{y+1};{x+1}H"
|
|
||||||
|
|
||||||
func escAttributes*(attributes: seq[uint8]): string =
|
|
||||||
let joined = attributes.join(";")
|
|
||||||
&"\e[{joined}m"
|
|
||||||
|
|
||||||
func escEraseCharacters*(n: int): string =
|
|
||||||
&"\e[{n}X"
|
|
|
@ -100,22 +100,7 @@ proc write*(buf: Buffer, text: string) =
|
||||||
for i in fromPos..toPos:
|
for i in fromPos..toPos:
|
||||||
buf.buffered[i] = Cell(text: runes[i-fromPos], attributes: buf.cursorAttributes)
|
buf.buffered[i] = Cell(text: runes[i-fromPos], attributes: buf.cursorAttributes)
|
||||||
|
|
||||||
buf.bufferX += runes.len()
|
buf.bufferX += runes.len()
|
||||||
|
|
||||||
proc print*(buf: Buffer, text: string) =
|
|
||||||
# write, but makes sure it's on its own line
|
|
||||||
if buf.bufferX > 0:
|
|
||||||
# TODO scroll implementation
|
|
||||||
buf.bufferX = 0
|
|
||||||
if buf.bufferY < buf.height - 1:
|
|
||||||
buf.bufferY += 1
|
|
||||||
|
|
||||||
buf.write(text)
|
|
||||||
|
|
||||||
# TODO scroll implementation
|
|
||||||
if text.len() > 0 and buf.bufferY < buf.height - 1:
|
|
||||||
buf.bufferY += 1
|
|
||||||
|
|
||||||
|
|
||||||
proc redraw*(buf: Buffer, force: bool = false) =
|
proc redraw*(buf: Buffer, force: bool = false) =
|
||||||
var toPrint = ""
|
var toPrint = ""
|
||||||
|
@ -130,7 +115,7 @@ proc redraw*(buf: Buffer, force: bool = false) =
|
||||||
let y = i div buf.width
|
let y = i div buf.width
|
||||||
let x = i mod buf.width
|
let x = i mod buf.width
|
||||||
# go to given place
|
# go to given place
|
||||||
toPrint &= escCursorPos(x+buf.positionX, y+buf.positionY)
|
toPrint &= escSetCursorPos(x+buf.positionX, y+buf.positionY)
|
||||||
|
|
||||||
# get the right attributes
|
# get the right attributes
|
||||||
# first reset
|
# first reset
|
||||||
|
@ -149,7 +134,7 @@ proc redraw*(buf: Buffer, force: bool = false) =
|
||||||
|
|
||||||
# finish
|
# finish
|
||||||
toPrint &= escAttributes(@[fsReset.uint8])
|
toPrint &= escAttributes(@[fsReset.uint8])
|
||||||
toPrint &= escCursorPos(buf.bufferX + buf.positionX, buf.bufferY + buf.positionY)
|
toPrint &= escSetCursorPos(buf.bufferX + buf.positionX, buf.bufferY + buf.positionY)
|
||||||
buf.stdout.write(toPrint)
|
buf.stdout.write(toPrint)
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,6 +142,7 @@ func getSize*(buf: Buffer): (int, int) =
|
||||||
(buf.width, buf.height)
|
(buf.width, buf.height)
|
||||||
|
|
||||||
proc resize*(buf: Buffer, newX, newY: int) =
|
proc resize*(buf: Buffer, newX, newY: int) =
|
||||||
|
# TODO
|
||||||
raise newException(Defect, "Not implemented")
|
raise newException(Defect, "Not implemented")
|
||||||
|
|
||||||
func getPosition*(buf: Buffer): (int, int) =
|
func getPosition*(buf: Buffer): (int, int) =
|
|
@ -0,0 +1,45 @@
|
||||||
|
# list of functions to generate escape sequences
|
||||||
|
# in the future, this can be expanded to support more platforms
|
||||||
|
|
||||||
|
import strformat
|
||||||
|
import strutils
|
||||||
|
import terminal
|
||||||
|
|
||||||
|
func escSetCursorPos*(x, y: int): string =
|
||||||
|
&"\e[{y+1};{x+1}H"
|
||||||
|
|
||||||
|
const escGetCursorPos* = "\e[6n"
|
||||||
|
|
||||||
|
type InvalidResponseError* = object of CatchableError
|
||||||
|
|
||||||
|
proc termGetCursorPos*(ouput: File): (int, int) =
|
||||||
|
|
||||||
|
ouput.write(escGetCursorPos)
|
||||||
|
|
||||||
|
var response = ""
|
||||||
|
if getch() != '\e':
|
||||||
|
raise newException(InvalidResponseError, "Unsupported terminal - can't get cursor position.")
|
||||||
|
if getch() != '[':
|
||||||
|
raise newException(InvalidResponseError, "Can't parse response in getCursorPos")
|
||||||
|
var newChar = getch()
|
||||||
|
while newChar != ';':
|
||||||
|
response &= newChar
|
||||||
|
newChar = getch()
|
||||||
|
let y = parseInt(response) - 1
|
||||||
|
response = ""
|
||||||
|
newChar = getch()
|
||||||
|
while newChar != 'R':
|
||||||
|
response &= newChar
|
||||||
|
newChar = getch()
|
||||||
|
let x = parseInt(response) - 1
|
||||||
|
|
||||||
|
return (x, y)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func escAttributes*(attributes: seq[uint8]): string =
|
||||||
|
let joined = attributes.join(";")
|
||||||
|
&"\e[{joined}m"
|
||||||
|
|
||||||
|
func escEraseCharacters*(n: int): string =
|
||||||
|
&"\e[{n}X"
|
|
@ -0,0 +1,34 @@
|
||||||
|
import terminal
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
import escapeSequences
|
||||||
|
|
||||||
|
proc termGetCursorPos*(ouput: File): (int, int) =
|
||||||
|
|
||||||
|
ouput.write(escGetCursorPos)
|
||||||
|
|
||||||
|
var response = ""
|
||||||
|
if getch() != '\e':
|
||||||
|
raise newException(InvalidResponseError, "Unsupported terminal - can't get cursor position.")
|
||||||
|
if getch() != '[':
|
||||||
|
raise newException(InvalidResponseError, "Can't parse response in getCursorPos")
|
||||||
|
var newChar = getch()
|
||||||
|
while newChar != ';':
|
||||||
|
response &= newChar
|
||||||
|
newChar = getch()
|
||||||
|
let y = parseInt(response) - 1
|
||||||
|
response = ""
|
||||||
|
newChar = getch()
|
||||||
|
while newChar != 'R':
|
||||||
|
response &= newChar
|
||||||
|
newChar = getch()
|
||||||
|
let x = parseInt(response) - 1
|
||||||
|
|
||||||
|
return (x, y)
|
||||||
|
|
||||||
|
proc termGetWidth*: int =
|
||||||
|
terminalWidth()
|
||||||
|
|
||||||
|
proc termGetHeight*: int =
|
||||||
|
terminalHeight()
|
||||||
|
|
Loading…
Reference in New Issue