mirror of https://github.com/veonik/squirssi
commit
2e5ad892be
@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
|
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Tyler Sommer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.dopame.me/veonik/squircy3/event"
|
||||
|
||||
"code.dopame.me/veonik/squirssi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ev := event.NewDispatcherLimit(512)
|
||||
srv, err := squirssi.NewServer(ev)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to initialize termui: %v", err)
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
srv.Start()
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package colors
|
||||
|
||||
import (
|
||||
ui "github.com/gizak/termui/v3"
|
||||
)
|
||||
|
||||
type Xterm = ui.Color
|
||||
|
||||
const Clear Xterm = -1
|
||||
|
||||
// Adapted from https://jonasjacek.github.io/colors/
|
||||
const (
|
||||
Black Xterm = iota
|
||||
Maroon
|
||||
Green
|
||||
Olive
|
||||
Navy
|
||||
Purple
|
||||
Teal
|
||||
Silver
|
||||
Grey
|
||||
Red
|
||||
Lime
|
||||
Yellow
|
||||
Blue
|
||||
Fuchsia
|
||||
Aqua
|
||||
White
|
||||
Grey0
|
||||
NavyBlue
|
||||
DarkBlue
|
||||
Blue3
|
||||
Blue2
|
||||
Blue1
|
||||
DarkGreen
|
||||
DeepSkyBlue7
|
||||
DeepSkyBlue6
|
||||
DeepSkyBlue5
|
||||
DodgerBlue3
|
||||
DodgerBlue2
|
||||
Green4
|
||||
SpringGreen6
|
||||
Turquoise4
|
||||
DeepSkyBlue4
|
||||
DeepSkyBlue3
|
||||
DodgerBlue1
|
||||
Green3
|
||||
SpringGreen5
|
||||
DarkCyan
|
||||
LightSeaGreen
|
||||
DeepSkyBlue2
|
||||
DeepSkyBlue1
|
||||
Green2
|
||||
SpringGreen4
|
||||
SpringGreen3
|
||||
Cyan3
|
||||
DarkTurquoise
|
||||
Turquoise2
|
||||
Green1
|
||||
SpringGreen2
|
||||
SpringGreen1
|
||||
MediumSpringGreen
|
||||
Cyan2
|
||||
Cyan1
|
||||
DarkRed1
|
||||
DeepPink8
|
||||
Purple5
|
||||
Purple4
|
||||
Purple3
|
||||
BlueViolet
|
||||
Orange5
|
||||
Grey37
|
||||
MediumPurple6
|
||||
SlateBlue4
|
||||
SlateBlue3
|
||||
RoyalBlue1
|
||||
Chartreuse6
|
||||
DarkSeaGreen9
|
||||
PaleTurquoise4
|
||||
SteelBlue
|
||||
SteelBlue3
|
||||
CornflowerBlue
|
||||
Chartreuse4
|
||||
DarkSeaGreen8
|
||||
CadetBlue2
|
||||
CadetBlue
|
||||
SkyBlue3
|
||||
SteelBlue2
|
||||
Chartreuse3
|
||||
PaleGreen4
|
||||
SeaGreen4
|
||||
Aquamarine3
|
||||
MediumTurquoise
|
||||
SteelBlue1
|
||||
Chartreuse2
|
||||
SeaGreen3
|
||||
SeaGreen2
|
||||
SeaGreen1
|
||||
Aquamarine2
|
||||
DarkSlateGray2
|
||||
DarkRed
|
||||
DeepPink7
|
||||
DarkMagenta1
|
||||
DarkMagenta
|
||||
DarkViolet
|
||||
Purple2
|
||||
Orange4
|
||||
LightPink4
|
||||
Plum4
|
||||
MediumPurple5
|
||||
MediumPurple4
|
||||
SlateBlue1
|
||||
Yellow6
|
||||
Wheat4
|
||||
Grey53
|
||||
LightSlateGrey
|
||||
MediumPurple
|
||||
LightSlateBlue
|
||||
Yellow5
|
||||
DarkOliveGreen6
|
||||
DarkSeaGreen
|
||||
LightSkyBlue4
|
||||
LightSkyBlue3
|
||||
SkyBlue2
|
||||
Chartreuse5
|
||||
DarkOliveGreen5
|
||||
PaleGreen3
|
||||
DarkSeaGreen7
|
||||
DarkSlateGray3
|
||||
SkyBlue1
|
||||
Chartreuse1
|
||||
LightGreen1
|
||||
LightGreen
|
||||
PaleGreen2
|
||||
Aquamarine1
|
||||
DarkSlateGray1
|
||||
Red4
|
||||
DeepPink6
|
||||
MediumVioletRed
|
||||
Magenta6
|
||||
DarkViolet1
|
||||
Purple1
|
||||
DarkOrange4
|
||||
IndianRed3
|
||||
HotPink5
|
||||
MediumOrchid3
|
||||
MediumOrchid
|
||||
MediumPurple3
|
||||
DarkGoldenrod
|
||||
LightSalmon4
|
||||
RosyBrown
|
||||
Grey63
|
||||
MediumPurple2
|
||||
MediumPurple1
|
||||
Gold4
|
||||
DarkKhaki
|
||||
NavajoWhite3
|
||||
Grey69
|
||||
LightSteelBlue3
|
||||
LightSteelBlue
|
||||
Yellow4
|
||||
DarkOliveGreen4
|
||||
DarkSeaGreen6
|
||||
DarkSeaGreen5
|
||||
LightCyan3
|
||||
LightSkyBlue1
|
||||
GreenYellow
|
||||
DarkOliveGreen3
|
||||
PaleGreen1
|
||||
DarkSeaGreen4
|
||||
DarkSeaGreen3
|
||||
PaleTurquoise1
|
||||
Red3
|
||||
DeepPink5
|
||||
DeepPink4
|
||||
Magenta5
|
||||
Magenta4
|
||||
Magenta3
|
||||
DarkOrange3
|
||||
IndianRed
|
||||
HotPink4
|
||||
HotPink3
|
||||
Orchid
|
||||
MediumOrchid2
|
||||
Orange3
|
||||
LightSalmon3
|
||||
LightPink3
|
||||
Pink3
|
||||
Plum3
|
||||
Violet
|
||||
Gold3
|
||||
LightGoldenrod5
|
||||
Tan
|
||||
MistyRose3
|
||||
Thistle3
|
||||
Plum2
|
||||
Yellow3
|
||||
Khaki3
|
||||
LightGoldenrod4
|
||||
LightYellow3
|
||||
Grey84
|
||||
LightSteelBlue1
|
||||
Yellow2
|
||||
DarkOliveGreen2
|
||||
DarkOliveGreen1
|
||||
DarkSeaGreen1
|
||||
Honeydew2
|
||||
LightCyan1
|
||||
Red1
|
||||
DeepPink3
|
||||
DeepPink2
|
||||
DeepPink1
|
||||
Magenta2
|
||||
Magenta1
|
||||
OrangeRed1
|
||||
IndianRed2
|
||||
IndianRed1
|
||||
HotPink2
|
||||
HotPink
|
||||
MediumOrchid1
|
||||
DarkOrange
|
||||
Salmon1
|
||||
LightCoral
|
||||
PaleVioletRed1
|
||||
Orchid2
|
||||
Orchid1
|
||||
Orange1
|
||||
SandyBrown
|
||||
LightSalmon1
|
||||
LightPink1
|
||||
Pink1
|
||||
Plum1
|
||||
Gold1
|
||||
LightGoldenrod3
|
||||
LightGoldenrod2
|
||||
NavajoWhite1
|
||||
MistyRose1
|
||||
Thistle1
|
||||
Yellow1
|
||||
LightGoldenrod1
|
||||
Khaki1
|
||||
Wheat1
|
||||
Cornsilk1
|
||||
Grey100
|
||||
Grey3
|
||||
Grey7
|
||||
Grey11
|
||||
Grey15
|
||||
Grey19
|
||||
Grey23
|
||||
Grey27
|
||||
Grey30
|
||||
Grey35
|
||||
Grey39
|
||||
Grey42
|
||||
Grey46
|
||||
Grey50
|
||||
Grey54
|
||||
Grey58
|
||||
Grey62
|
||||
Grey66
|
||||
Grey70
|
||||
Grey74
|
||||
Grey78
|
||||
Grey82
|
||||
Grey85
|
||||
Grey89
|
||||
Grey93
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
module code.dopame.me/veonik/squirssi
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
code.dopame.me/veonik/squircy3 v0.0.0-20200628150707-3ccbcd3262ff
|
||||
github.com/gizak/termui/v3 v3.1.0
|
||||
)
|
@ -0,0 +1,50 @@
|
||||
code.dopame.me/veonik/squircy3 v0.0.0-20200628150707-3ccbcd3262ff h1:V3R5nl3pVJY2lZFUYF4pRMJ8ddtny70VCaUavs0ZLJ0=
|
||||
code.dopame.me/veonik/squircy3 v0.0.0-20200628150707-3ccbcd3262ff/go.mod h1:FMNo74A2CmtfQKFHBGA0AwZcfkAB8QH9KGcwQTK0iuI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dop251/goja v0.0.0-20200526165454-f1752421c432/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
||||
github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA=
|
||||
github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
|
||||
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
|
||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/thoj/go-ircevent v0.0.0-20190807115034-8e7ce4b5a1eb/go.mod h1:I0ZT9x8wStY6VOxtNOrLpnDURFs7HS0z1e1vhuKUEVc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7 h1:wYqz/tQaWUgGKyx+B/rssSE6wkIKdY5Ee6ryOmzarIg=
|
||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/mattes/go-expand-tilde.v1 v1.0.0-20150330173918-cb884138e64c/go.mod h1:j6QavCO5cYWud1+2/PFTXL1y6tjjkhSs+qcWgibOIc0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
@ -0,0 +1,320 @@
|
||||
// import "code.dopame.me/veonik/squirssi"
|
||||
package squirssi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"code.dopame.me/veonik/squircy3/event"
|
||||
ui "github.com/gizak/termui/v3"
|
||||
"github.com/gizak/termui/v3/widgets"
|
||||
|
||||
"code.dopame.me/veonik/squirssi/colors"
|
||||
)
|
||||
|
||||
type Window interface {
|
||||
Title() string
|
||||
Lines() []string
|
||||
HasActivity() bool
|
||||
}
|
||||
|
||||
type WindowWithNicklist interface {
|
||||
Window
|
||||
Nicklist() []string
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
name string
|
||||
topic string
|
||||
modes string
|
||||
users []string
|
||||
lines []string
|
||||
current int
|
||||
|
||||
hasUnseen bool
|
||||
}
|
||||
|
||||
func (c *Channel) HasActivity() bool {
|
||||
return c.hasUnseen
|
||||
}
|
||||
|
||||
func (c *Channel) Title() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c *Channel) Lines() []string {
|
||||
return c.lines
|
||||
}
|
||||
|
||||
func (c *Channel) Nicklist() []string {
|
||||
return c.users
|
||||
}
|
||||
|
||||
type DirectMessage struct {
|
||||
user string
|
||||
lines []string
|
||||
current int
|
||||
|
||||
hasUnseen bool
|
||||
}
|
||||
|
||||
func (c *DirectMessage) Title() string {
|
||||
return c.user
|
||||
}
|
||||
|
||||
func (c *DirectMessage) Lines() []string {
|
||||
return c.lines
|
||||
}
|
||||
|
||||
func (c *DirectMessage) HasActivity() bool {
|
||||
return c.hasUnseen
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
ScreenWidth, ScreenHeight int
|
||||
|
||||
mainWindow *ui.Grid
|
||||
statusBar *widgets.TabPane
|
||||
|
||||
inputTextBox *widgets.Paragraph
|
||||
chatPane *widgets.List
|
||||
nicklistPane *widgets.Table
|
||||
|
||||
input *string
|
||||
|
||||
events *event.Dispatcher
|
||||
|
||||
windows []Window
|
||||
}
|
||||
|
||||
func NewServer(ev *event.Dispatcher) (*Server, error) {
|
||||
if err := ui.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w, h := ui.TerminalDimensions()
|
||||
return &Server{
|
||||
ScreenWidth: w,
|
||||
ScreenHeight: h,
|
||||
events: ev,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (srv *Server) Close() {
|
||||
ui.Close()
|
||||
}
|
||||
|
||||
type ScreenItem int
|
||||
|
||||
const (
|
||||
InputTextBox ScreenItem = iota
|
||||
StatusBar
|
||||
MainWindow
|
||||
)
|
||||
|
||||
func (srv *Server) RenderOnly(items ...ScreenItem) {
|
||||
var its []ui.Drawable
|
||||
for _, it := range items {
|
||||
switch it {
|
||||
case InputTextBox:
|
||||
its = append(its, srv.inputTextBox)
|
||||
case StatusBar:
|
||||
its = append(its, srv.statusBar)
|
||||
case MainWindow:
|
||||
its = append(its, srv.mainWindow)
|
||||
}
|
||||
}
|
||||
ui.Render(its...)
|
||||
}
|
||||
|
||||
func (srv *Server) Render() {
|
||||
channel := srv.windows[srv.statusBar.ActiveTabIndex]
|
||||
if channel == nil {
|
||||
return
|
||||
}
|
||||
srv.chatPane.Rows = channel.Lines()
|
||||
var rows [][]string
|
||||
if v, ok := channel.(WindowWithNicklist); ok {
|
||||
for _, nick := range v.Nicklist() {
|
||||
rows = append(rows, []string{nick})
|
||||
}
|
||||
}
|
||||
srv.nicklistPane.Rows = rows
|
||||
srv.chatPane.Title = channel.Title()
|
||||
ui.Render(srv.mainWindow, srv.statusBar, srv.inputTextBox)
|
||||
}
|
||||
|
||||
func (srv *Server) handleKey(e ui.Event) {
|
||||
switch e.ID {
|
||||
case "<C-c>":
|
||||
srv.Close()
|
||||
os.Exit(0)
|
||||
return
|
||||
case "<PageUp>":
|
||||
srv.chatPane.ScrollPageUp()
|
||||
srv.Render()
|
||||
case "<PageDown>":
|
||||
srv.chatPane.ScrollPageDown()
|
||||
srv.Render()
|
||||
case "<Space>":
|
||||
srv.appendInput(" ")
|
||||
srv.RenderOnly(InputTextBox)
|
||||
case "<Backspace>":
|
||||
srv.backspaceInput()
|
||||
case "<C-5>":
|
||||
srv.statusBar.FocusRight()
|
||||
srv.Render()
|
||||
case "<Escape>":
|
||||
srv.statusBar.FocusLeft()
|
||||
srv.Render()
|
||||
case "<Enter>":
|
||||
channel := srv.windows[srv.statusBar.ActiveTabIndex]
|
||||
if channel == nil {
|
||||
return
|
||||
}
|
||||
if c, ok := channel.(*Channel); ok {
|
||||
c.lines = append(c.lines, "<veonik> "+srv.consumeInput())
|
||||
srv.Render()
|
||||
}
|
||||
default:
|
||||
if len(e.ID) != 1 {
|
||||
// a single key resulted in more than one character, probably not a regular char
|
||||
return
|
||||
}
|
||||
srv.appendInput(e.ID)
|
||||
srv.RenderOnly(InputTextBox)
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) consumeInput() string {
|
||||
defer srv.resetInput()
|
||||
if len(*srv.input) < 2 {
|
||||
return ""
|
||||
}
|
||||
return (*srv.input)[2:]
|
||||
}
|
||||
|
||||
func (srv *Server) resetInput() {
|
||||
*srv.input = "> "
|
||||
}
|
||||
|
||||
func (srv *Server) appendInput(in string) {
|
||||
*srv.input = *srv.input + in
|
||||
}
|
||||
|
||||
func (srv *Server) backspaceInput() {
|
||||
if len(srv.inputTextBox.Text) > 2 {
|
||||
*srv.input = (*srv.input)[0 : len(*srv.input)-1]
|
||||
srv.RenderOnly(InputTextBox)
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) resize() {
|
||||
srv.statusBar.SetRect(0, srv.ScreenHeight-3, srv.ScreenWidth, srv.ScreenHeight)
|
||||
srv.inputTextBox.SetRect(0, srv.ScreenHeight-srv.statusBar.Dy()-1, srv.ScreenWidth, srv.ScreenHeight-srv.statusBar.Dy())
|
||||
srv.mainWindow.SetRect(0, 0, srv.ScreenWidth, srv.ScreenHeight-srv.statusBar.Dy()-srv.inputTextBox.Dy())
|
||||
}
|
||||
|
||||
func (srv *Server) Start() {
|
||||
nicklist := widgets.NewTable()
|
||||
nicklist.Rows = [][]string{}
|
||||
nicklist.Border = false
|
||||
nicklist.BorderStyle.Fg = ui.ColorBlack
|
||||
nicklist.RowSeparator = false
|
||||
nicklist.Title = "Users"
|
||||
nicklist.TextAlignment = ui.AlignRight
|
||||
nicklist.PaddingRight = 1
|
||||
|
||||
chat := widgets.NewList()
|
||||
chat.Rows = []string{}
|
||||
chat.BorderStyle.Fg = colors.DodgerBlue1
|
||||
chat.Border = true
|
||||
chat.PaddingLeft = 1
|
||||
chat.PaddingRight = 1
|
||||
|
||||
statusbar := widgets.NewTabPane(" 0 ", " 1 ", " 2 ")
|
||||
statusbar.SetRect(0, srv.ScreenHeight-3, srv.ScreenWidth, srv.ScreenHeight)
|
||||
statusbar.ActiveTabStyle.Fg = colors.DodgerBlue1
|
||||
statusbar.Border = true
|
||||
statusbar.BorderTop = true
|
||||
statusbar.BorderLeft = false
|
||||
statusbar.BorderRight = false
|
||||
statusbar.BorderBottom = false
|
||||
statusbar.BorderStyle.Fg = colors.DodgerBlue1
|
||||
|
||||
input := widgets.NewParagraph()
|
||||
|
||||
input.Border = false
|
||||
input.Text = "> "
|
||||
|
||||
window := ui.NewGrid()
|
||||
|
||||
window.Set(
|
||||
ui.NewCol(.9, chat),
|
||||
ui.NewCol(.1, nicklist),
|
||||
)
|
||||
|
||||
chan0 := Channel{
|
||||
name: "##somechan",
|
||||
lines: []string{"<veonik> this is a test", "<squishyj> this is only a test"},
|
||||
users: []string{"@veonik", "+squishyj"},
|
||||
}
|
||||
chan1 := Channel{
|
||||
name: "#uwot",
|
||||
lines: []string{"<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi", "<trub0> u wot m8", "<veonik> hi"},
|
||||
users: []string{"trub0", "veonik"},
|
||||
}
|
||||
chan2 := Channel{
|
||||
name: "#squishyslab",
|
||||
lines: []string{"<angrywombat> i dont think thats right", "<veonik> you are right"},
|
||||
users: []string{"angrywombat", "veonik"},
|
||||
}
|
||||
|
||||
srv.windows = []Window{&chan0, &chan1, &chan2}
|
||||
srv.statusBar = statusbar
|
||||
srv.mainWindow = window
|
||||
srv.inputTextBox = input
|
||||
srv.chatPane = chat
|
||||
srv.nicklistPane = nicklist
|
||||
|
||||
srv.input = &srv.inputTextBox.Text
|
||||
|
||||
srv.resize()
|
||||
srv.Render()
|
||||
|
||||
uiEvents := ui.PollEvents()
|
||||
|
||||
for {
|
||||
e := <-uiEvents
|
||||
switch e.Type {
|
||||
case ui.KeyboardEvent:
|
||||
srv.handleKey(e)
|
||||
srv.events.Emit("ui.KEYPRESS", map[string]interface{}{
|
||||
"key": e.ID,
|
||||
})
|
||||
case ui.MouseEvent:
|
||||
mouse, ok := e.Payload.(ui.Mouse)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("received termui Mouse event but Payload was unexpected type %T", e.Payload))
|
||||
}
|
||||
srv.events.Emit("ui.MOUSE", map[string]interface{}{
|
||||
"kind": e.ID,
|
||||
"x": mouse.X,
|
||||
"y": mouse.Y,
|
||||
"drag": mouse.Drag,
|
||||
})
|
||||
case ui.ResizeEvent:
|
||||
resize, ok := e.Payload.(ui.Resize)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("received termui Resize event but Payload was unexpected type %T", e.Payload))
|
||||
}
|
||||
srv.ScreenHeight = resize.Height
|
||||
srv.ScreenWidth = resize.Width
|
||||
srv.resize()
|
||||
srv.events.Emit("ui.RESIZE", map[string]interface{}{
|
||||
"width": resize.Width,
|
||||
"height": resize.Height,
|
||||
})
|
||||
srv.Render()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue