Skip to content

Commit

Permalink
Prompt improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
gabyx committed Oct 10, 2020
1 parent 386b508 commit 99dcf6f
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 34 deletions.
7 changes: 5 additions & 2 deletions githooks/common/ctty_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

package common

import "os"
import (
"io"
"os"
)

// GetCtty gets the file descriptor of the controlling terminal.
func GetCtty() (*os.File, error) {
func GetCtty() (io.Reader, error) {
return os.OpenFile("/dev/tty", os.O_RDONLY, 0)
}
40 changes: 30 additions & 10 deletions githooks/common/log.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package common

import (
"io"
"log"
"os"
"runtime/debug"
Expand Down Expand Up @@ -42,9 +43,6 @@ type ILogContext interface {
LogFatal(lines ...string)
LogFatalF(format string, args ...interface{})

LogPromptStartF(format string, args ...interface{})
LogPromptEnd()

// Assert helper functions
AssertWarn(condition bool, lines ...string)
AssertWarnF(condition bool, format string, args ...interface{})
Expand All @@ -56,6 +54,13 @@ type ILogContext interface {
AssertNoErrorWarnF(err error, format string, args ...interface{}) bool
AssertNoErrorFatal(err error, lines ...string)
AssertNoErrorFatalF(err error, format string, args ...interface{})

HasColors() bool

GetPromptFormatter() func(format string, args ...interface{}) string

GetInfoWriter() io.Writer
GetErrorWriter() io.Writer
}

// LogContext defines the data for a log context
Expand Down Expand Up @@ -107,6 +112,21 @@ func CreateLogContext() (ILogContext, error) {
return &LogContext{debug, info, warn, error, hasColors, renderInfo, renderError, renderPrompt}, nil
}

// HasColors returns if the log uses colors.
func (c *LogContext) HasColors() bool {
return c.isColorSupported
}

// GetErrorWriter returns the error writer.
func (c *LogContext) GetErrorWriter() io.Writer {
return c.error.Writer()
}

// GetInfoWriter returns the error writer.
func (c *LogContext) GetInfoWriter() io.Writer {
return c.info.Writer()
}

// LogDebug logs a debug message.
func (c *LogContext) LogDebug(lines ...string) {
if DebugLog {
Expand Down Expand Up @@ -151,14 +171,14 @@ func (c *LogContext) LogErrorF(format string, args ...interface{}) {
c.error.Printf(c.renderError(FormatMessageF(errorSuffix, errorIndent, format, args...)))
}

// LogPromptStartF outputs a prompt to `stdin`.
func (c *LogContext) LogPromptStartF(format string, args ...interface{}) {
c.info.Printf(c.renderPrompt(FormatMessageF(promptSuffix, promptIndent, format, args...)))
}
// GetPromptFormatter renders a prompt.
func (c *LogContext) GetPromptFormatter() func(format string, args ...interface{}) string {

fmt := func(format string, args ...interface{}) string {
return c.renderPrompt(FormatMessageF(promptSuffix, promptIndent, format, args...))
}

// LogPromptEnd outputs the end statement after prompt input to `stdin`.
func (c *LogContext) LogPromptEnd() {
c.info.Printf("\n")
return fmt
}

// LogErrorWithStacktrace logs and error with the stack trace.
Expand Down
8 changes: 4 additions & 4 deletions githooks/common/logasserts.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (c *LogContext) FatalIfF(condition bool, format string, args ...interface{}
// AssertNoErrorWarn Assert no error, and otherwise log it.
func (c *LogContext) AssertNoErrorWarn(err error, lines ...string) bool {
if err != nil {
c.LogWarn(append(lines, strs.SplitLines("-> error: [\n"+err.Error()+"\n]")...)...)
c.LogWarn(append(lines, strs.SplitLines("-> error: ["+err.Error()+"]")...)...)
return false
}
return true
Expand All @@ -56,7 +56,7 @@ func (c *LogContext) AssertNoErrorWarn(err error, lines ...string) bool {
// AssertNoErrorWarnF Assert no error, and otherwise log it.
func (c *LogContext) AssertNoErrorWarnF(err error, format string, args ...interface{}) bool {
if err != nil {
c.LogWarnF(format+"\n-> error: [\n"+err.Error()+"\n]", args...)
c.LogWarnF(format+"\n-> error: ["+err.Error()+"]", args...)
return false
}
return true
Expand All @@ -65,13 +65,13 @@ func (c *LogContext) AssertNoErrorWarnF(err error, format string, args ...interf
// AssertNoErrorFatal Assert no error, and otherwise log it.
func (c *LogContext) AssertNoErrorFatal(err error, lines ...string) {
if err != nil {
c.LogFatal(append(lines, strs.SplitLines("-> error: [\n"+err.Error()+"\n]")...)...)
c.LogFatal(append(lines, strs.SplitLines("-> error: ["+err.Error()+"]")...)...)
}
}

// AssertNoErrorFatalF Assert no error, and otherwise log it.
func (c *LogContext) AssertNoErrorFatalF(err error, format string, args ...interface{}) {
if err != nil {
c.LogFatalF(format+"\n-> error: [\n"+err.Error()+"\n]", args...)
c.LogFatalF(format+"\n-> error: ["+err.Error()+"]", args...)
}
}
49 changes: 32 additions & 17 deletions githooks/common/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"bufio"
"io"
"os"
"runtime"
strs "rycus86/githooks/strings"
Expand All @@ -17,13 +18,17 @@ type IPromptContext interface {
Close()
}

type PromptFormatter func(format string, args ...interface{}) string

// PromptContext defines the prompt context based on a `ILogContext`
// or as a fallback using the defined dialog tool if configured.
type PromptContext struct {
log ILogContext

// Fallback prompt over the log context if available.
log ILogContext
ctty *os.File // File descp. of the controlling terminal.
hasCtty bool // If a controlling terminal is available, e.g. `ctty` is valid.
promptFmt PromptFormatter
termOut io.Writer
termIn io.Reader

// Prompt over the tool script if existing.
execCtx IExecContext
Expand All @@ -32,24 +37,28 @@ type PromptContext struct {

// Close closes the prompt context
func (p *PromptContext) Close() {
if p.ctty != nil {
p.ctty.Close()

if f, ok := p.termIn.(*os.File); ok {
f.Close()
}
}

// CreatePromptContext creates a `PrompContext`.
func CreatePromptContext(log ILogContext,
execCtx IExecContext, toolPath string) (IPromptContext, error) {
ctty, err := GetCtty()
terminalReader, err := GetCtty()

p := PromptContext{
log: log,
ctty: ctty,
log: log,

promptFmt: log.GetPromptFormatter(),
termOut: log.GetInfoWriter(),
termIn: terminalReader,

execCtx: execCtx,
toolPath: toolPath}

if ctty != nil {
if terminalReader != nil {
runtime.SetFinalizer(&p, func(p *PromptContext) { p.Close() })
}

Expand Down Expand Up @@ -106,15 +115,18 @@ func (p *PromptContext) ShowPrompt(text string,
// from git), so read from /dev/tty, our controlling terminal,
// if it can be opened.
nPrompts := 0 // How many times we showed the prompt
if p.ctty != nil {
question := p.promptFmt("%s %s [%s]: ", text, hintText, shortOptions)

if p.termIn != nil {
maxPrompts := 3
answerIncorrect := true
for answerIncorrect && nPrompts < maxPrompts {

p.log.LogPromptStartF("%s %s [%s]: ", text, hintText, shortOptions)
p.termOut.Write([]byte(question))
nPrompts++

var ans string
reader := bufio.NewReader(p.ctty)
reader := bufio.NewReader(p.termIn)
ans, e := reader.ReadString('\n')

if e == nil {
Expand All @@ -129,21 +141,24 @@ func (p *PromptContext) ShowPrompt(text string,
return answer, nil
}

p.log.LogWarnF("Answer '%s' not in '%q', try again ...", answer, shortOptions)
warning := p.promptFmt("Answer '%s' not in '%q', try again ...", answer, shortOptions)
p.termOut.Write([]byte(warning))

} else {
p.log.LogWarnF("Could not read from ctty '%v'.", p.ctty)
p.termOut.Write([]byte("\n"))
err = CombineErrors(err, ErrorF("Could not read from terminal reader."))
break
}
}
} else {
err = CombineErrors(err, ErrorF("Dont have a controlling terminal."))
err = CombineErrors(err, ErrorF("Do not have a controlling terminal to show prompt."))
}

if nPrompts == 0 {
// Show the prompt once ...
p.log.LogPromptStartF("%s %s [%s]: \n", text, hintText, shortOptions)
p.termOut.Write([]byte(question))
}

p.log.LogWarnF("Answer not received -> Using default '%s'", defaultAnswer)
p.log.LogDebugF("Answer not received -> Using default '%s'", defaultAnswer)
return defaultAnswer, err
}
4 changes: 4 additions & 0 deletions githooks/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ module rycus86/githooks
go 1.15

require (
fyne.io/fyne v1.3.3
github.com/gizak/termui/v3 v3.1.0
github.com/goccy/go-yaml v1.8.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/gookit/color v1.3.1
github.com/gookit/config/v2 v2.0.17
github.com/loov/hrtime v1.0.1
github.com/mattn/go-isatty v0.0.10
github.com/mattn/go-tty v0.0.3
github.com/mitchellh/go-homedir v1.1.0
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666
gopkg.in/yaml.v2 v2.3.0
)

0 comments on commit 99dcf6f

Please sign in to comment.