func main() { scr, _ := gc.Init() defer gc.End() rows, cols := scr.Maxyx() gc.InitPair(ChatAreaColor, gc.C_WHITE, gc.C_BLACK) gc.InitPair(InputAreaColor, gc.C_BLACK, gc.C_WHITE) chatArea := scr.Derived(rows-1, cols, 0, 0) chatArea.SetBackground(gc.Character(' ' | gc.ColorPair(ChatAreaColor))) inputArea := scr.Derived(1, cols, rows-1, 0) chatArea.SetBackground(gc.Character(' ' | gc.ColorPair(InputAreaColor))) chat := make(chan string) go func() { for msg := range chat { msg = fmt.Sprintf("%v| %v", time.Now().Format("15:04:05"), msg) chatArea.Scroll(1) chatArea.MovePrint(rows-2, 0, msg) chatArea.Refresh() } }() defer close(chat) userInputChan := make(chan string) go func() { for msg := range userInputChan { if len(msg) > 0 && msg[0] == '/' { chat <- fmt.Sprintf("Command: %s", msg[1:]) } else { chat <- msg } } }() defer close(userInputChan) gc.Echo(false) gc.CBreak(true) gc.Raw(true) chatArea.ScrollOk(true) scr.Keypad(true) chat <- "Welcome to snails shitty chat thing." chat <- "Press esc to quit, it may or may not break stuff. " chat <- "If it does, do a 'reset' to fix it." buffer := "" for { chatArea.Refresh() key := inputArea.GetChar() switch key { case gc.Key(27): return case gc.KEY_RETURN: userInputChan <- buffer buffer = "" chatArea.Refresh() case gc.Key(127): //backspace l := len(buffer) if l > 0 { buffer = buffer[:l-1] } default: buffer = fmt.Sprintf("%s%c", buffer, key) } inputArea.Clear() inputArea.MovePrint(0, 0, buffer) } }
func cli() { var e error scr, e = goncurses.Init() if e != nil { log.Fatal(e) } defer goncurses.End() exit := false pageNum := 0 p := NewPageCache() for !exit { scr.Refresh() h, _ := scr.MaxYX() scr.Clear() height := h - BOTTOM_MARGIN start := height * pageNum end := start + height for end > len(p.Articles) { p.GetNext() } for i, ar := range p.Articles[start:end] { scr.Printf("%d. (%d): %s\n", start+i+1, ar.Karma, ar.Title) } scr.Print("\n(n: next, p: previous, <num>c: view comments, <num>o: open in browser, q: quit) ") scr.Refresh() doneWithInput := false input := "" for !doneWithInput { c := scr.GetChar() if c == 127 { c = goncurses.Key(goncurses.KEY_BACKSPACE) } ch := goncurses.KeyString(c) switch ch { case "c": if num, err := strconv.Atoi(input); err == nil { if num < 1 { doneWithInput = true break } for num-1 > len(p.Articles) { p.GetNext() } text := p.Articles[num-1].PrintComments() line := 0 cont := true for cont { scr.Clear() scr.Print(pagify(text, line)) scr.Print("\n\n(d/u scroll 30 lines; j/k: scroll 1 line; n/p scroll 1 page; q: quit)") scr.Refresh() a := scr.GetChar() switch goncurses.KeyString(a) { case "d": line += 30 break case "u": line -= 30 break case "j": line += 1 break case "k": line -= 1 break case "n": line += h break case "p": line -= h break case "q": cont = false break default: scr.DelChar() scr.DelChar() break } // Verify lines are not negative. Bad mojo if line < 0 { line = 0 } } doneWithInput = true } else { scr.Clear() scr.Print("\n\nPlease enter a number to select a comment\n\n") scr.Refresh() scr.GetChar() doneWithInput = true } case "o": if num, err := strconv.Atoi(input); err == nil { for num-1 > len(p.Articles) { p.GetNext() } viewInBrowser := exec.Command("xdg-open", p.Articles[num-1].Url) viewInBrowser.Start() doneWithInput = true } else { scr.Clear() scr.Print("\n\nPlease enter a number to view an article\n\n") scr.Refresh() doneWithInput = true } case "q": doneWithInput = true exit = true case "n": pageNum += 1 doneWithInput = true case "p": if pageNum > 0 { pageNum -= 1 } doneWithInput = true case "enter": continue case "backspace": //Not the prettiest but whatever cy, cx := scr.CursorYX() if len(input) > 0 { input = input[:len(input)-1] scr.MoveDelChar(cy, cx-3) scr.DelChar() scr.DelChar() } else { scr.MoveDelChar(cy, cx-2) scr.DelChar() scr.DelChar() } default: input += ch break } } } }