Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# CancelReader

[![Latest Release](https://img.shields.io/github/release/muesli/cancelreader.svg?style=for-the-badge)](https://github.com/muesli/cancelreader/releases)
[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://pkg.go.dev/github.com/muesli/cancelreader)
[![Latest Release](https://img.shields.io/github/release/abakum/cancelreader.svg?style=for-the-badge)](https://github.com/abakum/cancelreader/releases)
[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://pkg.go.dev/github.com/abakum/cancelreader)
[![Software License](https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge)](/LICENSE)
[![Build Status](https://img.shields.io/github/workflow/status/muesli/cancelreader/build?style=for-the-badge)](https://github.com/muesli/cancelreader/actions)
[![Go ReportCard](https://goreportcard.com/badge/github.com/muesli/cancelreader?style=for-the-badge)](https://goreportcard.com/report/muesli/cancelreader)
[![Build Status](https://img.shields.io/github/workflow/status/abakum/cancelreader/build?style=for-the-badge)](https://github.com/abakum/cancelreader/actions)
[![Go ReportCard](https://goreportcard.com/badge/github.com/abakum/cancelreader?style=for-the-badge)](https://goreportcard.com/report/abakum/cancelreader)

A cancelable reader for Go

Expand Down
16 changes: 5 additions & 11 deletions cancelreader_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"io"
"os"
"strings"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -92,30 +91,25 @@ func (r *kqueueCancelReader) Cancel() bool {
}

func (r *kqueueCancelReader) Close() error {
var errMsgs []string

var e1, e2, e3 error
// close kqueue
err := unix.Close(r.kQueue)
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing kqueue: %v", err))
e1 = fmt.Errorf("closing kqueue: %w", err)
}

// close pipe
err = r.cancelSignalWriter.Close()
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal writer: %v", err))
e2 = fmt.Errorf("closing cancel signal writer: %w", err)
}

err = r.cancelSignalReader.Close()
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal reader: %v", err))
}

if len(errMsgs) > 0 {
return fmt.Errorf(strings.Join(errMsgs, ", "))
e3 = fmt.Errorf("closing cancel signal reader: %w", err)
}

return nil
return errors.Join(e1, e2, e3)
}

func (r *kqueueCancelReader) wait() error {
Expand Down
14 changes: 5 additions & 9 deletions cancelreader_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"io"
"os"
"strings"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -101,30 +100,27 @@ func (r *epollCancelReader) Cancel() bool {
}

func (r *epollCancelReader) Close() error {
var errMsgs []string
var e1, e2, e3 error

// close kqueue
err := unix.Close(r.epoll)
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing epoll: %v", err))
e1 = fmt.Errorf("closing epoll: %w", err)
}

// close pipe
err = r.cancelSignalWriter.Close()
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal writer: %v", err))
e2 = fmt.Errorf("closing cancel signal writer: %w", err)
}

err = r.cancelSignalReader.Close()
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal reader: %v", err))
e3 = fmt.Errorf("closing cancel signal reader: %w", err)
}

if len(errMsgs) > 0 {
return fmt.Errorf(strings.Join(errMsgs, ", "))
}
return errors.Join(e1, e2, e3)

return nil
}

func (r *epollCancelReader) wait() error {
Expand Down
13 changes: 4 additions & 9 deletions cancelreader_select.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"io"
"os"
"strings"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -81,24 +80,20 @@ func (r *selectCancelReader) Cancel() bool {
}

func (r *selectCancelReader) Close() error {
var errMsgs []string
var e1, e2 error

// close pipe
err := r.cancelSignalWriter.Close()
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal writer: %v", err))
e1 = fmt.Errorf("closing cancel signal writer: %w", err)
}

err = r.cancelSignalReader.Close()
if err != nil {
errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal reader: %v", err))
e2 = fmt.Errorf("closing cancel signal reader: %w", err)
}

if len(errMsgs) > 0 {
return fmt.Errorf(strings.Join(errMsgs, ", "))
}

return nil
return errors.Join(e1, e2)
}

func waitForRead(reader, abort File) error {
Expand Down
67 changes: 7 additions & 60 deletions cancelreader_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cancelreader

import (
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -37,11 +38,6 @@ func NewReader(reader io.Reader) (CancelReader, error) {
return nil, fmt.Errorf("open CONIN$ in overlapping mode: %w", err)
}

resetConsole, err := prepareConsole(conin)
if err != nil {
return nil, fmt.Errorf("prepare console: %w", err)
}

// flush input, otherwise it can contain events which trigger
// WaitForMultipleObjects but which ReadFile cannot read, resulting in an
// un-cancelable read
Expand All @@ -58,7 +54,6 @@ func NewReader(reader io.Reader) (CancelReader, error) {
return &winCancelReader{
conin: conin,
cancelEvent: cancelEvent,
resetConsole: resetConsole,
blockingReadSignal: make(chan struct{}, 1),
}, nil
}
Expand All @@ -68,7 +63,6 @@ type winCancelReader struct {
cancelEvent windows.Handle
cancelMixin

resetConsole func() error
blockingReadSignal chan struct{}
}

Expand Down Expand Up @@ -116,22 +110,17 @@ func (r *winCancelReader) Cancel() bool {
}

func (r *winCancelReader) Close() error {
err := windows.CloseHandle(r.cancelEvent)
if err != nil {
return fmt.Errorf("closing cancel event handle: %w", err)
}
var e1, e2 error

err = r.resetConsole()
if err != nil {
return err
if err := windows.CloseHandle(r.cancelEvent); err != nil {
e1 = fmt.Errorf("closing cancel event handle: %w", err)
}

err = windows.Close(r.conin)
if err != nil {
return fmt.Errorf("closing CONIN$")
if err := windows.Close(r.conin); err != nil {
e2 = fmt.Errorf("closing CONIN$: %w", err)
}

return nil
return errors.Join(e1, e2)
}

func (r *winCancelReader) wait() error {
Expand Down Expand Up @@ -186,48 +175,6 @@ func (r *winCancelReader) readAsync(data []byte) (int, error) {
return int(n), nil
}

func prepareConsole(input windows.Handle) (reset func() error, err error) {
var originalMode uint32

err = windows.GetConsoleMode(input, &originalMode)
if err != nil {
return nil, fmt.Errorf("get console mode: %w", err)
}

var newMode uint32
newMode &^= windows.ENABLE_ECHO_INPUT
newMode &^= windows.ENABLE_LINE_INPUT
newMode &^= windows.ENABLE_MOUSE_INPUT
newMode &^= windows.ENABLE_WINDOW_INPUT
newMode &^= windows.ENABLE_PROCESSED_INPUT

newMode |= windows.ENABLE_EXTENDED_FLAGS
newMode |= windows.ENABLE_INSERT_MODE
newMode |= windows.ENABLE_QUICK_EDIT_MODE

// Enabling virtual terminal input is necessary for processing certain
// types of input like X10 mouse events and arrows keys with the current
// bytes-based input reader. It does, however, prevent cancelReader from
// being able to cancel input. The planned solution for this is to read
// Windows events in a more native fashion, rather than the current simple
// bytes-based input reader which works well on unix systems.
newMode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT

err = windows.SetConsoleMode(input, newMode)
if err != nil {
return nil, fmt.Errorf("set console mode: %w", err)
}

return func() error {
err := windows.SetConsoleMode(input, originalMode)
if err != nil {
return fmt.Errorf("reset console mode: %w", err)
}

return nil
}, nil
}

var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer")
Expand Down
7 changes: 7 additions & 0 deletions command/etc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !windows
// +build !windows

package main

func ConsoleCP(*bool) {}
func IsCygwinTerminal(fd uintptr) bool { return false }
Loading