mirror of https://github.com/grafana/grafana.git
				
				
				
			updated lib
This commit is contained in:
		
							parent
							
								
									1f9f439acb
								
							
						
					
					
						commit
						749da42ffc
					
				| 
						 | 
				
			
			@ -64,6 +64,11 @@
 | 
			
		|||
			"Comment": "v1.0.0",
 | 
			
		||||
			"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/bmizerany/assert",
 | 
			
		||||
			"Comment": "release.r60-6-ge17e998",
 | 
			
		||||
			"Rev": "e17e99893cb6509f428e1728281c2ad60a6b31e3"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/bradfitz/gomemcache/memcache",
 | 
			
		||||
			"Comment": "release.r60-40-g72a6864",
 | 
			
		||||
| 
						 | 
				
			
			@ -123,10 +128,6 @@
 | 
			
		|||
			"Comment": "v0.4.4-44-gf561133",
 | 
			
		||||
			"Rev": "f56113384f2c63dfe4cd8e768e349f1c35122b58"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/gopherjs/gopherjs/js",
 | 
			
		||||
			"Rev": "14d893dca2e4adb93a5ccc9494040acc0821cd8d"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/gosimple/slug",
 | 
			
		||||
			"Rev": "8d258463b4459f161f51d6a357edacd3eef9d663"
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +161,15 @@
 | 
			
		|||
			"ImportPath": "github.com/klauspost/crc32",
 | 
			
		||||
			"Rev": "6834731faf32e62a2dd809d99fb24d1e4ae5a92d"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/kr/pretty",
 | 
			
		||||
			"Comment": "go.weekly.2011-12-22-27-ge6ac2fc",
 | 
			
		||||
			"Rev": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/kr/text",
 | 
			
		||||
			"Rev": "bb797dc4fb8320488f47bf11de07a733d7233e1f"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/lib/pq",
 | 
			
		||||
			"Comment": "go1.0-cutoff-13-g19eeca3",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
_go_.*
 | 
			
		||||
_gotest_.*
 | 
			
		||||
_obj
 | 
			
		||||
_test
 | 
			
		||||
_testmain.go
 | 
			
		||||
*.out
 | 
			
		||||
*.[568]
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
# Assert (c) Blake Mizerany and Keith Rarick -- MIT LICENCE
 | 
			
		||||
 | 
			
		||||
## Assertions for Go tests
 | 
			
		||||
 | 
			
		||||
## Install
 | 
			
		||||
 | 
			
		||||
    $ go get github.com/bmizerany/assert
 | 
			
		||||
 | 
			
		||||
## Use
 | 
			
		||||
 | 
			
		||||
**point.go**
 | 
			
		||||
 | 
			
		||||
    package point
 | 
			
		||||
 | 
			
		||||
    type Point struct {
 | 
			
		||||
        x, y int
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
**point_test.go**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    package point
 | 
			
		||||
 | 
			
		||||
    import (
 | 
			
		||||
        "testing"
 | 
			
		||||
        "github.com/bmizerany/assert"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    func TestAsserts(t *testing.T) {
 | 
			
		||||
        p1 := Point{1, 1}
 | 
			
		||||
        p2 := Point{2, 1}
 | 
			
		||||
 | 
			
		||||
        assert.Equal(t, p1, p2)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
**output**
 | 
			
		||||
    $ go test
 | 
			
		||||
     --- FAIL: TestAsserts (0.00 seconds)
 | 
			
		||||
	 assert.go:15: /Users/flavio.barbosa/dev/stewie/src/point_test.go:12
 | 
			
		||||
         assert.go:24: ! X: 1 != 2
 | 
			
		||||
	 FAIL
 | 
			
		||||
 | 
			
		||||
## Docs
 | 
			
		||||
 | 
			
		||||
    http://github.com/bmizerany/assert
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
package assert
 | 
			
		||||
// Testing helpers for doozer.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/kr/pretty"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func assert(t *testing.T, result bool, f func(), cd int) {
 | 
			
		||||
	if !result {
 | 
			
		||||
		_, file, line, _ := runtime.Caller(cd + 1)
 | 
			
		||||
		t.Errorf("%s:%d", file, line)
 | 
			
		||||
		f()
 | 
			
		||||
		t.FailNow()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func equal(t *testing.T, exp, got interface{}, cd int, args ...interface{}) {
 | 
			
		||||
	fn := func() {
 | 
			
		||||
		for _, desc := range pretty.Diff(exp, got) {
 | 
			
		||||
			t.Error("!", desc)
 | 
			
		||||
		}
 | 
			
		||||
		if len(args) > 0 {
 | 
			
		||||
			t.Error("!", " -", fmt.Sprint(args...))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	result := reflect.DeepEqual(exp, got)
 | 
			
		||||
	assert(t, result, fn, cd+1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tt(t *testing.T, result bool, cd int, args ...interface{}) {
 | 
			
		||||
	fn := func() {
 | 
			
		||||
		t.Errorf("!  Failure")
 | 
			
		||||
		if len(args) > 0 {
 | 
			
		||||
			t.Error("!", " -", fmt.Sprint(args...))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	assert(t, result, fn, cd+1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func T(t *testing.T, result bool, args ...interface{}) {
 | 
			
		||||
	tt(t, result, 1, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Tf(t *testing.T, result bool, format string, args ...interface{}) {
 | 
			
		||||
	tt(t, result, 1, fmt.Sprintf(format, args...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Equal(t *testing.T, exp, got interface{}, args ...interface{}) {
 | 
			
		||||
	equal(t, exp, got, 1, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Equalf(t *testing.T, exp, got interface{}, format string, args ...interface{}) {
 | 
			
		||||
	equal(t, exp, got, 1, fmt.Sprintf(format, args...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NotEqual(t *testing.T, exp, got interface{}, args ...interface{}) {
 | 
			
		||||
	fn := func() {
 | 
			
		||||
		t.Errorf("!  Unexpected: <%#v>", exp)
 | 
			
		||||
		if len(args) > 0 {
 | 
			
		||||
			t.Error("!", " -", fmt.Sprint(args...))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	result := !reflect.DeepEqual(exp, got)
 | 
			
		||||
	assert(t, result, fn, 1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Panic(t *testing.T, err interface{}, fn func()) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		equal(t, err, recover(), 3)
 | 
			
		||||
	}()
 | 
			
		||||
	fn()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
package assert
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestLineNumbers(t *testing.T) {
 | 
			
		||||
	Equal(t, "foo", "foo", "msg!")
 | 
			
		||||
	//Equal(t, "foo", "bar", "this should blow up")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNotEqual(t *testing.T) {
 | 
			
		||||
	NotEqual(t, "foo", "bar", "msg!")
 | 
			
		||||
	//NotEqual(t, "foo", "foo", "this should blow up")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
package point
 | 
			
		||||
 | 
			
		||||
type Point struct {
 | 
			
		||||
	X, Y int
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								Godeps/_workspace/src/github.com/bmizerany/assert/example/point_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										13
									
								
								Godeps/_workspace/src/github.com/bmizerany/assert/example/point_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
package point
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestAsserts(t *testing.T) {
 | 
			
		||||
	p1 := Point{1, 1}
 | 
			
		||||
	p2 := Point{2, 1}
 | 
			
		||||
 | 
			
		||||
	assert.Equal(t, p1, p2)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,168 +0,0 @@
 | 
			
		|||
// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax.
 | 
			
		||||
//
 | 
			
		||||
// Use MakeWrapper to expose methods to JavaScript. When passing values directly, the following type conversions are performed:
 | 
			
		||||
//
 | 
			
		||||
//  | Go type               | JavaScript type       | Conversions back to interface{} |
 | 
			
		||||
//  | --------------------- | --------------------- | ------------------------------- |
 | 
			
		||||
//  | bool                  | Boolean               | bool                            |
 | 
			
		||||
//  | integers and floats   | Number                | float64                         |
 | 
			
		||||
//  | string                | String                | string                          |
 | 
			
		||||
//  | []int8                | Int8Array             | []int8                          |
 | 
			
		||||
//  | []int16               | Int16Array            | []int16                         |
 | 
			
		||||
//  | []int32, []int        | Int32Array            | []int                           |
 | 
			
		||||
//  | []uint8               | Uint8Array            | []uint8                         |
 | 
			
		||||
//  | []uint16              | Uint16Array           | []uint16                        |
 | 
			
		||||
//  | []uint32, []uint      | Uint32Array           | []uint                          |
 | 
			
		||||
//  | []float32             | Float32Array          | []float32                       |
 | 
			
		||||
//  | []float64             | Float64Array          | []float64                       |
 | 
			
		||||
//  | all other slices      | Array                 | []interface{}                   |
 | 
			
		||||
//  | arrays                | see slice type        | see slice type                  |
 | 
			
		||||
//  | functions             | Function              | func(...interface{}) *js.Object |
 | 
			
		||||
//  | time.Time             | Date                  | time.Time                       |
 | 
			
		||||
//  | -                     | instanceof Node       | *js.Object                      |
 | 
			
		||||
//  | maps, structs         | instanceof Object     | map[string]interface{}          |
 | 
			
		||||
//
 | 
			
		||||
// Additionally, for a struct containing a *js.Object field, only the content of the field will be passed to JavaScript and vice versa.
 | 
			
		||||
package js
 | 
			
		||||
 | 
			
		||||
// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. A nil pointer to Object is equal to JavaScript's "null". Object can not be used as a map key.
 | 
			
		||||
type Object struct{ object *Object }
 | 
			
		||||
 | 
			
		||||
// Get returns the object's property with the given key.
 | 
			
		||||
func (o *Object) Get(key string) *Object { return o.object.Get(key) }
 | 
			
		||||
 | 
			
		||||
// Set assigns the value to the object's property with the given key.
 | 
			
		||||
func (o *Object) Set(key string, value interface{}) { o.object.Set(key, value) }
 | 
			
		||||
 | 
			
		||||
// Delete removes the object's property with the given key.
 | 
			
		||||
func (o *Object) Delete(key string) { o.object.Delete(key) }
 | 
			
		||||
 | 
			
		||||
// Length returns the object's "length" property, converted to int.
 | 
			
		||||
func (o *Object) Length() int { return o.object.Length() }
 | 
			
		||||
 | 
			
		||||
// Index returns the i'th element of an array.
 | 
			
		||||
func (o *Object) Index(i int) *Object { return o.object.Index(i) }
 | 
			
		||||
 | 
			
		||||
// SetIndex sets the i'th element of an array.
 | 
			
		||||
func (o *Object) SetIndex(i int, value interface{}) { o.object.SetIndex(i, value) }
 | 
			
		||||
 | 
			
		||||
// Call calls the object's method with the given name.
 | 
			
		||||
func (o *Object) Call(name string, args ...interface{}) *Object { return o.object.Call(name, args...) }
 | 
			
		||||
 | 
			
		||||
// Invoke calls the object itself. This will fail if it is not a function.
 | 
			
		||||
func (o *Object) Invoke(args ...interface{}) *Object { return o.object.Invoke(args...) }
 | 
			
		||||
 | 
			
		||||
// New creates a new instance of this type object. This will fail if it not a function (constructor).
 | 
			
		||||
func (o *Object) New(args ...interface{}) *Object { return o.object.New(args...) }
 | 
			
		||||
 | 
			
		||||
// Bool returns the object converted to bool according to JavaScript type conversions.
 | 
			
		||||
func (o *Object) Bool() bool { return o.object.Bool() }
 | 
			
		||||
 | 
			
		||||
// String returns the object converted to string according to JavaScript type conversions.
 | 
			
		||||
func (o *Object) String() string { return o.object.String() }
 | 
			
		||||
 | 
			
		||||
// Int returns the object converted to int according to JavaScript type conversions (parseInt).
 | 
			
		||||
func (o *Object) Int() int { return o.object.Int() }
 | 
			
		||||
 | 
			
		||||
// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
 | 
			
		||||
func (o *Object) Int64() int64 { return o.object.Int64() }
 | 
			
		||||
 | 
			
		||||
// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
 | 
			
		||||
func (o *Object) Uint64() uint64 { return o.object.Uint64() }
 | 
			
		||||
 | 
			
		||||
// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
 | 
			
		||||
func (o *Object) Float() float64 { return o.object.Float() }
 | 
			
		||||
 | 
			
		||||
// Interface returns the object converted to interface{}. See GopherJS' README for details.
 | 
			
		||||
func (o *Object) Interface() interface{} { return o.object.Interface() }
 | 
			
		||||
 | 
			
		||||
// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
 | 
			
		||||
func (o *Object) Unsafe() uintptr { return o.object.Unsafe() }
 | 
			
		||||
 | 
			
		||||
// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be recovered, giving an *Error that holds the JavaScript error object.
 | 
			
		||||
type Error struct {
 | 
			
		||||
	*Object
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error returns the message of the encapsulated JavaScript error object.
 | 
			
		||||
func (err *Error) Error() string {
 | 
			
		||||
	return "JavaScript error: " + err.Get("message").String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stack returns the stack property of the encapsulated JavaScript error object.
 | 
			
		||||
func (err *Error) Stack() string {
 | 
			
		||||
	return err.Get("stack").String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js).
 | 
			
		||||
var Global *Object
 | 
			
		||||
 | 
			
		||||
// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'.
 | 
			
		||||
var Module *Object
 | 
			
		||||
 | 
			
		||||
// Undefined gives the JavaScript value "undefined".
 | 
			
		||||
var Undefined *Object
 | 
			
		||||
 | 
			
		||||
// Debugger gets compiled to JavaScript's "debugger;" statement.
 | 
			
		||||
func Debugger() {}
 | 
			
		||||
 | 
			
		||||
// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
 | 
			
		||||
func InternalObject(i interface{}) *Object {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MakeFunc wraps a function and gives access to the values of JavaScript's "this" and "arguments" keywords.
 | 
			
		||||
func MakeFunc(func(this *Object, arguments []*Object) interface{}) *Object {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Keys returns the keys of the given JavaScript object.
 | 
			
		||||
func Keys(o *Object) []string {
 | 
			
		||||
	if o == nil || o == Undefined {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	a := Global.Get("Object").Call("keys", o)
 | 
			
		||||
	s := make([]string, a.Length())
 | 
			
		||||
	for i := 0; i < a.Length(); i++ {
 | 
			
		||||
		s[i] = a.Index(i).String()
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MakeWrapper creates a JavaScript object which has wrappers for the exported methods of i. Use explicit getter and setter methods to expose struct fields to JavaScript.
 | 
			
		||||
func MakeWrapper(i interface{}) *Object {
 | 
			
		||||
	v := InternalObject(i)
 | 
			
		||||
	o := Global.Get("Object").New()
 | 
			
		||||
	o.Set("__internal_object__", v)
 | 
			
		||||
	methods := v.Get("constructor").Get("methods")
 | 
			
		||||
	for i := 0; i < methods.Length(); i++ {
 | 
			
		||||
		m := methods.Index(i)
 | 
			
		||||
		if m.Get("pkg").String() != "" { // not exported
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		o.Set(m.Get("name").String(), func(args ...*Object) *Object {
 | 
			
		||||
			return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true).Call("apply", v, args)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return o
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewArrayBuffer creates a JavaScript ArrayBuffer from a byte slice.
 | 
			
		||||
func NewArrayBuffer(b []byte) *Object {
 | 
			
		||||
	slice := InternalObject(b)
 | 
			
		||||
	offset := slice.Get("$offset").Int()
 | 
			
		||||
	length := slice.Get("$length").Int()
 | 
			
		||||
	return slice.Get("$array").Get("buffer").Call("slice", offset, offset+length)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
 | 
			
		||||
type M map[string]interface{}
 | 
			
		||||
 | 
			
		||||
// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
 | 
			
		||||
type S []interface{}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	// avoid dead code elimination
 | 
			
		||||
	e := Error{}
 | 
			
		||||
	_ = e
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
[568].out
 | 
			
		||||
_go*
 | 
			
		||||
_test*
 | 
			
		||||
_obj
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright 2012 Keith Rarick
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
package pretty
 | 
			
		||||
 | 
			
		||||
    import "github.com/kr/pretty"
 | 
			
		||||
 | 
			
		||||
    Package pretty provides pretty-printing for Go values.
 | 
			
		||||
 | 
			
		||||
Documentation
 | 
			
		||||
 | 
			
		||||
    http://godoc.org/github.com/kr/pretty
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,158 @@
 | 
			
		|||
package pretty
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sbuf []string
 | 
			
		||||
 | 
			
		||||
func (s *sbuf) Write(b []byte) (int, error) {
 | 
			
		||||
	*s = append(*s, string(b))
 | 
			
		||||
	return len(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Diff returns a slice where each element describes
 | 
			
		||||
// a difference between a and b.
 | 
			
		||||
func Diff(a, b interface{}) (desc []string) {
 | 
			
		||||
	Fdiff((*sbuf)(&desc), a, b)
 | 
			
		||||
	return desc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fdiff writes to w a description of the differences between a and b.
 | 
			
		||||
func Fdiff(w io.Writer, a, b interface{}) {
 | 
			
		||||
	diffWriter{w: w}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type diffWriter struct {
 | 
			
		||||
	w io.Writer
 | 
			
		||||
	l string // label
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w diffWriter) printf(f string, a ...interface{}) {
 | 
			
		||||
	var l string
 | 
			
		||||
	if w.l != "" {
 | 
			
		||||
		l = w.l + ": "
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w.w, l+f, a...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w diffWriter) diff(av, bv reflect.Value) {
 | 
			
		||||
	if !av.IsValid() && bv.IsValid() {
 | 
			
		||||
		w.printf("nil != %#v", bv.Interface())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if av.IsValid() && !bv.IsValid() {
 | 
			
		||||
		w.printf("%#v != nil", av.Interface())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if !av.IsValid() && !bv.IsValid() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	at := av.Type()
 | 
			
		||||
	bt := bv.Type()
 | 
			
		||||
	if at != bt {
 | 
			
		||||
		w.printf("%v != %v", at, bt)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// numeric types, including bool
 | 
			
		||||
	if at.Kind() < reflect.Array {
 | 
			
		||||
		a, b := av.Interface(), bv.Interface()
 | 
			
		||||
		if a != b {
 | 
			
		||||
			w.printf("%#v != %#v", a, b)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch at.Kind() {
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		a, b := av.Interface(), bv.Interface()
 | 
			
		||||
		if a != b {
 | 
			
		||||
			w.printf("%q != %q", a, b)
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		switch {
 | 
			
		||||
		case av.IsNil() && !bv.IsNil():
 | 
			
		||||
			w.printf("nil != %v", bv.Interface())
 | 
			
		||||
		case !av.IsNil() && bv.IsNil():
 | 
			
		||||
			w.printf("%v != nil", av.Interface())
 | 
			
		||||
		case !av.IsNil() && !bv.IsNil():
 | 
			
		||||
			w.diff(av.Elem(), bv.Elem())
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		for i := 0; i < av.NumField(); i++ {
 | 
			
		||||
			w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		lenA := av.Len()
 | 
			
		||||
		lenB := bv.Len()
 | 
			
		||||
		if lenA != lenB {
 | 
			
		||||
			w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		for i := 0; i < lenA; i++ {
 | 
			
		||||
			w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
 | 
			
		||||
		for _, k := range ak {
 | 
			
		||||
			w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
 | 
			
		||||
			w.printf("%q != (missing)", av.MapIndex(k))
 | 
			
		||||
		}
 | 
			
		||||
		for _, k := range both {
 | 
			
		||||
			w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
 | 
			
		||||
			w.diff(av.MapIndex(k), bv.MapIndex(k))
 | 
			
		||||
		}
 | 
			
		||||
		for _, k := range bk {
 | 
			
		||||
			w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
 | 
			
		||||
			w.printf("(missing) != %q", bv.MapIndex(k))
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Interface:
 | 
			
		||||
		w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface()))
 | 
			
		||||
	default:
 | 
			
		||||
		if !reflect.DeepEqual(av.Interface(), bv.Interface()) {
 | 
			
		||||
			w.printf("%# v != %# v", Formatter(av.Interface()), Formatter(bv.Interface()))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d diffWriter) relabel(name string) (d1 diffWriter) {
 | 
			
		||||
	d1 = d
 | 
			
		||||
	if d.l != "" && name[0] != '[' {
 | 
			
		||||
		d1.l += "."
 | 
			
		||||
	}
 | 
			
		||||
	d1.l += name
 | 
			
		||||
	return d1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
 | 
			
		||||
	for _, av := range a {
 | 
			
		||||
		inBoth := false
 | 
			
		||||
		for _, bv := range b {
 | 
			
		||||
			if reflect.DeepEqual(av.Interface(), bv.Interface()) {
 | 
			
		||||
				inBoth = true
 | 
			
		||||
				both = append(both, av)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !inBoth {
 | 
			
		||||
			ak = append(ak, av)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, bv := range b {
 | 
			
		||||
		inBoth := false
 | 
			
		||||
		for _, av := range a {
 | 
			
		||||
			if reflect.DeepEqual(av.Interface(), bv.Interface()) {
 | 
			
		||||
				inBoth = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !inBoth {
 | 
			
		||||
			bk = append(bk, bv)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
package pretty
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type difftest struct {
 | 
			
		||||
	a   interface{}
 | 
			
		||||
	b   interface{}
 | 
			
		||||
	exp []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type S struct {
 | 
			
		||||
	A int
 | 
			
		||||
	S *S
 | 
			
		||||
	I interface{}
 | 
			
		||||
	C []int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var diffs = []difftest{
 | 
			
		||||
	{a: nil, b: nil},
 | 
			
		||||
	{a: S{A: 1}, b: S{A: 1}},
 | 
			
		||||
 | 
			
		||||
	{0, "", []string{`int != string`}},
 | 
			
		||||
	{0, 1, []string{`0 != 1`}},
 | 
			
		||||
	{S{}, new(S), []string{`pretty.S != *pretty.S`}},
 | 
			
		||||
	{"a", "b", []string{`"a" != "b"`}},
 | 
			
		||||
	{S{}, S{A: 1}, []string{`A: 0 != 1`}},
 | 
			
		||||
	{new(S), &S{A: 1}, []string{`A: 0 != 1`}},
 | 
			
		||||
	{S{S: new(S)}, S{S: &S{A: 1}}, []string{`S.A: 0 != 1`}},
 | 
			
		||||
	{S{}, S{I: 0}, []string{`I: nil != 0`}},
 | 
			
		||||
	{S{I: 1}, S{I: "x"}, []string{`I: int != string`}},
 | 
			
		||||
	{S{}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
 | 
			
		||||
	{S{C: []int{}}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
 | 
			
		||||
	{S{C: []int{1, 2, 3}}, S{C: []int{1, 2, 4}}, []string{`C[2]: 3 != 4`}},
 | 
			
		||||
	{S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &{0 <nil> <nil> []}`}},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDiff(t *testing.T) {
 | 
			
		||||
	for _, tt := range diffs {
 | 
			
		||||
		got := Diff(tt.a, tt.b)
 | 
			
		||||
		eq := len(got) == len(tt.exp)
 | 
			
		||||
		if eq {
 | 
			
		||||
			for i := range got {
 | 
			
		||||
				eq = eq && got[i] == tt.exp[i]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !eq {
 | 
			
		||||
			t.Errorf("diffing % #v", tt.a)
 | 
			
		||||
			t.Errorf("with    % #v", tt.b)
 | 
			
		||||
			diffdiff(t, got, tt.exp)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffdiff(t *testing.T, got, exp []string) {
 | 
			
		||||
	minus(t, "unexpected:", got, exp)
 | 
			
		||||
	minus(t, "missing:", exp, got)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func minus(t *testing.T, s string, a, b []string) {
 | 
			
		||||
	var i, j int
 | 
			
		||||
	for i = 0; i < len(a); i++ {
 | 
			
		||||
		for j = 0; j < len(b); j++ {
 | 
			
		||||
			if a[i] == b[j] {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if j == len(b) {
 | 
			
		||||
			t.Error(s, a[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
package pretty_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/kr/pretty"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Example() {
 | 
			
		||||
	type myType struct {
 | 
			
		||||
		a, b int
 | 
			
		||||
	}
 | 
			
		||||
	var x = []myType{{1, 2}, {3, 4}, {5, 6}}
 | 
			
		||||
	fmt.Printf("%# v", pretty.Formatter(x))
 | 
			
		||||
	// output:
 | 
			
		||||
	// []pretty_test.myType{
 | 
			
		||||
	//     {a:1, b:2},
 | 
			
		||||
	//     {a:3, b:4},
 | 
			
		||||
	//     {a:5, b:6},
 | 
			
		||||
	// }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,337 @@
 | 
			
		|||
package pretty
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"text/tabwriter"
 | 
			
		||||
 | 
			
		||||
	"github.com/kr/text"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	limit = 50
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type formatter struct {
 | 
			
		||||
	x     interface{}
 | 
			
		||||
	force bool
 | 
			
		||||
	quote bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Formatter makes a wrapper, f, that will format x as go source with line
 | 
			
		||||
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
 | 
			
		||||
// "#" and " " (space) flags are set, for example:
 | 
			
		||||
//
 | 
			
		||||
//     fmt.Sprintf("%# v", Formatter(x))
 | 
			
		||||
//
 | 
			
		||||
// If one of these two flags is not set, or any other verb is used, f will
 | 
			
		||||
// format x according to the usual rules of package fmt.
 | 
			
		||||
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
 | 
			
		||||
func Formatter(x interface{}) (f fmt.Formatter) {
 | 
			
		||||
	return formatter{x: x, quote: true}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fo formatter) String() string {
 | 
			
		||||
	return fmt.Sprint(fo.x) // unwrap it
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fo formatter) passThrough(f fmt.State, c rune) {
 | 
			
		||||
	s := "%"
 | 
			
		||||
	for i := 0; i < 128; i++ {
 | 
			
		||||
		if f.Flag(i) {
 | 
			
		||||
			s += string(i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if w, ok := f.Width(); ok {
 | 
			
		||||
		s += fmt.Sprintf("%d", w)
 | 
			
		||||
	}
 | 
			
		||||
	if p, ok := f.Precision(); ok {
 | 
			
		||||
		s += fmt.Sprintf(".%d", p)
 | 
			
		||||
	}
 | 
			
		||||
	s += string(c)
 | 
			
		||||
	fmt.Fprintf(f, s, fo.x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fo formatter) Format(f fmt.State, c rune) {
 | 
			
		||||
	if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
 | 
			
		||||
		w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
 | 
			
		||||
		p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
 | 
			
		||||
		p.printValue(reflect.ValueOf(fo.x), true, fo.quote)
 | 
			
		||||
		w.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	fo.passThrough(f, c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type printer struct {
 | 
			
		||||
	io.Writer
 | 
			
		||||
	tw      *tabwriter.Writer
 | 
			
		||||
	visited map[visit]int
 | 
			
		||||
	depth   int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *printer) indent() *printer {
 | 
			
		||||
	q := *p
 | 
			
		||||
	q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
 | 
			
		||||
	q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
 | 
			
		||||
	return &q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
 | 
			
		||||
	if showType {
 | 
			
		||||
		io.WriteString(p, v.Type().String())
 | 
			
		||||
		fmt.Fprintf(p, "(%#v)", x)
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Fprintf(p, "%#v", x)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// printValue must keep track of already-printed pointer values to avoid
 | 
			
		||||
// infinite recursion.
 | 
			
		||||
type visit struct {
 | 
			
		||||
	v   uintptr
 | 
			
		||||
	typ reflect.Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
 | 
			
		||||
	if p.depth > 10 {
 | 
			
		||||
		io.WriteString(p, "!%v(DEPTH EXCEEDED)")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch v.Kind() {
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		p.printInline(v, v.Bool(), showType)
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		p.printInline(v, v.Int(), showType)
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
			
		||||
		p.printInline(v, v.Uint(), showType)
 | 
			
		||||
	case reflect.Float32, reflect.Float64:
 | 
			
		||||
		p.printInline(v, v.Float(), showType)
 | 
			
		||||
	case reflect.Complex64, reflect.Complex128:
 | 
			
		||||
		fmt.Fprintf(p, "%#v", v.Complex())
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		p.fmtString(v.String(), quote)
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		t := v.Type()
 | 
			
		||||
		if showType {
 | 
			
		||||
			io.WriteString(p, t.String())
 | 
			
		||||
		}
 | 
			
		||||
		writeByte(p, '{')
 | 
			
		||||
		if nonzero(v) {
 | 
			
		||||
			expand := !canInline(v.Type())
 | 
			
		||||
			pp := p
 | 
			
		||||
			if expand {
 | 
			
		||||
				writeByte(p, '\n')
 | 
			
		||||
				pp = p.indent()
 | 
			
		||||
			}
 | 
			
		||||
			keys := v.MapKeys()
 | 
			
		||||
			for i := 0; i < v.Len(); i++ {
 | 
			
		||||
				showTypeInStruct := true
 | 
			
		||||
				k := keys[i]
 | 
			
		||||
				mv := v.MapIndex(k)
 | 
			
		||||
				pp.printValue(k, false, true)
 | 
			
		||||
				writeByte(pp, ':')
 | 
			
		||||
				if expand {
 | 
			
		||||
					writeByte(pp, '\t')
 | 
			
		||||
				}
 | 
			
		||||
				showTypeInStruct = t.Elem().Kind() == reflect.Interface
 | 
			
		||||
				pp.printValue(mv, showTypeInStruct, true)
 | 
			
		||||
				if expand {
 | 
			
		||||
					io.WriteString(pp, ",\n")
 | 
			
		||||
				} else if i < v.Len()-1 {
 | 
			
		||||
					io.WriteString(pp, ", ")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if expand {
 | 
			
		||||
				pp.tw.Flush()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		writeByte(p, '}')
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		t := v.Type()
 | 
			
		||||
		if v.CanAddr() {
 | 
			
		||||
			addr := v.UnsafeAddr()
 | 
			
		||||
			vis := visit{addr, t}
 | 
			
		||||
			if vd, ok := p.visited[vis]; ok && vd < p.depth {
 | 
			
		||||
				p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
 | 
			
		||||
				break // don't print v again
 | 
			
		||||
			}
 | 
			
		||||
			p.visited[vis] = p.depth
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if showType {
 | 
			
		||||
			io.WriteString(p, t.String())
 | 
			
		||||
		}
 | 
			
		||||
		writeByte(p, '{')
 | 
			
		||||
		if nonzero(v) {
 | 
			
		||||
			expand := !canInline(v.Type())
 | 
			
		||||
			pp := p
 | 
			
		||||
			if expand {
 | 
			
		||||
				writeByte(p, '\n')
 | 
			
		||||
				pp = p.indent()
 | 
			
		||||
			}
 | 
			
		||||
			for i := 0; i < v.NumField(); i++ {
 | 
			
		||||
				showTypeInStruct := true
 | 
			
		||||
				if f := t.Field(i); f.Name != "" {
 | 
			
		||||
					io.WriteString(pp, f.Name)
 | 
			
		||||
					writeByte(pp, ':')
 | 
			
		||||
					if expand {
 | 
			
		||||
						writeByte(pp, '\t')
 | 
			
		||||
					}
 | 
			
		||||
					showTypeInStruct = labelType(f.Type)
 | 
			
		||||
				}
 | 
			
		||||
				pp.printValue(getField(v, i), showTypeInStruct, true)
 | 
			
		||||
				if expand {
 | 
			
		||||
					io.WriteString(pp, ",\n")
 | 
			
		||||
				} else if i < v.NumField()-1 {
 | 
			
		||||
					io.WriteString(pp, ", ")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if expand {
 | 
			
		||||
				pp.tw.Flush()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		writeByte(p, '}')
 | 
			
		||||
	case reflect.Interface:
 | 
			
		||||
		switch e := v.Elem(); {
 | 
			
		||||
		case e.Kind() == reflect.Invalid:
 | 
			
		||||
			io.WriteString(p, "nil")
 | 
			
		||||
		case e.IsValid():
 | 
			
		||||
			pp := *p
 | 
			
		||||
			pp.depth++
 | 
			
		||||
			pp.printValue(e, showType, true)
 | 
			
		||||
		default:
 | 
			
		||||
			io.WriteString(p, v.Type().String())
 | 
			
		||||
			io.WriteString(p, "(nil)")
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Array, reflect.Slice:
 | 
			
		||||
		t := v.Type()
 | 
			
		||||
		if showType {
 | 
			
		||||
			io.WriteString(p, t.String())
 | 
			
		||||
		}
 | 
			
		||||
		if v.Kind() == reflect.Slice && v.IsNil() && showType {
 | 
			
		||||
			io.WriteString(p, "(nil)")
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if v.Kind() == reflect.Slice && v.IsNil() {
 | 
			
		||||
			io.WriteString(p, "nil")
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		writeByte(p, '{')
 | 
			
		||||
		expand := !canInline(v.Type())
 | 
			
		||||
		pp := p
 | 
			
		||||
		if expand {
 | 
			
		||||
			writeByte(p, '\n')
 | 
			
		||||
			pp = p.indent()
 | 
			
		||||
		}
 | 
			
		||||
		for i := 0; i < v.Len(); i++ {
 | 
			
		||||
			showTypeInSlice := t.Elem().Kind() == reflect.Interface
 | 
			
		||||
			pp.printValue(v.Index(i), showTypeInSlice, true)
 | 
			
		||||
			if expand {
 | 
			
		||||
				io.WriteString(pp, ",\n")
 | 
			
		||||
			} else if i < v.Len()-1 {
 | 
			
		||||
				io.WriteString(pp, ", ")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if expand {
 | 
			
		||||
			pp.tw.Flush()
 | 
			
		||||
		}
 | 
			
		||||
		writeByte(p, '}')
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		e := v.Elem()
 | 
			
		||||
		if !e.IsValid() {
 | 
			
		||||
			writeByte(p, '(')
 | 
			
		||||
			io.WriteString(p, v.Type().String())
 | 
			
		||||
			io.WriteString(p, ")(nil)")
 | 
			
		||||
		} else {
 | 
			
		||||
			pp := *p
 | 
			
		||||
			pp.depth++
 | 
			
		||||
			writeByte(pp, '&')
 | 
			
		||||
			pp.printValue(e, true, true)
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Chan:
 | 
			
		||||
		x := v.Pointer()
 | 
			
		||||
		if showType {
 | 
			
		||||
			writeByte(p, '(')
 | 
			
		||||
			io.WriteString(p, v.Type().String())
 | 
			
		||||
			fmt.Fprintf(p, ")(%#v)", x)
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt.Fprintf(p, "%#v", x)
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Func:
 | 
			
		||||
		io.WriteString(p, v.Type().String())
 | 
			
		||||
		io.WriteString(p, " {...}")
 | 
			
		||||
	case reflect.UnsafePointer:
 | 
			
		||||
		p.printInline(v, v.Pointer(), showType)
 | 
			
		||||
	case reflect.Invalid:
 | 
			
		||||
		io.WriteString(p, "nil")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func canInline(t reflect.Type) bool {
 | 
			
		||||
	switch t.Kind() {
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		return !canExpand(t.Elem())
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		for i := 0; i < t.NumField(); i++ {
 | 
			
		||||
			if canExpand(t.Field(i).Type) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	case reflect.Interface:
 | 
			
		||||
		return false
 | 
			
		||||
	case reflect.Array, reflect.Slice:
 | 
			
		||||
		return !canExpand(t.Elem())
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		return false
 | 
			
		||||
	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func canExpand(t reflect.Type) bool {
 | 
			
		||||
	switch t.Kind() {
 | 
			
		||||
	case reflect.Map, reflect.Struct,
 | 
			
		||||
		reflect.Interface, reflect.Array, reflect.Slice,
 | 
			
		||||
		reflect.Ptr:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func labelType(t reflect.Type) bool {
 | 
			
		||||
	switch t.Kind() {
 | 
			
		||||
	case reflect.Interface, reflect.Struct:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *printer) fmtString(s string, quote bool) {
 | 
			
		||||
	if quote {
 | 
			
		||||
		s = strconv.Quote(s)
 | 
			
		||||
	}
 | 
			
		||||
	io.WriteString(p, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tryDeepEqual(a, b interface{}) bool {
 | 
			
		||||
	defer func() { recover() }()
 | 
			
		||||
	return reflect.DeepEqual(a, b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeByte(w io.Writer, b byte) {
 | 
			
		||||
	w.Write([]byte{b})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getField(v reflect.Value, i int) reflect.Value {
 | 
			
		||||
	val := v.Field(i)
 | 
			
		||||
	if val.Kind() == reflect.Interface && !val.IsNil() {
 | 
			
		||||
		val = val.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	return val
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,261 @@
 | 
			
		|||
package pretty
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type test struct {
 | 
			
		||||
	v interface{}
 | 
			
		||||
	s string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LongStructTypeName struct {
 | 
			
		||||
	longFieldName      interface{}
 | 
			
		||||
	otherLongFieldName interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SA struct {
 | 
			
		||||
	t *T
 | 
			
		||||
	v T
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type T struct {
 | 
			
		||||
	x, y int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type F int
 | 
			
		||||
 | 
			
		||||
func (f F) Format(s fmt.State, c rune) {
 | 
			
		||||
	fmt.Fprintf(s, "F(%d)", int(f))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 | 
			
		||||
 | 
			
		||||
var gosyntax = []test{
 | 
			
		||||
	{nil, `nil`},
 | 
			
		||||
	{"", `""`},
 | 
			
		||||
	{"a", `"a"`},
 | 
			
		||||
	{1, "int(1)"},
 | 
			
		||||
	{1.0, "float64(1)"},
 | 
			
		||||
	{[]int(nil), "[]int(nil)"},
 | 
			
		||||
	{[0]int{}, "[0]int{}"},
 | 
			
		||||
	{complex(1, 0), "(1+0i)"},
 | 
			
		||||
	//{make(chan int), "(chan int)(0x1234)"},
 | 
			
		||||
	{unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("unsafe.Pointer(0x%02x)", uintptr(unsafe.Pointer(&long)))},
 | 
			
		||||
	{func(int) {}, "func(int) {...}"},
 | 
			
		||||
	{map[int]int{1: 1}, "map[int]int{1:1}"},
 | 
			
		||||
	{int32(1), "int32(1)"},
 | 
			
		||||
	{io.EOF, `&errors.errorString{s:"EOF"}`},
 | 
			
		||||
	{[]string{"a"}, `[]string{"a"}`},
 | 
			
		||||
	{
 | 
			
		||||
		[]string{long},
 | 
			
		||||
		`[]string{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"}`,
 | 
			
		||||
	},
 | 
			
		||||
	{F(5), "pretty.F(5)"},
 | 
			
		||||
	{
 | 
			
		||||
		SA{&T{1, 2}, T{3, 4}},
 | 
			
		||||
		`pretty.SA{
 | 
			
		||||
    t:  &pretty.T{x:1, y:2},
 | 
			
		||||
    v:  pretty.T{x:3, y:4},
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		map[int][]byte{1: {}},
 | 
			
		||||
		`map[int][]uint8{
 | 
			
		||||
    1:  {},
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		map[int]T{1: {}},
 | 
			
		||||
		`map[int]pretty.T{
 | 
			
		||||
    1:  {},
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		long,
 | 
			
		||||
		`"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		LongStructTypeName{
 | 
			
		||||
			longFieldName:      LongStructTypeName{},
 | 
			
		||||
			otherLongFieldName: long,
 | 
			
		||||
		},
 | 
			
		||||
		`pretty.LongStructTypeName{
 | 
			
		||||
    longFieldName:      pretty.LongStructTypeName{},
 | 
			
		||||
    otherLongFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		&LongStructTypeName{
 | 
			
		||||
			longFieldName:      &LongStructTypeName{},
 | 
			
		||||
			otherLongFieldName: (*LongStructTypeName)(nil),
 | 
			
		||||
		},
 | 
			
		||||
		`&pretty.LongStructTypeName{
 | 
			
		||||
    longFieldName:      &pretty.LongStructTypeName{},
 | 
			
		||||
    otherLongFieldName: (*pretty.LongStructTypeName)(nil),
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]LongStructTypeName{
 | 
			
		||||
			{nil, nil},
 | 
			
		||||
			{3, 3},
 | 
			
		||||
			{long, nil},
 | 
			
		||||
		},
 | 
			
		||||
		`[]pretty.LongStructTypeName{
 | 
			
		||||
    {},
 | 
			
		||||
    {
 | 
			
		||||
        longFieldName:      int(3),
 | 
			
		||||
        otherLongFieldName: int(3),
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        longFieldName:      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
 | 
			
		||||
        otherLongFieldName: nil,
 | 
			
		||||
    },
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{
 | 
			
		||||
			LongStructTypeName{nil, nil},
 | 
			
		||||
			[]byte{1, 2, 3},
 | 
			
		||||
			T{3, 4},
 | 
			
		||||
			LongStructTypeName{long, nil},
 | 
			
		||||
		},
 | 
			
		||||
		`[]interface {}{
 | 
			
		||||
    pretty.LongStructTypeName{},
 | 
			
		||||
    []uint8{0x1, 0x2, 0x3},
 | 
			
		||||
    pretty.T{x:3, y:4},
 | 
			
		||||
    pretty.LongStructTypeName{
 | 
			
		||||
        longFieldName:      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
 | 
			
		||||
        otherLongFieldName: nil,
 | 
			
		||||
    },
 | 
			
		||||
}`,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGoSyntax(t *testing.T) {
 | 
			
		||||
	for _, tt := range gosyntax {
 | 
			
		||||
		s := fmt.Sprintf("%# v", Formatter(tt.v))
 | 
			
		||||
		if tt.s != s {
 | 
			
		||||
			t.Errorf("expected %q", tt.s)
 | 
			
		||||
			t.Errorf("got      %q", s)
 | 
			
		||||
			t.Errorf("expraw\n%s", tt.s)
 | 
			
		||||
			t.Errorf("gotraw\n%s", s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type I struct {
 | 
			
		||||
	i int
 | 
			
		||||
	R interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *I) I() *I { return i.R.(*I) }
 | 
			
		||||
 | 
			
		||||
func TestCycle(t *testing.T) {
 | 
			
		||||
	type A struct{ *A }
 | 
			
		||||
	v := &A{}
 | 
			
		||||
	v.A = v
 | 
			
		||||
 | 
			
		||||
	// panics from stack overflow without cycle detection
 | 
			
		||||
	t.Logf("Example cycle:\n%# v", Formatter(v))
 | 
			
		||||
 | 
			
		||||
	p := &A{}
 | 
			
		||||
	s := fmt.Sprintf("%# v", Formatter([]*A{p, p}))
 | 
			
		||||
	if strings.Contains(s, "CYCLIC") {
 | 
			
		||||
		t.Errorf("Repeated address detected as cyclic reference:\n%s", s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type R struct {
 | 
			
		||||
		i int
 | 
			
		||||
		*R
 | 
			
		||||
	}
 | 
			
		||||
	r := &R{
 | 
			
		||||
		i: 1,
 | 
			
		||||
		R: &R{
 | 
			
		||||
			i: 2,
 | 
			
		||||
			R: &R{
 | 
			
		||||
				i: 3,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	r.R.R.R = r
 | 
			
		||||
	t.Logf("Example longer cycle:\n%# v", Formatter(r))
 | 
			
		||||
 | 
			
		||||
	r = &R{
 | 
			
		||||
		i: 1,
 | 
			
		||||
		R: &R{
 | 
			
		||||
			i: 2,
 | 
			
		||||
			R: &R{
 | 
			
		||||
				i: 3,
 | 
			
		||||
				R: &R{
 | 
			
		||||
					i: 4,
 | 
			
		||||
					R: &R{
 | 
			
		||||
						i: 5,
 | 
			
		||||
						R: &R{
 | 
			
		||||
							i: 6,
 | 
			
		||||
							R: &R{
 | 
			
		||||
								i: 7,
 | 
			
		||||
								R: &R{
 | 
			
		||||
									i: 8,
 | 
			
		||||
									R: &R{
 | 
			
		||||
										i: 9,
 | 
			
		||||
										R: &R{
 | 
			
		||||
											i: 10,
 | 
			
		||||
											R: &R{
 | 
			
		||||
												i: 11,
 | 
			
		||||
											},
 | 
			
		||||
										},
 | 
			
		||||
									},
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	// here be pirates
 | 
			
		||||
	r.R.R.R.R.R.R.R.R.R.R.R = r
 | 
			
		||||
	t.Logf("Example very long cycle:\n%# v", Formatter(r))
 | 
			
		||||
 | 
			
		||||
	i := &I{
 | 
			
		||||
		i: 1,
 | 
			
		||||
		R: &I{
 | 
			
		||||
			i: 2,
 | 
			
		||||
			R: &I{
 | 
			
		||||
				i: 3,
 | 
			
		||||
				R: &I{
 | 
			
		||||
					i: 4,
 | 
			
		||||
					R: &I{
 | 
			
		||||
						i: 5,
 | 
			
		||||
						R: &I{
 | 
			
		||||
							i: 6,
 | 
			
		||||
							R: &I{
 | 
			
		||||
								i: 7,
 | 
			
		||||
								R: &I{
 | 
			
		||||
									i: 8,
 | 
			
		||||
									R: &I{
 | 
			
		||||
										i: 9,
 | 
			
		||||
										R: &I{
 | 
			
		||||
											i: 10,
 | 
			
		||||
											R: &I{
 | 
			
		||||
												i: 11,
 | 
			
		||||
											},
 | 
			
		||||
										},
 | 
			
		||||
									},
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	iv := i.I().I().I().I().I().I().I().I().I().I()
 | 
			
		||||
	*iv = *i
 | 
			
		||||
	t.Logf("Example long interface cycle:\n%# v", Formatter(i))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,98 @@
 | 
			
		|||
// Package pretty provides pretty-printing for Go values. This is
 | 
			
		||||
// useful during debugging, to avoid wrapping long output lines in
 | 
			
		||||
// the terminal.
 | 
			
		||||
//
 | 
			
		||||
// It provides a function, Formatter, that can be used with any
 | 
			
		||||
// function that accepts a format string. It also provides
 | 
			
		||||
// convenience wrappers for functions in packages fmt and log.
 | 
			
		||||
package pretty
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Errorf is a convenience wrapper for fmt.Errorf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Errorf(f, x, y) is equivalent to
 | 
			
		||||
// fmt.Errorf(f, Formatter(x), Formatter(y)).
 | 
			
		||||
func Errorf(format string, a ...interface{}) error {
 | 
			
		||||
	return fmt.Errorf(format, wrap(a, false)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fprintf is a convenience wrapper for fmt.Fprintf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Fprintf(w, f, x, y) is equivalent to
 | 
			
		||||
// fmt.Fprintf(w, f, Formatter(x), Formatter(y)).
 | 
			
		||||
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) {
 | 
			
		||||
	return fmt.Fprintf(w, format, wrap(a, false)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Log is a convenience wrapper for log.Printf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Log(x, y) is equivalent to
 | 
			
		||||
// log.Print(Formatter(x), Formatter(y)), but each operand is
 | 
			
		||||
// formatted with "%# v".
 | 
			
		||||
func Log(a ...interface{}) {
 | 
			
		||||
	log.Print(wrap(a, true)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logf is a convenience wrapper for log.Printf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Logf(f, x, y) is equivalent to
 | 
			
		||||
// log.Printf(f, Formatter(x), Formatter(y)).
 | 
			
		||||
func Logf(format string, a ...interface{}) {
 | 
			
		||||
	log.Printf(format, wrap(a, false)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logln is a convenience wrapper for log.Printf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Logln(x, y) is equivalent to
 | 
			
		||||
// log.Println(Formatter(x), Formatter(y)), but each operand is
 | 
			
		||||
// formatted with "%# v".
 | 
			
		||||
func Logln(a ...interface{}) {
 | 
			
		||||
	log.Println(wrap(a, true)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Print pretty-prints its operands and writes to standard output.
 | 
			
		||||
//
 | 
			
		||||
// Calling Print(x, y) is equivalent to
 | 
			
		||||
// fmt.Print(Formatter(x), Formatter(y)), but each operand is
 | 
			
		||||
// formatted with "%# v".
 | 
			
		||||
func Print(a ...interface{}) (n int, errno error) {
 | 
			
		||||
	return fmt.Print(wrap(a, true)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Printf is a convenience wrapper for fmt.Printf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Printf(f, x, y) is equivalent to
 | 
			
		||||
// fmt.Printf(f, Formatter(x), Formatter(y)).
 | 
			
		||||
func Printf(format string, a ...interface{}) (n int, errno error) {
 | 
			
		||||
	return fmt.Printf(format, wrap(a, false)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Println pretty-prints its operands and writes to standard output.
 | 
			
		||||
//
 | 
			
		||||
// Calling Print(x, y) is equivalent to
 | 
			
		||||
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
 | 
			
		||||
// formatted with "%# v".
 | 
			
		||||
func Println(a ...interface{}) (n int, errno error) {
 | 
			
		||||
	return fmt.Println(wrap(a, true)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sprintf is a convenience wrapper for fmt.Sprintf.
 | 
			
		||||
//
 | 
			
		||||
// Calling Sprintf(f, x, y) is equivalent to
 | 
			
		||||
// fmt.Sprintf(f, Formatter(x), Formatter(y)).
 | 
			
		||||
func Sprintf(format string, a ...interface{}) string {
 | 
			
		||||
	return fmt.Sprintf(format, wrap(a, false)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wrap(a []interface{}, force bool) []interface{} {
 | 
			
		||||
	w := make([]interface{}, len(a))
 | 
			
		||||
	for i, x := range a {
 | 
			
		||||
		w[i] = formatter{x: x, force: force}
 | 
			
		||||
	}
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
package pretty
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func nonzero(v reflect.Value) bool {
 | 
			
		||||
	switch v.Kind() {
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		return v.Bool()
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		return v.Int() != 0
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
			
		||||
		return v.Uint() != 0
 | 
			
		||||
	case reflect.Float32, reflect.Float64:
 | 
			
		||||
		return v.Float() != 0
 | 
			
		||||
	case reflect.Complex64, reflect.Complex128:
 | 
			
		||||
		return v.Complex() != complex(0, 0)
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		return v.String() != ""
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		for i := 0; i < v.NumField(); i++ {
 | 
			
		||||
			if nonzero(getField(v, i)) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	case reflect.Array:
 | 
			
		||||
		for i := 0; i < v.Len(); i++ {
 | 
			
		||||
			if nonzero(v.Index(i)) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func:
 | 
			
		||||
		return !v.IsNil()
 | 
			
		||||
	case reflect.UnsafePointer:
 | 
			
		||||
		return v.Pointer() != 0
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
Copyright 2012 Keith Rarick
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
This is a Go package for manipulating paragraphs of text.
 | 
			
		||||
 | 
			
		||||
See http://go.pkgdoc.org/github.com/kr/text for full documentation.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
Package colwriter provides a write filter that formats
 | 
			
		||||
input lines in multiple columns.
 | 
			
		||||
 | 
			
		||||
The package is a straightforward translation from
 | 
			
		||||
/src/cmd/draw/mc.c in Plan 9 from User Space.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,147 @@
 | 
			
		|||
// Package colwriter provides a write filter that formats
 | 
			
		||||
// input lines in multiple columns.
 | 
			
		||||
//
 | 
			
		||||
// The package is a straightforward translation from
 | 
			
		||||
// /src/cmd/draw/mc.c in Plan 9 from User Space.
 | 
			
		||||
package colwriter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	tab = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Print each input line ending in a colon ':' separately.
 | 
			
		||||
	BreakOnColon uint = 1 << iota
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Writer is a filter that arranges input lines in as many columns as will
 | 
			
		||||
// fit in its width. Tab '\t' chars in the input are translated to sequences
 | 
			
		||||
// of spaces ending at multiples of 4 positions.
 | 
			
		||||
//
 | 
			
		||||
// If BreakOnColon is set, each input line ending in a colon ':' is written
 | 
			
		||||
// separately.
 | 
			
		||||
//
 | 
			
		||||
// The Writer assumes that all Unicode code points have the same width; this
 | 
			
		||||
// may not be true in some fonts.
 | 
			
		||||
type Writer struct {
 | 
			
		||||
	w     io.Writer
 | 
			
		||||
	buf   []byte
 | 
			
		||||
	width int
 | 
			
		||||
	flag  uint
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewWriter allocates and initializes a new Writer writing to w.
 | 
			
		||||
// Parameter width controls the total number of characters on each line
 | 
			
		||||
// across all columns.
 | 
			
		||||
func NewWriter(w io.Writer, width int, flag uint) *Writer {
 | 
			
		||||
	return &Writer{
 | 
			
		||||
		w:     w,
 | 
			
		||||
		width: width,
 | 
			
		||||
		flag:  flag,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes p to the writer w. The only errors returned are ones
 | 
			
		||||
// encountered while writing to the underlying output stream.
 | 
			
		||||
func (w *Writer) Write(p []byte) (n int, err error) {
 | 
			
		||||
	var linelen int
 | 
			
		||||
	var lastWasColon bool
 | 
			
		||||
	for i, c := range p {
 | 
			
		||||
		w.buf = append(w.buf, c)
 | 
			
		||||
		linelen++
 | 
			
		||||
		if c == '\t' {
 | 
			
		||||
			w.buf[len(w.buf)-1] = ' '
 | 
			
		||||
			for linelen%tab != 0 {
 | 
			
		||||
				w.buf = append(w.buf, ' ')
 | 
			
		||||
				linelen++
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if w.flag&BreakOnColon != 0 && c == ':' {
 | 
			
		||||
			lastWasColon = true
 | 
			
		||||
		} else if lastWasColon {
 | 
			
		||||
			if c == '\n' {
 | 
			
		||||
				pos := bytes.LastIndex(w.buf[:len(w.buf)-1], []byte{'\n'})
 | 
			
		||||
				if pos < 0 {
 | 
			
		||||
					pos = 0
 | 
			
		||||
				}
 | 
			
		||||
				line := w.buf[pos:]
 | 
			
		||||
				w.buf = w.buf[:pos]
 | 
			
		||||
				if err = w.columnate(); err != nil {
 | 
			
		||||
					if len(line) < i {
 | 
			
		||||
						return i - len(line), err
 | 
			
		||||
					}
 | 
			
		||||
					return 0, err
 | 
			
		||||
				}
 | 
			
		||||
				if n, err := w.w.Write(line); err != nil {
 | 
			
		||||
					if r := len(line) - n; r < i {
 | 
			
		||||
						return i - r, err
 | 
			
		||||
					}
 | 
			
		||||
					return 0, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			lastWasColon = false
 | 
			
		||||
		}
 | 
			
		||||
		if c == '\n' {
 | 
			
		||||
			linelen = 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return len(p), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Flush should be called after the last call to Write to ensure that any data
 | 
			
		||||
// buffered in the Writer is written to output.
 | 
			
		||||
func (w *Writer) Flush() error {
 | 
			
		||||
	return w.columnate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Writer) columnate() error {
 | 
			
		||||
	words := bytes.Split(w.buf, []byte{'\n'})
 | 
			
		||||
	w.buf = nil
 | 
			
		||||
	if len(words[len(words)-1]) == 0 {
 | 
			
		||||
		words = words[:len(words)-1]
 | 
			
		||||
	}
 | 
			
		||||
	maxwidth := 0
 | 
			
		||||
	for _, wd := range words {
 | 
			
		||||
		if n := utf8.RuneCount(wd); n > maxwidth {
 | 
			
		||||
			maxwidth = n
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	maxwidth++ // space char
 | 
			
		||||
	wordsPerLine := w.width / maxwidth
 | 
			
		||||
	if wordsPerLine <= 0 {
 | 
			
		||||
		wordsPerLine = 1
 | 
			
		||||
	}
 | 
			
		||||
	nlines := (len(words) + wordsPerLine - 1) / wordsPerLine
 | 
			
		||||
	for i := 0; i < nlines; i++ {
 | 
			
		||||
		col := 0
 | 
			
		||||
		endcol := 0
 | 
			
		||||
		for j := i; j < len(words); j += nlines {
 | 
			
		||||
			endcol += maxwidth
 | 
			
		||||
			_, err := w.w.Write(words[j])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			col += utf8.RuneCount(words[j])
 | 
			
		||||
			if j+nlines < len(words) {
 | 
			
		||||
				for col < endcol {
 | 
			
		||||
					_, err := w.w.Write([]byte{' '})
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					col++
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		_, err := w.w.Write([]byte{'\n'})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
package colwriter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var src = `
 | 
			
		||||
.git
 | 
			
		||||
.gitignore
 | 
			
		||||
.godir
 | 
			
		||||
Procfile:
 | 
			
		||||
README.md
 | 
			
		||||
api.go
 | 
			
		||||
apps.go
 | 
			
		||||
auth.go
 | 
			
		||||
darwin.go
 | 
			
		||||
data.go
 | 
			
		||||
dyno.go:
 | 
			
		||||
env.go
 | 
			
		||||
git.go
 | 
			
		||||
help.go
 | 
			
		||||
hkdist
 | 
			
		||||
linux.go
 | 
			
		||||
ls.go
 | 
			
		||||
main.go
 | 
			
		||||
plugin.go
 | 
			
		||||
run.go
 | 
			
		||||
scale.go
 | 
			
		||||
ssh.go
 | 
			
		||||
tail.go
 | 
			
		||||
term
 | 
			
		||||
unix.go
 | 
			
		||||
update.go
 | 
			
		||||
version.go
 | 
			
		||||
windows.go
 | 
			
		||||
`[1:]
 | 
			
		||||
 | 
			
		||||
var tests = []struct {
 | 
			
		||||
	wid  int
 | 
			
		||||
	flag uint
 | 
			
		||||
	src  string
 | 
			
		||||
	want string
 | 
			
		||||
}{
 | 
			
		||||
	{80, 0, "", ""},
 | 
			
		||||
	{80, 0, src, `
 | 
			
		||||
.git       README.md  darwin.go  git.go     ls.go      scale.go   unix.go
 | 
			
		||||
.gitignore api.go     data.go    help.go    main.go    ssh.go     update.go
 | 
			
		||||
.godir     apps.go    dyno.go:   hkdist     plugin.go  tail.go    version.go
 | 
			
		||||
Procfile:  auth.go    env.go     linux.go   run.go     term       windows.go
 | 
			
		||||
`[1:]},
 | 
			
		||||
	{80, BreakOnColon, src, `
 | 
			
		||||
.git       .gitignore .godir
 | 
			
		||||
 | 
			
		||||
Procfile:
 | 
			
		||||
README.md api.go    apps.go   auth.go   darwin.go data.go
 | 
			
		||||
 | 
			
		||||
dyno.go:
 | 
			
		||||
env.go     hkdist     main.go    scale.go   term       version.go
 | 
			
		||||
git.go     linux.go   plugin.go  ssh.go     unix.go    windows.go
 | 
			
		||||
help.go    ls.go      run.go     tail.go    update.go
 | 
			
		||||
`[1:]},
 | 
			
		||||
	{20, 0, `
 | 
			
		||||
Hello
 | 
			
		||||
Γειά σου
 | 
			
		||||
안녕
 | 
			
		||||
今日は
 | 
			
		||||
`[1:], `
 | 
			
		||||
Hello    안녕
 | 
			
		||||
Γειά σου 今日は
 | 
			
		||||
`[1:]},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWriter(t *testing.T) {
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		b := new(bytes.Buffer)
 | 
			
		||||
		w := NewWriter(b, test.wid, test.flag)
 | 
			
		||||
		if _, err := w.Write([]byte(test.src)); err != nil {
 | 
			
		||||
			t.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
		if err := w.Flush(); err != nil {
 | 
			
		||||
			t.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
		if g := b.String(); test.want != g {
 | 
			
		||||
			t.Log("\n" + test.want)
 | 
			
		||||
			t.Log("\n" + g)
 | 
			
		||||
			t.Errorf("%q != %q", test.want, g)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
// Package text provides rudimentary functions for manipulating text in
 | 
			
		||||
// paragraphs.
 | 
			
		||||
package text
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
package text
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Indent inserts prefix at the beginning of each non-empty line of s. The
 | 
			
		||||
// end-of-line marker is NL.
 | 
			
		||||
func Indent(s, prefix string) string {
 | 
			
		||||
	return string(IndentBytes([]byte(s), []byte(prefix)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IndentBytes inserts prefix at the beginning of each non-empty line of b.
 | 
			
		||||
// The end-of-line marker is NL.
 | 
			
		||||
func IndentBytes(b, prefix []byte) []byte {
 | 
			
		||||
	var res []byte
 | 
			
		||||
	bol := true
 | 
			
		||||
	for _, c := range b {
 | 
			
		||||
		if bol && c != '\n' {
 | 
			
		||||
			res = append(res, prefix...)
 | 
			
		||||
		}
 | 
			
		||||
		res = append(res, c)
 | 
			
		||||
		bol = c == '\n'
 | 
			
		||||
	}
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Writer indents each line of its input.
 | 
			
		||||
type indentWriter struct {
 | 
			
		||||
	w   io.Writer
 | 
			
		||||
	bol bool
 | 
			
		||||
	pre [][]byte
 | 
			
		||||
	sel int
 | 
			
		||||
	off int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewIndentWriter makes a new write filter that indents the input
 | 
			
		||||
// lines. Each line is prefixed in order with the corresponding
 | 
			
		||||
// element of pre. If there are more lines than elements, the last
 | 
			
		||||
// element of pre is repeated for each subsequent line.
 | 
			
		||||
func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer {
 | 
			
		||||
	return &indentWriter{
 | 
			
		||||
		w:   w,
 | 
			
		||||
		pre: pre,
 | 
			
		||||
		bol: true,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The only errors returned are from the underlying indentWriter.
 | 
			
		||||
func (w *indentWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
	for _, c := range p {
 | 
			
		||||
		if w.bol {
 | 
			
		||||
			var i int
 | 
			
		||||
			i, err = w.w.Write(w.pre[w.sel][w.off:])
 | 
			
		||||
			w.off += i
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return n, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		_, err = w.w.Write([]byte{c})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return n, err
 | 
			
		||||
		}
 | 
			
		||||
		n++
 | 
			
		||||
		w.bol = c == '\n'
 | 
			
		||||
		if w.bol {
 | 
			
		||||
			w.off = 0
 | 
			
		||||
			if w.sel < len(w.pre)-1 {
 | 
			
		||||
				w.sel++
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,119 @@
 | 
			
		|||
package text
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type T struct {
 | 
			
		||||
	inp, exp, pre string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var tests = []T{
 | 
			
		||||
	{
 | 
			
		||||
		"The quick brown fox\njumps over the lazy\ndog.\nBut not quickly.\n",
 | 
			
		||||
		"xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\nxxxBut not quickly.\n",
 | 
			
		||||
		"xxx",
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"The quick brown fox\njumps over the lazy\ndog.\n\nBut not quickly.",
 | 
			
		||||
		"xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\n\nxxxBut not quickly.",
 | 
			
		||||
		"xxx",
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIndent(t *testing.T) {
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		got := Indent(test.inp, test.pre)
 | 
			
		||||
		if got != test.exp {
 | 
			
		||||
			t.Errorf("mismatch %q != %q", got, test.exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IndentWriterTest struct {
 | 
			
		||||
	inp, exp string
 | 
			
		||||
	pre      []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ts = []IndentWriterTest{
 | 
			
		||||
	{
 | 
			
		||||
		`
 | 
			
		||||
The quick brown fox
 | 
			
		||||
jumps over the lazy
 | 
			
		||||
dog.
 | 
			
		||||
But not quickly.
 | 
			
		||||
`[1:],
 | 
			
		||||
		`
 | 
			
		||||
xxxThe quick brown fox
 | 
			
		||||
xxxjumps over the lazy
 | 
			
		||||
xxxdog.
 | 
			
		||||
xxxBut not quickly.
 | 
			
		||||
`[1:],
 | 
			
		||||
		[]string{"xxx"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		`
 | 
			
		||||
The quick brown fox
 | 
			
		||||
jumps over the lazy
 | 
			
		||||
dog.
 | 
			
		||||
But not quickly.
 | 
			
		||||
`[1:],
 | 
			
		||||
		`
 | 
			
		||||
xxaThe quick brown fox
 | 
			
		||||
xxxjumps over the lazy
 | 
			
		||||
xxxdog.
 | 
			
		||||
xxxBut not quickly.
 | 
			
		||||
`[1:],
 | 
			
		||||
		[]string{"xxa", "xxx"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		`
 | 
			
		||||
The quick brown fox
 | 
			
		||||
jumps over the lazy
 | 
			
		||||
dog.
 | 
			
		||||
But not quickly.
 | 
			
		||||
`[1:],
 | 
			
		||||
		`
 | 
			
		||||
xxaThe quick brown fox
 | 
			
		||||
xxbjumps over the lazy
 | 
			
		||||
xxcdog.
 | 
			
		||||
xxxBut not quickly.
 | 
			
		||||
`[1:],
 | 
			
		||||
		[]string{"xxa", "xxb", "xxc", "xxx"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		`
 | 
			
		||||
The quick brown fox
 | 
			
		||||
jumps over the lazy
 | 
			
		||||
dog.
 | 
			
		||||
 | 
			
		||||
But not quickly.`[1:],
 | 
			
		||||
		`
 | 
			
		||||
xxaThe quick brown fox
 | 
			
		||||
xxxjumps over the lazy
 | 
			
		||||
xxxdog.
 | 
			
		||||
xxx
 | 
			
		||||
xxxBut not quickly.`[1:],
 | 
			
		||||
		[]string{"xxa", "xxx"},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIndentWriter(t *testing.T) {
 | 
			
		||||
	for _, test := range ts {
 | 
			
		||||
		b := new(bytes.Buffer)
 | 
			
		||||
		pre := make([][]byte, len(test.pre))
 | 
			
		||||
		for i := range test.pre {
 | 
			
		||||
			pre[i] = []byte(test.pre[i])
 | 
			
		||||
		}
 | 
			
		||||
		w := NewIndentWriter(b, pre...)
 | 
			
		||||
		if _, err := w.Write([]byte(test.inp)); err != nil {
 | 
			
		||||
			t.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
		if got := b.String(); got != test.exp {
 | 
			
		||||
			t.Errorf("mismatch %q != %q", got, test.exp)
 | 
			
		||||
			t.Log(got)
 | 
			
		||||
			t.Log(test.exp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
Command mc prints in multiple columns.
 | 
			
		||||
 | 
			
		||||
  Usage: mc [-] [-N] [file...]
 | 
			
		||||
 | 
			
		||||
Mc splits the input into as many columns as will fit in N
 | 
			
		||||
print positions. If the output is a tty, the default N is
 | 
			
		||||
the number of characters in a terminal line; otherwise the
 | 
			
		||||
default N is 80. Under option - each input line ending in
 | 
			
		||||
a colon ':' is printed separately.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
// Command mc prints in multiple columns.
 | 
			
		||||
//
 | 
			
		||||
//   Usage: mc [-] [-N] [file...]
 | 
			
		||||
//
 | 
			
		||||
// Mc splits the input into as many columns as will fit in N
 | 
			
		||||
// print positions. If the output is a tty, the default N is
 | 
			
		||||
// the number of characters in a terminal line; otherwise the
 | 
			
		||||
// default N is 80. Under option - each input line ending in
 | 
			
		||||
// a colon ':' is printed separately.
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/kr/pty"
 | 
			
		||||
	"github.com/kr/text/colwriter"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var width int
 | 
			
		||||
	var flag uint
 | 
			
		||||
	args := os.Args[1:]
 | 
			
		||||
	for len(args) > 0 && len(args[0]) > 0 && args[0][0] == '-' {
 | 
			
		||||
		if len(args[0]) > 1 {
 | 
			
		||||
			width, _ = strconv.Atoi(args[0][1:])
 | 
			
		||||
		} else {
 | 
			
		||||
			flag |= colwriter.BreakOnColon
 | 
			
		||||
		}
 | 
			
		||||
		args = args[1:]
 | 
			
		||||
	}
 | 
			
		||||
	if width < 1 {
 | 
			
		||||
		_, width, _ = pty.Getsize(os.Stdout)
 | 
			
		||||
	}
 | 
			
		||||
	if width < 1 {
 | 
			
		||||
		width = 80
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w := colwriter.NewWriter(os.Stdout, width, flag)
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		for _, s := range args {
 | 
			
		||||
			if f, err := os.Open(s); err == nil {
 | 
			
		||||
				copyin(w, f)
 | 
			
		||||
				f.Close()
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Println(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		copyin(w, os.Stdin)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyin(w *colwriter.Writer, r io.Reader) {
 | 
			
		||||
	if _, err := io.Copy(w, r); err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := w.Flush(); err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
package text
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"math"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	nl = []byte{'\n'}
 | 
			
		||||
	sp = []byte{' '}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const defaultPenalty = 1e5
 | 
			
		||||
 | 
			
		||||
// Wrap wraps s into a paragraph of lines of length lim, with minimal
 | 
			
		||||
// raggedness.
 | 
			
		||||
func Wrap(s string, lim int) string {
 | 
			
		||||
	return string(WrapBytes([]byte(s), lim))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
 | 
			
		||||
// raggedness.
 | 
			
		||||
func WrapBytes(b []byte, lim int) []byte {
 | 
			
		||||
	words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
 | 
			
		||||
	var lines [][]byte
 | 
			
		||||
	for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
 | 
			
		||||
		lines = append(lines, bytes.Join(line, sp))
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.Join(lines, nl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WrapWords is the low-level line-breaking algorithm, useful if you need more
 | 
			
		||||
// control over the details of the text wrapping process. For most uses, either
 | 
			
		||||
// Wrap or WrapBytes will be sufficient and more convenient.
 | 
			
		||||
//
 | 
			
		||||
// WrapWords splits a list of words into lines with minimal "raggedness",
 | 
			
		||||
// treating each byte as one unit, accounting for spc units between adjacent
 | 
			
		||||
// words on each line, and attempting to limit lines to lim units. Raggedness
 | 
			
		||||
// is the total error over all lines, where error is the square of the
 | 
			
		||||
// difference of the length of the line and lim. Too-long lines (which only
 | 
			
		||||
// happen when a single word is longer than lim units) have pen penalty units
 | 
			
		||||
// added to the error.
 | 
			
		||||
func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
 | 
			
		||||
	n := len(words)
 | 
			
		||||
 | 
			
		||||
	length := make([][]int, n)
 | 
			
		||||
	for i := 0; i < n; i++ {
 | 
			
		||||
		length[i] = make([]int, n)
 | 
			
		||||
		length[i][i] = len(words[i])
 | 
			
		||||
		for j := i + 1; j < n; j++ {
 | 
			
		||||
			length[i][j] = length[i][j-1] + spc + len(words[j])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nbrk := make([]int, n)
 | 
			
		||||
	cost := make([]int, n)
 | 
			
		||||
	for i := range cost {
 | 
			
		||||
		cost[i] = math.MaxInt32
 | 
			
		||||
	}
 | 
			
		||||
	for i := n - 1; i >= 0; i-- {
 | 
			
		||||
		if length[i][n-1] <= lim || i == n-1 {
 | 
			
		||||
			cost[i] = 0
 | 
			
		||||
			nbrk[i] = n
 | 
			
		||||
		} else {
 | 
			
		||||
			for j := i + 1; j < n; j++ {
 | 
			
		||||
				d := lim - length[i][j-1]
 | 
			
		||||
				c := d*d + cost[j]
 | 
			
		||||
				if length[i][j-1] > lim {
 | 
			
		||||
					c += pen // too-long lines get a worse penalty
 | 
			
		||||
				}
 | 
			
		||||
				if c < cost[i] {
 | 
			
		||||
					cost[i] = c
 | 
			
		||||
					nbrk[i] = j
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var lines [][][]byte
 | 
			
		||||
	i := 0
 | 
			
		||||
	for i < n {
 | 
			
		||||
		lines = append(lines, words[i:nbrk[i]])
 | 
			
		||||
		i = nbrk[i]
 | 
			
		||||
	}
 | 
			
		||||
	return lines
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
package text
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var text = "The quick brown fox jumps over the lazy dog."
 | 
			
		||||
 | 
			
		||||
func TestWrap(t *testing.T) {
 | 
			
		||||
	exp := [][]string{
 | 
			
		||||
		{"The", "quick", "brown", "fox"},
 | 
			
		||||
		{"jumps", "over", "the", "lazy", "dog."},
 | 
			
		||||
	}
 | 
			
		||||
	words := bytes.Split([]byte(text), sp)
 | 
			
		||||
	got := WrapWords(words, 1, 24, defaultPenalty)
 | 
			
		||||
	if len(exp) != len(got) {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	for i := range exp {
 | 
			
		||||
		if len(exp[i]) != len(got[i]) {
 | 
			
		||||
			t.Fail()
 | 
			
		||||
		}
 | 
			
		||||
		for j := range exp[i] {
 | 
			
		||||
			if exp[i][j] != string(got[i][j]) {
 | 
			
		||||
				t.Fatal(i, exp[i][j], got[i][j])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWrapNarrow(t *testing.T) {
 | 
			
		||||
	exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog."
 | 
			
		||||
	if Wrap(text, 5) != exp {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWrapOneLine(t *testing.T) {
 | 
			
		||||
	exp := "The quick brown fox jumps over the lazy dog."
 | 
			
		||||
	if Wrap(text, 500) != exp {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWrapBug1(t *testing.T) {
 | 
			
		||||
	cases := []struct {
 | 
			
		||||
		limit int
 | 
			
		||||
		text  string
 | 
			
		||||
		want  string
 | 
			
		||||
	}{
 | 
			
		||||
		{4, "aaaaa", "aaaaa"},
 | 
			
		||||
		{4, "a aaaaa", "a\naaaaa"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range cases {
 | 
			
		||||
		got := Wrap(test.text, test.limit)
 | 
			
		||||
		if got != test.want {
 | 
			
		||||
			t.Errorf("Wrap(%q, %d) = %q want %q", test.text, test.limit, got, test.want)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue