gizak / termui

Golang terminal dashboard
MIT License
13.14k stars 787 forks source link

The calling order of event handlers is non-deterministic #99

Closed z-rui closed 7 years ago

z-rui commented 8 years ago

It can be seen that (in events.go) the event handlers are called in a separate goroutine. Therefore, there is no guarantee of the order of the handlers being called.

This is especially harmful to keyboard events. Consider this situation: some characters are pasted to the terminal and so a bunch of keyboard events are generated in a short time, but the order of the corresponding handlers being called are kind of random. If the program is a text editor, the actual pasted text will be shuffled.

To fix the problem, event handlers should be called synchrously. A separate goroutine can always be created in the event handler if needed.

PS: The order of keyboard events seemed to be preserved after I changed two go statements (in evtKbd() and (*EvtStream) Loop()) to simple synchrounous function calls.

wanzysky commented 7 years ago

+1

hasryan commented 7 years ago

@z-rui can you share the code changes you made? I am trying to accept strings pasted from the clipboard but the characters arrived in scrambled order, and I suspect it is caused by the issue you've described here.

z-rui commented 7 years ago

Last time I tried:

diff --git a/events.go b/events.go
index 177bbb4..3ff7fdd 100644
--- a/events.go
+++ b/events.go
@@ -126,7 +126,7 @@ func hookTermboxEvt() {
                e := termbox.PollEvent()

                for _, c := range sysEvtChs {
-                       go func(ch chan Event) {
+                       func(ch chan Event) {
                                ch <- crtTermboxEvt(e)
                        }(c)
                }
@@ -236,7 +236,7 @@ func (es *EvtStream) Loop() {
                case "/sig/stoploop":
                        return
                }
-               go func(a Event) {
+               func(a Event) {
                        es.RLock()
                        defer es.RUnlock()
                        if pattern := es.match(a.Path); pattern != "" {
hasryan commented 7 years ago

Thank you @z-rui your patch fixed the problem for me.