mirror of
https://github.com/IllusionMan1212/gorc.git
synced 2026-10-24 18:12:33 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfe490cd5c
|
||
|
|
bd4d332b75
|
||
|
|
c965143264
|
||
|
|
076277938e
|
@@ -1,16 +1,30 @@
|
|||||||
module github.com/illusionman1212/gorc
|
module github.com/illusionman1212/gorc
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
replace github.com/charmbracelet/bubbles => /home/illusion/Desktop/repos/bubbles
|
replace github.com/charmbracelet/bubbles => /home/illusion/Desktop/repos/bubbles
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/charmbracelet/bubbles v0.10.2
|
github.com/charmbracelet/bubbles v0.15.0
|
||||||
github.com/charmbracelet/bubbletea v0.19.3
|
github.com/charmbracelet/bubbletea v0.23.2
|
||||||
github.com/charmbracelet/lipgloss v0.4.0
|
github.com/charmbracelet/lipgloss v0.6.0
|
||||||
github.com/containerd/console v1.0.3 // indirect
|
)
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
|
||||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
|
require (
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
github.com/aymanbagabas/go-osc52 v1.2.1 // indirect
|
||||||
|
github.com/containerd/console v1.0.3 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
|
github.com/muesli/termenv v0.14.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.3 // indirect
|
||||||
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
|
golang.org/x/term v0.5.0 // indirect
|
||||||
|
golang.org/x/text v0.7.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,44 +1,62 @@
|
|||||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/charmbracelet/bubbletea v0.19.3 h1:OKeO/Y13rQQqt4snX+lePB0QrnW80UdrMNolnCcmoAw=
|
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||||
github.com/charmbracelet/bubbletea v0.19.3/go.mod h1:VuXF2pToRxDUHcBUcPmCRUHRvFATM4Ckb/ql1rBl3KA=
|
github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E=
|
||||||
github.com/charmbracelet/harmonica v0.1.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||||
github.com/charmbracelet/lipgloss v0.4.0 h1:768h64EFkGUr8V5yAKV7/Ta0NiVceiPaV+PphaW1K9g=
|
github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI=
|
||||||
github.com/charmbracelet/lipgloss v0.4.0/go.mod h1:vmdkHvce7UzX6xkyf4cca8WlwdQ5RQr8fzta+xl7BOM=
|
github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74=
|
||||||
github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
|
github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
|
||||||
|
github.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps=
|
||||||
|
github.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM=
|
||||||
|
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||||
|
github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
|
||||||
|
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
|
||||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||||
|
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA=
|
github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a h1:jlDOeO5TU0pYlbc/y6PFguab5IjANI0Knrpg3u/ton4=
|
||||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
||||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||||
github.com/muesli/termenv v0.9.0 h1:wnbOaGz+LUR3jNT0zOzinPnyDaCZUQRZj9GxK8eRVl8=
|
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||||
github.com/muesli/termenv v0.9.0/go.mod h1:R/LzAKf+suGs4IsO95y7+7DpFHO0KABgnZqtlyx2mBw=
|
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/muesli/termenv v0.14.0 h1:8x9NFfOe8lmIWK4pgy3IfVEy47f+ppe3tUqdPZG2Uy0=
|
||||||
|
github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
||||||
|
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20210422114643-f5beecf764ed/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
+8
-4
@@ -82,8 +82,13 @@ type Client struct {
|
|||||||
|
|
||||||
// Index of the last visible tab in the tab bar
|
// Index of the last visible tab in the tab bar
|
||||||
LastTabIndexInTabBar int
|
LastTabIndexInTabBar int
|
||||||
|
|
||||||
|
// The acknowledged capabilities
|
||||||
|
EnabledCapabilities Capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Capabilities map[string]string
|
||||||
|
|
||||||
type MsgFmtOpts struct {
|
type MsgFmtOpts struct {
|
||||||
WithTimestamp bool
|
WithTimestamp bool
|
||||||
AsServerMsg bool
|
AsServerMsg bool
|
||||||
@@ -138,6 +143,7 @@ func (s *Client) Initialize(host string, port string, tlsEnabled bool) {
|
|||||||
s.Port = port
|
s.Port = port
|
||||||
s.ActiveChannel = host
|
s.ActiveChannel = host
|
||||||
s.Channels = make([]Channel, 0)
|
s.Channels = make([]Channel, 0)
|
||||||
|
s.EnabledCapabilities = make(Capabilities, 0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +162,7 @@ func (s *Client) Initialize(host string, port string, tlsEnabled bool) {
|
|||||||
s.Port = port
|
s.Port = port
|
||||||
s.ActiveChannel = host
|
s.ActiveChannel = host
|
||||||
s.Channels = make([]Channel, 0)
|
s.Channels = make([]Channel, 0)
|
||||||
|
s.EnabledCapabilities = make(Capabilities, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Register(nick string, password string, channel string) {
|
func (c *Client) Register(nick string, password string, channel string) {
|
||||||
@@ -164,17 +171,14 @@ func (c *Client) Register(nick string, password string, channel string) {
|
|||||||
Users: make(map[string]User),
|
Users: make(map[string]User),
|
||||||
})
|
})
|
||||||
|
|
||||||
c.SendCommand(commands.CAP, "LS")
|
c.SendCommand(commands.CAP, "LS", "302")
|
||||||
if password != "" {
|
if password != "" {
|
||||||
c.SendCommand(commands.PASS, password)
|
c.SendCommand(commands.PASS, password)
|
||||||
}
|
}
|
||||||
// TODO: check if nickname has spaces and remove them
|
|
||||||
c.SendCommand(commands.NICK, nick)
|
c.SendCommand(commands.NICK, nick)
|
||||||
// set user-wanted nickname
|
// set user-wanted nickname
|
||||||
c.Nickname = nick
|
c.Nickname = nick
|
||||||
c.SendCommand(commands.USER, nick, "0", "*", nick)
|
c.SendCommand(commands.USER, nick, "0", "*", nick)
|
||||||
// TODO: CAP REQ :whatever capability the client recognizes and supports
|
|
||||||
c.SendCommand(commands.CAP, "END")
|
|
||||||
// joining a channel when registering is optional
|
// joining a channel when registering is optional
|
||||||
if channel != "" {
|
if channel != "" {
|
||||||
c.SendCommand(commands.JOIN, channel)
|
c.SendCommand(commands.JOIN, channel)
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ const (
|
|||||||
RPL_MYINFO = "004" // RFC2812 - Implemented
|
RPL_MYINFO = "004" // RFC2812 - Implemented
|
||||||
RPL_ISUPPORT = "005" // ??????? - Not Implemented (TODO:)
|
RPL_ISUPPORT = "005" // ??????? - Not Implemented (TODO:)
|
||||||
RPL_BOUNCE = "010" // ??????? - Not Implemented (TODO:)
|
RPL_BOUNCE = "010" // ??????? - Not Implemented (TODO:)
|
||||||
|
RPL_REMOTEISUPPORT = "105" // ??????? - Not Implemented (TODO:) // Exact same as RPL_ISUPPORT but for remote servers
|
||||||
RPL_TRACELINK = "200" // RFC1459 - Not Implemented (TODO:)
|
RPL_TRACELINK = "200" // RFC1459 - Not Implemented (TODO:)
|
||||||
RPL_TRACECONNECTING = "201" // RFC1459 - Not Implemented (TODO:)
|
RPL_TRACECONNECTING = "201" // RFC1459 - Not Implemented (TODO:)
|
||||||
RPL_TRACEHANDSHAKE = "202" // RFC1459 - Not Implemented (TODO:)
|
RPL_TRACEHANDSHAKE = "202" // RFC1459 - Not Implemented (TODO:)
|
||||||
@@ -240,7 +241,7 @@ const (
|
|||||||
ERR_NOTOPLEVEL = "413" // RFC1459 - Not Implemented (TODO:)
|
ERR_NOTOPLEVEL = "413" // RFC1459 - Not Implemented (TODO:)
|
||||||
ERR_WILDTOPLEVEL = "414" // RFC1459 - Not Implemented (TODO:)
|
ERR_WILDTOPLEVEL = "414" // RFC1459 - Not Implemented (TODO:)
|
||||||
ERR_BADMASK = "415" // RFC2812 - Not Implemented (TODO:)
|
ERR_BADMASK = "415" // RFC2812 - Not Implemented (TODO:)
|
||||||
ERR_UNKNOWNCOMMAND = "421" // RFC1459 - Not Implemented (TODO:)
|
ERR_UNKNOWNCOMMAND = "421" // RFC1459 - Implemented
|
||||||
ERR_NOMOTD = "422" // RFC1459 - Not Implemented (TODO:)
|
ERR_NOMOTD = "422" // RFC1459 - Not Implemented (TODO:)
|
||||||
ERR_NOADMININFO = "423" // RFC1459 - Not Implemented (TODO:)
|
ERR_NOADMININFO = "423" // RFC1459 - Not Implemented (TODO:)
|
||||||
ERR_FILEERROR = "424" // RFC1459 - Not Implemented (TODO:)
|
ERR_FILEERROR = "424" // RFC1459 - Not Implemented (TODO:)
|
||||||
@@ -312,7 +313,7 @@ var Features = map[string]bool{
|
|||||||
"CHANLIMIT": true,
|
"CHANLIMIT": true,
|
||||||
"CHANMODES": true,
|
"CHANMODES": true,
|
||||||
"CHANNELLEN": true,
|
"CHANNELLEN": true,
|
||||||
"CHANTYPES": true,
|
"CHANTYPES": true, // Channel Types. Default is #. Available are #&
|
||||||
"CHARSET": true, // Deprecated but might still be used
|
"CHARSET": true, // Deprecated but might still be used
|
||||||
"CLIENTVER": true, // Deprecated but might still be used
|
"CLIENTVER": true, // Deprecated but might still be used
|
||||||
"CNOTICE": true,
|
"CNOTICE": true,
|
||||||
@@ -364,7 +365,42 @@ var Features = map[string]bool{
|
|||||||
"WHOX": true,
|
"WHOX": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages MUST end in CRLF and SHOULD be encoded and decoded using UTF-8 (with fallbacks such as Latin-1).
|
var Capabilities = map[string]bool{
|
||||||
// Names are casemapped, read the casemapping from the RPL_ISUPPORT the server sends when registration is completed.
|
// Twitch-specific capabilities
|
||||||
|
"twitch.tv/membership": false,
|
||||||
|
"twitch.tv/commands": false,
|
||||||
|
"twitch.tv/tags": false,
|
||||||
|
|
||||||
// When receiving a numeric reply, client MUST be able to handle any number of parameters on a numeric reply.
|
// Solanum-specific capabilities
|
||||||
|
"solanum.chat/identify-msg": false,
|
||||||
|
"solanum.chat/oper": false,
|
||||||
|
"solanum.chat/realhost": false,
|
||||||
|
|
||||||
|
// IRCv3 capabilities
|
||||||
|
"account-notify": false,
|
||||||
|
"account-registration": false, // Draft
|
||||||
|
"account-tag": false,
|
||||||
|
"away-notify": false,
|
||||||
|
"batch": false,
|
||||||
|
"cap-notify": true,
|
||||||
|
"channel-rename": false, // Draft
|
||||||
|
"chathistory": false, // Draft
|
||||||
|
"chghost": false,
|
||||||
|
"echo-message": false,
|
||||||
|
"event-playback": false, // Draft
|
||||||
|
"extended-join": false,
|
||||||
|
"extended-monitor": false,
|
||||||
|
"invite-notify": false,
|
||||||
|
"labeled-response": false,
|
||||||
|
"message-tags": false,
|
||||||
|
"metadata": false,
|
||||||
|
"monitor": false,
|
||||||
|
"multi-prefix": false,
|
||||||
|
"multiline": false, // Draft
|
||||||
|
"read-marker": false, // Draft
|
||||||
|
"sasl": false,
|
||||||
|
"server-time": true,
|
||||||
|
"setname": false,
|
||||||
|
"tls": false, // Deprecated
|
||||||
|
"userhost-in-names": false,
|
||||||
|
}
|
||||||
|
|||||||
@@ -169,6 +169,87 @@ func handlePart(msg parser.IRCMessage, client *irc.Client) {
|
|||||||
client.Tea.Send(cmds.SwitchChannels())
|
client.Tea.Send(cmds.SwitchChannels())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleCAP(msg parser.IRCMessage, client *irc.Client) {
|
||||||
|
switch msg.Parameters[1] {
|
||||||
|
case "LIST":
|
||||||
|
fallthrough
|
||||||
|
case "NEW":
|
||||||
|
fallthrough
|
||||||
|
case "LS":
|
||||||
|
caps := strings.Split(msg.Parameters[2], " ")
|
||||||
|
recognizedCaps := make([]irc.Capabilities, 0)
|
||||||
|
capabilities := make(irc.Capabilities, 0)
|
||||||
|
length := 0
|
||||||
|
|
||||||
|
for _, capability := range caps {
|
||||||
|
// NOTE: not sure if I should store the cap value the server advertises or use my own
|
||||||
|
parts := strings.Split(capability, "=")
|
||||||
|
key := parts[0]
|
||||||
|
value := ""
|
||||||
|
if len(parts) > 1 {
|
||||||
|
value = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if commands.Capabilities[key] {
|
||||||
|
// When the final parameter approaches 510 bytes,
|
||||||
|
// we send multiple REQ commands
|
||||||
|
// (https://ircv3.net/specs/extensions/capability-negotiation.html#the-cap-req-subcommand)
|
||||||
|
if length+len(capability) >= 500 {
|
||||||
|
recognizedCaps = append(recognizedCaps, capabilities)
|
||||||
|
capabilities = make(irc.Capabilities, 0)
|
||||||
|
length = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
capabilities[key] = value
|
||||||
|
length += len(capability)
|
||||||
|
} else {
|
||||||
|
log.Println("Unknown capability:", capability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recognizedCaps = append(recognizedCaps, capabilities)
|
||||||
|
|
||||||
|
for _, capsList := range recognizedCaps {
|
||||||
|
list := make([]string, 0)
|
||||||
|
for key, value := range capsList {
|
||||||
|
if len(value) > 0 {
|
||||||
|
list = append(list, key+"="+value)
|
||||||
|
} else {
|
||||||
|
list = append(list, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.SendCommand(commands.CAP, "REQ", strings.Join(list, " "))
|
||||||
|
}
|
||||||
|
client.SendCommand(commands.CAP, "END")
|
||||||
|
case "ACK":
|
||||||
|
caps := strings.Split(msg.Parameters[2], " ")
|
||||||
|
for _, capability := range caps {
|
||||||
|
if capability[0] == '-' {
|
||||||
|
delete(client.EnabledCapabilities, capability[1:])
|
||||||
|
} else {
|
||||||
|
parts := strings.Split(capability, "=")
|
||||||
|
key := parts[0]
|
||||||
|
value := ""
|
||||||
|
if len(parts) > 1 {
|
||||||
|
value = parts[1]
|
||||||
|
}
|
||||||
|
client.EnabledCapabilities[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "NAK":
|
||||||
|
caps := strings.Split(msg.Parameters[2], " ")
|
||||||
|
msgOpts := irc.MsgFmtOpts{
|
||||||
|
WithTimestamp: true,
|
||||||
|
AsServerMsg: true,
|
||||||
|
}
|
||||||
|
client.Channels[0].AppendMsg(msg.Timestamp, "Unrecognized capabilities: "+strings.Join(caps, " "), msgOpts)
|
||||||
|
case "DEL":
|
||||||
|
caps := strings.Split(msg.Parameters[2], " ")
|
||||||
|
for _, capability := range caps {
|
||||||
|
delete(client.EnabledCapabilities, capability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handleWELCOME(msg parser.IRCMessage, client *irc.Client) {
|
func handleWELCOME(msg parser.IRCMessage, client *irc.Client) {
|
||||||
nick := msg.Parameters[0]
|
nick := msg.Parameters[0]
|
||||||
welcomeMsg := msg.Parameters[1]
|
welcomeMsg := msg.Parameters[1]
|
||||||
@@ -467,6 +548,17 @@ func handleNOSUCHSERVER(msg parser.IRCMessage, client *irc.Client) {
|
|||||||
client.Channels[0].AppendMsg(msg.Timestamp, message, msgOpts)
|
client.Channels[0].AppendMsg(msg.Timestamp, message, msgOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleUNKNOWNCOMMAND(msg parser.IRCMessage, client *irc.Client) {
|
||||||
|
message := msg.Parameters[1] + " " + msg.Parameters[2]
|
||||||
|
|
||||||
|
msgOpts := irc.MsgFmtOpts{
|
||||||
|
WithTimestamp: true,
|
||||||
|
AsServerMsg: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Channels[0].AppendMsg(msg.Timestamp, message, msgOpts)
|
||||||
|
}
|
||||||
|
|
||||||
func handleNONICKNAMEGIVEN(msg parser.IRCMessage, client *irc.Client) {
|
func handleNONICKNAMEGIVEN(msg parser.IRCMessage, client *irc.Client) {
|
||||||
message := msg.Parameters[1]
|
message := msg.Parameters[1]
|
||||||
|
|
||||||
@@ -513,6 +605,8 @@ func HandleCommand(msg parser.IRCMessage, client *irc.Client) {
|
|||||||
handleQuit(msg, client)
|
handleQuit(msg, client)
|
||||||
case commands.PART:
|
case commands.PART:
|
||||||
handlePart(msg, client)
|
handlePart(msg, client)
|
||||||
|
case commands.CAP:
|
||||||
|
handleCAP(msg, client)
|
||||||
case commands.RPL_WELCOME:
|
case commands.RPL_WELCOME:
|
||||||
handleWELCOME(msg, client)
|
handleWELCOME(msg, client)
|
||||||
case commands.RPL_YOURHOST:
|
case commands.RPL_YOURHOST:
|
||||||
@@ -569,6 +663,8 @@ func HandleCommand(msg parser.IRCMessage, client *irc.Client) {
|
|||||||
handleWHOISMODES(msg, client)
|
handleWHOISMODES(msg, client)
|
||||||
case commands.ERR_NOSUCHSERVER:
|
case commands.ERR_NOSUCHSERVER:
|
||||||
handleNOSUCHSERVER(msg, client)
|
handleNOSUCHSERVER(msg, client)
|
||||||
|
case commands.ERR_UNKNOWNCOMMAND:
|
||||||
|
handleUNKNOWNCOMMAND(msg, client)
|
||||||
case commands.ERR_NONICKNAMEGIVEN:
|
case commands.ERR_NONICKNAMEGIVEN:
|
||||||
handleNONICKNAMEGIVEN(msg, client)
|
handleNONICKNAMEGIVEN(msg, client)
|
||||||
case commands.ERR_NEEDMOREPARAMS:
|
case commands.ERR_NEEDMOREPARAMS:
|
||||||
|
|||||||
+55
-2
@@ -18,6 +18,7 @@ package parser
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -34,10 +35,45 @@ type IRCMessage struct {
|
|||||||
type Tags map[string]string
|
type Tags map[string]string
|
||||||
|
|
||||||
func (m *IRCMessage) setTimestamp() {
|
func (m *IRCMessage) setTimestamp() {
|
||||||
// TODO: get timestamp from time tag
|
if serverTime, ok := m.Tags["time"]; ok {
|
||||||
|
t, err := time.Parse("2006-01-02T15:04:05.000Z", serverTime)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: properly handle error
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
m.Timestamp = fmt.Sprintf("[%02d:%02d]", t.Local().Hour(), t.Local().Minute())
|
||||||
|
} else {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
m.Timestamp = fmt.Sprintf("[%02d:%02d]", now.Hour(), now.Minute())
|
m.Timestamp = fmt.Sprintf("[%02d:%02d]", now.Hour(), now.Minute())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func escapeCharacters(char rune) string {
|
||||||
|
switch char {
|
||||||
|
case 's':
|
||||||
|
return " "
|
||||||
|
case 'n':
|
||||||
|
return "\n"
|
||||||
|
case 'r':
|
||||||
|
return "\r"
|
||||||
|
case 'b':
|
||||||
|
return "\b"
|
||||||
|
case 't':
|
||||||
|
return "\t"
|
||||||
|
case 'f':
|
||||||
|
return "\f"
|
||||||
|
case ':':
|
||||||
|
return ";"
|
||||||
|
case '\\':
|
||||||
|
fallthrough
|
||||||
|
case '\'':
|
||||||
|
fallthrough
|
||||||
|
case '"':
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return string(char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func parseTags(rawTags string) Tags {
|
func parseTags(rawTags string) Tags {
|
||||||
tags := make(Tags, 0)
|
tags := make(Tags, 0)
|
||||||
@@ -51,7 +87,24 @@ func parseTags(rawTags string) Tags {
|
|||||||
|
|
||||||
// we need to make sure a "value" exists before accessing str[1]
|
// we need to make sure a "value" exists before accessing str[1]
|
||||||
if len(str) > 1 {
|
if len(str) > 1 {
|
||||||
value = str[1]
|
rawValue := str[1]
|
||||||
|
for idx := 0; idx < len(rawValue); {
|
||||||
|
// if we have a backslash at the end of the string
|
||||||
|
// we need to ignore it
|
||||||
|
if idx == len(rawValue)-1 && rawValue[idx] == '\\' {
|
||||||
|
idx += 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if rawValue[idx] == '\\' {
|
||||||
|
value += escapeCharacters(rune(rawValue[idx+1]))
|
||||||
|
idx += 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
value += string(rawValue[idx])
|
||||||
|
idx++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tags[key] = value
|
tags[key] = value
|
||||||
|
|||||||
@@ -341,7 +341,6 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: fails
|
|
||||||
t.Run("Test escaped tags", func(t *testing.T) {
|
t.Run("Test escaped tags", func(t *testing.T) {
|
||||||
testMessage := "@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo"
|
testMessage := "@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo"
|
||||||
ircMessage, valid := ParseIRCMessage(testMessage)
|
ircMessage, valid := ParseIRCMessage(testMessage)
|
||||||
@@ -401,7 +400,6 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: FAIL
|
|
||||||
t.Run("Test single param with preceeding :", func(t *testing.T) {
|
t.Run("Test single param with preceeding :", func(t *testing.T) {
|
||||||
testMessage := ":src JOIN :#chan"
|
testMessage := ":src JOIN :#chan"
|
||||||
ircMessage, valid := ParseIRCMessage(testMessage)
|
ircMessage, valid := ParseIRCMessage(testMessage)
|
||||||
@@ -652,7 +650,6 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: FAIL
|
|
||||||
t.Run("Test yaml encoding with slashes", func(t *testing.T) {
|
t.Run("Test yaml encoding with slashes", func(t *testing.T) {
|
||||||
testMessage := "@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND"
|
testMessage := "@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND"
|
||||||
ircMessage, valid := ParseIRCMessage(testMessage)
|
ircMessage, valid := ParseIRCMessage(testMessage)
|
||||||
@@ -749,7 +746,6 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: FAIL
|
|
||||||
t.Run("Test tags. they should be parsed char-at-a-time", func(t *testing.T) {
|
t.Run("Test tags. they should be parsed char-at-a-time", func(t *testing.T) {
|
||||||
testMessage := "@tag1=value\\\\ntest COMMAND"
|
testMessage := "@tag1=value\\\\ntest COMMAND"
|
||||||
ircMessage, valid := ParseIRCMessage(testMessage)
|
ircMessage, valid := ParseIRCMessage(testMessage)
|
||||||
@@ -771,7 +767,6 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: FAIl
|
|
||||||
t.Run("Test tag escape for char that doesn't need it", func(t *testing.T) {
|
t.Run("Test tag escape for char that doesn't need it", func(t *testing.T) {
|
||||||
testMessage := "@tag1=value\\1 COMMAND"
|
testMessage := "@tag1=value\\1 COMMAND"
|
||||||
ircMessage, valid := ParseIRCMessage(testMessage)
|
ircMessage, valid := ParseIRCMessage(testMessage)
|
||||||
@@ -789,7 +784,6 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: FAIL
|
|
||||||
t.Run("Test slash at end of tag", func(t *testing.T) {
|
t.Run("Test slash at end of tag", func(t *testing.T) {
|
||||||
testMessage := "@tag1=value1\\ COMMAND"
|
testMessage := "@tag1=value1\\ COMMAND"
|
||||||
ircMessage, valid := ParseIRCMessage(testMessage)
|
ircMessage, valid := ParseIRCMessage(testMessage)
|
||||||
|
|||||||
+4
-1
@@ -61,18 +61,21 @@ func NewLogin() State {
|
|||||||
t.Focus()
|
t.Focus()
|
||||||
t.CharLimit = 40
|
t.CharLimit = 40
|
||||||
t.TextStyle = FocusedStyle
|
t.TextStyle = FocusedStyle
|
||||||
|
t.Validate = NoSpacesValidation
|
||||||
case 1:
|
case 1:
|
||||||
t.Placeholder = "Port"
|
t.Placeholder = "Port"
|
||||||
t.CharLimit = 5
|
t.CharLimit = 5
|
||||||
|
t.Validate = ValidatePort
|
||||||
case 2:
|
case 2:
|
||||||
t.Placeholder = "Channel"
|
t.Placeholder = "Channel"
|
||||||
t.CharLimit = 32
|
t.CharLimit = 32
|
||||||
case 3:
|
case 3:
|
||||||
t.Placeholder = "Nickname"
|
t.Placeholder = "Nickname"
|
||||||
t.CharLimit = 32
|
t.CharLimit = 32
|
||||||
|
t.Validate = NoSpacesValidation
|
||||||
case 4:
|
case 4:
|
||||||
t.Placeholder = "Password"
|
t.Placeholder = "Password"
|
||||||
t.CharLimit = 32
|
t.CharLimit = 64
|
||||||
t.EchoMode = textinput.EchoPassword
|
t.EchoMode = textinput.EchoPassword
|
||||||
t.EchoCharacter = '•'
|
t.EchoCharacter = '•'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// gorc project
|
||||||
|
// Copyright (C) 2023 IllusionMan1212
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see https://www.gnu.org/licenses.
|
||||||
|
|
||||||
|
package login
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NoSpacesValidation(input string) error {
|
||||||
|
if strings.Contains(input, " ") {
|
||||||
|
return errors.New("Field cannot contain spaces")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidatePort(input string) error {
|
||||||
|
pNum, err := strconv.ParseUint(input, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pNum < 1 || pNum > 65535 {
|
||||||
|
return errors.New("Invalid port number")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -57,7 +57,6 @@ type State struct {
|
|||||||
|
|
||||||
func NewMainScreen(client *irc.Client) State {
|
func NewMainScreen(client *irc.Client) State {
|
||||||
newViewport := viewport.New(0, 0)
|
newViewport := viewport.New(0, 0)
|
||||||
newViewport.Wrap = viewport.Wrap
|
|
||||||
newViewport.Style = MessagesStyle.Copy()
|
newViewport.Style = MessagesStyle.Copy()
|
||||||
|
|
||||||
return State{
|
return State{
|
||||||
@@ -227,13 +226,13 @@ func (s *State) Blur() {
|
|||||||
|
|
||||||
func (s *State) SetSize(width, height int) {
|
func (s *State) SetSize(width, height int) {
|
||||||
s.InputBox.SetSize(width)
|
s.InputBox.SetSize(width)
|
||||||
s.SidePanel.SetSize(width, height, s.InputBox.Style.GetVerticalFrameSize())
|
s.SidePanel.SetSize(width, height, s.InputBox.Style.GetVerticalPadding())
|
||||||
|
|
||||||
// We floor because width is an int and some fractions are lost when casting
|
// We floor because width is an int and some fractions are lost when casting
|
||||||
// and also because we ceil the sidepanel's width
|
// and also because we ceil the sidepanel's width
|
||||||
// -3 for the tab bar height
|
// -3 for the tab bar height
|
||||||
newWidth := int(math.Floor(float64(width)*8/10) - float64(s.Viewport.Style.GetHorizontalFrameSize()))
|
newWidth := int(math.Floor(float64(width) * 8 / 10))
|
||||||
newHeight := height - s.InputBox.Style.GetVerticalFrameSize() - s.Viewport.Style.GetVerticalFrameSize() - 3
|
newHeight := height - s.InputBox.Style.GetVerticalFrameSize() - 3
|
||||||
|
|
||||||
s.Viewport.Width = newWidth
|
s.Viewport.Width = newWidth
|
||||||
s.Viewport.Height = newHeight
|
s.Viewport.Height = newHeight
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (s *SidePanelState) getHeader() string {
|
|||||||
if len(s.Client.Channels) != 0 {
|
if len(s.Client.Channels) != 0 {
|
||||||
usersCount = len(s.Client.Channels[s.Client.ActiveChannelIndex].Users)
|
usersCount = len(s.Client.Channels[s.Client.ActiveChannelIndex].Users)
|
||||||
}
|
}
|
||||||
separator := strings.Repeat("—", s.Viewport.Width) + "\n"
|
separator := strings.Repeat("—", s.Viewport.Width-s.Viewport.Style.GetHorizontalFrameSize()) + "\n"
|
||||||
header := fmt.Sprintf("Users in this channel (%d)\n", usersCount) + separator
|
header := fmt.Sprintf("Users in this channel (%d)\n", usersCount) + separator
|
||||||
|
|
||||||
return header
|
return header
|
||||||
@@ -61,7 +61,6 @@ func (s *SidePanelState) getLatestNicks() []string {
|
|||||||
func NewSidePanel(client *irc.Client) *SidePanelState {
|
func NewSidePanel(client *irc.Client) *SidePanelState {
|
||||||
newViewport := viewport.New(0, 0)
|
newViewport := viewport.New(0, 0)
|
||||||
newViewport.Style = SidePanelStyle.Copy()
|
newViewport.Style = SidePanelStyle.Copy()
|
||||||
newViewport.Wrap = viewport.Wrap
|
|
||||||
|
|
||||||
return &SidePanelState{
|
return &SidePanelState{
|
||||||
Client: client,
|
Client: client,
|
||||||
@@ -119,7 +118,7 @@ func (s *SidePanelState) UpdateNicks() {
|
|||||||
func (s *SidePanelState) SetSize(width, height, inputboxHeight int) {
|
func (s *SidePanelState) SetSize(width, height, inputboxHeight int) {
|
||||||
// We ceil here because width is an int and some fractions are lost
|
// We ceil here because width is an int and some fractions are lost
|
||||||
// -1 is for some extra invisible margin or padding between the sidepanel and the inputbox
|
// -1 is for some extra invisible margin or padding between the sidepanel and the inputbox
|
||||||
newWidth := int(math.Ceil(math.Ceil((float64(width) * 2 / 10)) - float64(s.Viewport.Style.GetHorizontalFrameSize())))
|
newWidth := int(math.Ceil((float64(width) * 2 / 10)))
|
||||||
newHeight := height - inputboxHeight - s.Viewport.Style.GetVerticalFrameSize() - 1
|
newHeight := height - inputboxHeight - s.Viewport.Style.GetVerticalFrameSize() - 1
|
||||||
|
|
||||||
s.Viewport.Style = s.Viewport.Style.Width(newWidth)
|
s.Viewport.Style = s.Viewport.Style.Width(newWidth)
|
||||||
|
|||||||
Reference in New Issue
Block a user