summaryrefslogtreecommitdiffstats
path: root/LibTerm/Term.swift
diff options
context:
space:
mode:
Diffstat (limited to 'LibTerm/Term.swift')
-rw-r--r--LibTerm/Term.swift280
1 files changed, 280 insertions, 0 deletions
diff --git a/LibTerm/Term.swift b/LibTerm/Term.swift
new file mode 100644
index 0000000..9ca17dc
--- /dev/null
+++ b/LibTerm/Term.swift
@@ -0,0 +1,280 @@
+//
+// Term.swift
+// CmdLine
+//
+// Created by Jacky Jack on 25/02/2023.
+//
+
+import Foundation
+import Darwin
+
+class Term {
+ let esc = "\u{001B}"
+
+ var ifd:Int32
+ var ofd:Int32
+ var orig_i:termios
+ var orig_o:termios
+ var raw_i:termios
+ var raw_o:termios
+
+ init() {
+
+
+
+ self.ifd = Darwin.STDIN_FILENO
+ self.ofd = Darwin.STDOUT_FILENO
+
+ self.orig_i = termios()
+ self.orig_o = termios()
+ self.raw_i = termios()
+ self.raw_o = termios()
+
+ //let p_i<> = UnsafeMutablePointer(self.orig_i)
+ if (-1 == tcgetattr(self.ifd, UnsafeMutablePointer(&self.orig_i))) {
+ print("tcgetattr error")
+ return
+ }
+ self.raw_i = self.orig_i
+
+ if ( -1 == tcgetattr(self.ofd, UnsafeMutablePointer(&self.orig_o))) {
+ print("tcgetattr error")
+ return
+ }
+ self.raw_o = self.orig_o
+
+ if (isatty(STDIN_FILENO) == 0) {
+ print("isatty failed")
+ return
+ }
+
+ }
+
+ func setSpeed(speed: speed_t) {
+ var ret:Int32=0
+ let raw_out = UnsafeMutablePointer(&self.raw_o)
+ ret = cfsetospeed(raw_out, speed)
+ tcsetattr(self.ofd, TCSANOW, raw_out)
+
+ let raw_in = UnsafeMutablePointer(&self.raw_o)
+ ret = cfsetispeed(raw_in, speed)
+ tcsetattr(self.ifd, TCSANOW, raw_in)
+ }
+
+ func getMaxCol() -> Int {
+ let orig_c = getC()
+ //go to right marging and get position
+ if (write(ofd, "\u{001B}[999C", 6) != 6) {
+ return -1
+ }
+ //get the position
+ let cur_c = getC()
+ if (cur_c == -1) {
+ return -1
+ }
+
+ //restore previouse position
+ let restore_position = "\u{001B}[\(cur_c-orig_c)D"
+ write(ofd, restore_position, restore_position.count)
+
+ return cur_c
+ }
+
+ func getMaxRow() -> Int {
+ let orig_r = getR()
+ //go to right marging and get position
+ if (write(ofd, "\u{001B}[999B", 6) != 6) {
+ return -1
+ }
+ //get the position
+ let cur_r = getR()
+ if (cur_r == -1) {
+ return -1
+ }
+
+ //restore previouse position
+ let restore_position = "\u{001B}[\(cur_r-orig_r)A"
+ write(ofd, restore_position, restore_position.count)
+
+ return cur_r
+ }
+
+ func getR() -> Int {
+ var buf = [UInt8](repeating: 0, count: 32)
+
+ if (write(ofd, "\u{001B}[6n", 4) != 4) {
+ print("Cant push escape codes for column")
+ }
+ var i=0;
+ while (i<buf.capacity-1) {
+ if (read(ifd, &buf[i], 1) == -1) {
+ break
+ }
+ //if eq R
+ if (buf[i] == 0x52) {
+ break
+ }
+ i+=1
+ }
+ //maybe not most optimal way
+ while (buf.count-1 > i) {
+ buf.removeLast()
+ }
+ if (buf[0] != 0x1b) && (buf[1] != 0x5b) {
+ return -1
+ }
+
+ var bufs:String = ""
+ for i in 0..<buf.count {
+ bufs += String(Character(UnicodeScalar(buf[i])))
+ }
+ let sindex = bufs.index(bufs.startIndex, offsetBy: 2)
+ let split = bufs.suffix(from:sindex).components(separatedBy: ";")
+ let s1 = split[0] // row
+ let s2 = split[1] //column
+
+ return Int(s1)!
+ }
+
+ func getC() -> Int {
+ var buf = [UInt8](repeating: 0, count: 32)
+ if (write(ofd, "\u{001B}[6n", 4) != 4) {
+ //print("Cant push escape codes for column")
+ }
+ var i=0;
+ while (i<buf.capacity-1) {
+ if (read(ifd, &buf[i], 1) == -1) {
+ break
+ }
+ //if eq R
+ if (buf[i] == 0x52) {
+ break
+ }
+ i+=1
+ }
+ //maybe not most optimal way
+ var j=0
+ while (buf.count > i) {
+ buf.removeLast()
+ j+=1
+ }
+ if (buf[0] != 0x1b) && (buf[1] != 0x5b) {
+ return -1
+ }
+
+ var bufs:String = ""
+ for i in 0..<buf.count {
+ bufs += String(Character(UnicodeScalar(buf[i])))
+ }
+ let sindex = bufs.index(bufs.startIndex, offsetBy: 2)
+ let split = bufs.suffix(from:sindex).components(separatedBy: ";")
+ let s1 = split[0] // row
+ let s2 = split[1] //column
+
+ return Int(s2)!
+ }
+
+ func setC(_ pos_c: Int) {
+ let cur_r = getR()
+ let escape_string = "\u{001B}[\(cur_r);\(pos_c)H"
+ write(ofd, escape_string, escape_string.count)
+ }
+
+ func setR(_ pos_r: Int) {
+ let cur_c = getC()
+ let escape_string = "\u{001B}[\(pos_r);\(cur_c)H"
+ write(ofd, escape_string, escape_string.count)
+ }
+
+ func setCR(_ pos_c:Int, _ pos_r: Int) {
+ let escape_string = "\u{001B}[\(pos_c);\(pos_r)H"
+ write(ofd, escape_string, escape_string.count)
+ }
+
+ func clearScreen() {
+ //let escape = String(Unicode.Scalar(0x1b)!)
+ let s = "\u{001B}[H\u{001B}[2J"
+ //print(s.count)
+ let ret = write(self.ofd, s, 7);
+ //let ret = write(self.ofd, String("\u{001b}[2J"),4);
+ //print("\(esc)[2J".utf8)
+ }
+
+ func setRawMode() {
+ if ( tcgetattr(self.ifd, UnsafeMutablePointer(&self.orig_i)) == -1) {
+ print("Cannot get terminal attribures")
+ return
+ }
+
+ raw_i = orig_i
+ var c_iflag:Int32 = Int32(raw_i.c_iflag)
+ c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
+ raw_i.c_iflag = UInt(c_iflag)
+
+ var c_oflag:Int32 = Int32(raw_i.c_oflag)
+ c_oflag &= ~(OPOST)
+ raw_i.c_oflag = UInt(c_oflag)
+
+ var c_cflag:Int32 = Int32(raw_i.c_cflag)
+ c_cflag |= (CS8)
+ raw_i.c_cflag = UInt(c_cflag)
+
+ var c_lflag:Int32 = Int32(raw_i.c_lflag)
+ c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG)
+ raw_i.c_lflag = UInt(c_lflag)
+ //https://stackoverflow.com/questions/31465943/using-termios-in-swift
+ //raw_i.c_cc[VTIME] = 1
+ //raw_i.c_cc[VMIN] = 0;
+ /*withUnsafeMutablePointer(to: &raw_i.c_cc) { (tuplePtr) -> Void in
+ tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: raw_i.c_cc)) {
+ $0[Int(VMIN)] = 1
+ //$0[Int(VTIME)] = 0
+ }
+ }*/
+ //print("\(raw_i)")
+ //print("VMIN=\(VMIN)")
+ raw_i.c_cc.16 = 1
+ //print("VTIME=\(VTIME)")
+ raw_i.c_cc.17 = 0
+ let p:UnsafePointer<termios> = UnsafePointer(&self.raw_i)
+ if (tcsetattr(self.ifd, TCSAFLUSH, UnsafePointer(p)) == -1) {
+ print("Cannot set new terminal input attribures")
+ }
+ }
+
+ func setConfigMode(c_iflag:Int32, c_oflag:Int32, c_cflag:Int32, c_lflag:Int32, vmin: UInt8, vtime: UInt8) {
+ if ( tcgetattr(self.ifd, UnsafeMutablePointer(&self.orig_i)) == -1) {
+ print("Cannot get terminal attribures")
+ return
+ }
+
+ raw_i.c_iflag = UInt(c_iflag)
+ raw_i.c_oflag = UInt(c_oflag)
+ raw_i.c_cflag = UInt(c_cflag)
+ raw_i.c_lflag = UInt(c_lflag)
+ raw_i.c_cc.16 = vmin
+ raw_i.c_cc.17 = vtime
+ let p:UnsafePointer<termios> = UnsafePointer(&self.raw_i)
+ if (tcsetattr(self.ifd, TCSAFLUSH, UnsafePointer(p)) == -1) {
+ print("Cannot set new terminal input attribures")
+ }
+ }
+
+ func modeRows() {
+
+ }
+
+ func modeColumns() {
+
+ }
+
+ func setOrigMode() {
+ if (tcsetattr(self.ifd, TCSAFLUSH, UnsafePointer(&self.orig_i)) == -1) {
+ print("Cannot set new terminal input attribures")
+ }
+ }
+
+ func print(_ s: String) {
+ write(self.ofd, s, s.count)
+ }
+}