diff options
-rw-r--r-- | Gopkg.lock | 6 | ||||
-rw-r--r-- | Gopkg.toml | 2 | ||||
-rw-r--r-- | bridge/core/auth/credential.go | 30 | ||||
-rw-r--r-- | bridge/core/auth/token.go | 6 | ||||
-rw-r--r-- | bridge/core/bridge.go | 43 | ||||
-rw-r--r-- | bridge/github/config.go | 17 | ||||
-rw-r--r-- | bridge/github/import.go | 4 | ||||
-rw-r--r-- | bridge/github/import_test.go | 3 | ||||
-rw-r--r-- | bridge/gitlab/config.go | 17 | ||||
-rw-r--r-- | bridge/gitlab/import.go | 4 | ||||
-rw-r--r-- | bridge/gitlab/import_test.go | 3 | ||||
-rw-r--r-- | commands/bridge_auth.go | 21 | ||||
-rw-r--r-- | commands/bridge_auth_show.go | 29 | ||||
-rw-r--r-- | commands/bridge_configure.go | 2 | ||||
-rw-r--r-- | commands/bridge_pull.go | 2 | ||||
-rw-r--r-- | commands/user_adopt.go | 12 | ||||
-rw-r--r-- | vendor/github.com/MichaelMure/go-term-text/.travis.yml | 2 | ||||
-rw-r--r-- | vendor/github.com/MichaelMure/go-term-text/Readme.md | 9 | ||||
-rw-r--r-- | vendor/github.com/MichaelMure/go-term-text/escape_state.go | 265 | ||||
-rw-r--r-- | vendor/github.com/MichaelMure/go-term-text/go.mod | 4 | ||||
-rw-r--r-- | vendor/github.com/MichaelMure/go-term-text/go.sum | 4 | ||||
-rw-r--r-- | vendor/github.com/MichaelMure/go-term-text/wrap.go | 149 |
22 files changed, 549 insertions, 85 deletions
@@ -25,12 +25,12 @@ version = "v0.9.2" [[projects]] - digest = "1:b46ef47d5fcc120e6fc1f75e75106f31cbb51fe9981234b5c191d0083d8f9867" + digest = "1:364c89f564ef045872f82ff2f156fd3cb09274e4a3bdbf89aef2c2370c955f95" name = "github.com/MichaelMure/go-term-text" packages = ["."] pruneopts = "UT" - revision = "60f9049b9d18b9370b8ed1247fe4334af5db131a" - version = "v0.2.1" + revision = "6d868251433124ef4ed19c9f8e973ac610d42ef5" + version = "v0.2.4" [[projects]] digest = "1:897d91c431ce469d35a5e6030e60e617dccd9a0e95bdffa6a80594f5c5800d29" @@ -82,7 +82,7 @@ [[constraint]] name = "github.com/MichaelMure/go-term-text" - version = "0.2.1" + version = "0.2.4" [[constraint]] branch = "master" diff --git a/bridge/core/auth/credential.go b/bridge/core/auth/credential.go index a462a116..fd026c5d 100644 --- a/bridge/core/auth/credential.go +++ b/bridge/core/auth/credential.go @@ -32,9 +32,15 @@ func NewErrMultipleMatchCredential(matching []entity.Id) *entity.ErrMultipleMatc return entity.NewErrMultipleMatch("credential", matching) } +// Special Id to mark a credential as being associated to the default user, whoever it might be. +// The intended use is for the bridge configuration, to be able to create and store a credential +// with no identities created yet, and then select one with `git-bug user adopt` +const DefaultUserId = entity.Id("default-user") + type Credential interface { ID() entity.Id UserId() entity.Id + updateUserId(id entity.Id) Target() string Kind() CredentialKind CreateTime() time.Time @@ -42,7 +48,7 @@ type Credential interface { // Return all the specific properties of the credential that need to be saved into the configuration. // This does not include Target, User, Kind and CreateTime. - ToConfig() map[string]string + toConfig() map[string]string } // Load loads a credential from the repo config @@ -90,6 +96,7 @@ func LoadWithPrefix(repo repository.RepoConfig, prefix string) (Credential, erro return matching[0], nil } +// loadFromConfig is a helper to construct a Credential from the set of git configs func loadFromConfig(rawConfigs map[string]string, id entity.Id) (Credential, error) { keyPrefix := fmt.Sprintf("%s.%s.", configKeyPrefix, id) @@ -168,7 +175,7 @@ func PrefixExist(repo repository.RepoConfig, prefix string) bool { // Store stores a credential in the global git config func Store(repo repository.RepoConfig, cred Credential) error { - confs := cred.ToConfig() + confs := cred.toConfig() prefix := fmt.Sprintf("%s.%s.", configKeyPrefix, cred.ID()) @@ -213,6 +220,25 @@ func Remove(repo repository.RepoConfig, id entity.Id) error { return repo.GlobalConfig().RemoveAll(keyPrefix) } +// ReplaceDefaultUser update all the credential attributed to the temporary "default user" +// with a real user Id +func ReplaceDefaultUser(repo repository.RepoConfig, id entity.Id) error { + list, err := List(repo, WithUserId(DefaultUserId)) + if err != nil { + return err + } + + for _, cred := range list { + cred.updateUserId(id) + err = Store(repo, cred) + if err != nil { + return err + } + } + + return nil +} + /* * Sorting */ diff --git a/bridge/core/auth/token.go b/bridge/core/auth/token.go index 12a3bfc0..8333ef12 100644 --- a/bridge/core/auth/token.go +++ b/bridge/core/auth/token.go @@ -59,6 +59,10 @@ func (t *Token) UserId() entity.Id { return t.userId } +func (t *Token) updateUserId(id entity.Id) { + t.userId = id +} + func (t *Token) Target() string { return t.target } @@ -88,7 +92,7 @@ func (t *Token) Validate() error { return nil } -func (t *Token) ToConfig() map[string]string { +func (t *Token) toConfig() map[string]string { return map[string]string{ tokenValueKey: t.Value, } diff --git a/bridge/core/bridge.go b/bridge/core/bridge.go index c6731ff9..1d0a4681 100644 --- a/bridge/core/bridge.go +++ b/bridge/core/bridge.go @@ -43,13 +43,14 @@ type BridgeParams struct { // Bridge is a wrapper around a BridgeImpl that will bind low-level // implementation with utility code to provide high-level functions. type Bridge struct { - Name string - repo *cache.RepoCache - impl BridgeImpl - importer Importer - exporter Exporter - conf Configuration - initDone bool + Name string + repo *cache.RepoCache + impl BridgeImpl + importer Importer + exporter Exporter + conf Configuration + initImportDone bool + initExportDone bool } // Register will register a new BridgeImpl @@ -273,8 +274,25 @@ func (b *Bridge) getExporter() Exporter { return b.exporter } -func (b *Bridge) ensureInit() error { - if b.initDone { +func (b *Bridge) ensureImportInit() error { + if b.initImportDone { + return nil + } + + importer := b.getImporter() + if importer != nil { + err := importer.Init(b.repo, b.conf) + if err != nil { + return err + } + } + + b.initImportDone = true + return nil +} + +func (b *Bridge) ensureExportInit() error { + if b.initExportDone { return nil } @@ -294,8 +312,7 @@ func (b *Bridge) ensureInit() error { } } - b.initDone = true - + b.initExportDone = true return nil } @@ -313,7 +330,7 @@ func (b *Bridge) ImportAllSince(ctx context.Context, since time.Time) (<-chan Im return nil, err } - err = b.ensureInit() + err = b.ensureImportInit() if err != nil { return nil, err } @@ -367,7 +384,7 @@ func (b *Bridge) ExportAll(ctx context.Context, since time.Time) (<-chan ExportR return nil, err } - err = b.ensureInit() + err = b.ensureExportInit() if err != nil { return nil, err } diff --git a/bridge/github/config.go b/bridge/github/config.go index bc26a2fc..ea4b622f 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -25,6 +25,7 @@ import ( "github.com/MichaelMure/git-bug/bridge/core/auth" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/colors" "github.com/MichaelMure/git-bug/util/interrupt" @@ -89,10 +90,16 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor } user, err := repo.GetUserIdentity() - if err != nil { + if err != nil && err != identity.ErrNoIdentitySet { return nil, err } + // default to a "to be filled" user Id if we don't have a valid one yet + userId := auth.DefaultUserId + if user != nil { + userId = user.Id() + } + var cred auth.Credential switch { @@ -101,13 +108,13 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor if err != nil { return nil, err } - if cred.UserId() != user.Id() { + if user != nil && cred.UserId() != user.Id() { return nil, fmt.Errorf("selected credential don't match the user") } case params.TokenRaw != "": - cred = auth.NewToken(user.Id(), params.TokenRaw, target) + cred = auth.NewToken(userId, params.TokenRaw, target) default: - cred, err = promptTokenOptions(repo, user.Id(), owner, project) + cred, err = promptTokenOptions(repo, userId, owner, project) if err != nil { return nil, err } @@ -326,7 +333,7 @@ func promptToken() (string, error) { return token, nil } - fmt.Println("token is invalid") + fmt.Println("token has incorrect format") } } diff --git a/bridge/github/import.go b/bridge/github/import.go index 092e3e71..dfc851fd 100644 --- a/bridge/github/import.go +++ b/bridge/github/import.go @@ -12,6 +12,7 @@ import ( "github.com/MichaelMure/git-bug/bug" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/text" ) @@ -47,6 +48,9 @@ func (gi *githubImporter) Init(repo *cache.RepoCache, conf core.Configuration) e if err == nil { opts = append(opts, auth.WithUserId(user.Id())) } + if err == identity.ErrNoIdentitySet { + opts = append(opts, auth.WithUserId(auth.DefaultUserId)) + } creds, err := auth.List(repo, opts...) if err != nil { diff --git a/bridge/github/import_test.go b/bridge/github/import_test.go index 304229a0..57bab61e 100644 --- a/bridge/github/import_test.go +++ b/bridge/github/import_test.go @@ -143,6 +143,9 @@ func Test_Importer(t *testing.T) { err = author.Commit(repo) require.NoError(t, err) + err = identity.SetUserIdentity(repo, author) + require.NoError(t, err) + token := auth.NewToken(author.Id(), envToken, target) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/gitlab/config.go b/bridge/gitlab/config.go index ce066766..1f542d39 100644 --- a/bridge/gitlab/config.go +++ b/bridge/gitlab/config.go @@ -19,6 +19,7 @@ import ( "github.com/MichaelMure/git-bug/bridge/core/auth" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/colors" ) @@ -73,10 +74,16 @@ func (g *Gitlab) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor } user, err := repo.GetUserIdentity() - if err != nil { + if err != nil && err != identity.ErrNoIdentitySet { return nil, err } + // default to a "to be filled" user Id if we don't have a valid one yet + userId := auth.DefaultUserId + if user != nil { + userId = user.Id() + } + var cred auth.Credential switch { @@ -85,13 +92,13 @@ func (g *Gitlab) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor if err != nil { return nil, err } - if cred.UserId() != user.Id() { + if user != nil && cred.UserId() != user.Id() { return nil, fmt.Errorf("selected credential don't match the user") } case params.TokenRaw != "": - cred = auth.NewToken(user.Id(), params.TokenRaw, target) + cred = auth.NewToken(userId, params.TokenRaw, target) default: - cred, err = promptTokenOptions(repo, user.Id()) + cred, err = promptTokenOptions(repo, userId) if err != nil { return nil, err } @@ -289,7 +296,7 @@ func promptToken() (string, error) { return token, nil } - fmt.Println("token format is invalid") + fmt.Println("token has incorrect format") } } diff --git a/bridge/gitlab/import.go b/bridge/gitlab/import.go index 4fa37505..fa6bbfb6 100644 --- a/bridge/gitlab/import.go +++ b/bridge/gitlab/import.go @@ -13,6 +13,7 @@ import ( "github.com/MichaelMure/git-bug/bug" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/text" ) @@ -42,6 +43,9 @@ func (gi *gitlabImporter) Init(repo *cache.RepoCache, conf core.Configuration) e if err == nil { opts = append(opts, auth.WithUserId(user.Id())) } + if err == identity.ErrNoIdentitySet { + opts = append(opts, auth.WithUserId(auth.DefaultUserId)) + } creds, err := auth.List(repo, opts...) if err != nil { diff --git a/bridge/gitlab/import_test.go b/bridge/gitlab/import_test.go index 6e378b07..1e2f5d50 100644 --- a/bridge/gitlab/import_test.go +++ b/bridge/gitlab/import_test.go @@ -97,6 +97,9 @@ func TestImport(t *testing.T) { err = author.Commit(repo) require.NoError(t, err) + err = identity.SetUserIdentity(repo, author) + require.NoError(t, err) + token := auth.NewToken(author.Id(), envToken, target) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/commands/bridge_auth.go b/commands/bridge_auth.go index 4e8b50c4..bfbab33c 100644 --- a/commands/bridge_auth.go +++ b/commands/bridge_auth.go @@ -37,14 +37,21 @@ func runBridgeAuth(cmd *cobra.Command, args []string) error { value = cred.Value } - user, err := backend.ResolveIdentity(cred.UserId()) - if err != nil { - return err - } - userFmt := user.DisplayName() + var userFmt string + + switch cred.UserId() { + case auth.DefaultUserId: + userFmt = colors.Red("default user") + default: + user, err := backend.ResolveIdentity(cred.UserId()) + if err != nil { + return err + } + userFmt = user.DisplayName() - if cred.UserId() == defaultUser.Id() { - userFmt = colors.Red(userFmt) + if cred.UserId() == defaultUser.Id() { + userFmt = colors.Red(userFmt) + } } fmt.Printf("%s %s %s %s %s\n", diff --git a/commands/bridge_auth_show.go b/commands/bridge_auth_show.go index 5352957d..02c56806 100644 --- a/commands/bridge_auth_show.go +++ b/commands/bridge_auth_show.go @@ -7,17 +7,46 @@ import ( "github.com/spf13/cobra" "github.com/MichaelMure/git-bug/bridge/core/auth" + "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/util/colors" + "github.com/MichaelMure/git-bug/util/interrupt" ) func runBridgeAuthShow(cmd *cobra.Command, args []string) error { + backend, err := cache.NewRepoCache(repo) + if err != nil { + return err + } + defer backend.Close() + interrupt.RegisterCleaner(backend.Close) + cred, err := auth.LoadWithPrefix(repo, args[0]) if err != nil { return err } + var userFmt string + + switch cred.UserId() { + case auth.DefaultUserId: + userFmt = colors.Red("default user") + default: + user, err := backend.ResolveIdentity(cred.UserId()) + if err != nil { + return err + } + userFmt = user.DisplayName() + + defaultUser, _ := backend.GetUserIdentity() + if cred.UserId() == defaultUser.Id() { + userFmt = colors.Red(userFmt) + } + } + fmt.Printf("Id: %s\n", cred.ID()) fmt.Printf("Target: %s\n", cred.Target()) fmt.Printf("Kind: %s\n", cred.Kind()) + fmt.Printf("User: %s\n", userFmt) fmt.Printf("Creation: %s\n", cred.CreateTime().Format(time.RFC822)) switch cred := cred.(type) { diff --git a/commands/bridge_configure.go b/commands/bridge_configure.go index 26bd7bc2..0e29d06a 100644 --- a/commands/bridge_configure.go +++ b/commands/bridge_configure.go @@ -206,7 +206,7 @@ git bug bridge configure \ --target=github \ --url=https://github.com/michaelmure/git-bug \ --token=$(TOKEN)`, - PreRunE: loadRepoEnsureUser, + PreRunE: loadRepo, RunE: runBridgeConfigure, } diff --git a/commands/bridge_pull.go b/commands/bridge_pull.go index 692ec5e9..2dd3d93e 100644 --- a/commands/bridge_pull.go +++ b/commands/bridge_pull.go @@ -138,7 +138,7 @@ func parseSince(since string) (time.Time, error) { var bridgePullCmd = &cobra.Command{ Use: "pull [<name>]", Short: "Pull updates.", - PreRunE: loadRepoEnsureUser, + PreRunE: loadRepo, RunE: runBridgePull, Args: cobra.MaximumNArgs(1), } diff --git a/commands/user_adopt.go b/commands/user_adopt.go index d84d4048..a7de54d9 100644 --- a/commands/user_adopt.go +++ b/commands/user_adopt.go @@ -4,7 +4,9 @@ import ( "fmt" "os" + "github.com/MichaelMure/git-bug/bridge/core/auth" "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/interrupt" "github.com/spf13/cobra" ) @@ -24,6 +26,16 @@ func runUserAdopt(cmd *cobra.Command, args []string) error { return err } + _, err = backend.GetUserIdentity() + if err == identity.ErrNoIdentitySet { + err = auth.ReplaceDefaultUser(repo, i.Id()) + if err != nil { + return err + } + } else if err != nil { + return err + } + err = backend.SetUserIdentity(i) if err != nil { return err diff --git a/vendor/github.com/MichaelMure/go-term-text/.travis.yml b/vendor/github.com/MichaelMure/go-term-text/.travis.yml index 496ca056..c5db9518 100644 --- a/vendor/github.com/MichaelMure/go-term-text/.travis.yml +++ b/vendor/github.com/MichaelMure/go-term-text/.travis.yml @@ -1,9 +1,9 @@ language: go go: - - 1.10.x - 1.11.x - 1.12.x + - 1.13.x env: - GO111MODULE=on diff --git a/vendor/github.com/MichaelMure/go-term-text/Readme.md b/vendor/github.com/MichaelMure/go-term-text/Readme.md index 457b4472..25722ee9 100644 --- a/vendor/github.com/MichaelMure/go-term-text/Readme.md +++ b/vendor/github.com/MichaelMure/go-term-text/Readme.md @@ -20,6 +20,7 @@ Included algorithms cover: - trimming - alignment - escape sequence extraction and reapplication +- escape sequence snapshot and simplification - truncation ## Example @@ -31,7 +32,7 @@ import ( "fmt" "strings" - text "github.com/MichaelMure/go-term-text" + "github.com/MichaelMure/go-term-text" ) func main() { @@ -41,8 +42,10 @@ func main() { "various graphic design. 一只 A Quick \x1b[31m敏捷的狐 Fox " + "狸跳过了\x1b[0mDog一只懒狗。" - output, n := text.WrapWithPadIndent(input, 60, - "\x1b[34m<-indent-> \x1b[0m", "\x1b[33m<-pad-> \x1b[0m") + output, n := text.Wrap(input, 60, + text.WrapIndent("\x1b[34m<-indent-> \x1b[0m"), + text.WrapPad("\x1b[33m<-pad-> \x1b[0m"), + ) fmt.Printf("output has %d lines\n\n", n) diff --git a/vendor/github.com/MichaelMure/go-term-text/escape_state.go b/vendor/github.com/MichaelMure/go-term-text/escape_state.go new file mode 100644 index 00000000..cec35c26 --- /dev/null +++ b/vendor/github.com/MichaelMure/go-term-text/escape_state.go @@ -0,0 +1,265 @@ +package text + +import ( + "fmt" + "strconv" + "strings" +) + +const Escape = '\x1b' + +type EscapeState struct { + Bold bool + Dim bool + Italic bool + Underlined bool + Blink bool + Reverse bool + Hidden bool + CrossedOut bool + + FgColor Color + BgColor Color +} + +type Color interface { + Codes() []string +} + +func (es *EscapeState) Witness(s string) { + inEscape := false + var start int + + runes := []rune(s) + + for i, r := range runes { + if r == Escape { + inEscape = true + start = i + continue + } + if inEscape { + if r == 'm' { + inEscape = false + es.witnessCode(string(runes[start+1 : i])) + } + continue + } + } +} + +func (es *EscapeState) witnessCode(s string) { + if s == "" { + return + } + if s == "[" { + es.reset() + return + } + if len(s) < 2 { + return + } + if s[0] != '[' { + return + } + + s = s[1:] + split := strings.Split(s, ";") + + dequeue := func() { + split = split[1:] + } + + color := func(ground int) Color { + if len(split) < 1 { + // the whole sequence is broken, ignoring the rest + return nil + } + + subCode := split[0] + dequeue() + + switch subCode { + case "2": + if len(split) < 3 { + return nil + } + r, err := strconv.Atoi(split[0]) + dequeue() + if err != nil { + return nil + } + g, err := strconv.Atoi(split[0]) + dequeue() + if err != nil { + return nil + } + b, err := strconv.Atoi(split[0]) + dequeue() + if err != nil { + return nil + } + return &ColorRGB{ground: ground, R: r, G: g, B: b} + + case "5": + if len(split) < 1 { + return nil + } + index, err := strconv.Atoi(split[0]) + dequeue() + if err != nil { + return nil + } + return &Color256{ground: ground, Index: index} + + } + return nil + } + + for len(split) > 0 { + code, err := strconv.Atoi(split[0]) + if err != nil { + return + } + dequeue() + + switch { + case code == 0: + es.reset() + + case code == 1: + es.Bold = true + case code == 2: + es.Dim = true + case code == 3: + es.Italic = true + case code == 4: + es.Underlined = true + case code == 5: + es.Blink = true + // case code == 6: + case code == 7: + es.Reverse = true + case code == 8: + es.Hidden = true + case code == 9: + es.CrossedOut = true + + case code == 21: + es.Bold = false + case code == 22: + es.Dim = false + case code == 23: + es.Italic = false + case code == 24: + es.Underlined = false + case code == 25: + es.Blink = false + // case code == 26: + case code == 27: + es.Reverse = false + case code == 28: + es.Hidden = false + case code == 29: + es.CrossedOut = false + + case (code >= 30 && code <= 37) || code == 39 || (code >= 90 && code <= 97): + es.FgColor = ColorIndex(code) + + case (code >= 40 && code <= 47) || code == 49 || (code >= 100 && code <= 107): + es.BgColor = ColorIndex(code) + + case code == 38: + es.FgColor = color(code) + if es.FgColor == nil { + return + } + + case code == 48: + es.BgColor = color(code) + if es.BgColor == nil { + return + } + } + } +} + +func (es *EscapeState) reset() { + *es = EscapeState{} +} + +func (es *EscapeState) String() string { + var codes []string + + if es.Bold { + codes = append(codes, strconv.Itoa(1)) + } + if es.Dim { + codes = append(codes, strconv.Itoa(2)) + } + if es.Italic { + codes = append(codes, strconv.Itoa(3)) + } + if es.Underlined { + codes = append(codes, strconv.Itoa(4)) + } + if es.Blink { + codes = append(codes, strconv.Itoa(5)) + } + if es.Reverse { + codes = append(codes, strconv.Itoa(7)) + } + if es.Hidden { + codes = append(codes, strconv.Itoa(8)) + } + if es.CrossedOut { + codes = append(codes, strconv.Itoa(9)) + } + + if es.FgColor != nil { + codes = append(codes, es.FgColor.Codes()...) + } + if es.BgColor != nil { + codes = append(codes, es.BgColor.Codes()...) + } + + if len(codes) == 0 { + return "\x1b[0m" + } + + return fmt.Sprintf("\x1b[%sm", strings.Join(codes, ";")) +} + +type ColorIndex int + +func (cInd ColorIndex) Codes() []string { + return []string{strconv.Itoa(int(cInd))} +} + +type Color256 struct { + ground int + Index int +} + +func (c256 Color256) Codes() []string { + return []string{ + strconv.Itoa(c256.ground), + "5", + strconv.Itoa(c256.Index), + } +} + +type ColorRGB struct { + ground int + R, G, B int +} + +func (cRGB ColorRGB) Codes() []string { + return []string{ + strconv.Itoa(cRGB.ground), + "2", + strconv.Itoa(cRGB.R), + strconv.Itoa(cRGB.G), + strconv.Itoa(cRGB.B), + } +} diff --git a/vendor/github.com/MichaelMure/go-term-text/go.mod b/vendor/github.com/MichaelMure/go-term-text/go.mod index 162c5dac..a03c8606 100644 --- a/vendor/github.com/MichaelMure/go-term-text/go.mod +++ b/vendor/github.com/MichaelMure/go-term-text/go.mod @@ -1,8 +1,8 @@ module github.com/MichaelMure/go-term-text -go 1.10 +go 1.11 require ( - github.com/mattn/go-runewidth v0.0.4 + github.com/mattn/go-runewidth v0.0.6 github.com/stretchr/testify v1.3.0 ) diff --git a/vendor/github.com/MichaelMure/go-term-text/go.sum b/vendor/github.com/MichaelMure/go-term-text/go.sum index 0aaedf16..a119b457 100644 --- a/vendor/github.com/MichaelMure/go-term-text/go.sum +++ b/vendor/github.com/MichaelMure/go-term-text/go.sum @@ -1,7 +1,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/vendor/github.com/MichaelMure/go-term-text/wrap.go b/vendor/github.com/MichaelMure/go-term-text/wrap.go index 2fd6ed5f..eba9e0b8 100644 --- a/vendor/github.com/MichaelMure/go-term-text/wrap.go +++ b/vendor/github.com/MichaelMure/go-term-text/wrap.go @@ -13,52 +13,89 @@ func init() { runewidth.DefaultCondition.EastAsianWidth = false } -// Wrap a text for a given line size. -// Handle properly terminal color escape code -func Wrap(text string, lineWidth int) (string, int) { - return WrapLeftPadded(text, lineWidth, 0) +type wrapOpts struct { + indent string + pad string + align Alignment } -// WrapLeftPadded wrap a text for a given line size with a left padding. -// Handle properly terminal color escape code -func WrapLeftPadded(text string, lineWidth int, leftPad int) (string, int) { - pad := strings.Repeat(" ", leftPad) - return WrapWithPad(text, lineWidth, pad) +// WrapOption is a functional option for the Wrap() function +type WrapOption func(opts *wrapOpts) + +// WrapPad configure the padding with a string for Wrap() +func WrapPad(pad string) WrapOption { + return func(opts *wrapOpts) { + opts.pad = pad + } } -// WrapWithPad wrap a text for a given line size with a custom left padding -// Handle properly terminal color escape code -func WrapWithPad(text string, lineWidth int, pad string) (string, int) { - return WrapWithPadIndent(text, lineWidth, pad, pad) +// WrapPadded configure the padding with a number of space characters for Wrap() +func WrapPadded(padLen int) WrapOption { + return func(opts *wrapOpts) { + opts.pad = strings.Repeat(" ", padLen) + } } -// WrapWithPad wrap a text for a given line size with a custom left padding -// This function also align the result depending on the requested alignment. -// Handle properly terminal color escape code -func WrapWithPadAlign(text string, lineWidth int, pad string, align Alignment) (string, int) { - return WrapWithPadIndentAlign(text, lineWidth, pad, pad, align) +// WrapPad configure the indentation on the first line for Wrap() +func WrapIndent(indent string) WrapOption { + return func(opts *wrapOpts) { + opts.indent = indent + } } -// WrapWithPadIndent wrap a text for a given line size with a custom left padding -// and a first line indent. The padding is not effective on the first line, indent -// is used instead, which allow to implement indents and outdents. -// Handle properly terminal color escape code -func WrapWithPadIndent(text string, lineWidth int, indent string, pad string) (string, int) { - return WrapWithPadIndentAlign(text, lineWidth, indent, pad, NoAlign) +// WrapAlign configure the text alignment for Wrap() +func WrapAlign(align Alignment) WrapOption { + return func(opts *wrapOpts) { + opts.align = align + } } -// WrapWithPadIndentAlign wrap a text for a given line size with a custom left padding -// and a first line indent. The padding is not effective on the first line, indent -// is used instead, which allow to implement indents and outdents. -// This function also align the result depending on the requested alignment. +// allWrapOpts compile the set of WrapOption into a final wrapOpts +// from the default values. +func allWrapOpts(opts []WrapOption) *wrapOpts { + wrapOpts := &wrapOpts{ + indent: "", + pad: "", + align: NoAlign, + } + for _, opt := range opts { + opt(wrapOpts) + } + if wrapOpts.indent == "" { + wrapOpts.indent = wrapOpts.pad + } + return wrapOpts +} + +// Wrap a text for a given line size. // Handle properly terminal color escape code -func WrapWithPadIndentAlign(text string, lineWidth int, indent string, pad string, align Alignment) (string, int) { +// Options are accepted to configure things like indent, padding or alignment. +// Return the wrapped text and the number of lines +func Wrap(text string, lineWidth int, opts ...WrapOption) (string, int) { + wrapOpts := allWrapOpts(opts) + + if lineWidth <= 0 { + return "", 1 + } + var lines []string nbLine := 0 + if len(wrapOpts.indent) >= lineWidth { + // fallback rendering + lines = append(lines, strings.Repeat("⭬", lineWidth)) + nbLine++ + wrapOpts.indent = wrapOpts.pad + } + if len(wrapOpts.pad) >= lineWidth { + // fallback rendering + line := strings.Repeat("⭬", lineWidth) + return strings.Repeat(line+"\n", 5), 5 + } + // Start with the indent - padStr := indent - padLen := Len(indent) + padStr := wrapOpts.indent + padLen := Len(wrapOpts.indent) // tabs are formatted as 4 spaces text = strings.Replace(text, "\t", " ", -1) @@ -67,8 +104,8 @@ func WrapWithPadIndentAlign(text string, lineWidth int, indent string, pad strin for i, line := range strings.Split(text, "\n") { // on the second line, use the padding instead if i == 1 { - padStr = pad - padLen = Len(pad) + padStr = wrapOpts.pad + padLen = Len(wrapOpts.pad) } if line == "" || strings.TrimSpace(line) == "" { @@ -87,14 +124,14 @@ func WrapWithPadIndentAlign(text string, lineWidth int, indent string, pad strin // use the first wrapped line, ignore everything else and // wrap the remaining of the line with the normal padding. - content := LineAlign(strings.TrimRight(split[0], " "), lineWidth-padLen, align) + content := LineAlign(strings.TrimRight(split[0], " "), lineWidth-padLen, wrapOpts.align) lines = append(lines, padStr+content) nbLine++ line = strings.TrimPrefix(line, split[0]) line = strings.TrimLeft(line, " ") - padStr = pad - padLen = Len(pad) + padStr = wrapOpts.pad + padLen = Len(wrapOpts.pad) wrapped = softwrapLine(line, lineWidth-padLen) split = strings.Split(wrapped, "\n") } @@ -102,10 +139,10 @@ func WrapWithPadIndentAlign(text string, lineWidth int, indent string, pad strin for j, seg := range split { if j == 0 { // keep the left padding of the wrapped line - content := LineAlign(strings.TrimRight(seg, " "), lineWidth-padLen, align) + content := LineAlign(strings.TrimRight(seg, " "), lineWidth-padLen, wrapOpts.align) lines = append(lines, padStr+content) } else { - content := LineAlign(strings.TrimSpace(seg), lineWidth-padLen, align) + content := LineAlign(strings.TrimSpace(seg), lineWidth-padLen, wrapOpts.align) lines = append(lines, padStr+content) } nbLine++ @@ -115,6 +152,42 @@ func WrapWithPadIndentAlign(text string, lineWidth int, indent string, pad strin return strings.Join(lines, "\n"), nbLine } +// WrapLeftPadded wrap a text for a given line size with a left padding. +// Handle properly terminal color escape code +func WrapLeftPadded(text string, lineWidth int, leftPad int) (string, int) { + return Wrap(text, lineWidth, WrapPadded(leftPad)) +} + +// WrapWithPad wrap a text for a given line size with a custom left padding +// Handle properly terminal color escape code +func WrapWithPad(text string, lineWidth int, pad string) (string, int) { + return Wrap(text, lineWidth, WrapPad(pad)) +} + +// WrapWithPad wrap a text for a given line size with a custom left padding +// This function also align the result depending on the requested alignment. +// Handle properly terminal color escape code +func WrapWithPadAlign(text string, lineWidth int, pad string, align Alignment) (string, int) { + return Wrap(text, lineWidth, WrapPad(pad), WrapAlign(align)) +} + +// WrapWithPadIndent wrap a text for a given line size with a custom left padding +// and a first line indent. The padding is not effective on the first line, indent +// is used instead, which allow to implement indents and outdents. +// Handle properly terminal color escape code +func WrapWithPadIndent(text string, lineWidth int, indent string, pad string) (string, int) { + return Wrap(text, lineWidth, WrapIndent(indent), WrapPad(pad)) +} + +// WrapWithPadIndentAlign wrap a text for a given line size with a custom left padding +// and a first line indent. The padding is not effective on the first line, indent +// is used instead, which allow to implement indents and outdents. +// This function also align the result depending on the requested alignment. +// Handle properly terminal color escape code +func WrapWithPadIndentAlign(text string, lineWidth int, indent string, pad string, align Alignment) (string, int) { + return Wrap(text, lineWidth, WrapIndent(indent), WrapPad(pad), WrapAlign(align)) +} + // Break a line into several lines so that each line consumes at most // 'textWidth' cells. Lines break at groups of white spaces and multibyte // chars. Nothing is removed from the original text so that it behaves like a |