Commit b0253219 by Marcus Efraimsson Committed by GitHub

Use v0.33.0 of SDK (#23031)

parent 15455ab5
......@@ -32,7 +32,7 @@ require (
github.com/gorilla/websocket v1.4.1
github.com/gosimple/slug v1.4.2
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
github.com/grafana/grafana-plugin-sdk-go v0.31.0
github.com/grafana/grafana-plugin-sdk-go v0.33.0
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd
github.com/hashicorp/go-plugin v1.0.1
github.com/hashicorp/go-version v1.1.0
......
......@@ -129,8 +129,8 @@ github.com/gosimple/slug v1.4.2 h1:jDmprx3q/9Lfk4FkGZtvzDQ9Cj9eAmsjzeQGp24PeiQ=
github.com/gosimple/slug v1.4.2/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0=
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 h1:SPdxCL9BChFTlyi0Khv64vdCW4TMna8+sxL7+Chx+Ag=
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4/go.mod h1:nc0XxBzjeGcrMltCDw269LoWF9S8ibhgxolCdA1R8To=
github.com/grafana/grafana-plugin-sdk-go v0.31.0 h1:n4UscOh5T+KtOwk0iVbIOUD00Ig0qf3FgKKTlYf7TDg=
github.com/grafana/grafana-plugin-sdk-go v0.31.0/go.mod h1:G6Ov9M+FDOZXNw8eKXINO6XzqdUvTs7huwyQp5jLTBQ=
github.com/grafana/grafana-plugin-sdk-go v0.33.0 h1:+eFcOV/KioHTTRNimENZeajlkw31B+m92RNRShooPEQ=
github.com/grafana/grafana-plugin-sdk-go v0.33.0/go.mod h1:4rVPIvfv7SzFC0AA/8T5tmDRxIsrvDJOF9p4SrQGS1M=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
......@@ -190,6 +190,8 @@ github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+v
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
......@@ -207,6 +209,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
......
......@@ -3,8 +3,7 @@ package backendplugin
import (
"os/exec"
"github.com/grafana/grafana-plugin-sdk-go/backend/plugin"
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin"
"github.com/grafana/grafana/pkg/infra/log"
datasourceV1 "github.com/grafana/grafana-plugin-model/go/datasource"
......@@ -27,8 +26,8 @@ var handshake = goplugin.HandshakeConfig{
ProtocolVersion: DefaultProtocolVersion,
// The magic cookie values should NEVER be changed.
MagicCookieKey: plugin.MagicCookieKey,
MagicCookieValue: plugin.MagicCookieValue,
MagicCookieKey: grpcplugin.MagicCookieKey,
MagicCookieValue: grpcplugin.MagicCookieValue,
}
func newClientConfig(executablePath string, logger log.Logger, versionedPlugins map[int]goplugin.PluginSet) *goplugin.ClientConfig {
......@@ -73,11 +72,11 @@ func NewBackendPluginDescriptor(pluginID, executablePath string, startFns Plugin
DefaultProtocolVersion: {
pluginID: &datasourceV1.DatasourcePluginImpl{},
},
plugin.ProtocolVersion: {
"diagnostics": &plugin.DiagnosticsGRPCPlugin{},
"resource": &plugin.ResourceGRPCPlugin{},
"data": &plugin.DataGRPCPlugin{},
"transform": &plugin.TransformGRPCPlugin{},
grpcplugin.ProtocolVersion: {
"diagnostics": &grpcplugin.DiagnosticsGRPCPlugin{},
"resource": &grpcplugin.ResourceGRPCPlugin{},
"data": &grpcplugin.DataGRPCPlugin{},
"transform": &grpcplugin.TransformGRPCPlugin{},
},
},
startFns: startFns,
......@@ -101,19 +100,19 @@ func NewRendererPluginDescriptor(pluginID, executablePath string, startFns Plugi
}
type DiagnosticsPlugin interface {
plugin.DiagnosticsClient
grpcplugin.DiagnosticsClient
}
type ResourcePlugin interface {
plugin.ResourceClient
grpcplugin.ResourceClient
}
type DataPlugin interface {
plugin.DataClient
grpcplugin.DataClient
}
type TransformPlugin interface {
plugin.TransformClient
grpcplugin.TransformClient
}
// LegacyClient client for communicating with a plugin using the old plugin protocol.
......
// Package grpcplugin provides support for serving plugin over gRPC.
//
// This package is internal and meant to be used internally by the
// SDK and Grafana.
package grpcplugin
package data
import (
"fmt"
"math"
"strconv"
"time"
)
// Field represents a typed column of data within a Frame.
// The data in the Field is a not exported, so methods on the Field are used to to manipulate its data.
type Field struct {
Name string
Config *FieldConfig
vector vector
Labels Labels
}
// Fields is a slice of Field pointers.
type Fields []*Field
// NewField returns a instance of *Field.
//
// Supported types for values are: []int8, []*int8, []int16, []*int16, []int32, []*int32, []int64, []*int64,
// []uint8, []*uint8, []uint16, []*uint16, []uint32, []*uint32, []uint64, []*uint64,
// []float32, []*float32, []float64, []*float64,
// []string, []*string, []bool, []*bool, []time.Time, and []*time.Time.
//
// If an unsupported values type is passed, NewField will panic.
func NewField(name string, labels Labels, values interface{}) *Field {
var vec vector
switch v := values.(type) {
case []int8:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*int8:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []int16:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*int16:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []int32:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*int32:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []int64:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*int64:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []uint8:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*uint8:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []uint16:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*uint16:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []uint32:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*uint32:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []uint64:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*uint64:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []float32:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*float32:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []float64:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*float64:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []string:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*string:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []bool:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*bool:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []time.Time:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
case []*time.Time:
vec = newVector(v, len(v))
for i := 0; i < len(v); i++ {
vec.Set(i, v[i])
}
default:
panic(fmt.Errorf("unsupported field type %T", v))
}
return &Field{
Name: name,
vector: vec,
Labels: labels,
}
}
// Set sets the Field's value at index idx to val.
// It will panic if idx is out of range.
func (f *Field) Set(idx int, val interface{}) {
f.vector.Set(idx, val)
}
// Append appends element i to the Field.
func (f *Field) Append(i interface{}) {
f.vector.Append(i)
}
// Extend extends the Field length by i.
func (f *Field) Extend(i int) {
f.vector.Extend(i)
}
// At returns the the element at index idx of the Field.
// It will panic if idx is out of range.
func (f *Field) At(idx int) interface{} {
return f.vector.At(idx)
}
// Len returns the number of elements in the Field.
func (f *Field) Len() int {
return f.vector.Len()
}
// Type returns the underlying primitive type of the Field.
func (f *Field) Type() FieldType {
return f.vector.Type()
}
// PointerAt returns a pointer to the value at idx of the Field.
// It will panic if idx is out of range.
func (f *Field) PointerAt(idx int) interface{} {
return f.vector.PointerAt(idx)
}
// CopyAt returns a copy of the value of the specified index idx.
// It will panic if idx is out of range.
func (f *Field) CopyAt(idx int) interface{} {
return f.vector.CopyAt(idx)
}
// ConcreteAt returns the concrete value at the specified index idx.
// A non-pointer type is returned regardless if the underlying vector is a pointer
// type or not. If the value is a pointer type, and is nil, then the zero value
// is returned and ok will be false.
func (f *Field) ConcreteAt(idx int) (val interface{}, ok bool) {
return f.vector.ConcreteAt(idx)
}
// Nullable returns if the the Field's elements are nullable.
func (f *Field) Nullable() bool {
return f.Type().Nullable()
}
// FloatAt returns a float64 at the specified index idx.
// It will panic if idx is out of range.
// If the Field type is numeric and the value at idx is nil, NaN is returned. Precision may be lost on large numbers.
// If the Field type is a bool then 0 is return if false or nil, and 1 if true.
// If the Field type is time.Time, then the millisecond epoch representation of the time
// is returned, or NaN is the value is nil.
// If the Field type is a string, then strconv.ParseFloat is called on it and will return
// an error if ParseFloat errors. If the value is nil, NaN is returned.
func (f *Field) FloatAt(idx int) (float64, error) {
switch f.Type() {
case FieldTypeInt8:
return float64(f.At(idx).(int8)), nil
case FieldTypeNullableInt8:
iv := f.At(idx).(*int8)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeInt16:
return float64(f.At(idx).(int16)), nil
case FieldTypeNullableInt16:
iv := f.At(idx).(*int16)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeInt32:
return float64(f.At(idx).(int32)), nil
case FieldTypeNullableInt32:
iv := f.At(idx).(*int32)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeInt64:
return float64(f.At(idx).(int64)), nil
case FieldTypeNullableInt64:
iv := f.At(idx).(*int64)
if iv == nil {
return math.NaN(), nil
}
return float64(*iv), nil
case FieldTypeUint8:
return float64(f.At(idx).(uint8)), nil
case FieldTypeNullableUint8:
uiv := f.At(idx).(*uint8)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
case FieldTypeUint16:
return float64(f.At(idx).(uint16)), nil
case FieldTypeNullableUint16:
uiv := f.At(idx).(*uint16)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
case FieldTypeUint32:
return float64(f.At(idx).(uint32)), nil
case FieldTypeNullableUint32:
uiv := f.At(idx).(*uint32)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
// TODO: third param for loss of precision?
// Maybe something in math/big can help with this (also see https://github.com/golang/go/issues/29463).
case FieldTypeUint64:
return float64(f.At(idx).(uint64)), nil
case FieldTypeNullableUint64:
uiv := f.At(idx).(*uint64)
if uiv == nil {
return math.NaN(), nil
}
return float64(*uiv), nil
case FieldTypeFloat32:
return float64(f.At(idx).(float32)), nil
case FieldTypeNullableFloat32:
fv := f.At(idx).(*float32)
if fv == nil {
return math.NaN(), nil
}
return float64(*fv), nil
case FieldTypeFloat64:
return f.At(idx).(float64), nil
case FieldTypeNullableFloat64:
fv := f.At(idx).(*float64)
if fv == nil {
return math.NaN(), nil
}
return *fv, nil
case FieldTypeString:
s := f.At(idx).(string)
ft, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, err
}
return ft, nil
case FieldTypeNullableString:
s := f.At(idx).(*string)
if s == nil {
return math.NaN(), nil
}
ft, err := strconv.ParseFloat(*s, 64)
if err != nil {
return 0, err
}
return ft, nil
case FieldTypeBool:
if f.At(idx).(bool) {
return 1, nil
}
return 0, nil
case FieldTypeNullableBool:
b := f.At(idx).(*bool)
if b == nil || !*b {
return 0, nil
}
return 1, nil
case FieldTypeTime:
return float64(f.At(idx).(time.Time).UnixNano() / int64(time.Millisecond)), nil
case FieldTypeNullableTime:
t := f.At(idx).(*time.Time)
if t == nil {
return math.NaN(), nil
}
return float64(f.At(idx).(*time.Time).UnixNano() / int64(time.Millisecond)), nil
}
return 0, fmt.Errorf("unsupported field type %T", f.Type())
}
......@@ -49,6 +49,7 @@ type FieldConfig struct {
// to null.
type ConfFloat64 float64
// MarshalJSON fullfills the json.Marshaler interface.
func (sf *ConfFloat64) MarshalJSON() ([]byte, error) {
if sf == nil || math.IsNaN(float64(*sf)) || math.IsInf(float64(*sf), -1) || math.IsInf(float64(*sf), 1) {
return []byte("null"), nil
......@@ -57,6 +58,7 @@ func (sf *ConfFloat64) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`%v`, float64(*sf))), nil
}
// UnmarshalJSON fullfills the json.Unmarshaler interface.
func (sf *ConfFloat64) UnmarshalJSON(data []byte) error {
s := string(data)
if s == "null" {
......
package data
import (
"fmt"
"sort"
"strings"
)
// Labels are used to add metadata to an object.
type Labels map[string]string
// Equals returns true if the argument has the same k=v pairs as the receiver.
func (l Labels) Equals(arg Labels) bool {
if len(l) != len(arg) {
return false
}
for k, v := range l {
if argVal, ok := arg[k]; !ok || argVal != v {
return false
}
}
return true
}
// Copy returns a copy of the labels.
func (l Labels) Copy() Labels {
c := make(Labels, len(l))
for k, v := range l {
c[k] = v
}
return c
}
// Contains returns true if all k=v pairs of the argument are in the receiver.
func (l Labels) Contains(arg Labels) bool {
if len(arg) > len(l) {
return false
}
for k, v := range arg {
if argVal, ok := l[k]; !ok || argVal != v {
return false
}
}
return true
}
func (l Labels) String() string {
// Better structure, should be sorted, copy prom probably
keys := make([]string, len(l))
i := 0
for k := range l {
keys[i] = k
i++
}
sort.Strings(keys)
var sb strings.Builder
i = 0
for _, k := range keys {
sb.WriteString(k)
sb.WriteString("=")
sb.WriteString(l[k])
if i != len(keys)-1 {
sb.WriteString(", ")
}
i++
}
return sb.String()
}
// LabelsFromString parses the output of Labels.String() into
// a Labels object. It probably has some flaws.
func LabelsFromString(s string) (Labels, error) {
if s == "" {
return nil, nil
}
labels := make(map[string]string)
for _, rawKV := range strings.Split(s, ", ") {
kV := strings.SplitN(rawKV, "=", 2)
if len(kV) != 2 {
return nil, fmt.Errorf(`invalid label key=value pair "%v"`, rawKV)
}
labels[kV[0]] = kV[1]
}
return labels, nil
}
......@@ -37,13 +37,13 @@ func NewFromSQLRows(rows *sql.Rows, converters ...SQLStringConverter) (*Frame, m
if mapper.ConversionFunc == nil {
continue
}
vec := frame.Fields[fieldIdx]
for i := 0; i < vec.Len(); i++ {
v, err := mapper.ConversionFunc(vec.vector.At(i).(*string))
field := frame.Fields[fieldIdx]
for i := 0; i < field.Len(); i++ {
v, err := mapper.ConversionFunc(field.At(i).(*string))
if err != nil {
return nil, nil, err
}
vec.vector.Set(i, v)
field.Set(i, v)
}
if mapper.Replacer == nil {
continue
......@@ -121,11 +121,10 @@ func newForSQLRows(rows *sql.Rows, converters ...SQLStringConverter) (*Frame, ma
func (f *Frame) newScannableRow() []interface{} {
row := make([]interface{}, len(f.Fields))
for i, field := range f.Fields {
vec := field.vector
vec.Extend(1)
field.Extend(1)
// non-nullable fields will be *T, and nullable fields will be **T
vecItemPointer := vec.PointerAt(vec.Len() - 1)
row[i] = vecItemPointer
ptr := field.PointerAt(field.Len() - 1)
row[i] = ptr
}
return row
}
......@@ -150,7 +149,7 @@ type SQLStringConverter struct {
// Note: SQLStringConverter is perhaps better understood as []byte. However, currently
// the Vector type ([][]byte) is not supported. https://github.com/grafana/grafana-plugin-sdk-go/issues/57
// StringFieldReplacer is used to replace a *string Field in a data. The type
// StringFieldReplacer is used to replace a *string Field in a Frame. The type
// returned by the ReplaceFunc must match the type of elements of VectorType.
// Both properties must be non-nil.
type StringFieldReplacer struct {
......
The MIT License (MIT)
Copyright (c) 2016 Yasuhiro Matsumoto
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.
go-runewidth
============
[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD)
[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth)
[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth)
Provides functions to get fixed width of the character or string.
Usage
-----
```go
runewidth.StringWidth("つのだ☆HIRO") == 12
```
Author
------
Yasuhiro Matsumoto
License
-------
under the MIT License: http://mattn.mit-license.org/2013
module github.com/mattn/go-runewidth
go 1.9
package runewidth
import (
"os"
)
//go:generate go run script/generate.go
var (
// EastAsianWidth will be set true if the current locale is CJK
EastAsianWidth bool
// ZeroWidthJoiner is flag to set to use UTR#51 ZWJ
ZeroWidthJoiner bool
// DefaultCondition is a condition in current locale
DefaultCondition = &Condition{}
)
func init() {
handleEnv()
}
func handleEnv() {
env := os.Getenv("RUNEWIDTH_EASTASIAN")
if env == "" {
EastAsianWidth = IsEastAsian()
} else {
EastAsianWidth = env == "1"
}
// update DefaultCondition
DefaultCondition.EastAsianWidth = EastAsianWidth
DefaultCondition.ZeroWidthJoiner = ZeroWidthJoiner
}
type interval struct {
first rune
last rune
}
type table []interval
func inTables(r rune, ts ...table) bool {
for _, t := range ts {
if inTable(r, t) {
return true
}
}
return false
}
func inTable(r rune, t table) bool {
// func (t table) IncludesRune(r rune) bool {
if r < t[0].first {
return false
}
bot := 0
top := len(t) - 1
for top >= bot {
mid := (bot + top) >> 1
switch {
case t[mid].last < r:
bot = mid + 1
case t[mid].first > r:
top = mid - 1
default:
return true
}
}
return false
}
var private = table{
{0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
}
var nonprint = table{
{0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
{0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
{0x2028, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
}
// Condition have flag EastAsianWidth whether the current locale is CJK or not.
type Condition struct {
EastAsianWidth bool
ZeroWidthJoiner bool
}
// NewCondition return new instance of Condition which is current locale.
func NewCondition() *Condition {
return &Condition{
EastAsianWidth: EastAsianWidth,
ZeroWidthJoiner: ZeroWidthJoiner,
}
}
// RuneWidth returns the number of cells in r.
// See http://www.unicode.org/reports/tr11/
func (c *Condition) RuneWidth(r rune) int {
switch {
case r < 0 || r > 0x10FFFF || inTables(r, nonprint, combining, notassigned):
return 0
case (c.EastAsianWidth && IsAmbiguousWidth(r)) || inTables(r, doublewidth):
return 2
default:
return 1
}
}
func (c *Condition) stringWidth(s string) (width int) {
for _, r := range []rune(s) {
width += c.RuneWidth(r)
}
return width
}
func (c *Condition) stringWidthZeroJoiner(s string) (width int) {
r1, r2 := rune(0), rune(0)
for _, r := range []rune(s) {
if r == 0xFE0E || r == 0xFE0F {
continue
}
w := c.RuneWidth(r)
if r2 == 0x200D && inTables(r, emoji) && inTables(r1, emoji) {
if width < w {
width = w
}
} else {
width += w
}
r1, r2 = r2, r
}
return width
}
// StringWidth return width as you can see
func (c *Condition) StringWidth(s string) (width int) {
if c.ZeroWidthJoiner {
return c.stringWidthZeroJoiner(s)
}
return c.stringWidth(s)
}
// Truncate return string truncated with w cells
func (c *Condition) Truncate(s string, w int, tail string) string {
if c.StringWidth(s) <= w {
return s
}
r := []rune(s)
tw := c.StringWidth(tail)
w -= tw
width := 0
i := 0
for ; i < len(r); i++ {
cw := c.RuneWidth(r[i])
if width+cw > w {
break
}
width += cw
}
return string(r[0:i]) + tail
}
// Wrap return string wrapped with w cells
func (c *Condition) Wrap(s string, w int) string {
width := 0
out := ""
for _, r := range []rune(s) {
cw := RuneWidth(r)
if r == '\n' {
out += string(r)
width = 0
continue
} else if width+cw > w {
out += "\n"
width = 0
out += string(r)
width += cw
continue
}
out += string(r)
width += cw
}
return out
}
// FillLeft return string filled in left by spaces in w cells
func (c *Condition) FillLeft(s string, w int) string {
width := c.StringWidth(s)
count := w - width
if count > 0 {
b := make([]byte, count)
for i := range b {
b[i] = ' '
}
return string(b) + s
}
return s
}
// FillRight return string filled in left by spaces in w cells
func (c *Condition) FillRight(s string, w int) string {
width := c.StringWidth(s)
count := w - width
if count > 0 {
b := make([]byte, count)
for i := range b {
b[i] = ' '
}
return s + string(b)
}
return s
}
// RuneWidth returns the number of cells in r.
// See http://www.unicode.org/reports/tr11/
func RuneWidth(r rune) int {
return DefaultCondition.RuneWidth(r)
}
// IsAmbiguousWidth returns whether is ambiguous width or not.
func IsAmbiguousWidth(r rune) bool {
return inTables(r, private, ambiguous)
}
// IsNeutralWidth returns whether is neutral width or not.
func IsNeutralWidth(r rune) bool {
return inTable(r, neutral)
}
// StringWidth return width as you can see
func StringWidth(s string) (width int) {
return DefaultCondition.StringWidth(s)
}
// Truncate return string truncated with w cells
func Truncate(s string, w int, tail string) string {
return DefaultCondition.Truncate(s, w, tail)
}
// Wrap return string wrapped with w cells
func Wrap(s string, w int) string {
return DefaultCondition.Wrap(s, w)
}
// FillLeft return string filled in left by spaces in w cells
func FillLeft(s string, w int) string {
return DefaultCondition.FillLeft(s, w)
}
// FillRight return string filled in left by spaces in w cells
func FillRight(s string, w int) string {
return DefaultCondition.FillRight(s, w)
}
// +build appengine
package runewidth
// IsEastAsian return true if the current locale is CJK
func IsEastAsian() bool {
return false
}
// +build js
// +build !appengine
package runewidth
func IsEastAsian() bool {
// TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
return false
}
// +build !windows
// +build !js
// +build !appengine
package runewidth
import (
"os"
"regexp"
"strings"
)
var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
var mblenTable = map[string]int{
"utf-8": 6,
"utf8": 6,
"jis": 8,
"eucjp": 3,
"euckr": 2,
"euccn": 2,
"sjis": 2,
"cp932": 2,
"cp51932": 2,
"cp936": 2,
"cp949": 2,
"cp950": 2,
"big5": 2,
"gbk": 2,
"gb2312": 2,
}
func isEastAsian(locale string) bool {
charset := strings.ToLower(locale)
r := reLoc.FindStringSubmatch(locale)
if len(r) == 2 {
charset = strings.ToLower(r[1])
}
if strings.HasSuffix(charset, "@cjk_narrow") {
return false
}
for pos, b := range []byte(charset) {
if b == '@' {
charset = charset[:pos]
break
}
}
max := 1
if m, ok := mblenTable[charset]; ok {
max = m
}
if max > 1 && (charset[0] != 'u' ||
strings.HasPrefix(locale, "ja") ||
strings.HasPrefix(locale, "ko") ||
strings.HasPrefix(locale, "zh")) {
return true
}
return false
}
// IsEastAsian return true if the current locale is CJK
func IsEastAsian() bool {
locale := os.Getenv("LC_CTYPE")
if locale == "" {
locale = os.Getenv("LANG")
}
// ignore C locale
if locale == "POSIX" || locale == "C" {
return false
}
if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
return false
}
return isEastAsian(locale)
}
// +build windows
// +build !appengine
package runewidth
import (
"syscall"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32")
procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
)
// IsEastAsian return true if the current locale is CJK
func IsEastAsian() bool {
r1, _, _ := procGetConsoleOutputCP.Call()
if r1 == 0 {
return false
}
switch int(r1) {
case 932, 51932, 936, 949, 950:
return true
}
return false
}
# Created by .ignore support plugin (hsz.mobi)
### Go template
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
Copyright (C) 2014 by Oleku Konko
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.
// Copyright 2014 Oleku Konko All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
// This module is a Table Writer API for the Go Programming Language.
// The protocols were written in pure Go and works on windows and unix systems
package tablewriter
import (
"encoding/csv"
"io"
"os"
)
// Start A new table by importing from a CSV file
// Takes io.Writer and csv File name
func NewCSV(writer io.Writer, fileName string, hasHeader bool) (*Table, error) {
file, err := os.Open(fileName)
if err != nil {
return &Table{}, err
}
defer file.Close()
csvReader := csv.NewReader(file)
t, err := NewCSVReader(writer, csvReader, hasHeader)
return t, err
}
// Start a New Table Writer with csv.Reader
// This enables customisation such as reader.Comma = ';'
// See http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94
func NewCSVReader(writer io.Writer, csvReader *csv.Reader, hasHeader bool) (*Table, error) {
t := NewWriter(writer)
if hasHeader {
// Read the first row
headers, err := csvReader.Read()
if err != nil {
return &Table{}, err
}
t.SetHeader(headers)
}
for {
record, err := csvReader.Read()
if err == io.EOF {
break
} else if err != nil {
return &Table{}, err
}
t.Append(record)
}
return t, nil
}
module github.com/olekukonko/tablewriter
go 1.12
require github.com/mattn/go-runewidth v0.0.7
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
package tablewriter
import (
"fmt"
"strconv"
"strings"
)
const ESC = "\033"
const SEP = ";"
const (
BgBlackColor int = iota + 40
BgRedColor
BgGreenColor
BgYellowColor
BgBlueColor
BgMagentaColor
BgCyanColor
BgWhiteColor
)
const (
FgBlackColor int = iota + 30
FgRedColor
FgGreenColor
FgYellowColor
FgBlueColor
FgMagentaColor
FgCyanColor
FgWhiteColor
)
const (
BgHiBlackColor int = iota + 100
BgHiRedColor
BgHiGreenColor
BgHiYellowColor
BgHiBlueColor
BgHiMagentaColor
BgHiCyanColor
BgHiWhiteColor
)
const (
FgHiBlackColor int = iota + 90
FgHiRedColor
FgHiGreenColor
FgHiYellowColor
FgHiBlueColor
FgHiMagentaColor
FgHiCyanColor
FgHiWhiteColor
)
const (
Normal = 0
Bold = 1
UnderlineSingle = 4
Italic
)
type Colors []int
func startFormat(seq string) string {
return fmt.Sprintf("%s[%sm", ESC, seq)
}
func stopFormat() string {
return fmt.Sprintf("%s[%dm", ESC, Normal)
}
// Making the SGR (Select Graphic Rendition) sequence.
func makeSequence(codes []int) string {
codesInString := []string{}
for _, code := range codes {
codesInString = append(codesInString, strconv.Itoa(code))
}
return strings.Join(codesInString, SEP)
}
// Adding ANSI escape sequences before and after string
func format(s string, codes interface{}) string {
var seq string
switch v := codes.(type) {
case string:
seq = v
case []int:
seq = makeSequence(v)
case Colors:
seq = makeSequence(v)
default:
return s
}
if len(seq) == 0 {
return s
}
return startFormat(seq) + s + stopFormat()
}
// Adding header colors (ANSI codes)
func (t *Table) SetHeaderColor(colors ...Colors) {
if t.colSize != len(colors) {
panic("Number of header colors must be equal to number of headers.")
}
for i := 0; i < len(colors); i++ {
t.headerParams = append(t.headerParams, makeSequence(colors[i]))
}
}
// Adding column colors (ANSI codes)
func (t *Table) SetColumnColor(colors ...Colors) {
if t.colSize != len(colors) {
panic("Number of column colors must be equal to number of headers.")
}
for i := 0; i < len(colors); i++ {
t.columnsParams = append(t.columnsParams, makeSequence(colors[i]))
}
}
// Adding column colors (ANSI codes)
func (t *Table) SetFooterColor(colors ...Colors) {
if len(t.footers) != len(colors) {
panic("Number of footer colors must be equal to number of footer.")
}
for i := 0; i < len(colors); i++ {
t.footerParams = append(t.footerParams, makeSequence(colors[i]))
}
}
func Color(colors ...int) []int {
return colors
}
// Copyright 2014 Oleku Konko All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
// This module is a Table Writer API for the Go Programming Language.
// The protocols were written in pure Go and works on windows and unix systems
package tablewriter
import (
"math"
"regexp"
"strings"
"github.com/mattn/go-runewidth"
)
var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]")
func DisplayWidth(str string) int {
return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, ""))
}
// Simple Condition for string
// Returns value based on condition
func ConditionString(cond bool, valid, inValid string) string {
if cond {
return valid
}
return inValid
}
func isNumOrSpace(r rune) bool {
return ('0' <= r && r <= '9') || r == ' '
}
// Format Table Header
// Replace _ , . and spaces
func Title(name string) string {
origLen := len(name)
rs := []rune(name)
for i, r := range rs {
switch r {
case '_':
rs[i] = ' '
case '.':
// ignore floating number 0.0
if (i != 0 && !isNumOrSpace(rs[i-1])) || (i != len(rs)-1 && !isNumOrSpace(rs[i+1])) {
rs[i] = ' '
}
}
}
name = string(rs)
name = strings.TrimSpace(name)
if len(name) == 0 && origLen > 0 {
// Keep at least one character. This is important to preserve
// empty lines in multi-line headers/footers.
name = " "
}
return strings.ToUpper(name)
}
// Pad String
// Attempts to place string in the center
func Pad(s, pad string, width int) string {
gap := width - DisplayWidth(s)
if gap > 0 {
gapLeft := int(math.Ceil(float64(gap / 2)))
gapRight := gap - gapLeft
return strings.Repeat(string(pad), gapLeft) + s + strings.Repeat(string(pad), gapRight)
}
return s
}
// Pad String Right position
// This would place string at the left side of the screen
func PadRight(s, pad string, width int) string {
gap := width - DisplayWidth(s)
if gap > 0 {
return s + strings.Repeat(string(pad), gap)
}
return s
}
// Pad String Left position
// This would place string at the right side of the screen
func PadLeft(s, pad string, width int) string {
gap := width - DisplayWidth(s)
if gap > 0 {
return strings.Repeat(string(pad), gap) + s
}
return s
}
// Copyright 2014 Oleku Konko All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
// This module is a Table Writer API for the Go Programming Language.
// The protocols were written in pure Go and works on windows and unix systems
package tablewriter
import (
"math"
"strings"
"github.com/mattn/go-runewidth"
)
var (
nl = "\n"
sp = " "
)
const defaultPenalty = 1e5
// Wrap wraps s into a paragraph of lines of length lim, with minimal
// raggedness.
func WrapString(s string, lim int) ([]string, int) {
words := strings.Split(strings.Replace(s, nl, sp, -1), sp)
var lines []string
max := 0
for _, v := range words {
max = runewidth.StringWidth(v)
if max > lim {
lim = max
}
}
for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
lines = append(lines, strings.Join(line, sp))
}
return lines, lim
}
// 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,
// WrapString will be sufficient and more convenient.
//
// WrapWords splits a list of words into lines with minimal "raggedness",
// treating each rune 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 []string, spc, lim, pen int) [][]string {
n := len(words)
length := make([][]int, n)
for i := 0; i < n; i++ {
length[i] = make([]int, n)
length[i][i] = runewidth.StringWidth(words[i])
for j := i + 1; j < n; j++ {
length[i][j] = length[i][j-1] + spc + runewidth.StringWidth(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 {
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 [][]string
i := 0
for i < n {
lines = append(lines, words[i:nbrk[i]])
i = nbrk[i]
}
return lines
}
// getLines decomposes a multiline string into a slice of strings.
func getLines(s string) []string {
return strings.Split(s, nl)
}
......@@ -148,8 +148,8 @@ github.com/gosimple/slug
# github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
github.com/grafana/grafana-plugin-model/go/datasource
github.com/grafana/grafana-plugin-model/go/renderer
# github.com/grafana/grafana-plugin-sdk-go v0.31.0
github.com/grafana/grafana-plugin-sdk-go/backend/plugin
# github.com/grafana/grafana-plugin-sdk-go v0.33.0
github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin
github.com/grafana/grafana-plugin-sdk-go/data
github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2
# github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd
......@@ -190,6 +190,8 @@ github.com/mattetti/filebuffer
github.com/mattn/go-colorable
# github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-isatty
# github.com/mattn/go-runewidth v0.0.7
github.com/mattn/go-runewidth
# github.com/mattn/go-sqlite3 v1.11.0
github.com/mattn/go-sqlite3
# github.com/matttproud/golang_protobuf_extensions v1.0.1
......@@ -202,6 +204,8 @@ github.com/modern-go/concurrent
github.com/modern-go/reflect2
# github.com/oklog/run v1.0.0
github.com/oklog/run
# github.com/olekukonko/tablewriter v0.0.4
github.com/olekukonko/tablewriter
# github.com/opentracing/opentracing-go v1.1.0
github.com/opentracing/opentracing-go
github.com/opentracing/opentracing-go/ext
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment