255 lines
5.8 KiB
Go
255 lines
5.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.rocketnine.space/tslocum/cview"
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/lrstanley/girc"
|
|
)
|
|
|
|
func main() {
|
|
cview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack.TrueColor()
|
|
cview.Styles.ContrastBackgroundColor = tcell.ColorBlack.TrueColor()
|
|
cview.Styles.MoreContrastBackgroundColor = tcell.ColorBlack.TrueColor()
|
|
|
|
app := cview.NewApplication()
|
|
|
|
buffer := cview.NewTextView()
|
|
buffer.SetScrollBarVisibility(cview.ScrollBarAlways)
|
|
buffer.SetDynamicColors(true)
|
|
|
|
drawBuffer := func() {
|
|
if len(state.channels) == 0 {
|
|
return
|
|
}
|
|
|
|
buffer.Clear()
|
|
for _, ch := range state.channels {
|
|
for i := range ch.buffer {
|
|
buffer.Write(ch.buffer[i])
|
|
buffer.Write([]byte("\n"))
|
|
}
|
|
break
|
|
}
|
|
app.Draw()
|
|
}
|
|
|
|
writeMsg := func(s string) {
|
|
buffer.Write(append(cview.EscapeBytes([]byte(s)), '\n'))
|
|
app.Draw()
|
|
}
|
|
|
|
writeDebugMsg := func(s string) {
|
|
var channel *Channel
|
|
for _, ch := range state.channels {
|
|
channel = ch
|
|
break
|
|
}
|
|
if channel == nil {
|
|
buffer.Write(append(cview.EscapeBytes([]byte("DEBUG: "+s)), '\n'))
|
|
app.Draw()
|
|
} else {
|
|
channel.buffer = append(channel.buffer, []byte("DEBUG: "+s))
|
|
drawBuffer()
|
|
}
|
|
}
|
|
_ = writeDebugMsg
|
|
|
|
bufR, bufW := io.Pipe()
|
|
|
|
go func() {
|
|
scanner := bufio.NewScanner(bufR)
|
|
for scanner.Scan() {
|
|
writeMsg(scanner.Text())
|
|
}
|
|
}()
|
|
|
|
client := girc.New(girc.Config{
|
|
Server: "irc.7chan.org",
|
|
Port: 6667,
|
|
Nick: "tee2",
|
|
User: "tee2",
|
|
Name: "cIRCa",
|
|
Version: "cIRCa https://code.rocket9labs.com/tslocum/circa",
|
|
Out: bufW,
|
|
RecoverFunc: func(c *girc.Client, e *girc.HandlerError) {
|
|
recover()
|
|
},
|
|
})
|
|
client.DisableTracking()
|
|
|
|
input := cview.NewInputField()
|
|
input.SetDoneFunc(func(_ tcell.Key) {
|
|
defer func() {
|
|
input.SetText("")
|
|
}()
|
|
split := strings.Split(input.GetText(), " ")
|
|
if len(split) == 0 {
|
|
return
|
|
}
|
|
cmd := split[0]
|
|
var params []string
|
|
if len(split) > 0 {
|
|
params = split[1:]
|
|
}
|
|
if cmd[0] == '/' {
|
|
cmd = strings.ToUpper(cmd[1:])
|
|
} else {
|
|
cmd = girc.PRIVMSG
|
|
var channel *Channel
|
|
for _, ch := range state.channels {
|
|
channel = ch
|
|
break
|
|
}
|
|
if channel == nil {
|
|
panic("TODO")
|
|
}
|
|
params = []string{channel.name, input.GetText()}
|
|
}
|
|
e := &girc.Event{Command: cmd, Params: params}
|
|
client.Send(e)
|
|
if e.Command == girc.PRIVMSG && len(params) > 0 {
|
|
for name, channel := range state.channels {
|
|
if strings.ToLower(name) == strings.ToLower(params[0]) {
|
|
channel.buffer = append(channel.buffer, []byte(fmt.Sprintf("<%s> %s", client.Config.Nick, strings.Join(params[1:], " "))))
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
// TODO write to status window instead
|
|
// writeMsg(fmt.Sprintf("%+v", &girc.Event{Command: cmd, Params: params}))
|
|
}
|
|
drawBuffer()
|
|
return
|
|
})
|
|
|
|
sideBar := cview.NewTextView()
|
|
sideBar.SetScrollBarVisibility(cview.ScrollBarAlways)
|
|
|
|
flexHorizontal := cview.NewFlex()
|
|
flexHorizontal.SetDirection(cview.FlexColumn)
|
|
flexHorizontal.AddItem(sideBar, 15, 0, false)
|
|
flexHorizontal.AddItem(cview.NewBox(), 1, 0, false)
|
|
flexHorizontal.AddItem(buffer, 0, 1, false)
|
|
|
|
statusLine := cview.NewTextView()
|
|
statusLine.SetTextColor(tcell.NewRGBColor(255, 255, 255))
|
|
statusLine.SetBackgroundColor(tcell.NewRGBColor(50, 50, 50))
|
|
statusLine.SetDynamicColors(true)
|
|
statusLine.Write([]byte("[::b]-- INSERT --[::-]"))
|
|
|
|
flex := cview.NewFlex()
|
|
flex.SetDirection(cview.FlexRow)
|
|
flex.AddItem(flexHorizontal, 0, 1, false)
|
|
flex.AddItem(statusLine, 1, 0, false)
|
|
flex.AddItem(input, 1, 0, true)
|
|
|
|
app.SetRoot(flex, true)
|
|
|
|
updateSideBar := func() {
|
|
sideBar.Clear()
|
|
var i int
|
|
for name, channel := range state.channels {
|
|
if i != 0 {
|
|
sideBar.Write([]byte("\n"))
|
|
}
|
|
sideBar.Write([]byte(name))
|
|
_ = channel
|
|
i++
|
|
}
|
|
app.Draw()
|
|
}
|
|
|
|
go func() {
|
|
client.Handlers.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) {
|
|
// TODO
|
|
})
|
|
|
|
client.Handlers.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) {
|
|
if len(e.Params) == 0 {
|
|
return
|
|
}
|
|
|
|
paramChannel := e.Params[0]
|
|
paramMessage := e.Params[1:]
|
|
spaceIndex := strings.IndexRune(paramChannel, ' ')
|
|
if spaceIndex != -1 {
|
|
paramChannel = e.Params[0][:spaceIndex]
|
|
paramMessage = append([]string{e.Params[0][spaceIndex+1:]}, e.Params[1:]...)
|
|
}
|
|
|
|
writeDebugMsg(fmt.Sprintf("%s %+v %+v", paramChannel, paramMessage, e))
|
|
|
|
var channel *Channel
|
|
for name, ch := range state.channels {
|
|
if name == paramChannel {
|
|
channel = ch
|
|
break
|
|
}
|
|
}
|
|
if channel == nil {
|
|
// TODO this is a private privmsg, or external message
|
|
log.Fatal("no channel")
|
|
return
|
|
}
|
|
|
|
channel.buffer = append(channel.buffer, []byte(fmt.Sprintf("<%s> %s", e.Source.Name, strings.Join(paramMessage, " "))))
|
|
drawBuffer()
|
|
})
|
|
|
|
client.Handlers.Add(girc.JOIN, func(c *girc.Client, e girc.Event) {
|
|
if len(e.Params) == 0 {
|
|
return
|
|
}
|
|
if e.Source.Name == c.Config.Nick {
|
|
for _, channelName := range e.Params {
|
|
state.channels[channelName] = &Channel{
|
|
name: channelName,
|
|
}
|
|
}
|
|
updateSideBar()
|
|
} else {
|
|
// someone else joined a channel we are in
|
|
writeDebugMsg(fmt.Sprintf("other join %+v", e))
|
|
}
|
|
|
|
var channel *Channel
|
|
for name, ch := range state.channels {
|
|
if name == e.Params[0] {
|
|
channel = ch
|
|
break
|
|
}
|
|
}
|
|
if channel == nil {
|
|
// TODO this is a private privmsg, or external message
|
|
return
|
|
}
|
|
channel.buffer = append(channel.buffer, []byte(fmt.Sprintf("* %s joined %s", e.Source.Name, e.Params[1:])))
|
|
drawBuffer()
|
|
})
|
|
|
|
// An example of how you would add reconnect logic.
|
|
for {
|
|
if err := client.Connect(); err != nil {
|
|
writeMsg(fmt.Sprintf("error: %s", err))
|
|
|
|
writeMsg("reconnecting in 30 seconds...")
|
|
time.Sleep(30 * time.Second)
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
err := app.Run()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|