Repository: junegunn/fzf
File: src/terminal.go (Go)

Code before:
func (t *Terminal) killPreview(code int) {
	select {
	case t.killChan <- code:
	default:
		if code != exitCancel {
			os.Exit(code)
		}
	}
}

func (t *Terminal) cancelPreview() {
	t.killPreview(exitCancel)
}

// Loop is called to start Terminal I/O
func (t *Terminal) Loop() {
	// prof := profile.Start(profile.ProfilePath("/tmp/"))
	<-t.startChan
	{ // Late initialization
		intChan := make(chan os.Signal, 1)
		signal.Notify(intChan, os.Interrupt, syscall.SIGTERM)
		go func() {
			for {
				s := <-intChan
				// Don't quit by SIGINT while executing because it should be for the executing command and not for fzf itself
				if !(s == os.Interrupt && t.executing) {
					t.reqBox.Set(reqQuit, nil)
				}
			}
		}()

		contChan := make(chan os.Signal, 1)
		notifyOnCont(contChan)
		go func() {
			for {
				<-contChan
				t.reqBox.Set(reqReinit, nil)
			}
		}()

		resizeChan := make(chan os.Signal, 1)
		notifyOnResize(resizeChan) // Non-portable
		go func() {
			for {
				<-resizeChan
				t.reqBox.Set(reqRedraw, nil)
			}
		}()

		t.mutex.Lock()
		t.initFunc()

Review comment (bug):
This will generate a race condition warning.

```sh
rm /tmp/race.*; GORACE="log_path=/tmp/race" go run -race main.go --bind 'ctrl-l:execute:sleep 10'; cat /tmp/race.*
```

```
==================
WARNING: DATA RACE
Read at 0x00c000100d18 by goroutine 13:
  github.com/junegunn/fzf/src.(*Terminal).Loop.func1()
      /Users/jg/gdrive/sync/projects/fzf/src/terminal.go:1849 +0xe7

Previous write at 0x00c000100d18 by goroutine 10:
  github.com/junegunn/fzf/src.(*Terminal).executeCommand()
      /Users/jg/gdrive/sync/projects/fzf/src/terminal.go:1718 +0x509
  github.com/junegunn/fzf/src.(*Terminal).Loop.func17()
      /Users/jg/gdrive/sync/projects/fzf/src/terminal.go:2233 +0x6bcf
  github.com/junegunn/fzf/src.(*Terminal).Loop.func16()
      /Users/jg/gdrive/sync/projects/fzf/src/terminal.go:2223 +0xdb
  github.com/junegunn/fzf/src.(*Terminal).Loop()
      /Users/jg/gdrive/sync/projects/fzf/src/terminal.go:2628 +0x11dd

Goroutine 13 (running) created at:
  github.com/junegunn/fzf/src.(*Terminal).Loop()
      /Users/jg/gdrive/sync/projects/fzf/src/terminal.go:1845 +0x16b

Goroutine 10 (running) created at:
  github.com/junegunn/fzf/src.Run()
      /Users/jg/gdrive/sync/projects/fzf/src/core.go:220 +0xe5e
  main.main()
      /Users/jg/gdrive/sync/projects/fzf/main.go:13 +0xae
==================
```

Let's use an [AtomicBool](https://github.com/bitterfox/fzf/blob/sigint_while_executing/src/util/atomicbool.go).

Code after:
func (t *Terminal) killPreview(code int) {
	select {
	case t.killChan <- code:
	default:
		if code != exitCancel {
			os.Exit(code)
		}
	}
}

func (t *Terminal) cancelPreview() {
	t.killPreview(exitCancel)
}

// Loop is called to start Terminal I/O
func (t *Terminal) Loop() {
	// prof := profile.Start(profile.ProfilePath("/tmp/"))
	<-t.startChan
	{ // Late initialization
		intChan := make(chan os.Signal, 1)
		signal.Notify(intChan, os.Interrupt, syscall.SIGTERM)
		go func() {
			for s := range intChan {
				// Don't quit by SIGINT while executing because it should be for the executing command and not for fzf itself
				if !(s == os.Interrupt && t.executing.Get()) {
					t.reqBox.Set(reqQuit, nil)
				}
			}
		}()

		contChan := make(chan os.Signal, 1)
		notifyOnCont(contChan)
		go func() {
			for {
				<-contChan
				t.reqBox.Set(reqReinit, nil)
			}
		}()

		resizeChan := make(chan os.Signal, 1)
		notifyOnResize(resizeChan) // Non-portable
		go func() {
			for {
				<-resizeChan
				t.reqBox.Set(reqRedraw, nil)
			}
		}()

		t.mutex.Lock()
		t.initFunc()
		t.resizeWindows()