<commit_before>// Package httpexpect helps with end-to-end HTTP and REST API testing.
//
// Usage examples
//
// See example directory:
//  - https://godoc.org/github.com/gavv/httpexpect/example
//  - https://github.com/gavv/httpexpect/tree/master/example
//
// Communication mode
//
// There are two common ways to test API with httpexpect:
//  - start HTTP server and instruct httpexpect to use HTTP client for communication
//  - don't start server and instruct httpexpect to invoke http handler directly
//
// The second approach works only if the server is a Go module and its handler can
// be imported in tests.
//
// Concrete behaviour is determined by Client implementation passed to Config struct.
// If you're using http.Client, set its Transport field (http.RoundTriper) to one of
// the following:
//  1. default (nil) - use regular HTTP transport from net/http (you should start server)
//  2. httpexpect.Binder - invoke given http.Handler directly
//  4. httpexpect.FastBinder - invoke given fasthttp.RequestHandler directly
//
// Note that http handler can be usually obtained from http framework you're using.
// E.g., echo framework provides either http.Handler or fasthttp.RequestHandler.
//
// You can also provide your own Client or http.RoundTriper implementation and do
// whatever you want to convert http.Request to http.Response.
//
// If you're starting server from tests, it's very handy to use net/http/httptest
// for that.
//
// Value equality
//
// Whenever values are checked for equality in httpexpect, they are converted
// to "canonical form":
//  - type aliases are removed
//  - numeric types are converted to float64
//  - non-nil interfaces pointing to nil slices and maps are replaced with nil interfaces
//  - structs are converted to map[string]interface{}
//
// This is equivalent to subsequently json.Marshal() and json.Unmarshal() the value
// and currently is implemented so.
//
// Failure handling
//
// When some check fails, failure is reported. If non-fatal failures are used
// (see Reporter interface), execution is continued and instance that was checked
// is marked as failed.
//
// If specific instance is marked as failed, all subsequent checks are ignored
// for this instance and for any child instances retrieved after failure.
//
// Example:
//  array := NewArray(NewAssertReporter(t), []interface{}{"foo", 123})
//
//  e0 := array.Element(0)  // success
//  e1 := array.Element(1)  // success
//
//  s0 := e0.String()       // success
//  s1 := e1.String()       // failure; e1 and s1 are marked as failed, e0 and s0 are not
//
//  s0.Equal("foo")         // success
//  s1.Equal("bar")         // this check is ignored because s1 is marked as failed
package httpexpect

import (
	"golang.org/x/net/publicsuffix"
	"net/http"
	"net/http/cookiejar"
	"testing"
	"time"
)

// Expect is a toplevel object that contains user Config and allows
// to construct Request objects.
type Expect struct {
	config   Config
	builders []func(*Request)
}

// Config contains various settings.
type Config struct {
	// BaseURL is a URL to prepended to all request. My be empty. If
	// non-empty, trailing slash is allowed but not required and is
	// appended automatically.
	BaseURL string

	// Client is used to send http.Request and receive http.Response.
	// Should not be nil.
	//
	// You can use http.DefaultClient or http.Client, or provide
	// custom implementation.
	Client Client

	// Reporter is used to report failures.
	// Should not be nil.
	//
	// You can use AssertReporter, RequireReporter (they use testify),
	// or testing.T, or provide custom implementation.
	Reporter Reporter

	// Printers are used to print requests and responses.
	// May be nil.
	//
	// You can use CompactPrinter, DebugPrinter, CurlPrinter, or provide
	// custom implementation.
	//
	// You can also use builtin printers with alternative Logger if
	// you're happy with their format, but want to send logs somewhere
	// else instead of testing.T.
	Printers []Printer
}

// Client is used to send http.Request and receive http.Response.
// http.Client, Binder, and FastBinder implement this interface.
type Client interface {
	// Do sends request and returns response.
	Do(*http.Request) (*http.Response, error)
}

// Printer is used to print requests and responses.
// CompactPrinter, DebugPrinter, and CurlPrinter implement this interface.
type Printer interface {
	// Request is called before request is sent.
	Request(*http.Request)

	// Response is called after response is received.
	Response(*http.Response, time.Duration)
}

// Logger is used as output backend for Printer.
// testing.T implements this interface.
type Logger interface {
	// Logf writes message to log.
	Logf(fmt string, args ...interface{})
}

// Reporter is used to report failures.
// testing.T implements this interface. AssertReporter and RequireReporter,
// also implement this interface using testify.
type Reporter interface {
	// Errorf reports failure.
	// Allowed to return normally or terminate test using t.FailNow().
	Errorf(message string, args ...interface{})
}

// New returns a new Expect object.
//
// baseURL specifies URL to prepended to all request. My be empty. If non-empty,
// trailing slash is allowed but not required and is appended automatically.
//
// New is a shorthand for WithConfig. It uses:
//  - CompactPrinter as Printer with testing.T as Logger
//  - AssertReporter as Reporter
//
// Client is set to default client with non-nil Jar:
//  &http.Client{
//      Jar: httpexpect.NewJar(),
//  }
//
// Example:
//  func TestSomething(t *testing.T) {
//      e := httpexpect.New(t, "http://example.com/")
//
//      e.GET("/path").
//          Expect().
//          Status(http.StatusOK)
//  }
func New(t *testing.T, baseURL string) *Expect {
	return WithConfig(Config{
		BaseURL:  baseURL,
		Reporter: NewAssertReporter(t),
		Printers: []Printer{
			NewCompactPrinter(t),
		},
	})
}

// WithConfig returns a new Expect object with given config.
//
// Reporter should not be nil.
//
// If Client is nil, it's set to default client with non-nil Jar:
//  &http.Client{
//      Jar: httpexpect.NewJar(),
//  }
//
// Example:
//  func TestSomething(t *testing.T) {
//      e := httpexpect.WithConfig(httpexpect.Config{
//          BaseURL:  "http://example.com/",
//          Client:   &http.Client{
//              Transport: httpexpect.NewBinder(myHandler()),
//              Jar:       httpexpect.NewJar(),
//          },
//          Reporter: httpexpect.NewAssertReporter(t),
//          Printers: []httpexpect.Printer{
//              httpexpect.NewCurlPrinter(t),
//              httpexpect.NewDebugPrinter(t, true)
//          },
//      })
//
//      e.GET("/path").
//          Expect().
//          Status(http.StatusOK)
//  }
func WithConfig(config Config) *Expect {
	if config.Reporter == nil {
		panic("config.Reporter is nil")
	}
	if config.Client == nil {
		config.Client = &http.Client{
			Jar: NewJar(),
		}
	}
	return &Expect{
		config:   config,
		builders: nil,
	}
}

// NewJar returns a new http.CookieJar.
//
// Returned jar is implemented in net/http/cookiejar. PublicSuffixList is
// implemented in golang.org/x/net/publicsuffix.
//
// Note that this jar ignores cookies when request url is empty.
func NewJar() http.CookieJar {
	jar, err := cookiejar.New(&cookiejar.Options{
		PublicSuffixList: publicsuffix.List,
	})
	if err != nil {
		panic(err)
	}
	return jar
}

// Builder returns a copy of Expect instance with given builder attached to it.
// Returned copy contains all previously attached builders plus a new one.
// Builders are invoked from Request method, after constructing every new request.
//
// Example:
//  e := httpexpect.New(t, "http://example.com")
//
//  token := e.POST("/login").WithForm(Login{"ford", "betelgeuse7"}).
//      Expect().
//      Status(http.StatusOK).JSON().Object().Value("token").String().Raw()
//
//  auth := e.Builder(func (req *httpexpect.Request) {
//      req.WithHeader("Authorization", "Bearer "+token)
//  })
//
//  auth.GET("/restricted").
//     Expect().
//     Status(http.StatusOK)
func (e *Expect) Builder(builder func(*Request)) *Expect {
	ret := *e
	ret.builders = append(e.builders, builder)
	return &ret
}

// Request returns a new Request object.
// Arguments a similar to NewRequest.
// After creating request, all builders attached to Expect object are invoked.
// See Builder.
func (e *Expect) Request(method, path string, pathargs ...interface{}) *Request {
	req := NewRequest(e.config, method, path, pathargs...)

	for _, builder := range e.builders {
		builder(req)
	}

	return req
}

// OPTIONS is a shorthand for e.Request("OPTIONS", path, pathargs...).
func (e *Expect) OPTIONS(path string, pathargs ...interface{}) *Request {
	return e.Request("OPTIONS", path, pathargs...)
}

// HEAD is a shorthand for e.Request("HEAD", path, pathargs...).
func (e *Expect) HEAD(path string, pathargs ...interface{}) *Request {
	return e.Request("HEAD", path, pathargs...)
}

// GET is a shorthand for e.Request("GET", path, pathargs...).
func (e *Expect) GET(path string, pathargs ...interface{}) *Request {
	return e.Request("GET", path, pathargs...)
}

// POST is a shorthand for e.Request("POST", path, pathargs...).
func (e *Expect) POST(path string, pathargs ...interface{}) *Request {
	return e.Request("POST", path, pathargs...)
}

// PUT is a shorthand for e.Request("PUT", path, pathargs...).
func (e *Expect) PUT(path string, pathargs ...interface{}) *Request {
	return e.Request("PUT", path, pathargs...)
}

// PATCH is a shorthand for e.Request("PATCH", path, pathargs...).
func (e *Expect) PATCH(path string, pathargs ...interface{}) *Request {
	return e.Request("PATCH", path, pathargs...)
}

// DELETE is a shorthand for e.Request("DELETE", path, pathargs...).
func (e *Expect) DELETE(path string, pathargs ...interface{}) *Request {
	return e.Request("DELETE", path, pathargs...)
}

// Value is a shorthand for NewValue(e.config.Reporter, value).
func (e *Expect) Value(value interface{}) *Value {
	return NewValue(e.config.Reporter, value)
}

// Object is a shorthand for NewObject(e.config.Reporter, value).
func (e *Expect) Object(value map[string]interface{}) *Object {
	return NewObject(e.config.Reporter, value)
}

// Array is a shorthand for NewArray(e.config.Reporter, value).
func (e *Expect) Array(value []interface{}) *Array {
	return NewArray(e.config.Reporter, value)
}

// String is a shorthand for NewString(e.config.Reporter, value).
func (e *Expect) String(value string) *String {
	return NewString(e.config.Reporter, value)
}

// Number is a shorthand for NewNumber(e.config.Reporter, value).
func (e *Expect) Number(value float64) *Number {
	return NewNumber(e.config.Reporter, value)
}

// Boolean is a shorthand for NewBoolean(e.config.Reporter, value).
func (e *Expect) Boolean(value bool) *Boolean {
	return NewBoolean(e.config.Reporter, value)
}
<commit_msg>Use LoggerReporter interface instead of testing.T (#20)<commit_after>// Package httpexpect helps with end-to-end HTTP and REST API testing.
//
// Usage examples
//
// See example directory:
//  - https://godoc.org/github.com/gavv/httpexpect/example
//  - https://github.com/gavv/httpexpect/tree/master/example
//
// Communication mode
//
// There are two common ways to test API with httpexpect:
//  - start HTTP server and instruct httpexpect to use HTTP client for communication
//  - don't start server and instruct httpexpect to invoke http handler directly
//
// The second approach works only if the server is a Go module and its handler can
// be imported in tests.
//
// Concrete behaviour is determined by Client implementation passed to Config struct.
// If you're using http.Client, set its Transport field (http.RoundTriper) to one of
// the following:
//  1. default (nil) - use regular HTTP transport from net/http (you should start server)
//  2. httpexpect.Binder - invoke given http.Handler directly
//  4. httpexpect.FastBinder - invoke given fasthttp.RequestHandler directly
//
// Note that http handler can be usually obtained from http framework you're using.
// E.g., echo framework provides either http.Handler or fasthttp.RequestHandler.
//
// You can also provide your own Client or http.RoundTriper implementation and do
// whatever you want to convert http.Request to http.Response.
//
// If you're starting server from tests, it's very handy to use net/http/httptest
// for that.
//
// Value equality
//
// Whenever values are checked for equality in httpexpect, they are converted
// to "canonical form":
//  - type aliases are removed
//  - numeric types are converted to float64
//  - non-nil interfaces pointing to nil slices and maps are replaced with nil interfaces
//  - structs are converted to map[string]interface{}
//
// This is equivalent to subsequently json.Marshal() and json.Unmarshal() the value
// and currently is implemented so.
//
// Failure handling
//
// When some check fails, failure is reported. If non-fatal failures are used
// (see Reporter interface), execution is continued and instance that was checked
// is marked as failed.
//
// If specific instance is marked as failed, all subsequent checks are ignored
// for this instance and for any child instances retrieved after failure.
//
// Example:
//  array := NewArray(NewAssertReporter(t), []interface{}{"foo", 123})
//
//  e0 := array.Element(0)  // success
//  e1 := array.Element(1)  // success
//
//  s0 := e0.String()       // success
//  s1 := e1.String()       // failure; e1 and s1 are marked as failed, e0 and s0 are not
//
//  s0.Equal("foo")         // success
//  s1.Equal("bar")         // this check is ignored because s1 is marked as failed
package httpexpect

import (
	"golang.org/x/net/publicsuffix"
	"net/http"
	"net/http/cookiejar"
	"time"
)

// Expect is a toplevel object that contains user Config and allows
// to construct Request objects.
type Expect struct {
	config   Config
	builders []func(*Request)
}

// Config contains various settings.
type Config struct {
	// BaseURL is a URL to prepended to all request. My be empty. If
	// non-empty, trailing slash is allowed but not required and is
	// appended automatically.
	BaseURL string

	// Client is used to send http.Request and receive http.Response.
	// Should not be nil.
	//
	// You can use http.DefaultClient or http.Client, or provide
	// custom implementation.
	Client Client

	// Reporter is used to report failures.
	// Should not be nil.
	//
	// You can use AssertReporter, RequireReporter (they use testify),
	// or testing.T, or provide custom implementation.
	Reporter Reporter

	// Printers are used to print requests and responses.
	// May be nil.
	//
	// You can use CompactPrinter, DebugPrinter, CurlPrinter, or provide
	// custom implementation.
	//
	// You can also use builtin printers with alternative Logger if
	// you're happy with their format, but want to send logs somewhere
	// else instead of testing.T.
	Printers []Printer
}

// Client is used to send http.Request and receive http.Response.
// http.Client, Binder, and FastBinder implement this interface.
type Client interface {
	// Do sends request and returns response.
	Do(*http.Request) (*http.Response, error)
}

// Printer is used to print requests and responses.
// CompactPrinter, DebugPrinter, and CurlPrinter implement this interface.
type Printer interface {
	// Request is called before request is sent.
	Request(*http.Request)

	// Response is called after response is received.
	Response(*http.Response, time.Duration)
}

// Logger is used as output backend for Printer.
// testing.T implements this interface.
type Logger interface {
	// Logf writes message to log.
	Logf(fmt string, args ...interface{})
}

// Reporter is used to report failures.
// testing.T implements this interface. AssertReporter and RequireReporter,
// also implement this interface using testify.
type Reporter interface {
	// Errorf reports failure.
	// Allowed to return normally or terminate test using t.FailNow().
	Errorf(message string, args ...interface{})
}

// LoggerReporter combines Logger and Reporter interfaces.
type LoggerReporter interface {
	Logger
	Reporter
}

// New returns a new Expect object.
//
// baseURL specifies URL to prepended to all request. My be empty. If non-empty,
// trailing slash is allowed but not required and is appended automatically.
//
// New is a shorthand for WithConfig. It uses:
//  - CompactPrinter as Printer with testing.T as Logger
//  - AssertReporter as Reporter
//
// Client is set to default client with non-nil Jar:
//  &http.Client{
//      Jar: httpexpect.NewJar(),
//  }
//
// Example:
//  func TestSomething(t *testing.T) {
//      e := httpexpect.New(t, "http://example.com/")
//
//      e.GET("/path").
//          Expect().
//          Status(http.StatusOK)
//  }
func New(t LoggerReporter, baseURL string) *Expect {
	return WithConfig(Config{
		BaseURL:  baseURL,
		Reporter: NewAssertReporter(t),
		Printers: []Printer{
			NewCompactPrinter(t),
		},
	})
}

// WithConfig returns a new Expect object with given config.
//
// Reporter should not be nil.
//
// If Client is nil, it's set to default client with non-nil Jar:
//  &http.Client{
//      Jar: httpexpect.NewJar(),
//  }
//
// Example:
//  func TestSomething(t *testing.T) {
//      e := httpexpect.WithConfig(httpexpect.Config{
//          BaseURL:  "http://example.com/",
//          Client:   &http.Client{
//              Transport: httpexpect.NewBinder(myHandler()),
//              Jar:       httpexpect.NewJar(),
//          },
//          Reporter: httpexpect.NewAssertReporter(t),
//          Printers: []httpexpect.Printer{
//              httpexpect.NewCurlPrinter(t),
//              httpexpect.NewDebugPrinter(t, true)
//          },
//      })
//
//      e.GET("/path").
//          Expect().
//          Status(http.StatusOK)
//  }
func WithConfig(config Config) *Expect {
	if config.Reporter == nil {
		panic("config.Reporter is nil")
	}
	if config.Client == nil {
		config.Client = &http.Client{
			Jar: NewJar(),
		}
	}
	return &Expect{
		config:   config,
		builders: nil,
	}
}

// NewJar returns a new http.CookieJar.
//
// Returned jar is implemented in net/http/cookiejar. PublicSuffixList is
// implemented in golang.org/x/net/publicsuffix.
//
// Note that this jar ignores cookies when request url is empty.
func NewJar() http.CookieJar {
	jar, err := cookiejar.New(&cookiejar.Options{
		PublicSuffixList: publicsuffix.List,
	})
	if err != nil {
		panic(err)
	}
	return jar
}

// Builder returns a copy of Expect instance with given builder attached to it.
// Returned copy contains all previously attached builders plus a new one.
// Builders are invoked from Request method, after constructing every new request.
//
// Example:
//  e := httpexpect.New(t, "http://example.com")
//
//  token := e.POST("/login").WithForm(Login{"ford", "betelgeuse7"}).
//      Expect().
//      Status(http.StatusOK).JSON().Object().Value("token").String().Raw()
//
//  auth := e.Builder(func (req *httpexpect.Request) {
//      req.WithHeader("Authorization", "Bearer "+token)
//  })
//
//  auth.GET("/restricted").
//     Expect().
//     Status(http.StatusOK)
func (e *Expect) Builder(builder func(*Request)) *Expect {
	ret := *e
	ret.builders = append(e.builders, builder)
	return &ret
}

// Request returns a new Request object.
// Arguments a similar to NewRequest.
// After creating request, all builders attached to Expect object are invoked.
// See Builder.
func (e *Expect) Request(method, path string, pathargs ...interface{}) *Request {
	req := NewRequest(e.config, method, path, pathargs...)

	for _, builder := range e.builders {
		builder(req)
	}

	return req
}

// OPTIONS is a shorthand for e.Request("OPTIONS", path, pathargs...).
func (e *Expect) OPTIONS(path string, pathargs ...interface{}) *Request {
	return e.Request("OPTIONS", path, pathargs...)
}

// HEAD is a shorthand for e.Request("HEAD", path, pathargs...).
func (e *Expect) HEAD(path string, pathargs ...interface{}) *Request {
	return e.Request("HEAD", path, pathargs...)
}

// GET is a shorthand for e.Request("GET", path, pathargs...).
func (e *Expect) GET(path string, pathargs ...interface{}) *Request {
	return e.Request("GET", path, pathargs...)
}

// POST is a shorthand for e.Request("POST", path, pathargs...).
func (e *Expect) POST(path string, pathargs ...interface{}) *Request {
	return e.Request("POST", path, pathargs...)
}

// PUT is a shorthand for e.Request("PUT", path, pathargs...).
func (e *Expect) PUT(path string, pathargs ...interface{}) *Request {
	return e.Request("PUT", path, pathargs...)
}

// PATCH is a shorthand for e.Request("PATCH", path, pathargs...).
func (e *Expect) PATCH(path string, pathargs ...interface{}) *Request {
	return e.Request("PATCH", path, pathargs...)
}

// DELETE is a shorthand for e.Request("DELETE", path, pathargs...).
func (e *Expect) DELETE(path string, pathargs ...interface{}) *Request {
	return e.Request("DELETE", path, pathargs...)
}

// Value is a shorthand for NewValue(e.config.Reporter, value).
func (e *Expect) Value(value interface{}) *Value {
	return NewValue(e.config.Reporter, value)
}

// Object is a shorthand for NewObject(e.config.Reporter, value).
func (e *Expect) Object(value map[string]interface{}) *Object {
	return NewObject(e.config.Reporter, value)
}

// Array is a shorthand for NewArray(e.config.Reporter, value).
func (e *Expect) Array(value []interface{}) *Array {
	return NewArray(e.config.Reporter, value)
}

// String is a shorthand for NewString(e.config.Reporter, value).
func (e *Expect) String(value string) *String {
	return NewString(e.config.Reporter, value)
}

// Number is a shorthand for NewNumber(e.config.Reporter, value).
func (e *Expect) Number(value float64) *Number {
	return NewNumber(e.config.Reporter, value)
}

// Boolean is a shorthand for NewBoolean(e.config.Reporter, value).
func (e *Expect) Boolean(value bool) *Boolean {
	return NewBoolean(e.config.Reporter, value)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/evoL/gif/store"
	"os"
	"regexp"
)

func ExportCommand(c *cli.Context) {
	s := getStore()
	defer s.Close()

	var targetFile *os.File
	var err error

	output := c.String("output")
	if output == "-" {
		targetFile = os.Stdout
	} else {
		targetFile, err = os.Create(output)
		if err != nil {
			fmt.Println("Could not create file: " + err.Error())
			os.Exit(1)
		}
	}

	// Detect file extension and enable full export
	exportFiles := c.Bool("bundle") || regexp.MustCompile(`(?:\.tar\.gz|\.gifb)\z`).MatchString(output)

	writer := bufio.NewWriter(targetFile)
	defer writer.Flush()

	err = s.Export(writer, store.NullFilter{}, exportFiles)
	if err != nil {
		fmt.Println("Export error: " + err.Error())
		os.Exit(1)
	}
}
<commit_msg>Exporting local gifs make no sense when you don't include files.<commit_after>package main

import (
	"bufio"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/evoL/gif/store"
	"os"
	"regexp"
)

func ExportCommand(c *cli.Context) {
	s := getStore()
	defer s.Close()

	var targetFile *os.File
	var err error

	output := c.String("output")
	if output == "-" {
		targetFile = os.Stdout
	} else {
		targetFile, err = os.Create(output)
		if err != nil {
			fmt.Println("Could not create file: " + err.Error())
			os.Exit(1)
		}
	}

	// Detect file extension and enable full export
	exportFiles := c.Bool("bundle") || regexp.MustCompile(`(?:\.tar\.gz|\.gifb)\z`).MatchString(output)

	// Exporting local gifs makes no sense when you don't include files
	var filter store.Filter
	if exportFiles {
		filter = store.NullFilter{}
	} else {
		filter = store.RemoteFilter{Filter: store.NullFilter{}}
	}

	writer := bufio.NewWriter(targetFile)
	defer writer.Flush()

	err = s.Export(writer, filter, exportFiles)
	if err != nil {
		fmt.Println("Export error: " + err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package dbus

import (
	"encoding/binary"
	"errors"
	"reflect"
	"strings"
	"unicode"
)

var (
	errmsgInvalidArg = Error{
		"org.freedesktop.DBus.Error.InvalidArgs",
		[]interface{}{"Invalid type / number of args"},
	}
	errmsgUnknownMethod = Error{
		"org.freedesktop.DBus.Error.UnknownMethod",
		[]interface{}{"Unkown / invalid method"},
	}
)

func exportedMethod(v interface{}, name string) reflect.Value {
	if v == nil {
		return reflect.Value{}
	}
	m := reflect.ValueOf(v).MethodByName(name)
	if !m.IsValid() {
		return reflect.Value{}
	}
	t := m.Type()
	if t.NumOut() == 0 ||
		t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {

		return reflect.Value{}
	}
	return m
}

// handleCall handles the given method call (i.e. looks if it's one of the
// pre-implemented ones and searches for a corresponding handler if not).
func (conn *Conn) handleCall(msg *Message) {
	name := msg.Headers[FieldMember].value.(string)
	path := msg.Headers[FieldPath].value.(ObjectPath)
	ifaceName, hasIface := msg.Headers[FieldInterface].value.(string)
	sender := msg.Headers[FieldSender].value.(string)
	serial := msg.serial
	if ifaceName == "org.freedesktop.DBus.Peer" {
		switch name {
		case "Ping":
			conn.sendReply(sender, serial)
		case "GetMachineId":
			conn.sendReply(sender, serial, conn.uuid)
		default:
			conn.sendError(errmsgUnknownMethod, sender, serial)
		}
		return
	}
	if len(name) == 0 || unicode.IsLower([]rune(name)[0]) {
		conn.sendError(errmsgUnknownMethod, sender, serial)
	}
	var m reflect.Value
	if hasIface {
		conn.handlersLck.RLock()
		obj, ok := conn.handlers[path]
		if !ok {
			conn.sendError(errmsgUnknownMethod, sender, serial)
			conn.handlersLck.RUnlock()
			return
		}
		iface := obj[ifaceName]
		conn.handlersLck.RUnlock()
		m = exportedMethod(iface, name)
	} else {
		conn.handlersLck.RLock()
		for _, v := range conn.handlers[path] {
			m = exportedMethod(v, name)
			if m.IsValid() {
				break
			}
		}
		conn.handlersLck.RUnlock()
	}
	if !m.IsValid() {
		conn.sendError(errmsgUnknownMethod, sender, serial)
		return
	}
	t := m.Type()
	vs := msg.Body
	if t.NumIn() != len(vs) {
		conn.sendError(errmsgInvalidArg, sender, serial)
		return
	}
	for i := 0; i < t.NumIn(); i++ {
		if t.In(i) != reflect.TypeOf(vs[i]) {
			conn.sendError(errmsgInvalidArg, sender, serial)
			return
		}
	}
	params := make([]reflect.Value, len(vs))
	for i := 0; i < len(vs); i++ {
		params[i] = reflect.ValueOf(vs[i])
	}
	ret := m.Call(params)
	if em := ret[t.NumOut()-1].Interface().(*Error); em != nil {
		conn.sendError(*em, sender, serial)
		return
	}
	if msg.Flags&FlagNoReplyExpected == 0 {
		reply := new(Message)
		reply.Order = binary.LittleEndian
		reply.Type = TypeMethodReply
		reply.serial = <-conn.serial
		reply.Headers = make(map[HeaderField]Variant)
		reply.Headers[FieldDestination] = msg.Headers[FieldSender]
		reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
		reply.Body = make([]interface{}, len(ret)-1)
		for i := 0; i < len(ret)-1; i++ {
			reply.Body[i] = ret[i].Interface()
		}
		if len(ret) != 1 {
			reply.Headers[FieldSignature] = MakeVariant(GetSignature(reply.Body...))
		}
		conn.outLck.RLock()
		if !conn.closed {
			conn.out <- reply
		}
		conn.outLck.RUnlock()
	}
}

// Emit emits the given signal on the message bus. The name parameter must be
// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
	if !path.IsValid() {
		return errors.New("invalid object path")
	}
	i := strings.LastIndex(name, ".")
	if i == -1 {
		return errors.New("invalid method name")
	}
	iface := name[:i]
	member := name[i+1:]
	if !isValidMember(member) {
		return errors.New("invalid method name")
	}
	if !isValidInterface(iface) {
		return errors.New("invalid interface name")
	}
	msg := new(Message)
	msg.Order = binary.LittleEndian
	msg.Type = TypeSignal
	msg.serial = <-conn.serial
	msg.Headers = make(map[HeaderField]Variant)
	msg.Headers[FieldInterface] = MakeVariant(iface)
	msg.Headers[FieldMember] = MakeVariant(member)
	msg.Headers[FieldPath] = MakeVariant(path)
	msg.Body = values
	if len(values) > 0 {
		msg.Headers[FieldSignature] = MakeVariant(GetSignature(values...))
	}
	conn.outLck.RLock()
	defer conn.outLck.RUnlock()
	if conn.closed {
		return ErrClosed
	} else {
		conn.out <- msg
		return nil
	}
}

// Export registers the given value to be exported as an object on the
// message bus.
//
// If a method call on the given path and interface is received, an exported
// method with the same name is called with v as the receiver if the
// parameters match and the last return value is of type *ErrorMessage.
// If this *ErrorMessage is not nil, it is sent back to the caller as an error.
// Otherwise, a method reply is sent with the other return values as its body.
//
// Every method call is executed in a new goroutine, so the method may be called
// in multiple goroutines at once.
//
// Method calls on the interface org.freedesktop.DBus.Peer will be automatically
// handled for every object.
//
// Export returns an error if path is not a valid path name.
func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
	if !path.IsValid() {
		return errors.New("invalid path name")
	}
	conn.handlersLck.Lock()
	if _, ok := conn.handlers[path]; !ok {
		conn.handlers[path] = make(map[string]interface{})
	}
	conn.handlers[path][iface] = v
	conn.handlersLck.Unlock()
	return nil
}

// ReleaseName calls org.freedesktop.DBus.ReleaseName. You should use only this
// method to release a name (see below).
func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) {
	var r uint32
	err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r)
	if err != nil {
		return 0, err
	}
	if r == uint32(ReleaseNameReplyReleased) {
		conn.namesLck.Lock()
		for i, v := range conn.names {
			if v == name {
				copy(conn.names[i:], conn.names[i+1:])
				conn.names = conn.names[:len(conn.names)-1]
			}
		}
		conn.namesLck.Unlock()
	}
	return ReleaseNameReply(r), nil
}

// RequestName calls org.freedesktop.DBus.RequestName. You should use only this
// method to request a name because package dbus needs to keep track of all
// names that the connection has.
func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) {
	var r uint32
	err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r)
	if err != nil {
		return 0, err
	}
	if r == uint32(RequestNameReplyPrimaryOwner) {
		conn.namesLck.Lock()
		conn.names = append(conn.names, name)
		conn.namesLck.Unlock()
	}
	return RequestNameReply(r), nil
}

// Unexport causes conn to cease handling method calls on the given combination
// of path and interface.
func (conn *Conn) Unexport(path ObjectPath, iface string) {
	conn.handlersLck.Lock()
	if _, ok := conn.handlers[path]; ok {
		delete(conn.handlers[path], iface)
		if len(conn.handlers) == 0 {
			delete(conn.handlers, path)
		}
	}
	conn.handlersLck.Unlock()
}

// ReleaseNameReply is the reply to a ReleaseName call.
type ReleaseNameReply uint32

const (
	ReleaseNameReplyReleased ReleaseNameReply = 1 + iota
	ReleaseNameReplyNonExistent
	ReleaseNameReplyNotOwner
)

// RequestNameFlags represents the possible flags for a RequestName call.
type RequestNameFlags uint32

const (
	NameFlagAllowReplacement RequestNameFlags = 1 << iota
	NameFlagReplaceExisting
	NameFlagDoNotQueue
)

// RequestNameReply is the reply to a RequestName call.
type RequestNameReply uint32

const (
	RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota
	RequestNameReplyInQueue
	RequestNameReplyExists
	RequestNameReplyAlreadyOwner
)
<commit_msg>Send better error message for missing object<commit_after>package dbus

import (
	"encoding/binary"
	"errors"
	"reflect"
	"strings"
	"unicode"
)

var (
	errmsgInvalidArg = Error{
		"org.freedesktop.DBus.Error.InvalidArgs",
		[]interface{}{"Invalid type / number of args"},
	}
	errmsgNoObject = Error{
		"org.freedesktop.DBus.Error.NoSuchObject",
		[]interface{}{"No such object"},
	}
	errmsgUnknownMethod = Error{
		"org.freedesktop.DBus.Error.UnknownMethod",
		[]interface{}{"Unkown / invalid method"},
	}
)

func exportedMethod(v interface{}, name string) reflect.Value {
	if v == nil {
		return reflect.Value{}
	}
	m := reflect.ValueOf(v).MethodByName(name)
	if !m.IsValid() {
		return reflect.Value{}
	}
	t := m.Type()
	if t.NumOut() == 0 ||
		t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {

		return reflect.Value{}
	}
	return m
}

// handleCall handles the given method call (i.e. looks if it's one of the
// pre-implemented ones and searches for a corresponding handler if not).
func (conn *Conn) handleCall(msg *Message) {
	name := msg.Headers[FieldMember].value.(string)
	path := msg.Headers[FieldPath].value.(ObjectPath)
	ifaceName, hasIface := msg.Headers[FieldInterface].value.(string)
	sender := msg.Headers[FieldSender].value.(string)
	serial := msg.serial
	if ifaceName == "org.freedesktop.DBus.Peer" {
		switch name {
		case "Ping":
			conn.sendReply(sender, serial)
		case "GetMachineId":
			conn.sendReply(sender, serial, conn.uuid)
		default:
			conn.sendError(errmsgUnknownMethod, sender, serial)
		}
		return
	}
	if len(name) == 0 || unicode.IsLower([]rune(name)[0]) {
		conn.sendError(errmsgUnknownMethod, sender, serial)
	}
	var m reflect.Value
	if hasIface {
		conn.handlersLck.RLock()
		obj, ok := conn.handlers[path]
		if !ok {
			conn.sendError(errmsgNoObject, sender, serial)
			conn.handlersLck.RUnlock()
			return
		}
		iface := obj[ifaceName]
		conn.handlersLck.RUnlock()
		m = exportedMethod(iface, name)
	} else {
		conn.handlersLck.RLock()
		if _, ok := conn.handlers[path]; !ok {
			conn.sendError(errmsgNoObject, sender, serial)
			conn.handlersLck.RUnlock()
			return
		}
		for _, v := range conn.handlers[path] {
			m = exportedMethod(v, name)
			if m.IsValid() {
				break
			}
		}
		conn.handlersLck.RUnlock()
	}
	if !m.IsValid() {
		conn.sendError(errmsgUnknownMethod, sender, serial)
		return
	}
	t := m.Type()
	vs := msg.Body
	if t.NumIn() != len(vs) {
		conn.sendError(errmsgInvalidArg, sender, serial)
		return
	}
	for i := 0; i < t.NumIn(); i++ {
		if t.In(i) != reflect.TypeOf(vs[i]) {
			conn.sendError(errmsgInvalidArg, sender, serial)
			return
		}
	}
	params := make([]reflect.Value, len(vs))
	for i := 0; i < len(vs); i++ {
		params[i] = reflect.ValueOf(vs[i])
	}
	ret := m.Call(params)
	if em := ret[t.NumOut()-1].Interface().(*Error); em != nil {
		conn.sendError(*em, sender, serial)
		return
	}
	if msg.Flags&FlagNoReplyExpected == 0 {
		reply := new(Message)
		reply.Order = binary.LittleEndian
		reply.Type = TypeMethodReply
		reply.serial = <-conn.serial
		reply.Headers = make(map[HeaderField]Variant)
		reply.Headers[FieldDestination] = msg.Headers[FieldSender]
		reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
		reply.Body = make([]interface{}, len(ret)-1)
		for i := 0; i < len(ret)-1; i++ {
			reply.Body[i] = ret[i].Interface()
		}
		if len(ret) != 1 {
			reply.Headers[FieldSignature] = MakeVariant(GetSignature(reply.Body...))
		}
		conn.outLck.RLock()
		if !conn.closed {
			conn.out <- reply
		}
		conn.outLck.RUnlock()
	}
}

// Emit emits the given signal on the message bus. The name parameter must be
// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
	if !path.IsValid() {
		return errors.New("invalid object path")
	}
	i := strings.LastIndex(name, ".")
	if i == -1 {
		return errors.New("invalid method name")
	}
	iface := name[:i]
	member := name[i+1:]
	if !isValidMember(member) {
		return errors.New("invalid method name")
	}
	if !isValidInterface(iface) {
		return errors.New("invalid interface name")
	}
	msg := new(Message)
	msg.Order = binary.LittleEndian
	msg.Type = TypeSignal
	msg.serial = <-conn.serial
	msg.Headers = make(map[HeaderField]Variant)
	msg.Headers[FieldInterface] = MakeVariant(iface)
	msg.Headers[FieldMember] = MakeVariant(member)
	msg.Headers[FieldPath] = MakeVariant(path)
	msg.Body = values
	if len(values) > 0 {
		msg.Headers[FieldSignature] = MakeVariant(GetSignature(values...))
	}
	conn.outLck.RLock()
	defer conn.outLck.RUnlock()
	if conn.closed {
		return ErrClosed
	} else {
		conn.out <- msg
		return nil
	}
}

// Export registers the given value to be exported as an object on the
// message bus.
//
// If a method call on the given path and interface is received, an exported
// method with the same name is called with v as the receiver if the
// parameters match and the last return value is of type *ErrorMessage.
// If this *ErrorMessage is not nil, it is sent back to the caller as an error.
// Otherwise, a method reply is sent with the other return values as its body.
//
// Every method call is executed in a new goroutine, so the method may be called
// in multiple goroutines at once.
//
// Method calls on the interface org.freedesktop.DBus.Peer will be automatically
// handled for every object.
//
// Export returns an error if path is not a valid path name.
func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
	if !path.IsValid() {
		return errors.New("invalid path name")
	}
	conn.handlersLck.Lock()
	if _, ok := conn.handlers[path]; !ok {
		conn.handlers[path] = make(map[string]interface{})
	}
	conn.handlers[path][iface] = v
	conn.handlersLck.Unlock()
	return nil
}

// ReleaseName calls org.freedesktop.DBus.ReleaseName. You should use only this
// method to release a name (see below).
func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) {
	var r uint32
	err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r)
	if err != nil {
		return 0, err
	}
	if r == uint32(ReleaseNameReplyReleased) {
		conn.namesLck.Lock()
		for i, v := range conn.names {
			if v == name {
				copy(conn.names[i:], conn.names[i+1:])
				conn.names = conn.names[:len(conn.names)-1]
			}
		}
		conn.namesLck.Unlock()
	}
	return ReleaseNameReply(r), nil
}

// RequestName calls org.freedesktop.DBus.RequestName. You should use only this
// method to request a name because package dbus needs to keep track of all
// names that the connection has.
func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) {
	var r uint32
	err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r)
	if err != nil {
		return 0, err
	}
	if r == uint32(RequestNameReplyPrimaryOwner) {
		conn.namesLck.Lock()
		conn.names = append(conn.names, name)
		conn.namesLck.Unlock()
	}
	return RequestNameReply(r), nil
}

// Unexport causes conn to cease handling method calls on the given combination
// of path and interface.
func (conn *Conn) Unexport(path ObjectPath, iface string) {
	conn.handlersLck.Lock()
	if _, ok := conn.handlers[path]; ok {
		delete(conn.handlers[path], iface)
		if len(conn.handlers) == 0 {
			delete(conn.handlers, path)
		}
	}
	conn.handlersLck.Unlock()
}

// ReleaseNameReply is the reply to a ReleaseName call.
type ReleaseNameReply uint32

const (
	ReleaseNameReplyReleased ReleaseNameReply = 1 + iota
	ReleaseNameReplyNonExistent
	ReleaseNameReplyNotOwner
)

// RequestNameFlags represents the possible flags for a RequestName call.
type RequestNameFlags uint32

const (
	NameFlagAllowReplacement RequestNameFlags = 1 << iota
	NameFlagReplaceExisting
	NameFlagDoNotQueue
)

// RequestNameReply is the reply to a RequestName call.
type RequestNameReply uint32

const (
	RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota
	RequestNameReplyInQueue
	RequestNameReplyExists
	RequestNameReplyAlreadyOwner
)
<|endoftext|>


<commit_before>package peco

import (
	"bufio"
	"bytes"
	"os/exec"
	"regexp"
	"sort"
	"sync"

	"github.com/lestrrat/go-pdebug"
	"github.com/peco/peco/hub"
	"github.com/peco/peco/internal/util"
	"github.com/peco/peco/pipeline"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

func (fx *FilterSet) Reset() {
	fx.current = 0
}

func (fs *FilterSet) Size() int {
	return len(fs.filters)
}

func (fs *FilterSet) Add(lf LineFilter) error {
	fs.filters = append(fs.filters, lf)
	return nil
}

func (fs *FilterSet) Rotate() {
	fs.current++
	if fs.current >= len(fs.filters) {
		fs.current = 0
	}
	if pdebug.Enabled {
		pdebug.Printf("FilterSet.Rotate: now filter in effect is %s", fs.filters[fs.current])
	}
}

func (fs *FilterSet) SetCurrentByName(name string) error {
	for i, f := range fs.filters {
		if f.String() == name {
			fs.current = i
			return nil
		}
	}
	return ErrFilterNotFound
}

func (fs *FilterSet) Current() LineFilter {
	return fs.filters[fs.current]
}

func NewFilter(state *Peco) *Filter {
	return &Filter{
		state: state,
	}
}

// Work is the actual work horse that that does the matching
// in a goroutine of its own. It wraps Matcher.Match().
func (f *Filter) Work(ctx context.Context, q hub.Payload) {
	defer q.Done()

	query, ok := q.Data().(string)
	if !ok {
		return
	}

	if pdebug.Enabled {
		pdebug.Printf("New query '%s'", query)
	}

	state := f.state
	if query == "" {
		state.ResetCurrentLineBuffer()
		if !state.config.StickySelection {
			state.Selection().Reset()
		}
		return
	}

	// Create a new pipeline
	p := pipeline.New()
	p.SetSource(state.Source())
	thisf := state.Filters().Current().Clone()
	thisf.SetQuery(query)
	p.Add(thisf)

	buf := NewMemoryBuffer()
	p.SetDestination(buf)
	state.SetCurrentLineBuffer(buf)

	go func() {
		defer state.Hub().SendDraw(true)
		if err := p.Run(ctx); err != nil {
			state.Hub().SendStatusMsg(err.Error())
		}
	}()

	go func() {
		if pdebug.Enabled {
			pdebug.Printf("waiting for query to finish")
			defer pdebug.Printf("Filter.Work: finished running query")
		}
		<-p.Done()
		state.Hub().SendStatusMsg("")
	}()

	if !state.config.StickySelection {
		state.Selection().Reset()
	}
}

// Loop keeps watching for incoming queries, and upon receiving
// a query, spawns a goroutine to do the heavy work. It also
// checks for previously running queries, so we can avoid
// running many goroutines doing the grep at the same time
func (f *Filter) Loop(ctx context.Context, cancel func()) error {
	defer cancel()

	// previous holds the function that can cancel the previous
	// query. This is used when multiple queries come in succession
	// and the previous query is discarded anyway
	var mutex sync.Mutex
	var previous func()
	previous = func() {} // no op func
	for {
		select {
		case <-ctx.Done():
			return nil
		case q := <-f.state.Hub().QueryCh():
			workctx, workcancel := context.WithCancel(ctx)

			mutex.Lock()
			previous()
			previous = workcancel
			mutex.Unlock()

			f.state.Hub().SendStatusMsg("Running query...")

			go func() {
				f.Work(workctx, q)
			}()
		}
	}
}

func NewRegexpFilter() *RegexpFilter {
	return &RegexpFilter{
		flags: regexpFlagList(defaultFlags),
		name:  "Regexp",
		outCh: pipeline.OutputChannel(make(chan interface{})),
	}
}

func (rf RegexpFilter) OutCh() <-chan interface{} {
	return rf.outCh
}

func (rf RegexpFilter) Clone() LineFilter {
	return &RegexpFilter{
		flags:     rf.flags,
		quotemeta: rf.quotemeta,
		query:     rf.query,
		name:      rf.name,
		outCh:     pipeline.OutputChannel(make(chan interface{})),
	}
}

const filterBufSize = 1000
var filterBufPool = sync.Pool{
	New: func() interface{} {
		return make([]Line, 0, filterBufSize)
	},
}

func releaseRegexpFilterBuf(l []Line) {
	if l == nil {
		return
	}
	l = l[0:0]
	filterBufPool.Put(l)
}

func getRegexpFilterBuf() []Line {
	l := filterBufPool.Get().([]Line)
	return l
}

func (rf *RegexpFilter) Accept(ctx context.Context, p pipeline.Producer) {
	if pdebug.Enabled {
		g := pdebug.Marker("RegexpFilter.Accept")
		defer g.End()
	}
	defer rf.outCh.SendEndMark("end of RegexpFilter")

	flush := make(chan []Line)
	flushDone := make(chan struct{})
	go func() {
		defer close(flushDone)
		for buf := range flush {
			for _, in := range buf {
				if l, err := rf.filter(in); err == nil {
					rf.outCh.Send(l)
				}
			}
			releaseRegexpFilterBuf(buf)
		}
	}()

	buf := getRegexpFilterBuf()
	defer func() { releaseRegexpFilterBuf(buf) }()
	defer func() { <-flushDone }() // Wait till the flush goroutine is done
	defer close(flush) // Kill the flush goroutine

	for {
		select {
		case <-ctx.Done():
			if pdebug.Enabled {
				pdebug.Printf("RegexpFilter received done")
			}
			return
		case v := <-p.OutCh():
			switch v.(type) {
			case error:
				if pipeline.IsEndMark(v.(error)) {
					if pdebug.Enabled {
						pdebug.Printf("RegexpFilter received end mark")
					}
					if len(buf) > 0 {
						flush <-buf
						buf = nil
					}
				}
				return
			case Line:
				buf = append(buf, v.(Line))
				if len(buf) >= cap(buf) {
					flush <- buf
					buf = getRegexpFilterBuf()
				}
			}
		}
	}
}

func (rf *RegexpFilter) filter(l Line) (Line, error) {
	regexps, err := rf.getQueryAsRegexps()
	if err != nil {
		return nil, errors.Wrap(err, "failed to compile queries as regular expression")
	}
	v := l.DisplayString()
	allMatched := true
	matches := [][]int{}
TryRegexps:
	for _, rx := range regexps {
		match := rx.FindAllStringSubmatchIndex(v, -1)
		if match == nil {
			allMatched = false
			break TryRegexps
		}
		matches = append(matches, match...)
	}

	if !allMatched {
		return nil, errors.New("filter did not match against given line")
	}

	sort.Sort(byMatchStart(matches))

	// We need to "dedupe" the results. For example, if we matched the
	// same region twice, we don't want that to be drawn

	deduped := make([][]int, 0, len(matches))

	for i, m := range matches {
		// Always push the first one
		if i == 0 {
			deduped = append(deduped, m)
			continue
		}

		prev := deduped[len(deduped)-1]
		switch {
		case matchContains(prev, m):
			// If the previous match contains this one, then
			// don't do anything
			continue
		case matchOverlaps(prev, m):
			// If the previous match overlaps with this one,
			// merge the results and make it a bigger one
			deduped[len(deduped)-1] = mergeMatches(prev, m)
		default:
			deduped = append(deduped, m)
		}
	}
	return NewMatchedLine(l, deduped), nil
}

func (rf *RegexpFilter) getQueryAsRegexps() ([]*regexp.Regexp, error) {
	if q := rf.compiledQuery; q != nil {
		return q, nil
	}
	q, err := queryToRegexps(rf.flags, rf.quotemeta, rf.query)
	if err != nil {
		return nil, errors.Wrap(err, "failed to compile queries as regular expression")
	}

	rf.compiledQuery = q
	return q, nil
}

func (rf *RegexpFilter) SetQuery(q string) {
	rf.query = q
	rf.compiledQuery = nil
}

func (rf RegexpFilter) String() string {
	return rf.name
}

var ErrFilterNotFound = errors.New("specified filter was not found")

func NewIgnoreCaseFilter() *RegexpFilter {
	rf := NewRegexpFilter()
	rf.flags = ignoreCaseFlags
	rf.quotemeta = true
	rf.name = "IgnoreCase"
	return rf
}

func NewCaseSensitiveFilter() *RegexpFilter {
	rf := NewRegexpFilter()
	rf.quotemeta = true
	rf.name = "CaseSensitive"
	return rf
}

// SmartCaseFilter turns ON the ignore-case flag in the regexp
// if the query contains a upper-case character
func NewSmartCaseFilter() *RegexpFilter {
	rf := NewRegexpFilter()
	rf.quotemeta = true
	rf.name = "SmartCase"
	rf.flags = regexpFlagFunc(func(q string) []string {
		if util.ContainsUpper(q) {
			return defaultFlags
		}
		return []string{"i"}
	})
	return rf
}

func NewExternalCmdFilter(name string, cmd string, args []string, threshold int, enableSep bool) *ExternalCmdFilter {
	if len(args) == 0 {
		args = []string{"$QUERY"}
	}

	if threshold <= 0 {
		threshold = DefaultCustomFilterBufferThreshold
	}

	return &ExternalCmdFilter{
		args:            args,
		cmd:             cmd,
		enableSep:       enableSep,
		name:            name,
		outCh:           pipeline.OutputChannel(make(chan interface{})),
		thresholdBufsiz: threshold,
	}
}

func (ecf ExternalCmdFilter) Clone() LineFilter {
	return &ExternalCmdFilter{
		args:            ecf.args,
		cmd:             ecf.cmd,
		enableSep:       ecf.enableSep,
		name:            ecf.name,
		outCh:           pipeline.OutputChannel(make(chan interface{})),
		thresholdBufsiz: ecf.thresholdBufsiz,
	}
}

func (ecf *ExternalCmdFilter) Verify() error {
	if ecf.cmd == "" {
		return errors.Errorf("no executable specified for custom matcher '%s'", ecf.name)
	}

	if _, err := exec.LookPath(ecf.cmd); err != nil {
		return errors.Wrap(err, "failed to locate command")
	}
	return nil
}

func (ecf *ExternalCmdFilter) Accept(ctx context.Context, p pipeline.Producer) {
	if pdebug.Enabled {
		g := pdebug.Marker("ExternalCmdFilter.Accept")
		defer g.End()
	}
	defer ecf.outCh.SendEndMark("end of ExternalCmdFilter")

	buf := make([]Line, 0, ecf.thresholdBufsiz)
	for {
		select {
		case <-ctx.Done():
			if pdebug.Enabled {
				pdebug.Printf("ExternalCmdFilter received done")
			}
			return
		case v := <-p.OutCh():
			switch v.(type) {
			case error:
				if pipeline.IsEndMark(v.(error)) {
					if pdebug.Enabled {
						pdebug.Printf("ExternalCmdFilter received end mark")
					}
					if len(buf) > 0 {
						ecf.launchExternalCmd(ctx, buf)
					}
				}
				return
			case Line:
				if pdebug.Enabled {
					pdebug.Printf("ExternalCmdFilter received new line")
				}
				buf = append(buf, v.(Line))
				if len(buf) < ecf.thresholdBufsiz {
					continue
				}

				ecf.launchExternalCmd(ctx, buf)
				buf = buf[0:0]
			}
		}
	}
}

func (ecf ExternalCmdFilter) OutCh() <-chan interface{} {
	return ecf.outCh
}

func (ecf *ExternalCmdFilter) SetQuery(q string) {
	ecf.query = q
}

func (ecf ExternalCmdFilter) String() string {
	return ecf.name
}

func (ecf *ExternalCmdFilter) launchExternalCmd(ctx context.Context, buf []Line) {
	defer func() { recover() }() // ignore errors
	if pdebug.Enabled {
		g := pdebug.Marker("ExternalCmdFilter.launchExternalCmd")
		defer g.End()
	}

	args := append([]string(nil), ecf.args...)
	for i, v := range args {
		if v == "$QUERY" {
			args[i] = ecf.query
		}
	}
	cmd := exec.Command(ecf.cmd, args...)
	if pdebug.Enabled {
		pdebug.Printf("Executing command %s %v", cmd.Path, cmd.Args)
	}

	inbuf := &bytes.Buffer{}
	for _, l := range buf {
		inbuf.WriteString(l.DisplayString() + "\n")
	}

	cmd.Stdin = inbuf
	r, err := cmd.StdoutPipe()
	if err != nil {
		return
	}

	err = cmd.Start()
	if err != nil {
		return
	}

	go cmd.Wait()

	cmdCh := make(chan Line)
	go func(cmdCh chan Line, rdr *bufio.Reader) {
		defer func() { recover() }()
		defer close(cmdCh)
		for {
			b, _, err := rdr.ReadLine()
			if len(b) > 0 {
				// TODO: need to redo the spec for custom matchers
				// This is the ONLY location where we need to actually
				// RECREATE a RawLine, and thus the only place where
				// ctx.enableSep is required.
				cmdCh <- NewMatchedLine(NewRawLine(string(b), ecf.enableSep), nil)
			}
			if err != nil {
				break
			}
		}
	}(cmdCh, bufio.NewReader(r))

	defer func() {
		if p := cmd.Process; p != nil {
			p.Kill()
		}
	}()

	for {
		select {
		case <-ctx.Done():
			return
		case l, ok := <-cmdCh:
			if l == nil || !ok {
				return
			}
			ecf.outCh.Send(l)
		}
	}
}
<commit_msg>Draw while waiting<commit_after>package peco

import (
	"bufio"
	"bytes"
	"os/exec"
	"regexp"
	"sort"
	"sync"
	"time"

	"github.com/lestrrat/go-pdebug"
	"github.com/peco/peco/hub"
	"github.com/peco/peco/internal/util"
	"github.com/peco/peco/pipeline"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

func (fx *FilterSet) Reset() {
	fx.current = 0
}

func (fs *FilterSet) Size() int {
	return len(fs.filters)
}

func (fs *FilterSet) Add(lf LineFilter) error {
	fs.filters = append(fs.filters, lf)
	return nil
}

func (fs *FilterSet) Rotate() {
	fs.current++
	if fs.current >= len(fs.filters) {
		fs.current = 0
	}
	if pdebug.Enabled {
		pdebug.Printf("FilterSet.Rotate: now filter in effect is %s", fs.filters[fs.current])
	}
}

func (fs *FilterSet) SetCurrentByName(name string) error {
	for i, f := range fs.filters {
		if f.String() == name {
			fs.current = i
			return nil
		}
	}
	return ErrFilterNotFound
}

func (fs *FilterSet) Current() LineFilter {
	return fs.filters[fs.current]
}

func NewFilter(state *Peco) *Filter {
	return &Filter{
		state: state,
	}
}

// Work is the actual work horse that that does the matching
// in a goroutine of its own. It wraps Matcher.Match().
func (f *Filter) Work(ctx context.Context, q hub.Payload) {
	defer q.Done()

	query, ok := q.Data().(string)
	if !ok {
		return
	}

	if pdebug.Enabled {
		pdebug.Printf("New query '%s'", query)
	}

	state := f.state
	if query == "" {
		state.ResetCurrentLineBuffer()
		if !state.config.StickySelection {
			state.Selection().Reset()
		}
		return
	}

	// Create a new pipeline
	p := pipeline.New()
	p.SetSource(state.Source())
	thisf := state.Filters().Current().Clone()
	thisf.SetQuery(query)
	p.Add(thisf)

	buf := NewMemoryBuffer()
	p.SetDestination(buf)
	state.SetCurrentLineBuffer(buf)

	go func() {
		defer state.Hub().SendDraw(true)
		if err := p.Run(ctx); err != nil {
			state.Hub().SendStatusMsg(err.Error())
		}
	}()

	go func() {
		if pdebug.Enabled {
			pdebug.Printf("waiting for query to finish")
			defer pdebug.Printf("Filter.Work: finished running query")
		}
		t := time.NewTicker(100 * time.Millisecond)
		defer t.Stop()
		for {
			select {
			case <-p.Done():
				break
			case <-t.C:
				state.Hub().SendDraw(true)
			}
		}
		state.Hub().SendStatusMsg("")
	}()

	if !state.config.StickySelection {
		state.Selection().Reset()
	}
}

// Loop keeps watching for incoming queries, and upon receiving
// a query, spawns a goroutine to do the heavy work. It also
// checks for previously running queries, so we can avoid
// running many goroutines doing the grep at the same time
func (f *Filter) Loop(ctx context.Context, cancel func()) error {
	defer cancel()

	// previous holds the function that can cancel the previous
	// query. This is used when multiple queries come in succession
	// and the previous query is discarded anyway
	var mutex sync.Mutex
	var previous func()
	previous = func() {} // no op func
	for {
		select {
		case <-ctx.Done():
			return nil
		case q := <-f.state.Hub().QueryCh():
			workctx, workcancel := context.WithCancel(ctx)

			mutex.Lock()
			previous()
			previous = workcancel
			mutex.Unlock()

			f.state.Hub().SendStatusMsg("Running query...")

			go func() {
				f.Work(workctx, q)
			}()
		}
	}
}

func NewRegexpFilter() *RegexpFilter {
	return &RegexpFilter{
		flags: regexpFlagList(defaultFlags),
		name:  "Regexp",
		outCh: pipeline.OutputChannel(make(chan interface{})),
	}
}

func (rf RegexpFilter) OutCh() <-chan interface{} {
	return rf.outCh
}

func (rf RegexpFilter) Clone() LineFilter {
	return &RegexpFilter{
		flags:     rf.flags,
		quotemeta: rf.quotemeta,
		query:     rf.query,
		name:      rf.name,
		outCh:     pipeline.OutputChannel(make(chan interface{})),
	}
}

const filterBufSize = 1000
var filterBufPool = sync.Pool{
	New: func() interface{} {
		return make([]Line, 0, filterBufSize)
	},
}

func releaseRegexpFilterBuf(l []Line) {
	if l == nil {
		return
	}
	l = l[0:0]
	filterBufPool.Put(l)
}

func getRegexpFilterBuf() []Line {
	l := filterBufPool.Get().([]Line)
	return l
}

func (rf *RegexpFilter) Accept(ctx context.Context, p pipeline.Producer) {
	if pdebug.Enabled {
		g := pdebug.Marker("RegexpFilter.Accept")
		defer g.End()
	}
	defer rf.outCh.SendEndMark("end of RegexpFilter")

	flush := make(chan []Line)
	flushDone := make(chan struct{})
	go func() {
		defer close(flushDone)
		for buf := range flush {
			for _, in := range buf {
				if l, err := rf.filter(in); err == nil {
					rf.outCh.Send(l)
				}
			}
			releaseRegexpFilterBuf(buf)
		}
	}()

	buf := getRegexpFilterBuf()
	defer func() { releaseRegexpFilterBuf(buf) }()
	defer func() { <-flushDone }() // Wait till the flush goroutine is done
	defer close(flush) // Kill the flush goroutine

	for {
		select {
		case <-ctx.Done():
			if pdebug.Enabled {
				pdebug.Printf("RegexpFilter received done")
			}
			return
		case v := <-p.OutCh():
			switch v.(type) {
			case error:
				if pipeline.IsEndMark(v.(error)) {
					if pdebug.Enabled {
						pdebug.Printf("RegexpFilter received end mark")
					}
					if len(buf) > 0 {
						flush <-buf
						buf = nil
					}
				}
				return
			case Line:
				buf = append(buf, v.(Line))
				if len(buf) >= cap(buf) {
					flush <- buf
					buf = getRegexpFilterBuf()
				}
			}
		}
	}
}

func (rf *RegexpFilter) filter(l Line) (Line, error) {
	regexps, err := rf.getQueryAsRegexps()
	if err != nil {
		return nil, errors.Wrap(err, "failed to compile queries as regular expression")
	}
	v := l.DisplayString()
	allMatched := true
	matches := [][]int{}
TryRegexps:
	for _, rx := range regexps {
		match := rx.FindAllStringSubmatchIndex(v, -1)
		if match == nil {
			allMatched = false
			break TryRegexps
		}
		matches = append(matches, match...)
	}

	if !allMatched {
		return nil, errors.New("filter did not match against given line")
	}

	sort.Sort(byMatchStart(matches))

	// We need to "dedupe" the results. For example, if we matched the
	// same region twice, we don't want that to be drawn

	deduped := make([][]int, 0, len(matches))

	for i, m := range matches {
		// Always push the first one
		if i == 0 {
			deduped = append(deduped, m)
			continue
		}

		prev := deduped[len(deduped)-1]
		switch {
		case matchContains(prev, m):
			// If the previous match contains this one, then
			// don't do anything
			continue
		case matchOverlaps(prev, m):
			// If the previous match overlaps with this one,
			// merge the results and make it a bigger one
			deduped[len(deduped)-1] = mergeMatches(prev, m)
		default:
			deduped = append(deduped, m)
		}
	}
	return NewMatchedLine(l, deduped), nil
}

func (rf *RegexpFilter) getQueryAsRegexps() ([]*regexp.Regexp, error) {
	if q := rf.compiledQuery; q != nil {
		return q, nil
	}
	q, err := queryToRegexps(rf.flags, rf.quotemeta, rf.query)
	if err != nil {
		return nil, errors.Wrap(err, "failed to compile queries as regular expression")
	}

	rf.compiledQuery = q
	return q, nil
}

func (rf *RegexpFilter) SetQuery(q string) {
	rf.query = q
	rf.compiledQuery = nil
}

func (rf RegexpFilter) String() string {
	return rf.name
}

var ErrFilterNotFound = errors.New("specified filter was not found")

func NewIgnoreCaseFilter() *RegexpFilter {
	rf := NewRegexpFilter()
	rf.flags = ignoreCaseFlags
	rf.quotemeta = true
	rf.name = "IgnoreCase"
	return rf
}

func NewCaseSensitiveFilter() *RegexpFilter {
	rf := NewRegexpFilter()
	rf.quotemeta = true
	rf.name = "CaseSensitive"
	return rf
}

// SmartCaseFilter turns ON the ignore-case flag in the regexp
// if the query contains a upper-case character
func NewSmartCaseFilter() *RegexpFilter {
	rf := NewRegexpFilter()
	rf.quotemeta = true
	rf.name = "SmartCase"
	rf.flags = regexpFlagFunc(func(q string) []string {
		if util.ContainsUpper(q) {
			return defaultFlags
		}
		return []string{"i"}
	})
	return rf
}

func NewExternalCmdFilter(name string, cmd string, args []string, threshold int, enableSep bool) *ExternalCmdFilter {
	if len(args) == 0 {
		args = []string{"$QUERY"}
	}

	if threshold <= 0 {
		threshold = DefaultCustomFilterBufferThreshold
	}

	return &ExternalCmdFilter{
		args:            args,
		cmd:             cmd,
		enableSep:       enableSep,
		name:            name,
		outCh:           pipeline.OutputChannel(make(chan interface{})),
		thresholdBufsiz: threshold,
	}
}

func (ecf ExternalCmdFilter) Clone() LineFilter {
	return &ExternalCmdFilter{
		args:            ecf.args,
		cmd:             ecf.cmd,
		enableSep:       ecf.enableSep,
		name:            ecf.name,
		outCh:           pipeline.OutputChannel(make(chan interface{})),
		thresholdBufsiz: ecf.thresholdBufsiz,
	}
}

func (ecf *ExternalCmdFilter) Verify() error {
	if ecf.cmd == "" {
		return errors.Errorf("no executable specified for custom matcher '%s'", ecf.name)
	}

	if _, err := exec.LookPath(ecf.cmd); err != nil {
		return errors.Wrap(err, "failed to locate command")
	}
	return nil
}

func (ecf *ExternalCmdFilter) Accept(ctx context.Context, p pipeline.Producer) {
	if pdebug.Enabled {
		g := pdebug.Marker("ExternalCmdFilter.Accept")
		defer g.End()
	}
	defer ecf.outCh.SendEndMark("end of ExternalCmdFilter")

	buf := make([]Line, 0, ecf.thresholdBufsiz)
	for {
		select {
		case <-ctx.Done():
			if pdebug.Enabled {
				pdebug.Printf("ExternalCmdFilter received done")
			}
			return
		case v := <-p.OutCh():
			switch v.(type) {
			case error:
				if pipeline.IsEndMark(v.(error)) {
					if pdebug.Enabled {
						pdebug.Printf("ExternalCmdFilter received end mark")
					}
					if len(buf) > 0 {
						ecf.launchExternalCmd(ctx, buf)
					}
				}
				return
			case Line:
				if pdebug.Enabled {
					pdebug.Printf("ExternalCmdFilter received new line")
				}
				buf = append(buf, v.(Line))
				if len(buf) < ecf.thresholdBufsiz {
					continue
				}

				ecf.launchExternalCmd(ctx, buf)
				buf = buf[0:0]
			}
		}
	}
}

func (ecf ExternalCmdFilter) OutCh() <-chan interface{} {
	return ecf.outCh
}

func (ecf *ExternalCmdFilter) SetQuery(q string) {
	ecf.query = q
}

func (ecf ExternalCmdFilter) String() string {
	return ecf.name
}

func (ecf *ExternalCmdFilter) launchExternalCmd(ctx context.Context, buf []Line) {
	defer func() { recover() }() // ignore errors
	if pdebug.Enabled {
		g := pdebug.Marker("ExternalCmdFilter.launchExternalCmd")
		defer g.End()
	}

	args := append([]string(nil), ecf.args...)
	for i, v := range args {
		if v == "$QUERY" {
			args[i] = ecf.query
		}
	}
	cmd := exec.Command(ecf.cmd, args...)
	if pdebug.Enabled {
		pdebug.Printf("Executing command %s %v", cmd.Path, cmd.Args)
	}

	inbuf := &bytes.Buffer{}
	for _, l := range buf {
		inbuf.WriteString(l.DisplayString() + "\n")
	}

	cmd.Stdin = inbuf
	r, err := cmd.StdoutPipe()
	if err != nil {
		return
	}

	err = cmd.Start()
	if err != nil {
		return
	}

	go cmd.Wait()

	cmdCh := make(chan Line)
	go func(cmdCh chan Line, rdr *bufio.Reader) {
		defer func() { recover() }()
		defer close(cmdCh)
		for {
			b, _, err := rdr.ReadLine()
			if len(b) > 0 {
				// TODO: need to redo the spec for custom matchers
				// This is the ONLY location where we need to actually
				// RECREATE a RawLine, and thus the only place where
				// ctx.enableSep is required.
				cmdCh <- NewMatchedLine(NewRawLine(string(b), ecf.enableSep), nil)
			}
			if err != nil {
				break
			}
		}
	}(cmdCh, bufio.NewReader(r))

	defer func() {
		if p := cmd.Process; p != nil {
			p.Kill()
		}
	}()

	for {
		select {
		case <-ctx.Done():
			return
		case l, ok := <-cmdCh:
			if l == nil || !ok {
				return
			}
			ecf.outCh.Send(l)
		}
	}
}
<|endoftext|>


<commit_before>package app

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"html/template"
	"net"
	"net/http"

	"golang.org/x/text/language"

	"github.com/gowww/check"
	"github.com/gowww/fatal"
	"github.com/gowww/i18n"
	"github.com/gowww/router"
)

// A Context contains the data for a handler.
type Context struct {
	Res http.ResponseWriter
	Req *http.Request
}

// contextHandle wraps the router for setting headers and deferring their write.
func contextHandle(h http.Handler) http.Handler {
	return Handler(func(c *Context) {
		cw := &contextWriter{ResponseWriter: c.Res}
		defer func() {
			if cw.status != 0 {
				c.Res.WriteHeader(cw.status)
			}
		}()
		cw.Header().Set("Connection", "keep-alive")
		h.ServeHTTP(cw, c.Req)
	})
}

// logWriter keeps the status code from WriteHeader to allow setting headers after a Context.Status call.
// Required when using Context.Status with Context.JSON, for example.
type contextWriter struct {
	http.ResponseWriter
	status int
}

func (cw *contextWriter) WriteHeader(status int) {
	cw.status = status
}

func (cw *contextWriter) Write(b []byte) (int, error) {
	if cw.status != 0 {
		cw.ResponseWriter.WriteHeader(cw.status)
		cw.status = 0
	}
	return cw.ResponseWriter.Write(b)
}

// CloseNotify implements the http.CloseNotifier interface.
// No channel is returned if CloseNotify is not implemented by an upstream response writer.
func (cw *contextWriter) CloseNotify() <-chan bool {
	n, ok := cw.ResponseWriter.(http.CloseNotifier)
	if !ok {
		return nil
	}
	return n.CloseNotify()
}

// Flush implements the http.Flusher interface.
// Nothing is done if Flush is not implemented by an upstream response writer.
func (cw *contextWriter) Flush() {
	f, ok := cw.ResponseWriter.(http.Flusher)
	if ok {
		f.Flush()
	}
}

// Hijack implements the http.Hijacker interface.
// Error http.ErrNotSupported is returned if Hijack is not implemented by an upstream response writer.
func (cw *contextWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	h, ok := cw.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, http.ErrNotSupported
	}
	return h.Hijack()
}

// Push implements the http.Pusher interface.
// http.ErrNotSupported is returned if Push is not implemented by an upstream response writer or not supported by the client.
func (cw *contextWriter) Push(target string, opts *http.PushOptions) error {
	p, ok := cw.ResponseWriter.(http.Pusher)
	if !ok {
		return http.ErrNotSupported
	}
	return p.Push(target, opts)
}

// Get returns a context value.
func (c *Context) Get(key interface{}) interface{} {
	return c.Req.Context().Value(key)
}

// Set sets a context value.
func (c *Context) Set(key, val interface{}) {
	c.Req = c.Req.WithContext(context.WithValue(c.Req.Context(), key, val))
}

// PathValue returns the value of path parameter.
func (c *Context) PathValue(key string) string {
	return router.Parameter(c.Req, key)
}

// FormValue gets the form value from the request.
func (c *Context) FormValue(key string) string {
	return c.Req.FormValue(key)
}

// HasFormValue checks if the form value exists in the request.
func (c *Context) HasFormValue(key string) bool {
	return c.Req.FormValue(key) != ""
}

// Write writes the response.
func (c *Context) Write(b []byte) (int, error) {
	return c.Res.Write(b)
}

// Text writes the response with a string.
func (c *Context) Text(s string) {
	c.Write([]byte(s))
}

// Textf writes the response with a formatted string.
func (c *Context) Textf(s string, a ...interface{}) {
	fmt.Fprintf(c.Res, s, a...)
}

// Bytes writes the response with a bytes slice.
func (c *Context) Bytes(b []byte) {
	c.Write(b)
}

// Status sets the HTTP status of the response.
func (c *Context) Status(code int) {
	c.Res.WriteHeader(code)
}

// View writes the response with a rendered view.
// This data is always part of the rendering:
//	.	the GlobalViewData
//	.c	the Context
//	.errors	the translated errors map
func (c *Context) View(name string, data ...ViewData) {
	mdata := mergeViewData(data)
	mdata["c"] = c
	switch errs := mdata["errors"].(type) {
	case check.TranslatedErrors:
		break
	case check.Errors:
		mdata["errors"] = c.TErrors(errs)
	default:
		mdata["errors"] = make(check.TranslatedErrors)
	}
	err := views.ExecuteTemplate(c, name, mdata)
	if err != nil {
		c.Panic(err)
	}
}

// JSON writes the response with a marshalled JSON.
// If v has a JSON() interface{} method, it will be used.
func (c *Context) JSON(v interface{}) {
	c.Res.Header().Set("Content-Type", "application/json")
	enc := json.NewEncoder(c.Res)
	if vjson, ok := v.(interface {
		JSON() interface{}
	}); ok {
		if err := enc.Encode(vjson.JSON()); err != nil {
			c.Panic(err)
		}
		return
	}
	if err := enc.Encode(v); err != nil {
		c.Panic(err)
	}
}

// Check uses a check.Checker to validate request's data and always returns the non-nil errors map.
func (c *Context) Check(checker check.Checker) check.Errors {
	return checker.CheckRequest(c.Req)
}

// TErrors returns translated checking errors.
func (c *Context) TErrors(errs check.Errors) check.TranslatedErrors {
	return errs.T(i18n.RequestTranslator(c.Req))
}

// BadRequest uses a check.Checker to validate request form data, and a view name to execute on fail.
// If you don't provide a view name (empty string), the response will be a JSON errors map.
//
// If the check fails, it sets the status to "400 Bad Request" and returns true, allowing you to exit from the handler.
func (c *Context) BadRequest(checker check.Checker, view string, data ...ViewData) bool {
	errs := c.Check(checker)
	if errs.Empty() {
		return false
	}
	c.Status(http.StatusBadRequest)
	if view == "" {
		c.JSON(errs)
	} else {
		data = append(data, ViewData{"errors": c.TErrors(errs)})
		c.View(view, data...)
	}
	return true
}

// Redirect redirects the client to the url with status code.
func (c *Context) Redirect(url string, status int) {
	http.Redirect(c.Res, c.Req, url, status)
}

// Cookie returns the value of the named cookie.
// If multiple cookies match the given name, only one cookie value will be returned.
// If the secret key is set for app, value will be decrypted before returning.
// If cookie is not found or the decryption fails, an empty string is returned.
func (c *Context) Cookie(name string) string {
	ck, _ := c.Req.Cookie(name)
	if ck == nil {
		return ""
	}
	if encrypter == nil {
		return ck.Value
	}
	v, err := encrypter.DecryptBase64([]byte(ck.Value))
	if err != nil {
		c.DeleteCookie(name)
		return ""
	}
	return string(v)
}

// SetCookie sets a cookie to the response.
// If the secret key is set for app, value will be encrypted.
// If the app is not in a production environment, the "secure" flag will be set to false.
func (c *Context) SetCookie(cookie *http.Cookie) {
	if !production {
		cookie.Secure = false
	}
	if encrypter != nil {
		v, err := encrypter.EncryptBase64([]byte(cookie.Value))
		if err != nil {
			c.Panic(err)
		}
		cookie.Value = string(v)
	}
	http.SetCookie(c.Res, cookie)
}

// DeleteCookie removes a cookie from the client.
func (c *Context) DeleteCookie(name string) {
	http.SetCookie(c.Res, &http.Cookie{Name: name, MaxAge: -1})
}

// translator returns the request translator.
func (c *Context) translator() *i18n.Translator {
	rt := i18n.RequestTranslator(c.Req)
	if rt == nil {
		panic("app: no locales, no translator set")
	}
	return rt
}

// Locale returns the locale used for the client.
func (c *Context) Locale() language.Tag {
	return c.translator().Locale()
}

// T returns the translation associated to key, for the client locale.
func (c *Context) T(key string, a ...interface{}) string {
	return c.translator().T(key, a...)
}

// Tn returns the translation associated to key, for the client locale.
// If the translation defines plural forms (zero, one, other), it uses the most appropriate.
// All i18n.TnPlaceholder in the translation are replaced with number n.
// If translation is not found, an empty string is returned.
func (c *Context) Tn(key string, n int, args ...interface{}) string {
	return c.translator().Tn(key, n, args...)
}

// THTML works like T but returns an HTML unescaped translation. An "nl2br" function is applied to the result.
func (c *Context) THTML(key string, a ...interface{}) template.HTML {
	return c.translator().THTML(key, a...)
}

// TnHTML works like Tn but returns an HTML unescaped translation. An "nl2br" function is applied to the result.
func (c *Context) TnHTML(key string, n int, args ...interface{}) template.HTML {
	return c.translator().TnHTML(key, n, args...)
}

// FmtNumber returns a formatted number with decimal and thousands marks.
func (c *Context) FmtNumber(n interface{}) string {
	return i18n.FmtNumber(c.translator().Locale(), n)
}

// TODO: HTML link helper with i18n. See https://support.google.com/webmasters/answer/189077?hl=en.

// Push initiates an HTTP/2 server push if supported.
// See net/http.Pusher for documentation.
func (c *Context) Push(target string, opts *http.PushOptions) {
	if pusher, ok := c.Res.(http.Pusher); ok {
		pusher.Push(target, opts)
	}
}

// NotFound responds with the "not found" handler.
func (c *Context) NotFound() {
	if rt.NotFoundHandler != nil {
		rt.NotFoundHandler.ServeHTTP(c.Res, c.Req)
	} else {
		http.NotFound(c.Res, c.Req)
	}
}

// Panic logs error with stack trace and responds with the error handler if set.
func (c *Context) Panic(err error) {
	panic(fmt.Errorf("Failed serving %s: %v", c.Req.RemoteAddr, err))
}

// Error returns the error value stored in request's context after a recovering or a Context.Error call.
func (c *Context) Error() error {
	return fmt.Errorf("%v", fatal.Error(c.Req))
}
<commit_msg>Add Context.Log<commit_after>package app

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net"
	"net/http"

	"golang.org/x/text/language"

	"github.com/gowww/check"
	"github.com/gowww/fatal"
	"github.com/gowww/i18n"
	"github.com/gowww/router"
)

// A Context contains the data for a handler.
type Context struct {
	Res http.ResponseWriter
	Req *http.Request
}

// contextHandle wraps the router for setting headers and deferring their write.
func contextHandle(h http.Handler) http.Handler {
	return Handler(func(c *Context) {
		cw := &contextWriter{ResponseWriter: c.Res}
		defer func() {
			if cw.status != 0 {
				c.Res.WriteHeader(cw.status)
			}
		}()
		cw.Header().Set("Connection", "keep-alive")
		h.ServeHTTP(cw, c.Req)
	})
}

// logWriter keeps the status code from WriteHeader to allow setting headers after a Context.Status call.
// Required when using Context.Status with Context.JSON, for example.
type contextWriter struct {
	http.ResponseWriter
	status int
}

func (cw *contextWriter) WriteHeader(status int) {
	cw.status = status
}

func (cw *contextWriter) Write(b []byte) (int, error) {
	if cw.status != 0 {
		cw.ResponseWriter.WriteHeader(cw.status)
		cw.status = 0
	}
	return cw.ResponseWriter.Write(b)
}

// CloseNotify implements the http.CloseNotifier interface.
// No channel is returned if CloseNotify is not implemented by an upstream response writer.
func (cw *contextWriter) CloseNotify() <-chan bool {
	n, ok := cw.ResponseWriter.(http.CloseNotifier)
	if !ok {
		return nil
	}
	return n.CloseNotify()
}

// Flush implements the http.Flusher interface.
// Nothing is done if Flush is not implemented by an upstream response writer.
func (cw *contextWriter) Flush() {
	f, ok := cw.ResponseWriter.(http.Flusher)
	if ok {
		f.Flush()
	}
}

// Hijack implements the http.Hijacker interface.
// Error http.ErrNotSupported is returned if Hijack is not implemented by an upstream response writer.
func (cw *contextWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	h, ok := cw.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, http.ErrNotSupported
	}
	return h.Hijack()
}

// Push implements the http.Pusher interface.
// http.ErrNotSupported is returned if Push is not implemented by an upstream response writer or not supported by the client.
func (cw *contextWriter) Push(target string, opts *http.PushOptions) error {
	p, ok := cw.ResponseWriter.(http.Pusher)
	if !ok {
		return http.ErrNotSupported
	}
	return p.Push(target, opts)
}

// Get returns a context value.
func (c *Context) Get(key interface{}) interface{} {
	return c.Req.Context().Value(key)
}

// Set sets a context value.
func (c *Context) Set(key, val interface{}) {
	c.Req = c.Req.WithContext(context.WithValue(c.Req.Context(), key, val))
}

// PathValue returns the value of path parameter.
func (c *Context) PathValue(key string) string {
	return router.Parameter(c.Req, key)
}

// FormValue gets the form value from the request.
func (c *Context) FormValue(key string) string {
	return c.Req.FormValue(key)
}

// HasFormValue checks if the form value exists in the request.
func (c *Context) HasFormValue(key string) bool {
	return c.Req.FormValue(key) != ""
}

// Write writes the response.
func (c *Context) Write(b []byte) (int, error) {
	return c.Res.Write(b)
}

// Text writes the response with a string.
func (c *Context) Text(s string) {
	c.Write([]byte(s))
}

// Textf writes the response with a formatted string.
func (c *Context) Textf(s string, a ...interface{}) {
	fmt.Fprintf(c.Res, s, a...)
}

// Bytes writes the response with a bytes slice.
func (c *Context) Bytes(b []byte) {
	c.Write(b)
}

// Status sets the HTTP status of the response.
func (c *Context) Status(code int) {
	c.Res.WriteHeader(code)
}

// View writes the response with a rendered view.
// This data is always part of the rendering:
//	.	the GlobalViewData
//	.c	the Context
//	.errors	the translated errors map
func (c *Context) View(name string, data ...ViewData) {
	mdata := mergeViewData(data)
	mdata["c"] = c
	switch errs := mdata["errors"].(type) {
	case check.TranslatedErrors:
		break
	case check.Errors:
		mdata["errors"] = c.TErrors(errs)
	default:
		mdata["errors"] = make(check.TranslatedErrors)
	}
	err := views.ExecuteTemplate(c, name, mdata)
	if err != nil {
		c.Panic(err)
	}
}

// JSON writes the response with a marshalled JSON.
// If v has a JSON() interface{} method, it will be used.
func (c *Context) JSON(v interface{}) {
	c.Res.Header().Set("Content-Type", "application/json")
	enc := json.NewEncoder(c.Res)
	if vjson, ok := v.(interface {
		JSON() interface{}
	}); ok {
		if err := enc.Encode(vjson.JSON()); err != nil {
			c.Panic(err)
		}
		return
	}
	if err := enc.Encode(v); err != nil {
		c.Panic(err)
	}
}

// Check uses a check.Checker to validate request's data and always returns the non-nil errors map.
func (c *Context) Check(checker check.Checker) check.Errors {
	return checker.CheckRequest(c.Req)
}

// TErrors returns translated checking errors.
func (c *Context) TErrors(errs check.Errors) check.TranslatedErrors {
	return errs.T(i18n.RequestTranslator(c.Req))
}

// BadRequest uses a check.Checker to validate request form data, and a view name to execute on fail.
// If you don't provide a view name (empty string), the response will be a JSON errors map.
//
// If the check fails, it sets the status to "400 Bad Request" and returns true, allowing you to exit from the handler.
func (c *Context) BadRequest(checker check.Checker, view string, data ...ViewData) bool {
	errs := c.Check(checker)
	if errs.Empty() {
		return false
	}
	c.Status(http.StatusBadRequest)
	if view == "" {
		c.JSON(errs)
	} else {
		data = append(data, ViewData{"errors": c.TErrors(errs)})
		c.View(view, data...)
	}
	return true
}

// Redirect redirects the client to the url with status code.
func (c *Context) Redirect(url string, status int) {
	http.Redirect(c.Res, c.Req, url, status)
}

// Cookie returns the value of the named cookie.
// If multiple cookies match the given name, only one cookie value will be returned.
// If the secret key is set for app, value will be decrypted before returning.
// If cookie is not found or the decryption fails, an empty string is returned.
func (c *Context) Cookie(name string) string {
	ck, _ := c.Req.Cookie(name)
	if ck == nil {
		return ""
	}
	if encrypter == nil {
		return ck.Value
	}
	v, err := encrypter.DecryptBase64([]byte(ck.Value))
	if err != nil {
		c.DeleteCookie(name)
		return ""
	}
	return string(v)
}

// SetCookie sets a cookie to the response.
// If the secret key is set for app, value will be encrypted.
// If the app is not in a production environment, the "secure" flag will be set to false.
func (c *Context) SetCookie(cookie *http.Cookie) {
	if !production {
		cookie.Secure = false
	}
	if encrypter != nil {
		v, err := encrypter.EncryptBase64([]byte(cookie.Value))
		if err != nil {
			c.Panic(err)
		}
		cookie.Value = string(v)
	}
	http.SetCookie(c.Res, cookie)
}

// DeleteCookie removes a cookie from the client.
func (c *Context) DeleteCookie(name string) {
	http.SetCookie(c.Res, &http.Cookie{Name: name, MaxAge: -1})
}

// translator returns the request translator.
func (c *Context) translator() *i18n.Translator {
	rt := i18n.RequestTranslator(c.Req)
	if rt == nil {
		panic("app: no locales, no translator set")
	}
	return rt
}

// Locale returns the locale used for the client.
func (c *Context) Locale() language.Tag {
	return c.translator().Locale()
}

// T returns the translation associated to key, for the client locale.
func (c *Context) T(key string, a ...interface{}) string {
	return c.translator().T(key, a...)
}

// Tn returns the translation associated to key, for the client locale.
// If the translation defines plural forms (zero, one, other), it uses the most appropriate.
// All i18n.TnPlaceholder in the translation are replaced with number n.
// If translation is not found, an empty string is returned.
func (c *Context) Tn(key string, n int, args ...interface{}) string {
	return c.translator().Tn(key, n, args...)
}

// THTML works like T but returns an HTML unescaped translation. An "nl2br" function is applied to the result.
func (c *Context) THTML(key string, a ...interface{}) template.HTML {
	return c.translator().THTML(key, a...)
}

// TnHTML works like Tn but returns an HTML unescaped translation. An "nl2br" function is applied to the result.
func (c *Context) TnHTML(key string, n int, args ...interface{}) template.HTML {
	return c.translator().TnHTML(key, n, args...)
}

// FmtNumber returns a formatted number with decimal and thousands marks.
func (c *Context) FmtNumber(n interface{}) string {
	return i18n.FmtNumber(c.translator().Locale(), n)
}

// TODO: HTML link helper with i18n. See https://support.google.com/webmasters/answer/189077?hl=en.

// Push initiates an HTTP/2 server push if supported.
// See net/http.Pusher for documentation.
func (c *Context) Push(target string, opts *http.PushOptions) {
	if pusher, ok := c.Res.(http.Pusher); ok {
		pusher.Push(target, opts)
	}
}

// NotFound responds with the "not found" handler.
func (c *Context) NotFound() {
	if rt.NotFoundHandler != nil {
		rt.NotFoundHandler.ServeHTTP(c.Res, c.Req)
	} else {
		http.NotFound(c.Res, c.Req)
	}
}

// Log logs the message with the client address.
func (c *Context) Log(msg string) {
	log.Printf("Serving %s: %s", c.Req.RemoteAddr, msg)
}

// Panic logs error with stack trace and responds with the error handler if set.
func (c *Context) Panic(err error) {
	panic(fmt.Errorf("Failed serving %s: %v", c.Req.RemoteAddr, err))
}

// Error returns the error value stored in request's context after a recovering or a Context.Error call.
func (c *Context) Error() error {
	return fmt.Errorf("%v", fatal.Error(c.Req))
}
<|endoftext|>


<commit_before>package fauxgl

import (
	"image"
	"math"
	"runtime"
	"sync"
)

type Face int

const (
	_ Face = iota
	FaceCW
	FaceCCW
)

type Cull int

const (
	_ Cull = iota
	CullNone
	CullFront
	CullBack
)

type Context struct {
	Width        int
	Height       int
	ColorBuffer  *image.NRGBA
	DepthBuffer  []float64
	ClearColor   Color
	Shader       Shader
	ReadDepth    bool
	WriteDepth   bool
	WriteColor   bool
	AlphaBlend   bool
	Wireframe    bool
	FrontFace    Face
	Cull         Cull
	LineWidth    float64
	DepthBias    float64
	screenMatrix Matrix
	locks        []sync.Mutex
}

func NewContext(width, height int) *Context {
	dc := &Context{}
	dc.Width = width
	dc.Height = height
	dc.ColorBuffer = image.NewNRGBA(image.Rect(0, 0, width, height))
	dc.DepthBuffer = make([]float64, width*height)
	dc.ClearColor = Transparent
	dc.Shader = nil // TODO: default
	dc.ReadDepth = true
	dc.WriteDepth = true
	dc.WriteColor = true
	dc.AlphaBlend = true
	dc.Wireframe = false
	dc.FrontFace = FaceCCW
	dc.Cull = CullBack
	dc.LineWidth = 2
	dc.DepthBias = 0
	dc.screenMatrix = Screen(width, height)
	dc.locks = make([]sync.Mutex, 256)
	dc.ClearDepthBuffer()
	return dc
}

func (dc *Context) Image() image.Image {
	return dc.ColorBuffer
}

func (dc *Context) ClearColorBufferWith(color Color) {
	c := color.NRGBA()
	for y := 0; y < dc.Height; y++ {
		i := dc.ColorBuffer.PixOffset(0, y)
		for x := 0; x < dc.Width; x++ {
			dc.ColorBuffer.Pix[i+0] = c.R
			dc.ColorBuffer.Pix[i+1] = c.G
			dc.ColorBuffer.Pix[i+2] = c.B
			dc.ColorBuffer.Pix[i+3] = c.A
			i += 4
		}
	}
}

func (dc *Context) ClearColorBuffer() {
	dc.ClearColorBufferWith(dc.ClearColor)
}

func (dc *Context) ClearDepthBufferWith(value float64) {
	for i := range dc.DepthBuffer {
		dc.DepthBuffer[i] = value
	}
}

func (dc *Context) ClearDepthBuffer() {
	dc.ClearDepthBufferWith(math.MaxFloat64)
}

func edge(a, b, c Vector) float64 {
	return (b.X-c.X)*(a.Y-c.Y) - (b.Y-c.Y)*(a.X-c.X)
}

func (dc *Context) rasterize(v0, v1, v2 Vertex, s0, s1, s2 Vector) {
	// integer bounding box
	min := s0.Min(s1.Min(s2)).Floor()
	max := s0.Max(s1.Max(s2)).Ceil()
	x0 := int(min.X)
	x1 := int(max.X)
	y0 := int(min.Y)
	y1 := int(max.Y)

	// forward differencing variables
	p := Vector{float64(x0) + 0.5, float64(y0) + 0.5, 0}
	w00 := edge(s1, s2, p)
	w01 := edge(s2, s0, p)
	w02 := edge(s0, s1, p)
	a01 := s1.Y - s0.Y
	b01 := s0.X - s1.X
	a12 := s2.Y - s1.Y
	b12 := s1.X - s2.X
	a20 := s0.Y - s2.Y
	b20 := s2.X - s0.X

	// reciprocals
	ra := 1 / edge(s0, s1, s2)
	r0 := 1 / v0.Output.W
	r1 := 1 / v1.Output.W
	r2 := 1 / v2.Output.W
	ra12 := 1 / a12
	ra20 := 1 / a20
	ra01 := 1 / a01

	// iterate over all pixels in bounding box
	for y := y0; y <= y1; y++ {
		var d float64
		d0 := -w00 * ra12
		d1 := -w01 * ra20
		d2 := -w02 * ra01
		if w00 < 0 && d0 > d {
			d = d0
		}
		if w01 < 0 && d1 > d {
			d = d1
		}
		if w02 < 0 && d2 > d {
			d = d2
		}
		d = float64(int(d))
		if d < 0 {
			// occurs in pathological cases
			d = 0
		}
		w0 := w00 + a12*d
		w1 := w01 + a20*d
		w2 := w02 + a01*d
		wasInside := false
		for x := x0 + int(d); x <= x1; x++ {
			b0 := w0 * ra
			b1 := w1 * ra
			b2 := w2 * ra
			w0 += a12
			w1 += a20
			w2 += a01
			// check if inside triangle
			if b0 < 0 || b1 < 0 || b2 < 0 {
				if wasInside {
					break
				}
				continue
			}
			wasInside = true
			// check depth buffer for early abort
			i := y*dc.Width + x
			if i < 0 || i >= len(dc.DepthBuffer) {
				// TODO: clipping roundoff error; fix
				continue
			}
			z := b0*s0.Z + b1*s1.Z + b2*s2.Z
			bz := z + dc.DepthBias
			if dc.ReadDepth && bz > dc.DepthBuffer[i] { // safe w/out lock?
				continue
			}
			// perspective-correct interpolation of vertex data
			b := VectorW{b0 * r0, b1 * r1, b2 * r2, 0}
			b.W = 1 / (b.X + b.Y + b.Z)
			v := InterpolateVertexes(v0, v1, v2, b)
			// invoke fragment shader
			color := dc.Shader.Fragment(v)
			if color == Discard {
				continue
			}
			// update buffers atomically
			lock := &dc.locks[(x+y)&255]
			lock.Lock()
			// check depth buffer again
			if bz <= dc.DepthBuffer[i] || !dc.ReadDepth {
				if dc.WriteDepth {
					// update depth buffer
					dc.DepthBuffer[i] = z
				}
				if dc.WriteColor {
					// update color buffer
					if dc.AlphaBlend && color.A < 1 {
						sr, sg, sb, sa := color.NRGBA().RGBA()
						a := (0xffff - sa) * 0x101
						j := dc.ColorBuffer.PixOffset(x, y)
						dr := &dc.ColorBuffer.Pix[j+0]
						dg := &dc.ColorBuffer.Pix[j+1]
						db := &dc.ColorBuffer.Pix[j+2]
						da := &dc.ColorBuffer.Pix[j+3]
						*dr = uint8((uint32(*dr)*a/0xffff + sr) >> 8)
						*dg = uint8((uint32(*dg)*a/0xffff + sg) >> 8)
						*db = uint8((uint32(*db)*a/0xffff + sb) >> 8)
						*da = uint8((uint32(*da)*a/0xffff + sa) >> 8)
					} else {
						dc.ColorBuffer.SetNRGBA(x, y, color.NRGBA())
					}
				}
			}
			lock.Unlock()
		}
		w00 += b12
		w01 += b20
		w02 += b01
	}
}

func (dc *Context) line(v0, v1 Vertex, s0, s1 Vector) {
	n := s1.Sub(s0).Perpendicular().MulScalar(dc.LineWidth / 2)
	s0 = s0.Add(s0.Sub(s1).Normalize().MulScalar(dc.LineWidth / 2))
	s1 = s1.Add(s1.Sub(s0).Normalize().MulScalar(dc.LineWidth / 2))
	s00 := s0.Add(n)
	s01 := s0.Sub(n)
	s10 := s1.Add(n)
	s11 := s1.Sub(n)
	dc.rasterize(v1, v0, v0, s11, s01, s00)
	dc.rasterize(v1, v1, v0, s10, s11, s00)
}

func (dc *Context) wireframe(v0, v1, v2 Vertex, s0, s1, s2 Vector) {
	dc.line(v0, v1, s0, s1)
	dc.line(v1, v2, s1, s2)
	dc.line(v2, v0, s2, s0)
}

func (dc *Context) drawClippedTriangle(v0, v1, v2 Vertex) {
	// normalized device coordinates
	ndc0 := v0.Output.DivScalar(v0.Output.W).Vector()
	ndc1 := v1.Output.DivScalar(v1.Output.W).Vector()
	ndc2 := v2.Output.DivScalar(v2.Output.W).Vector()

	// back face culling
	if dc.Cull != CullNone {
		a := (ndc1.X-ndc0.X)*(ndc2.Y-ndc0.Y) - (ndc2.X-ndc0.X)*(ndc1.Y-ndc0.Y)
		if dc.Cull == CullFront {
			a = -a
		}
		if dc.FrontFace == FaceCW {
			a = -a
		}
		if a <= 0 {
			return
		}
	}

	// screen coordinates
	s0 := dc.screenMatrix.MulPosition(ndc0)
	s1 := dc.screenMatrix.MulPosition(ndc1)
	s2 := dc.screenMatrix.MulPosition(ndc2)

	// rasterize
	if dc.Wireframe {
		dc.wireframe(v0, v1, v2, s0, s1, s2)
	} else {
		dc.rasterize(v0, v1, v2, s0, s1, s2)
	}
}

func (dc *Context) drawClippedLine(v0, v1 Vertex) {
	// normalized device coordinates
	ndc0 := v0.Output.DivScalar(v0.Output.W).Vector()
	ndc1 := v1.Output.DivScalar(v1.Output.W).Vector()

	// screen coordinates
	s0 := dc.screenMatrix.MulPosition(ndc0)
	s1 := dc.screenMatrix.MulPosition(ndc1)

	// rasterize
	dc.line(v0, v1, s0, s1)
}

func (dc *Context) DrawLine(t *Line) {
	// invoke vertex shader
	v1 := dc.Shader.Vertex(t.V1)
	v2 := dc.Shader.Vertex(t.V2)

	if v1.Outside() || v2.Outside() {
		// clip to viewing volume
		line := ClipLine(NewLine(v1, v2))
		if line != nil {
			dc.drawClippedLine(line.V1, line.V2)
		}
	} else {
		// no need to clip
		dc.drawClippedLine(v1, v2)
	}
}

func (dc *Context) DrawLines(lines []*Line) {
	wn := runtime.NumCPU()
	done := make(chan bool, wn)
	for wi := 0; wi < wn; wi++ {
		go func(wi int) {
			for i, l := range lines {
				if i%wn == wi {
					dc.DrawLine(l)
				}
			}
			done <- true
		}(wi)
	}
	for wi := 0; wi < wn; wi++ {
		<-done
	}
}

func (dc *Context) DrawTriangle(t *Triangle) {
	// invoke vertex shader
	v1 := dc.Shader.Vertex(t.V1)
	v2 := dc.Shader.Vertex(t.V2)
	v3 := dc.Shader.Vertex(t.V3)

	if v1.Outside() || v2.Outside() || v3.Outside() {
		// clip to viewing volume
		triangles := ClipTriangle(NewTriangle(v1, v2, v3))
		for _, t := range triangles {
			dc.drawClippedTriangle(t.V1, t.V2, t.V3)
		}
	} else {
		// no need to clip
		dc.drawClippedTriangle(v1, v2, v3)
	}
}

func (dc *Context) DrawTriangles(triangles []*Triangle) {
	wn := runtime.NumCPU()
	done := make(chan bool, wn)
	for wi := 0; wi < wn; wi++ {
		go func(wi int) {
			for i, t := range triangles {
				if i%wn == wi {
					dc.DrawTriangle(t)
				}
			}
			done <- true
		}(wi)
	}
	for wi := 0; wi < wn; wi++ {
		<-done
	}
}

func (dc *Context) DrawMesh(mesh *Mesh) {
	dc.DrawTriangles(mesh.Triangles)
	dc.DrawLines(mesh.Lines)
}
<commit_msg>rearrange<commit_after>package fauxgl

import (
	"image"
	"math"
	"runtime"
	"sync"
)

type Face int

const (
	_ Face = iota
	FaceCW
	FaceCCW
)

type Cull int

const (
	_ Cull = iota
	CullNone
	CullFront
	CullBack
)

type Context struct {
	Width        int
	Height       int
	ColorBuffer  *image.NRGBA
	DepthBuffer  []float64
	ClearColor   Color
	Shader       Shader
	ReadDepth    bool
	WriteDepth   bool
	WriteColor   bool
	AlphaBlend   bool
	Wireframe    bool
	FrontFace    Face
	Cull         Cull
	LineWidth    float64
	DepthBias    float64
	screenMatrix Matrix
	locks        []sync.Mutex
}

func NewContext(width, height int) *Context {
	dc := &Context{}
	dc.Width = width
	dc.Height = height
	dc.ColorBuffer = image.NewNRGBA(image.Rect(0, 0, width, height))
	dc.DepthBuffer = make([]float64, width*height)
	dc.ClearColor = Transparent
	dc.Shader = nil // TODO: default
	dc.ReadDepth = true
	dc.WriteDepth = true
	dc.WriteColor = true
	dc.AlphaBlend = true
	dc.Wireframe = false
	dc.FrontFace = FaceCCW
	dc.Cull = CullBack
	dc.LineWidth = 2
	dc.DepthBias = 0
	dc.screenMatrix = Screen(width, height)
	dc.locks = make([]sync.Mutex, 256)
	dc.ClearDepthBuffer()
	return dc
}

func (dc *Context) Image() image.Image {
	return dc.ColorBuffer
}

func (dc *Context) ClearColorBufferWith(color Color) {
	c := color.NRGBA()
	for y := 0; y < dc.Height; y++ {
		i := dc.ColorBuffer.PixOffset(0, y)
		for x := 0; x < dc.Width; x++ {
			dc.ColorBuffer.Pix[i+0] = c.R
			dc.ColorBuffer.Pix[i+1] = c.G
			dc.ColorBuffer.Pix[i+2] = c.B
			dc.ColorBuffer.Pix[i+3] = c.A
			i += 4
		}
	}
}

func (dc *Context) ClearColorBuffer() {
	dc.ClearColorBufferWith(dc.ClearColor)
}

func (dc *Context) ClearDepthBufferWith(value float64) {
	for i := range dc.DepthBuffer {
		dc.DepthBuffer[i] = value
	}
}

func (dc *Context) ClearDepthBuffer() {
	dc.ClearDepthBufferWith(math.MaxFloat64)
}

func edge(a, b, c Vector) float64 {
	return (b.X-c.X)*(a.Y-c.Y) - (b.Y-c.Y)*(a.X-c.X)
}

func (dc *Context) rasterize(v0, v1, v2 Vertex, s0, s1, s2 Vector) {
	// integer bounding box
	min := s0.Min(s1.Min(s2)).Floor()
	max := s0.Max(s1.Max(s2)).Ceil()
	x0 := int(min.X)
	x1 := int(max.X)
	y0 := int(min.Y)
	y1 := int(max.Y)

	// forward differencing variables
	p := Vector{float64(x0) + 0.5, float64(y0) + 0.5, 0}
	w00 := edge(s1, s2, p)
	w01 := edge(s2, s0, p)
	w02 := edge(s0, s1, p)
	a01 := s1.Y - s0.Y
	b01 := s0.X - s1.X
	a12 := s2.Y - s1.Y
	b12 := s1.X - s2.X
	a20 := s0.Y - s2.Y
	b20 := s2.X - s0.X

	// reciprocals
	ra := 1 / edge(s0, s1, s2)
	r0 := 1 / v0.Output.W
	r1 := 1 / v1.Output.W
	r2 := 1 / v2.Output.W
	ra12 := 1 / a12
	ra20 := 1 / a20
	ra01 := 1 / a01

	// iterate over all pixels in bounding box
	for y := y0; y <= y1; y++ {
		var d float64
		d0 := -w00 * ra12
		d1 := -w01 * ra20
		d2 := -w02 * ra01
		if w00 < 0 && d0 > d {
			d = d0
		}
		if w01 < 0 && d1 > d {
			d = d1
		}
		if w02 < 0 && d2 > d {
			d = d2
		}
		d = float64(int(d))
		if d < 0 {
			// occurs in pathological cases
			d = 0
		}
		w0 := w00 + a12*d
		w1 := w01 + a20*d
		w2 := w02 + a01*d
		wasInside := false
		for x := x0 + int(d); x <= x1; x++ {
			b0 := w0 * ra
			b1 := w1 * ra
			b2 := w2 * ra
			w0 += a12
			w1 += a20
			w2 += a01
			// check if inside triangle
			if b0 < 0 || b1 < 0 || b2 < 0 {
				if wasInside {
					break
				}
				continue
			}
			wasInside = true
			// check depth buffer for early abort
			i := y*dc.Width + x
			if i < 0 || i >= len(dc.DepthBuffer) {
				// TODO: clipping roundoff error; fix
				// TODO: could also be from fat lines going off screen
				continue
			}
			z := b0*s0.Z + b1*s1.Z + b2*s2.Z
			bz := z + dc.DepthBias
			if dc.ReadDepth && bz > dc.DepthBuffer[i] { // safe w/out lock?
				continue
			}
			// perspective-correct interpolation of vertex data
			b := VectorW{b0 * r0, b1 * r1, b2 * r2, 0}
			b.W = 1 / (b.X + b.Y + b.Z)
			v := InterpolateVertexes(v0, v1, v2, b)
			// invoke fragment shader
			color := dc.Shader.Fragment(v)
			if color == Discard {
				continue
			}
			// update buffers atomically
			lock := &dc.locks[(x+y)&255]
			lock.Lock()
			// check depth buffer again
			if bz <= dc.DepthBuffer[i] || !dc.ReadDepth {
				if dc.WriteDepth {
					// update depth buffer
					dc.DepthBuffer[i] = z
				}
				if dc.WriteColor {
					// update color buffer
					if dc.AlphaBlend && color.A < 1 {
						sr, sg, sb, sa := color.NRGBA().RGBA()
						a := (0xffff - sa) * 0x101
						j := dc.ColorBuffer.PixOffset(x, y)
						dr := &dc.ColorBuffer.Pix[j+0]
						dg := &dc.ColorBuffer.Pix[j+1]
						db := &dc.ColorBuffer.Pix[j+2]
						da := &dc.ColorBuffer.Pix[j+3]
						*dr = uint8((uint32(*dr)*a/0xffff + sr) >> 8)
						*dg = uint8((uint32(*dg)*a/0xffff + sg) >> 8)
						*db = uint8((uint32(*db)*a/0xffff + sb) >> 8)
						*da = uint8((uint32(*da)*a/0xffff + sa) >> 8)
					} else {
						dc.ColorBuffer.SetNRGBA(x, y, color.NRGBA())
					}
				}
			}
			lock.Unlock()
		}
		w00 += b12
		w01 += b20
		w02 += b01
	}
}

func (dc *Context) line(v0, v1 Vertex, s0, s1 Vector) {
	n := s1.Sub(s0).Perpendicular().MulScalar(dc.LineWidth / 2)
	s0 = s0.Add(s0.Sub(s1).Normalize().MulScalar(dc.LineWidth / 2))
	s1 = s1.Add(s1.Sub(s0).Normalize().MulScalar(dc.LineWidth / 2))
	s00 := s0.Add(n)
	s01 := s0.Sub(n)
	s10 := s1.Add(n)
	s11 := s1.Sub(n)
	dc.rasterize(v1, v0, v0, s11, s01, s00)
	dc.rasterize(v1, v1, v0, s10, s11, s00)
}

func (dc *Context) wireframe(v0, v1, v2 Vertex, s0, s1, s2 Vector) {
	dc.line(v0, v1, s0, s1)
	dc.line(v1, v2, s1, s2)
	dc.line(v2, v0, s2, s0)
}

func (dc *Context) drawClippedLine(v0, v1 Vertex) {
	// normalized device coordinates
	ndc0 := v0.Output.DivScalar(v0.Output.W).Vector()
	ndc1 := v1.Output.DivScalar(v1.Output.W).Vector()

	// screen coordinates
	s0 := dc.screenMatrix.MulPosition(ndc0)
	s1 := dc.screenMatrix.MulPosition(ndc1)

	// rasterize
	dc.line(v0, v1, s0, s1)
}

func (dc *Context) drawClippedTriangle(v0, v1, v2 Vertex) {
	// normalized device coordinates
	ndc0 := v0.Output.DivScalar(v0.Output.W).Vector()
	ndc1 := v1.Output.DivScalar(v1.Output.W).Vector()
	ndc2 := v2.Output.DivScalar(v2.Output.W).Vector()

	// back face culling
	if dc.Cull != CullNone {
		a := (ndc1.X-ndc0.X)*(ndc2.Y-ndc0.Y) - (ndc2.X-ndc0.X)*(ndc1.Y-ndc0.Y)
		if dc.Cull == CullFront {
			a = -a
		}
		if dc.FrontFace == FaceCW {
			a = -a
		}
		if a <= 0 {
			return
		}
	}

	// screen coordinates
	s0 := dc.screenMatrix.MulPosition(ndc0)
	s1 := dc.screenMatrix.MulPosition(ndc1)
	s2 := dc.screenMatrix.MulPosition(ndc2)

	// rasterize
	if dc.Wireframe {
		dc.wireframe(v0, v1, v2, s0, s1, s2)
	} else {
		dc.rasterize(v0, v1, v2, s0, s1, s2)
	}
}

func (dc *Context) DrawLine(t *Line) {
	// invoke vertex shader
	v1 := dc.Shader.Vertex(t.V1)
	v2 := dc.Shader.Vertex(t.V2)

	if v1.Outside() || v2.Outside() {
		// clip to viewing volume
		line := ClipLine(NewLine(v1, v2))
		if line != nil {
			dc.drawClippedLine(line.V1, line.V2)
		}
	} else {
		// no need to clip
		dc.drawClippedLine(v1, v2)
	}
}

func (dc *Context) DrawTriangle(t *Triangle) {
	// invoke vertex shader
	v1 := dc.Shader.Vertex(t.V1)
	v2 := dc.Shader.Vertex(t.V2)
	v3 := dc.Shader.Vertex(t.V3)

	if v1.Outside() || v2.Outside() || v3.Outside() {
		// clip to viewing volume
		triangles := ClipTriangle(NewTriangle(v1, v2, v3))
		for _, t := range triangles {
			dc.drawClippedTriangle(t.V1, t.V2, t.V3)
		}
	} else {
		// no need to clip
		dc.drawClippedTriangle(v1, v2, v3)
	}
}

func (dc *Context) DrawLines(lines []*Line) {
	wn := runtime.NumCPU()
	done := make(chan bool, wn)
	for wi := 0; wi < wn; wi++ {
		go func(wi int) {
			for i, l := range lines {
				if i%wn == wi {
					dc.DrawLine(l)
				}
			}
			done <- true
		}(wi)
	}
	for wi := 0; wi < wn; wi++ {
		<-done
	}
}

func (dc *Context) DrawTriangles(triangles []*Triangle) {
	wn := runtime.NumCPU()
	done := make(chan bool, wn)
	for wi := 0; wi < wn; wi++ {
		go func(wi int) {
			for i, t := range triangles {
				if i%wn == wi {
					dc.DrawTriangle(t)
				}
			}
			done <- true
		}(wi)
	}
	for wi := 0; wi < wn; wi++ {
		<-done
	}
}

func (dc *Context) DrawMesh(mesh *Mesh) {
	dc.DrawTriangles(mesh.Triangles)
	dc.DrawLines(mesh.Lines)
}
<|endoftext|>