mirror of https://github.com/veonik/squirssi
commit
2e5ad892be
8 changed files with 695 additions and 0 deletions
@ -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