|
@@ -2,6 +2,7 @@ package door
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
+ "fmt"
|
|
|
"log"
|
|
|
"regexp"
|
|
|
"strconv"
|
|
@@ -60,11 +61,17 @@ func ParseColorArray(colorarray []int) ANSIColorParts {
|
|
|
acp.FG = -1
|
|
|
acp.BG = -1
|
|
|
|
|
|
+ if len(colorarray) == 0 {
|
|
|
+ colorarray = []int{0}
|
|
|
+ }
|
|
|
+
|
|
|
for _, c := range colorarray {
|
|
|
switch c {
|
|
|
case 0:
|
|
|
acp.FG = 7
|
|
|
acp.BG = 0
|
|
|
+ acp.Bold = false
|
|
|
+ acp.Blink = false
|
|
|
case 1:
|
|
|
acp.Bold = true
|
|
|
case 5:
|
|
@@ -148,63 +155,228 @@ func (d *Door) WriteS(output string) {
|
|
|
}
|
|
|
|
|
|
func (d *Door) WriteA(a ...interface{}) {
|
|
|
- d.Writer.Mutex.Lock()
|
|
|
- defer d.Writer.Mutex.Unlock()
|
|
|
+ d.writeMutex.Lock()
|
|
|
+ defer d.writeMutex.Unlock()
|
|
|
|
|
|
for _, item := range a {
|
|
|
switch item.(type) {
|
|
|
case string:
|
|
|
- d.Writer.OSWrite([]byte(item.(string)))
|
|
|
+ d.LockedWrite([]byte(item.(string)))
|
|
|
case []byte:
|
|
|
- d.Writer.OSWrite(item.([]byte))
|
|
|
+ d.LockedWrite(item.([]byte))
|
|
|
case *bytes.Buffer:
|
|
|
- d.Writer.OSWrite(item.(*bytes.Buffer).Bytes())
|
|
|
+ d.LockedWrite(item.(*bytes.Buffer).Bytes())
|
|
|
default:
|
|
|
log.Printf("Unknown/unsupported type: %T\n", item)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (d *Door) Write(output []byte) {
|
|
|
- if len(output) == 0 {
|
|
|
- return
|
|
|
+func EndCSI(c byte) bool {
|
|
|
+ return (c >= 0x40) && (c <= 0x7f)
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) ANSIProcess() {
|
|
|
+ var csi byte = d.ansiCode[len(d.ansiCode)-1]
|
|
|
+
|
|
|
+ switch csi {
|
|
|
+ case 's':
|
|
|
+ // Save Color
|
|
|
+ var slen int = len(d.LastColor)
|
|
|
+ if cap(d.Writer.LastSavedColor) < slen {
|
|
|
+ d.Writer.LastSavedColor = make([]int, slen)
|
|
|
+ } else {
|
|
|
+ d.Writer.LastSavedColor = d.Writer.LastSavedColor[0:slen]
|
|
|
+ }
|
|
|
+ copy(d.Writer.LastSavedColor, d.LastColor)
|
|
|
+ log.Printf("ColorSave: %d\n", d.Writer.LastSavedColor)
|
|
|
+ case 'u':
|
|
|
+ // Restore Color
|
|
|
+ var slen int = len(d.Writer.LastSavedColor)
|
|
|
+ if cap(d.LastColor) < slen {
|
|
|
+ d.LastColor = make([]int, slen)
|
|
|
+ } else {
|
|
|
+ d.LastColor = d.LastColor[0:slen]
|
|
|
+ }
|
|
|
+ copy(d.LastColor, d.Writer.LastSavedColor)
|
|
|
+ log.Printf("ColorRestore: %d\n", d.LastColor)
|
|
|
+ case 'm':
|
|
|
+ // Process color code
|
|
|
+ var color [5]int
|
|
|
+ var cpos int
|
|
|
+ var code int
|
|
|
+ var pos int
|
|
|
+ for pos = 0; pos < len(d.ansiCode); pos++ {
|
|
|
+ var b byte = d.ansiCode[pos]
|
|
|
+ switch b {
|
|
|
+ case ';':
|
|
|
+ color[cpos] = code
|
|
|
+ code = 0
|
|
|
+ cpos++
|
|
|
+ case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0':
|
|
|
+ code *= 10
|
|
|
+ code += int(b - '0')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if code != 0 {
|
|
|
+ color[cpos] = code
|
|
|
+ code = 0
|
|
|
+ cpos++
|
|
|
+ }
|
|
|
+
|
|
|
+ // Make sure there is always at least one code here.
|
|
|
+ if cpos == 0 {
|
|
|
+ color[cpos] = 0
|
|
|
+ cpos++
|
|
|
+ }
|
|
|
+
|
|
|
+ log.Printf("color: [%d]", color[0:cpos])
|
|
|
+ var newColor = ParseColorArray(d.LastColor)
|
|
|
+ for _, c := range color[0:cpos] {
|
|
|
+ switch c {
|
|
|
+ case 0:
|
|
|
+ newColor.FG = 7
|
|
|
+ newColor.BG = 0
|
|
|
+ newColor.Bold = false
|
|
|
+ newColor.Blink = false
|
|
|
+ case 1:
|
|
|
+ newColor.Bold = true
|
|
|
+ case 5:
|
|
|
+ newColor.Blink = true
|
|
|
+ case 30, 31, 32, 33, 34, 35, 36, 37:
|
|
|
+ newColor.FG = c - 30
|
|
|
+ case 40, 41, 42, 43, 44, 45, 46, 47:
|
|
|
+ newColor.BG = c - 40
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Reset LastColor
|
|
|
+ d.LastColor = d.LastColor[0:0]
|
|
|
+ d.LastColor = append(d.LastColor, 0)
|
|
|
+ if newColor.Blink {
|
|
|
+ d.LastColor = append(d.LastColor, 5)
|
|
|
+ }
|
|
|
+ if newColor.Bold {
|
|
|
+ d.LastColor = append(d.LastColor, 1)
|
|
|
+ }
|
|
|
+ if newColor.FG != -1 {
|
|
|
+ d.LastColor = append(d.LastColor, newColor.FG+30)
|
|
|
+ }
|
|
|
+ if newColor.BG != -1 {
|
|
|
+ d.LastColor = append(d.LastColor, newColor.BG+40)
|
|
|
+ }
|
|
|
+ log.Printf("LastColor: [%d]", d.LastColor)
|
|
|
}
|
|
|
|
|
|
- d.Writer.Write(output)
|
|
|
- /*
|
|
|
- d.
|
|
|
- d.writerMutex.Lock()
|
|
|
- defer d.writerMutex.Unlock()
|
|
|
- if d.WriterClosed {
|
|
|
+ var outputByte [20]byte
|
|
|
+ var output []byte = outputByte[0:0]
|
|
|
+
|
|
|
+ output = fmt.Appendf(output, "ANSI: [%q]\n", d.ansiCode)
|
|
|
+ log.Printf("%s", output)
|
|
|
+ d.ansiCode = d.ansiCode[0:0]
|
|
|
+ d.ansiCSI = false
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) ANSIScan(output []byte) {
|
|
|
+ var pos, nextpos int
|
|
|
+ var olen int = len(output)
|
|
|
+ var c byte
|
|
|
+
|
|
|
+ if d.ansiCSI {
|
|
|
+ for pos < olen {
|
|
|
+ c = output[pos]
|
|
|
+ d.ansiCode = append(d.ansiCode, c)
|
|
|
+ pos++
|
|
|
+ if EndCSI(c) {
|
|
|
+ d.ANSIProcess()
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if pos == olen {
|
|
|
return
|
|
|
+ // pos == -1 // end
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if strings.HasSuffix(output, RestorePos) {
|
|
|
- output += Color(d.LastColor)
|
|
|
+ for pos != -1 {
|
|
|
+ nextpos = bytes.Index(output[pos:], []byte{'\x1b'})
|
|
|
+ if nextpos != -1 {
|
|
|
+ // Found ESC
|
|
|
+ nextpos += pos + 1
|
|
|
|
|
|
+ if output[nextpos] == '[' {
|
|
|
+ d.ansiCSI = true
|
|
|
+ nextpos++
|
|
|
+ for nextpos < olen {
|
|
|
+ c = output[nextpos]
|
|
|
+ d.ansiCode = append(d.ansiCode, c)
|
|
|
+ nextpos++
|
|
|
+ if EndCSI(c) {
|
|
|
+ d.ANSIProcess()
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pos = nextpos
|
|
|
} else {
|
|
|
- d.UpdateLastColor(output, &d.LastColor)
|
|
|
+ return
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) LockedWrite(output []byte) {
|
|
|
+ if d.writeMutex.TryLock() {
|
|
|
+ log.Panic("LockedWrite: mutex was NOT locked.")
|
|
|
+ }
|
|
|
|
|
|
- d.OSWrite([]byte(output))
|
|
|
+ // var lastColorBytes [32]byte
|
|
|
+ var lastColor string // []byte = lastColorBytes[0:0]
|
|
|
+ /*
|
|
|
+ if (bytes.HasPrefix(output, []byte(SavePos))) &&
|
|
|
+ (bytes.HasSuffix(output, []byte(RestorePos))) {
|
|
|
*/
|
|
|
+ /*
|
|
|
+ if bytes.HasSuffix(output, []byte(RestorePos)) {
|
|
|
+ // Write the current color
|
|
|
+ lastColor = Color(d.LastColor)
|
|
|
+ //fmt.Append(lastColor, []byte(Color(d.LastColor)))
|
|
|
+ log.Printf("Restore LastColor: %d => %q", d.LastColor, lastColor)
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+ log.Printf(">> %q\n", output)
|
|
|
+ d.Writer.Write(output)
|
|
|
+ d.ANSIScan(output)
|
|
|
+
|
|
|
+ if bytes.HasSuffix(output, []byte(RestorePos)) {
|
|
|
+ lastColor = Color(d.LastColor)
|
|
|
+ //fmt.Append(lastColor, []byte(Color(d.LastColor)))
|
|
|
+ log.Printf("Restore LastColor: %d => %q", d.LastColor, lastColor)
|
|
|
+ d.Writer.Write([]byte(lastColor))
|
|
|
+ d.ANSIScan([]byte(lastColor))
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ if len(lastColor) != 0 {
|
|
|
+ log.Println("Restored HERE...")
|
|
|
+ d.Writer.Write([]byte(lastColor))
|
|
|
+ d.ANSIScan([]byte(lastColor))
|
|
|
+ }
|
|
|
+ */
|
|
|
+ // else {
|
|
|
+ // Only update if we're NOT restoring...
|
|
|
+ // Update
|
|
|
+ // d.ANSIScan(output)
|
|
|
+ // }
|
|
|
}
|
|
|
|
|
|
-// This uses go routine Writer. (Deprecated)
|
|
|
-// Write string to client.
|
|
|
-/*
|
|
|
-func (d *Door) WriteCh(output string) {
|
|
|
- if output == "" {
|
|
|
- // That was easy.
|
|
|
+func (d *Door) Write(output []byte) {
|
|
|
+ if len(output) == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- defer func() {
|
|
|
- if err := recover(); err != nil {
|
|
|
- log.Println("Write failed.", err)
|
|
|
- }
|
|
|
- }()
|
|
|
-
|
|
|
- d.writerChannel <- output
|
|
|
+ d.writeMutex.Lock()
|
|
|
+ defer d.writeMutex.Unlock()
|
|
|
+ d.LockedWrite(output)
|
|
|
}
|
|
|
-*/
|