1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

CmdRunner now displays ANSI color codes

This commit is contained in:
Chris Cummer 2018-07-18 16:16:28 -07:00
parent 31e77a59ad
commit 6e6d918bfe
25 changed files with 813 additions and 100 deletions

24
Gopkg.lock generated
View File

@ -4,8 +4,8 @@
[[projects]]
name = "cloud.google.com/go"
packages = ["compute/metadata"]
revision = "777200caa7fb8936aed0f12b1fd79af64cc83ec9"
version = "v0.24.0"
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
version = "v0.25.0"
[[projects]]
branch = "master"
@ -62,7 +62,7 @@
branch = "master"
name = "github.com/google/go-github"
packages = ["github"]
revision = "60f2773bd99aa86164bc80bf370be6ba63b47dea"
revision = "c0b63e2f9bb198baf328c8abf1ddcbe05ff9427e"
[[projects]]
branch = "master"
@ -100,6 +100,12 @@
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/pkg/profile"
packages = ["."]
revision = "5b67d428864e92711fcbd2f8629456121a56d91f"
version = "v1.2.1"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
@ -116,7 +122,7 @@
branch = "master"
name = "github.com/rivo/tview"
packages = ["."]
revision = "83483397e826c343edb7b8c1f33fb7983dda9fc5"
revision = "c33dd0cf8ef840e1c8905c838d5b1ce93050a825"
[[projects]]
name = "github.com/stretchr/testify"
@ -125,10 +131,10 @@
version = "v1.2.2"
[[projects]]
branch = "master"
name = "github.com/xanzy/go-gitlab"
packages = ["."]
revision = "79dad8e74fd097eb2e0fd0883f1978213e88107a"
version = "v0.10.7"
revision = "fb3ece09ef3e80cfa5c1e52dc75fcfb56c12e026"
[[projects]]
branch = "master"
@ -143,7 +149,7 @@
"context",
"context/ctxhttp"
]
revision = "039a4258aec0ad3c79b905677cceeab13b296a77"
revision = "8887df42c721e930089d31b28391090a10a497d7"
[[projects]]
branch = "master"
@ -179,7 +185,7 @@
"googleapi/internal/uritemplates",
"sheets/v4"
]
revision = "1d2d9cc0ae74226e8076e2a87e211c8fea38a160"
revision = "efcb5f25ac56eae06c8b5672456c0b7767522685"
[[projects]]
name = "google.golang.org/appengine"
@ -207,6 +213,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "9eaa70ed639c832e3cde26a4270f4c7b9124960952aa76506f702c2c296d5019"
inputs-digest = "8da356b338a76c5de5dce08eb73d808f139685850a2ef9ac3a9962197e36313f"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -5,6 +5,7 @@ import (
"os/exec"
"strings"
"github.com/rivo/tview"
"github.com/senorprogrammer/wtf/wtf"
)
@ -33,7 +34,7 @@ func (widget *Widget) Refresh() {
widget.UpdateRefreshedAt()
widget.execute()
title := wtf.Config.UString("wtf.mods.cmdrunner.title", widget.String())
title := tview.TranslateANSI(wtf.Config.UString("wtf.mods.cmdrunner.title", widget.String()))
widget.View.SetTitle(title)
widget.View.SetText(widget.result)
@ -46,5 +47,5 @@ func (widget *Widget) String() string {
func (widget *Widget) execute() {
cmd := exec.Command(widget.cmd, widget.args...)
widget.result = wtf.ExecuteCommand(cmd)
widget.result = tview.TranslateANSI(wtf.ExecuteCommand(cmd))
}

View File

@ -57,6 +57,8 @@ type Installation struct {
RepositorySelection *string `json:"repository_selection,omitempty"`
Events []string `json:"events,omitempty"`
Permissions *InstallationPermissions `json:"permissions,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
func (i Installation) String() string {

View File

@ -2828,6 +2828,14 @@ func (i *Installation) GetAppID() int64 {
return *i.AppID
}
// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
func (i *Installation) GetCreatedAt() time.Time {
if i == nil || i.CreatedAt == nil {
return time.Time{}
}
return *i.CreatedAt
}
// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
func (i *Installation) GetHTMLURL() string {
if i == nil || i.HTMLURL == nil {
@ -2892,6 +2900,14 @@ func (i *Installation) GetTargetType() string {
return *i.TargetType
}
// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
func (i *Installation) GetUpdatedAt() time.Time {
if i == nil || i.UpdatedAt == nil {
return time.Time{}
}
return *i.UpdatedAt
}
// GetAction returns the Action field if it's non-nil, zero value otherwise.
func (i *InstallationEvent) GetAction() string {
if i == nil || i.Action == nil {

View File

@ -45,9 +45,6 @@ const (
// Media Type values to access preview APIs
// https://developer.github.com/changes/2015-03-09-licenses-api/
mediaTypeLicensesPreview = "application/vnd.github.drax-preview+json"
// https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/
mediaTypeStarringPreview = "application/vnd.github.v3.star+json"

View File

@ -67,9 +67,6 @@ func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, erro
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
var licenses []*License
resp, err := s.client.Do(ctx, req, &licenses)
if err != nil {
@ -90,9 +87,6 @@ func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
license := new(License)
resp, err := s.client.Do(ctx, req, license)
if err != nil {

View File

@ -14,7 +14,7 @@ import (
// PullRequestComment represents a comment left on a pull request.
type PullRequestComment struct {
ID *int64 `json:"id,omitempty"`
InReplyTo *int64 `json:"in_reply_to,omitempty"`
InReplyTo *int64 `json:"in_reply_to_id,omitempty"`
Body *string `json:"body,omitempty"`
Path *string `json:"path,omitempty"`
DiffHunk *string `json:"diff_hunk,omitempty"`
@ -129,6 +129,32 @@ func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, r
return c, resp, nil
}
// CreateCommentInReplyTo creates a new comment as a reply to an existing pull request comment.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#alternative-input
func (s *PullRequestsService) CreateCommentInReplyTo(ctx context.Context, owner string, repo string, number int, body string, commentID int64) (*PullRequestComment, *Response, error) {
comment := &struct {
Body string `json:"body,omitempty"`
InReplyTo int64 `json:"in_reply_to,omitempty"`
}{
Body: body,
InReplyTo: commentID,
}
u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number)
req, err := s.client.NewRequest("POST", u, comment)
if err != nil {
return nil, nil, err
}
c := new(PullRequestComment)
resp, err := s.client.Do(ctx, req, c)
if err != nil {
return nil, resp, err
}
return c, resp, nil
}
// EditComment updates a pull request comment.
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
//

View File

@ -178,7 +178,7 @@ func (s *RepositoriesService) List(ctx context.Context, user string, opt *Reposi
}
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*Repository
@ -216,7 +216,7 @@ func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *Re
}
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*Repository
@ -297,7 +297,7 @@ func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Rep
// TODO: remove custom Accept header when the license support fully launches
// https://developer.github.com/v3/licenses/#get-a-repositorys-license
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
repository := new(Repository)
@ -341,10 +341,6 @@ func (s *RepositoriesService) GetByID(ctx context.Context, id int64) (*Repositor
return nil, nil, err
}
// TODO: remove custom Accept header when the license support fully launches
// https://developer.github.com/v3/licenses/#get-a-repositorys-license
req.Header.Set("Accept", mediaTypeLicensesPreview)
repository := new(Repository)
resp, err := s.client.Do(ctx, req, repository)
if err != nil {
@ -1018,7 +1014,7 @@ func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo
// TransferRequest represents a request to transfer a repository.
type TransferRequest struct {
NewOwner string `json:"new_owner"`
TeamID []int64 `json:"team_id,omitempty"`
TeamID []int64 `json:"team_ids,omitempty"`
}
// Transfer transfers a repository from one account or organization to another.

View File

@ -136,9 +136,13 @@ func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, i
if err != nil {
return nil, nil, err
}
hook := new(Hook)
resp, err := s.client.Do(ctx, req, hook)
return hook, resp, err
h := new(Hook)
resp, err := s.client.Do(ctx, req, h)
if err != nil {
return nil, resp, err
}
return h, resp, nil
}
// EditHook updates a specified Hook.
@ -152,7 +156,11 @@ func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string,
}
h := new(Hook)
resp, err := s.client.Do(ctx, req, h)
return h, resp, err
if err != nil {
return nil, resp, err
}
return h, resp, nil
}
// DeleteHook deletes a specified Hook.

11
vendor/github.com/pkg/profile/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,11 @@
language: go
go_import_path: github.com/pkg/profile
go:
- 1.4.3
- 1.5.2
- 1.6.3
- tip
script:
- go test github.com/pkg/profile
- go test -race github.com/pkg/profile

1
vendor/github.com/pkg/profile/AUTHORS generated vendored Normal file
View File

@ -0,0 +1 @@
Dave Cheney <dave@cheney.net>

24
vendor/github.com/pkg/profile/LICENSE generated vendored Normal file
View File

@ -0,0 +1,24 @@
Copyright (c) 2013 Dave Cheney. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

54
vendor/github.com/pkg/profile/README.md generated vendored Normal file
View File

@ -0,0 +1,54 @@
profile
=======
Simple profiling support package for Go
[![Build Status](https://travis-ci.org/pkg/profile.svg?branch=master)](https://travis-ci.org/pkg/profile) [![GoDoc](http://godoc.org/github.com/pkg/profile?status.svg)](http://godoc.org/github.com/pkg/profile)
installation
------------
go get github.com/pkg/profile
usage
-----
Enabling profiling in your application is as simple as one line at the top of your main function
```go
import "github.com/pkg/profile"
func main() {
defer profile.Start().Stop()
...
}
```
options
-------
What to profile is controlled by config value passed to profile.Start.
By default CPU profiling is enabled.
```go
import "github.com/pkg/profile"
func main() {
// p.Stop() must be called before the program exits to
// ensure profiling information is written to disk.
p := profile.Start(profile.MemProfile, profile.ProfilePath("."), profile.NoShutdownHook)
...
}
```
Several convenience package level values are provided for cpu, memory, and block (contention) profiling.
For more complex options, consult the [documentation](http://godoc.org/github.com/pkg/profile).
contributing
------------
We welcome pull requests, bug fixes and issue reports.
Before proposing a change, please discuss it first by raising an issue.

13
vendor/github.com/pkg/profile/mutex.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// +build go1.8
package profile
import "runtime"
func enableMutexProfile() {
runtime.SetMutexProfileFraction(1)
}
func disableMutexProfile() {
runtime.SetMutexProfileFraction(0)
}

9
vendor/github.com/pkg/profile/mutex17.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// +build !go1.8
package profile
// mock mutex support for Go 1.7 and earlier.
func enableMutexProfile() {}
func disableMutexProfile() {}

244
vendor/github.com/pkg/profile/profile.go generated vendored Normal file
View File

@ -0,0 +1,244 @@
// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile
import (
"io/ioutil"
"log"
"os"
"os/signal"
"path/filepath"
"runtime"
"runtime/pprof"
"sync/atomic"
)
const (
cpuMode = iota
memMode
mutexMode
blockMode
traceMode
)
// Profile represents an active profiling session.
type Profile struct {
// quiet suppresses informational messages during profiling.
quiet bool
// noShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
noShutdownHook bool
// mode holds the type of profiling that will be made
mode int
// path holds the base path where various profiling files are written.
// If blank, the base path will be generated by ioutil.TempDir.
path string
// memProfileRate holds the rate for the memory profile.
memProfileRate int
// closer holds a cleanup function that run after each profile
closer func()
// stopped records if a call to profile.Stop has been made
stopped uint32
}
// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *Profile) { p.noShutdownHook = true }
// Quiet suppresses informational messages during profiling.
func Quiet(p *Profile) { p.quiet = true }
// CPUProfile enables cpu profiling.
// It disables any previous profiling settings.
func CPUProfile(p *Profile) { p.mode = cpuMode }
// DefaultMemProfileRate is the default memory profiling rate.
// See also http://golang.org/pkg/runtime/#pkg-variables
const DefaultMemProfileRate = 4096
// MemProfile enables memory profiling.
// It disables any previous profiling settings.
func MemProfile(p *Profile) {
p.memProfileRate = DefaultMemProfileRate
p.mode = memMode
}
// MemProfileRate enables memory profiling at the preferred rate.
// It disables any previous profiling settings.
func MemProfileRate(rate int) func(*Profile) {
return func(p *Profile) {
p.memProfileRate = rate
p.mode = memMode
}
}
// MutexProfile enables mutex profiling.
// It disables any previous profiling settings.
//
// Mutex profiling is a no-op before go1.8.
func MutexProfile(p *Profile) { p.mode = mutexMode }
// BlockProfile enables block (contention) profiling.
// It disables any previous profiling settings.
func BlockProfile(p *Profile) { p.mode = blockMode }
// Trace profile controls if execution tracing will be enabled. It disables any previous profiling settings.
func TraceProfile(p *Profile) { p.mode = traceMode }
// ProfilePath controls the base path where various profiling
// files are written. If blank, the base path will be generated
// by ioutil.TempDir.
func ProfilePath(path string) func(*Profile) {
return func(p *Profile) {
p.path = path
}
}
// Stop stops the profile and flushes any unwritten data.
func (p *Profile) Stop() {
if !atomic.CompareAndSwapUint32(&p.stopped, 0, 1) {
// someone has already called close
return
}
p.closer()
atomic.StoreUint32(&started, 0)
}
// started is non zero if a profile is running.
var started uint32
// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*Profile)) interface {
Stop()
} {
if !atomic.CompareAndSwapUint32(&started, 0, 1) {
log.Fatal("profile: Start() already called")
}
var prof Profile
for _, option := range options {
option(&prof)
}
path, err := func() (string, error) {
if p := prof.path; p != "" {
return p, os.MkdirAll(p, 0777)
}
return ioutil.TempDir("", "profile")
}()
if err != nil {
log.Fatalf("profile: could not create initial output directory: %v", err)
}
logf := func(format string, args ...interface{}) {
if !prof.quiet {
log.Printf(format, args...)
}
}
switch prof.mode {
case cpuMode:
fn := filepath.Join(path, "cpu.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
}
logf("profile: cpu profiling enabled, %s", fn)
pprof.StartCPUProfile(f)
prof.closer = func() {
pprof.StopCPUProfile()
f.Close()
logf("profile: cpu profiling disabled, %s", fn)
}
case memMode:
fn := filepath.Join(path, "mem.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
}
old := runtime.MemProfileRate
runtime.MemProfileRate = prof.memProfileRate
logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
prof.closer = func() {
pprof.Lookup("heap").WriteTo(f, 0)
f.Close()
runtime.MemProfileRate = old
logf("profile: memory profiling disabled, %s", fn)
}
case mutexMode:
fn := filepath.Join(path, "mutex.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create mutex profile %q: %v", fn, err)
}
enableMutexProfile()
logf("profile: mutex profiling enabled, %s", fn)
prof.closer = func() {
if mp := pprof.Lookup("mutex"); mp != nil {
mp.WriteTo(f, 0)
}
f.Close()
disableMutexProfile()
logf("profile: mutex profiling disabled, %s", fn)
}
case blockMode:
fn := filepath.Join(path, "block.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create block profile %q: %v", fn, err)
}
runtime.SetBlockProfileRate(1)
logf("profile: block profiling enabled, %s", fn)
prof.closer = func() {
pprof.Lookup("block").WriteTo(f, 0)
f.Close()
runtime.SetBlockProfileRate(0)
logf("profile: block profiling disabled, %s", fn)
}
case traceMode:
fn := filepath.Join(path, "trace.out")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create trace output file %q: %v", fn, err)
}
if err := startTrace(f); err != nil {
log.Fatalf("profile: could not start trace: %v", err)
}
logf("profile: trace enabled, %s", fn)
prof.closer = func() {
stopTrace()
logf("profile: trace disabled, %s", fn)
}
}
if !prof.noShutdownHook {
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
log.Println("profile: caught interrupt, stopping profiles")
prof.Stop()
os.Exit(0)
}()
}
return &prof
}

8
vendor/github.com/pkg/profile/trace.go generated vendored Normal file
View File

@ -0,0 +1,8 @@
// +build go1.7
package profile
import "runtime/trace"
var startTrace = trace.Start
var stopTrace = trace.Stop

10
vendor/github.com/pkg/profile/trace16.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
// +build !go1.7
package profile
import "io"
// mock trace support for Go 1.6 and earlier.
func startTrace(w io.Writer) error { return nil }
func stopTrace() {}

View File

@ -71,7 +71,7 @@ Add your issue here on GitHub. Feel free to get in touch if you have any questio
- `Flex` and `Grid` don't clear their background per default, thus allowing for custom modals. See the [Wiki](https://github.com/rivo/tview/wiki/Modal) for an example.
- v0.14 (2018-04-13)
- Added an `Escape()` function which keep strings like color or region tags from being recognized as such.
- Added `ANSIIWriter()` and `TranslateANSII()` which convert ANSII escape sequences to `tview` color tags.
- Added `ANSIWriter()` and `TranslateANSI()` which convert ANSI escape sequences to `tview` color tags.
- v0.13 (2018-04-01)
- Added background colors and text attributes to color tags.
- v0.12 (2018-03-13)

View File

@ -8,44 +8,44 @@ import (
"strings"
)
// The states of the ANSII escape code parser.
// The states of the ANSI escape code parser.
const (
ansiiText = iota
ansiiEscape
ansiiSubstring
ansiiControlSequence
ansiText = iota
ansiEscape
ansiSubstring
ansiControlSequence
)
// ansii is a io.Writer which translates ANSII escape codes into tview color
// ansi is a io.Writer which translates ANSI escape codes into tview color
// tags.
type ansii struct {
type ansi struct {
io.Writer
// Reusable buffers.
buffer *bytes.Buffer // The entire output text of one Write().
csiParameter, csiIntermediate *bytes.Buffer // Partial CSI strings.
// The current state of the parser. One of the ansii constants.
// The current state of the parser. One of the ansi constants.
state int
}
// ANSIIWriter returns an io.Writer which translates any ANSII escape codes
// ANSIWriter returns an io.Writer which translates any ANSI escape codes
// written to it into tview color tags. Other escape codes don't have an effect
// and are simply removed. The translated text is written to the provided
// writer.
func ANSIIWriter(writer io.Writer) io.Writer {
return &ansii{
func ANSIWriter(writer io.Writer) io.Writer {
return &ansi{
Writer: writer,
buffer: new(bytes.Buffer),
csiParameter: new(bytes.Buffer),
csiIntermediate: new(bytes.Buffer),
state: ansiiText,
state: ansiText,
}
}
// Write parses the given text as a string of runes, translates ANSII escape
// Write parses the given text as a string of runes, translates ANSI escape
// codes to color tags and writes them to the output writer.
func (a *ansii) Write(text []byte) (int, error) {
func (a *ansi) Write(text []byte) (int, error) {
defer func() {
a.buffer.Reset()
}()
@ -54,23 +54,23 @@ func (a *ansii) Write(text []byte) (int, error) {
switch a.state {
// We just entered an escape sequence.
case ansiiEscape:
case ansiEscape:
switch r {
case '[': // Control Sequence Introducer.
a.csiParameter.Reset()
a.csiIntermediate.Reset()
a.state = ansiiControlSequence
a.state = ansiControlSequence
case 'c': // Reset.
fmt.Fprint(a.buffer, "[-:-:-]")
a.state = ansiiText
a.state = ansiText
case 'P', ']', 'X', '^', '_': // Substrings and commands.
a.state = ansiiSubstring
a.state = ansiSubstring
default: // Ignore.
a.state = ansiiText
a.state = ansiText
}
// CSI Sequences.
case ansiiControlSequence:
case ansiControlSequence:
switch {
case r >= 0x30 && r <= 0x3f: // Parameter bytes.
if _, err := a.csiParameter.WriteRune(r); err != nil {
@ -194,22 +194,22 @@ func (a *ansii) Write(text []byte) (int, error) {
fmt.Fprintf(a.buffer, "[%s:%s%s]", foreground, background, attributes)
}
}
a.state = ansiiText
a.state = ansiText
default: // Undefined byte.
a.state = ansiiText // Abort CSI.
a.state = ansiText // Abort CSI.
}
// We just entered a substring/command sequence.
case ansiiSubstring:
case ansiSubstring:
if r == 27 { // Most likely the end of the substring.
a.state = ansiiEscape
a.state = ansiEscape
} // Ignore all other characters.
// "ansiiText" and all others.
// "ansiText" and all others.
default:
if r == 27 {
// This is the start of an escape sequence.
a.state = ansiiEscape
a.state = ansiEscape
} else {
// Just a regular rune. Send to buffer.
if _, err := a.buffer.WriteRune(r); err != nil {
@ -227,11 +227,11 @@ func (a *ansii) Write(text []byte) (int, error) {
return len(text), nil
}
// TranslateANSII replaces ANSII escape sequences found in the provided string
// TranslateANSI replaces ANSI escape sequences found in the provided string
// with tview's color tags and returns the resulting string.
func TranslateANSII(text string) string {
func TranslateANSI(text string) string {
var buffer bytes.Buffer
writer := ANSIIWriter(&buffer)
writer := ANSIWriter(&buffer)
writer.Write([]byte(text))
return buffer.String()
}

39
vendor/github.com/rivo/tview/form.go generated vendored
View File

@ -218,6 +218,25 @@ func (f *Form) AddButton(label string, selected func()) *Form {
return f
}
// RemoveButton removes the button at the specified position, starting with 0
// for the button that was added first.
func (f *Form) RemoveButton(index int) *Form {
f.buttons = append(f.buttons[:index], f.buttons[index+1:]...)
return f
}
// GetButtonIndex returns the index of the button with the given label, starting
// with 0 for the button that was added first. If no such label was found, -1
// is returned.
func (f *Form) GetButtonIndex(label string) int {
for index, button := range f.buttons {
if button.GetLabel() == label {
return index
}
}
return -1
}
// Clear removes all input elements from the form, including the buttons if
// specified.
func (f *Form) Clear(includeButtons bool) *Form {
@ -251,6 +270,14 @@ func (f *Form) GetFormItem(index int) FormItem {
return f.items[index]
}
// RemoveFormItem removes the form element at the given position, starting with
// index 0. Elements are referenced in the order they were added. Buttons are
// not included.
func (f *Form) RemoveFormItem(index int) *Form {
f.items = append(f.items[:index], f.items[index+1:]...)
return f
}
// GetFormItemByLabel returns the first form element with the given label. If
// no such element is found, nil is returned. Buttons are not searched and will
// therefore not be returned.
@ -263,6 +290,18 @@ func (f *Form) GetFormItemByLabel(label string) FormItem {
return nil
}
// GetFormItemIndex returns the index of the first form element with the given
// label. If no such element is found, -1 is returned. Buttons are not searched
// and will therefore not be returned.
func (f *Form) GetFormItemIndex(label string) int {
for index, item := range f.items {
if item.GetLabel() == label {
return index
}
}
return -1
}
// SetCancelFunc sets a handler which is called when the user hits the Escape
// key.
func (f *Form) SetCancelFunc(callback func()) *Form {

View File

@ -93,7 +93,7 @@ func (s *TagsService) GetTag(pid interface{}, tag string, options ...OptionFunc)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), tag)
u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), url.QueryEscape(tag))
req, err := s.client.NewRequest("GET", u, nil, options)
if err != nil {
@ -154,7 +154,7 @@ func (s *TagsService) DeleteTag(pid interface{}, tag string, options ...OptionFu
if err != nil {
return nil, err
}
u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), tag)
u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), url.QueryEscape(tag))
req, err := s.client.NewRequest("DELETE", u, nil, options)
if err != nil {
@ -182,7 +182,7 @@ func (s *TagsService) CreateRelease(pid interface{}, tag string, opt *CreateRele
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/repository/tags/%s/release", url.QueryEscape(project), tag)
u := fmt.Sprintf("projects/%s/repository/tags/%s/release", url.QueryEscape(project), url.QueryEscape(tag))
req, err := s.client.NewRequest("POST", u, opt, options)
if err != nil {
@ -215,7 +215,7 @@ func (s *TagsService) UpdateRelease(pid interface{}, tag string, opt *UpdateRele
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/repository/tags/%s/release", url.QueryEscape(project), tag)
u := fmt.Sprintf("projects/%s/repository/tags/%s/release", url.QueryEscape(project), url.QueryEscape(tag))
req, err := s.client.NewRequest("PUT", u, opt, options)
if err != nil {

View File

@ -1,32 +0,0 @@
package prettyweather
import (
"regexp"
"strconv"
)
var colors = map[int]string{0: "#000000", 1: "#800000", 2: "#008000", 3: "#808000", 4: "#000080", 5: "#800080", 6: "#008080", 7: "#c0c0c0", 8: "#808080", 9: "#ff0000", 10: "#00ff00", 11: "#ffff00", 12: "#0000ff", 13: "#ff00ff", 14: "#00ffff", 15: "#ffffff", 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af", 20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f", 24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff", 28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af", 32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f", 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff", 40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af", 44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f", 48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff", 52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af", 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f", 60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff", 64: "#5f8700", 65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7", 69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87", 73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700", 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7", 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87", 85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000", 89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7", 93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87", 97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700", 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7", 105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87", 109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700", 113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7", 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87", 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000", 125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7", 129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87", 133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700", 137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7", 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87", 145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700", 149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7", 153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87", 157: "#afffaf", 158: "#afffd7", 159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087", 163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00", 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7", 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787", 175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00", 179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7", 183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787", 187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00", 191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7", 195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087", 199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00", 203: "#ff5f5f", 204: "#ff5f87", 205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700", 209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7", 213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87", 217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700", 221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7", 225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87", 229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808", 233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030", 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858", 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080", 245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8", 249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0", 253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee"}
func ASCIItoTviewColors(text string) string {
fgColorRegExp := regexp.MustCompile(`\033\[38;5;(?P<color>\d+)m`)
// bgColorRegExp := regexp.MustCompile(`\033\[48;5;(?P<color>\d+)m`)
boldRegExp := regexp.MustCompile(`\033\[1m`)
resColorRegExp := regexp.MustCompile(`\033\[0m`)
return resColorRegExp.ReplaceAllString(
boldRegExp.ReplaceAllString(
fgColorRegExp.ReplaceAllStringFunc(
text, replaceWithHexColorString), `[::b]`), `[-]`)
}
/* -------------------- Unexported Functions -------------------- */
func replaceWithHexColorString(substring string) string {
colorID, err := strconv.Atoi(substring[7 : len(substring)-1])
if err != nil {
return substring
}
hexColor := "[" + colors[colorID] + "]"
return hexColor
}

View File

@ -59,5 +59,5 @@ func (widget *Widget) prettyWeather() {
}
//widget.result = strings.TrimSpace(string(contents))
widget.result = strings.TrimSpace(ASCIItoTviewColors(string(contents)))
widget.result = strings.TrimSpace(wtf.ASCIItoTviewColors(string(contents)))
}

View File

@ -1,9 +1,271 @@
package wtf
import (
"regexp"
"strconv"
"github.com/gdamore/tcell"
)
var colorMap = map[int]string{
0: "#000000",
1: "#800000",
2: "#008000",
3: "#808000",
4: "#000080",
5: "#800080",
6: "#008080",
7: "#c0c0c0",
8: "#808080",
9: "#ff0000",
10: "#00ff00",
11: "#ffff00",
12: "#0000ff",
13: "#ff00ff",
14: "#00ffff",
15: "#ffffff",
16: "#000000",
17: "#00005f",
18: "#000087",
19: "#0000af",
20: "#0000d7",
21: "#0000ff",
22: "#005f00",
23: "#005f5f",
24: "#005f87",
25: "#005faf",
26: "#005fd7",
27: "#005fff",
28: "#008700",
29: "#00875f",
30: "#008787",
31: "#0087af",
32: "#0087d7",
33: "#0087ff",
34: "#00af00",
35: "#00af5f",
36: "#00af87",
37: "#00afaf",
38: "#00afd7",
39: "#00afff",
40: "#00d700",
41: "#00d75f",
42: "#00d787",
43: "#00d7af",
44: "#00d7d7",
45: "#00d7ff",
46: "#00ff00",
47: "#00ff5f",
48: "#00ff87",
49: "#00ffaf",
50: "#00ffd7",
51: "#00ffff",
52: "#5f0000",
53: "#5f005f",
54: "#5f0087",
55: "#5f00af",
56: "#5f00d7",
57: "#5f00ff",
58: "#5f5f00",
59: "#5f5f5f",
60: "#5f5f87",
61: "#5f5faf",
62: "#5f5fd7",
63: "#5f5fff",
64: "#5f8700",
65: "#5f875f",
66: "#5f8787",
67: "#5f87af",
68: "#5f87d7",
69: "#5f87ff",
70: "#5faf00",
71: "#5faf5f",
72: "#5faf87",
73: "#5fafaf",
74: "#5fafd7",
75: "#5fafff",
76: "#5fd700",
77: "#5fd75f",
78: "#5fd787",
79: "#5fd7af",
80: "#5fd7d7",
81: "#5fd7ff",
82: "#5fff00",
83: "#5fff5f",
84: "#5fff87",
85: "#5fffaf",
86: "#5fffd7",
87: "#5fffff",
88: "#870000",
89: "#87005f",
90: "#870087",
91: "#8700af",
92: "#8700d7",
93: "#8700ff",
94: "#875f00",
95: "#875f5f",
96: "#875f87",
97: "#875faf",
98: "#875fd7",
99: "#875fff",
100: "#878700",
101: "#87875f",
102: "#878787",
103: "#8787af",
104: "#8787d7",
105: "#8787ff",
106: "#87af00",
107: "#87af5f",
108: "#87af87",
109: "#87afaf",
110: "#87afd7",
111: "#87afff",
112: "#87d700",
113: "#87d75f",
114: "#87d787",
115: "#87d7af",
116: "#87d7d7",
117: "#87d7ff",
118: "#87ff00",
119: "#87ff5f",
120: "#87ff87",
121: "#87ffaf",
122: "#87ffd7",
123: "#87ffff",
124: "#af0000",
125: "#af005f",
126: "#af0087",
127: "#af00af",
128: "#af00d7",
129: "#af00ff",
130: "#af5f00",
131: "#af5f5f",
132: "#af5f87",
133: "#af5faf",
134: "#af5fd7",
135: "#af5fff",
136: "#af8700",
137: "#af875f",
138: "#af8787",
139: "#af87af",
140: "#af87d7",
141: "#af87ff",
142: "#afaf00",
143: "#afaf5f",
144: "#afaf87",
145: "#afafaf",
146: "#afafd7",
147: "#afafff",
148: "#afd700",
149: "#afd75f",
150: "#afd787",
151: "#afd7af",
152: "#afd7d7",
153: "#afd7ff",
154: "#afff00",
155: "#afff5f",
156: "#afff87",
157: "#afffaf",
158: "#afffd7",
159: "#afffff",
160: "#d70000",
161: "#d7005f",
162: "#d70087",
163: "#d700af",
164: "#d700d7",
165: "#d700ff",
166: "#d75f00",
167: "#d75f5f",
168: "#d75f87",
169: "#d75faf",
170: "#d75fd7",
171: "#d75fff",
172: "#d78700",
173: "#d7875f",
174: "#d78787",
175: "#d787af",
176: "#d787d7",
177: "#d787ff",
178: "#d7af00",
179: "#d7af5f",
180: "#d7af87",
181: "#d7afaf",
182: "#d7afd7",
183: "#d7afff",
184: "#d7d700",
185: "#d7d75f",
186: "#d7d787",
187: "#d7d7af",
188: "#d7d7d7",
189: "#d7d7ff",
190: "#d7ff00",
191: "#d7ff5f",
192: "#d7ff87",
193: "#d7ffaf",
194: "#d7ffd7",
195: "#d7ffff",
196: "#ff0000",
197: "#ff005f",
198: "#ff0087",
199: "#ff00af",
200: "#ff00d7",
201: "#ff00ff",
202: "#ff5f00",
203: "#ff5f5f",
204: "#ff5f87",
205: "#ff5faf",
206: "#ff5fd7",
207: "#ff5fff",
208: "#ff8700",
209: "#ff875f",
210: "#ff8787",
211: "#ff87af",
212: "#ff87d7",
213: "#ff87ff",
214: "#ffaf00",
215: "#ffaf5f",
216: "#ffaf87",
217: "#ffafaf",
218: "#ffafd7",
219: "#ffafff",
220: "#ffd700",
221: "#ffd75f",
222: "#ffd787",
223: "#ffd7af",
224: "#ffd7d7",
225: "#ffd7ff",
226: "#ffff00",
227: "#ffff5f",
228: "#ffff87",
229: "#ffffaf",
230: "#ffffd7",
231: "#ffffff",
232: "#080808",
233: "#121212",
234: "#1c1c1c",
235: "#262626",
236: "#303030",
237: "#3a3a3a",
238: "#444444",
239: "#4e4e4e",
240: "#585858",
241: "#626262",
242: "#6c6c6c",
243: "#767676",
244: "#808080",
245: "#8a8a8a",
246: "#949494",
247: "#9e9e9e",
248: "#a8a8a8",
249: "#b2b2b2",
250: "#bcbcbc",
251: "#c6c6c6",
252: "#d0d0d0",
253: "#dadada",
254: "#e4e4e4",
255: "#eeeeee",
}
var colors = map[string]tcell.Color{
"aliceblue": tcell.ColorAliceBlue,
"antiquewhite": tcell.ColorAntiqueWhite,
@ -147,6 +409,17 @@ var colors = map[string]tcell.Color{
"yellowgreen": tcell.ColorYellowGreen,
}
func ASCIItoTviewColors(text string) string {
boldRegExp := regexp.MustCompile(`\033\[1m`)
fgColorRegExp := regexp.MustCompile(`\033\[38;5;(?P<color>\d+)m`)
resColorRegExp := regexp.MustCompile(`\033\[0m`)
return resColorRegExp.ReplaceAllString(
boldRegExp.ReplaceAllString(
fgColorRegExp.ReplaceAllStringFunc(
text, replaceWithHexColorString), `[::b]`), `[-]`)
}
func ColorFor(label string) tcell.Color {
if _, ok := colors[label]; ok {
return colors[label]
@ -154,3 +427,16 @@ func ColorFor(label string) tcell.Color {
return tcell.ColorGreen
}
}
/* -------------------- Unexported Functions -------------------- */
func replaceWithHexColorString(substring string) string {
colorID, err := strconv.Atoi(substring[7 : len(substring)-1])
if err != nil {
return substring
}
hexColor := "[" + colorMap[colorID] + "]"
return hexColor
}