Browse Source

This has working write channel. LastColor works.

testdoor has a demo go routine that updates the time while
we're inputting.  (It preserves color correctly.)
Steve Thielemann 3 years ago
parent
commit
e85feb6eee
3 changed files with 140 additions and 13 deletions
  1. 3 0
      door/door_linux.go
  2. 127 13
      door/write_linux.go
  3. 10 0
      testdoor/testdoor.go

+ 3 - 0
door/door_linux.go

@@ -31,6 +31,8 @@ import (
 	"time"
 )
 
+const SavePos = "\x1b[s"              // Save Cursor Position
+const RestorePos = "\x1b[u"           // Restore Cursor Position
 const CRNL = "\r\n"                   // BBS Line Ending
 const Clrscr = "\x1b[0m\x1b[2J\x1b[H" // Clear screen, home cursor
 const HideCursor = "\x1b[?25l"        // Hide Cursor
@@ -81,6 +83,7 @@ type Door struct {
 	TimeOut      time.Time // Fixed point in time, when time expires
 	StartTime    time.Time
 	Pushback     FIFOBuffer
+	LastColor    []int
 }
 
 // Return the amount of time left as time.Duration

+ 127 - 13
door/write_linux.go

@@ -1,7 +1,10 @@
 package door
 
 import (
-	"fmt"
+	"log"
+	"regexp"
+	"strconv"
+	"strings"
 	"syscall"
 )
 
@@ -27,6 +30,105 @@ ok == false
 writing to a closed channel is a panic.
 
 */
+func find_ansicolor(text string) [][]int {
+	var color_codes [][]int
+
+	word, _ := regexp.Compile("\x1b\\[([0-9;]+)m")
+	colors := word.FindAllStringIndex(text, -1)
+	// regexp seems to be ignoring the capture groups.
+	// colors := word.FindAllSubmatchIndex([]byte(text), len(text))
+	for _, pos := range colors {
+		txt := text[pos[0]+2 : pos[1]-1]
+		if txt == "" {
+			txt = "0"
+		}
+		log.Printf("Text: [%s]\n", txt)
+		codes := strings.Split(txt, ";")
+		log.Printf("Codes: [%#v]\n", codes)
+		code := make([]int, len(codes))
+		for idx, c := range codes {
+			var err error
+			code[idx], err = strconv.Atoi(c)
+			if err != nil {
+				log.Printf("Atoi: %#v [%s]\n", err, c)
+			}
+			color_codes = append(color_codes, code)
+		}
+
+	}
+	return color_codes
+}
+
+type ANSIColorParts struct {
+	Bold  bool
+	Blink bool
+	FG    int
+	BG    int
+}
+
+func ParseColorArray(colorarray []int) ANSIColorParts {
+	var acp ANSIColorParts
+	acp.FG = -1
+	acp.BG = -1
+
+	for _, c := range colorarray {
+		switch c {
+		case 0:
+			acp.FG = 7
+			acp.BG = 0
+		case 1:
+			acp.Bold = true
+		case 5:
+			acp.Blink = true
+		case 30, 31, 32, 33, 34, 35, 36, 37:
+			acp.FG = c - 30
+		case 40, 41, 42, 43, 44, 45, 46, 47:
+			acp.BG = c - 40
+		}
+	}
+	return acp
+}
+
+func (d *Door) ParseLastColor(output string) {
+	// use the last color information + whatever is in the string to
+	// track the last color set
+	updated := ParseColorArray(d.LastColor)
+	colors := find_ansicolor(output)
+	for _, codes := range colors {
+		if codes[0] == 0 {
+			updated = ParseColorArray(codes)
+		} else {
+			newCode := ParseColorArray(codes)
+			if newCode.Bold {
+				updated.Bold = true
+			}
+			if newCode.Blink {
+				updated.Blink = true
+			}
+			if (newCode.FG != -1) && (newCode.FG != updated.FG) {
+				updated.FG = newCode.FG
+			}
+			if (newCode.BG != -1) && (newCode.BG != updated.BG) {
+				updated.BG = newCode.BG
+			}
+		}
+	}
+
+	d.LastColor = make([]int, 1)
+	d.LastColor[0] = 0
+	if updated.Blink {
+		d.LastColor = append(d.LastColor, 5)
+	}
+	if updated.Bold {
+		d.LastColor = append(d.LastColor, 1)
+	}
+	if updated.FG != -1 {
+		d.LastColor = append(d.LastColor, updated.FG+30)
+	}
+	if updated.BG != -1 {
+		d.LastColor = append(d.LastColor, updated.BG+40)
+	}
+}
 
 // Write string to client.
 func (d *Door) Write(output string) {
@@ -36,23 +138,35 @@ func (d *Door) Write(output string) {
 
 	defer func() {
 		if r := recover(); r != nil {
-			fmt.println("Write error/HANGUP.")
+			log.Println("Write error/HANGUP.")
 			d.Disconnected = true
+		}
 	}()
 
+	if strings.HasSuffix(output, RestorePos) {
+		output += Color(d.LastColor...)
+	} else {
+		d.ParseLastColor(output)
+	}
+
+	/*
+		temp := strings.Replace(output, "\x1b", "^[", -1)
+		log.Printf("Parse: [%s]\n", temp)
+	*/
+
 	writerChannel <- output
 
 	/*
-	buffer := []byte(output)
-	n, err := syscall.Write(d.WRITEFD, buffer)
-	if err != nil {
-		fmt.Println("Write error/HANGUP?", n)
-		d.Disconnected = true
-	}
-	// No, this isn't it.  The # of bytes in buffer == bytes written.
-	if n != len(buffer) {
-		fmt.Printf("Write fail: %d != %d\n", len(buffer), n)
-	}
+		buffer := []byte(output)
+		n, err := syscall.Write(d.WRITEFD, buffer)
+		if err != nil {
+			fmt.Println("Write error/HANGUP?", n)
+			d.Disconnected = true
+		}
+		// No, this isn't it.  The # of bytes in buffer == bytes written.
+		if n != len(buffer) {
+			fmt.Printf("Write fail: %d != %d\n", len(buffer), n)
+		}
 	*/
-	
+
 }

+ 10 - 0
testdoor/testdoor.go

@@ -289,6 +289,15 @@ func font_demo(d *door.Door) {
 }
 
 func input_demo(d *door.Door) {
+	ticker := time.NewTicker(time.Second)
+
+	go func() {
+		for t := range ticker.C {
+			output := door.SavePos + door.Goto(5, 1) + door.ColorText("CYAN ON BLACK") + t.Format(time.RFC3339) + door.RestorePos
+			d.Write(output)
+		}
+	}()
+
 	inputColor := door.ColorText("BRI WHI ON BLUE")
 	inputColor2 := door.ColorText("BRI WHI ON GREEN")
 	prompt := door.Line{Text: "What is YOUR Name: "}
@@ -304,6 +313,7 @@ func input_demo(d *door.Door) {
 	d.Write(prompt.Output() + inputColor2)
 	color := d.Input(15)
 	d.Write(door.Reset + door.CRNL)
+	ticker.Stop()
 	d.Write(fmt.Sprintf("You're %s on the %s quest, and fond of %s."+door.CRNL, name, quest, color))
 }