mirror of
https://github.com/go-task/task.git
synced 2025-06-23 00:38:19 +02:00
feat: better functional options for reader (#2148)
This commit is contained in:
111
executor.go
111
executor.go
@ -17,7 +17,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// An ExecutorOption is a functional option for an [Executor].
|
// An ExecutorOption is any type that can apply a configuration to an
|
||||||
|
// [Executor].
|
||||||
ExecutorOption interface {
|
ExecutorOption interface {
|
||||||
ApplyToExecutor(*Executor)
|
ApplyToExecutor(*Executor)
|
||||||
}
|
}
|
||||||
@ -112,14 +113,14 @@ func (e *Executor) Options(opts ...ExecutorOption) {
|
|||||||
// WithDir sets the working directory of the [Executor]. By default, the
|
// WithDir sets the working directory of the [Executor]. By default, the
|
||||||
// directory is set to the user's current working directory.
|
// directory is set to the user's current working directory.
|
||||||
func WithDir(dir string) ExecutorOption {
|
func WithDir(dir string) ExecutorOption {
|
||||||
return dirOption{dir}
|
return &dirOption{dir}
|
||||||
}
|
}
|
||||||
|
|
||||||
type dirOption struct {
|
type dirOption struct {
|
||||||
dir string
|
dir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o dirOption) ApplyToExecutor(e *Executor) {
|
func (o *dirOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Dir = o.dir
|
e.Dir = o.dir
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,14 +128,14 @@ func (o dirOption) ApplyToExecutor(e *Executor) {
|
|||||||
// default, Task will search for one of the default Taskfiles in the given
|
// default, Task will search for one of the default Taskfiles in the given
|
||||||
// directory.
|
// directory.
|
||||||
func WithEntrypoint(entrypoint string) ExecutorOption {
|
func WithEntrypoint(entrypoint string) ExecutorOption {
|
||||||
return entrypointOption{entrypoint}
|
return &entrypointOption{entrypoint}
|
||||||
}
|
}
|
||||||
|
|
||||||
type entrypointOption struct {
|
type entrypointOption struct {
|
||||||
entrypoint string
|
entrypoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o entrypointOption) ApplyToExecutor(e *Executor) {
|
func (o *entrypointOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Entrypoint = o.entrypoint
|
e.Entrypoint = o.entrypoint
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,98 +143,98 @@ func (o entrypointOption) ApplyToExecutor(e *Executor) {
|
|||||||
// storing temporary files like checksums and cached remote files. By default,
|
// storing temporary files like checksums and cached remote files. By default,
|
||||||
// the temporary directory is set to the user's temporary directory.
|
// the temporary directory is set to the user's temporary directory.
|
||||||
func WithTempDir(tempDir TempDir) ExecutorOption {
|
func WithTempDir(tempDir TempDir) ExecutorOption {
|
||||||
return tempDirOption{tempDir}
|
return &tempDirOption{tempDir}
|
||||||
}
|
}
|
||||||
|
|
||||||
type tempDirOption struct {
|
type tempDirOption struct {
|
||||||
tempDir TempDir
|
tempDir TempDir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o tempDirOption) ApplyToExecutor(e *Executor) {
|
func (o *tempDirOption) ApplyToExecutor(e *Executor) {
|
||||||
e.TempDir = o.tempDir
|
e.TempDir = o.tempDir
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithForce ensures that the [Executor] always runs a task, even when
|
// WithForce ensures that the [Executor] always runs a task, even when
|
||||||
// fingerprinting or prompts would normally stop it.
|
// fingerprinting or prompts would normally stop it.
|
||||||
func WithForce(force bool) ExecutorOption {
|
func WithForce(force bool) ExecutorOption {
|
||||||
return forceOption{force}
|
return &forceOption{force}
|
||||||
}
|
}
|
||||||
|
|
||||||
type forceOption struct {
|
type forceOption struct {
|
||||||
force bool
|
force bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o forceOption) ApplyToExecutor(e *Executor) {
|
func (o *forceOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Force = o.force
|
e.Force = o.force
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithForceAll ensures that the [Executor] always runs all tasks (including
|
// WithForceAll ensures that the [Executor] always runs all tasks (including
|
||||||
// subtasks), even when fingerprinting or prompts would normally stop them.
|
// subtasks), even when fingerprinting or prompts would normally stop them.
|
||||||
func WithForceAll(forceAll bool) ExecutorOption {
|
func WithForceAll(forceAll bool) ExecutorOption {
|
||||||
return forceAllOption{forceAll}
|
return &forceAllOption{forceAll}
|
||||||
}
|
}
|
||||||
|
|
||||||
type forceAllOption struct {
|
type forceAllOption struct {
|
||||||
forceAll bool
|
forceAll bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o forceAllOption) ApplyToExecutor(e *Executor) {
|
func (o *forceAllOption) ApplyToExecutor(e *Executor) {
|
||||||
e.ForceAll = o.forceAll
|
e.ForceAll = o.forceAll
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithInsecure allows the [Executor] to make insecure connections when reading
|
// WithInsecure allows the [Executor] to make insecure connections when reading
|
||||||
// remote taskfiles. By default, insecure connections are rejected.
|
// remote taskfiles. By default, insecure connections are rejected.
|
||||||
func WithInsecure(insecure bool) ExecutorOption {
|
func WithInsecure(insecure bool) ExecutorOption {
|
||||||
return insecureOption{insecure}
|
return &insecureOption{insecure}
|
||||||
}
|
}
|
||||||
|
|
||||||
type insecureOption struct {
|
type insecureOption struct {
|
||||||
insecure bool
|
insecure bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o insecureOption) ApplyToExecutor(e *Executor) {
|
func (o *insecureOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Insecure = o.insecure
|
e.Insecure = o.insecure
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDownload forces the [Executor] to download a fresh copy of the taskfile
|
// WithDownload forces the [Executor] to download a fresh copy of the taskfile
|
||||||
// from the remote source.
|
// from the remote source.
|
||||||
func WithDownload(download bool) ExecutorOption {
|
func WithDownload(download bool) ExecutorOption {
|
||||||
return downloadOption{download}
|
return &downloadOption{download}
|
||||||
}
|
}
|
||||||
|
|
||||||
type downloadOption struct {
|
type downloadOption struct {
|
||||||
download bool
|
download bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o downloadOption) ApplyToExecutor(e *Executor) {
|
func (o *downloadOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Download = o.download
|
e.Download = o.download
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithOffline stops the [Executor] from being able to make network connections.
|
// WithOffline stops the [Executor] from being able to make network connections.
|
||||||
// It will still be able to read local files and cached copies of remote files.
|
// It will still be able to read local files and cached copies of remote files.
|
||||||
func WithOffline(offline bool) ExecutorOption {
|
func WithOffline(offline bool) ExecutorOption {
|
||||||
return offlineOption{offline}
|
return &offlineOption{offline}
|
||||||
}
|
}
|
||||||
|
|
||||||
type offlineOption struct {
|
type offlineOption struct {
|
||||||
offline bool
|
offline bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o offlineOption) ApplyToExecutor(e *Executor) {
|
func (o *offlineOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Offline = o.offline
|
e.Offline = o.offline
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTimeout sets the [Executor]'s timeout for fetching remote taskfiles. By
|
// WithTimeout sets the [Executor]'s timeout for fetching remote taskfiles. By
|
||||||
// default, the timeout is set to 10 seconds.
|
// default, the timeout is set to 10 seconds.
|
||||||
func WithTimeout(timeout time.Duration) ExecutorOption {
|
func WithTimeout(timeout time.Duration) ExecutorOption {
|
||||||
return timeoutOption{timeout}
|
return &timeoutOption{timeout}
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeoutOption struct {
|
type timeoutOption struct {
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o timeoutOption) ApplyToExecutor(e *Executor) {
|
func (o *timeoutOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Timeout = o.timeout
|
e.Timeout = o.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,166 +242,166 @@ func (o timeoutOption) ApplyToExecutor(e *Executor) {
|
|||||||
// for changes to the fingerprint of the tasks that are run. When changes are
|
// for changes to the fingerprint of the tasks that are run. When changes are
|
||||||
// detected, a new task run is triggered.
|
// detected, a new task run is triggered.
|
||||||
func WithWatch(watch bool) ExecutorOption {
|
func WithWatch(watch bool) ExecutorOption {
|
||||||
return watchOption{watch}
|
return &watchOption{watch}
|
||||||
}
|
}
|
||||||
|
|
||||||
type watchOption struct {
|
type watchOption struct {
|
||||||
watch bool
|
watch bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o watchOption) ApplyToExecutor(e *Executor) {
|
func (o *watchOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Watch = o.watch
|
e.Watch = o.watch
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithVerbose tells the [Executor] to output more information about the tasks
|
// WithVerbose tells the [Executor] to output more information about the tasks
|
||||||
// that are run.
|
// that are run.
|
||||||
func WithVerbose(verbose bool) ExecutorOption {
|
func WithVerbose(verbose bool) ExecutorOption {
|
||||||
return verboseOption{verbose}
|
return &verboseOption{verbose}
|
||||||
}
|
}
|
||||||
|
|
||||||
type verboseOption struct {
|
type verboseOption struct {
|
||||||
verbose bool
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o verboseOption) ApplyToExecutor(e *Executor) {
|
func (o *verboseOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Verbose = o.verbose
|
e.Verbose = o.verbose
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSilent tells the [Executor] to suppress all output except for the output
|
// WithSilent tells the [Executor] to suppress all output except for the output
|
||||||
// of the tasks that are run.
|
// of the tasks that are run.
|
||||||
func WithSilent(silent bool) ExecutorOption {
|
func WithSilent(silent bool) ExecutorOption {
|
||||||
return silentOption{silent}
|
return &silentOption{silent}
|
||||||
}
|
}
|
||||||
|
|
||||||
type silentOption struct {
|
type silentOption struct {
|
||||||
silent bool
|
silent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o silentOption) ApplyToExecutor(e *Executor) {
|
func (o *silentOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Silent = o.silent
|
e.Silent = o.silent
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAssumeYes tells the [Executor] to assume "yes" for all prompts.
|
// WithAssumeYes tells the [Executor] to assume "yes" for all prompts.
|
||||||
func WithAssumeYes(assumeYes bool) ExecutorOption {
|
func WithAssumeYes(assumeYes bool) ExecutorOption {
|
||||||
return assumeYesOption{assumeYes}
|
return &assumeYesOption{assumeYes}
|
||||||
}
|
}
|
||||||
|
|
||||||
type assumeYesOption struct {
|
type assumeYesOption struct {
|
||||||
assumeYes bool
|
assumeYes bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o assumeYesOption) ApplyToExecutor(e *Executor) {
|
func (o *assumeYesOption) ApplyToExecutor(e *Executor) {
|
||||||
e.AssumeYes = o.assumeYes
|
e.AssumeYes = o.assumeYes
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAssumeTerm is used for testing purposes to simulate a terminal.
|
// WithAssumeTerm is used for testing purposes to simulate a terminal.
|
||||||
func WithAssumeTerm(assumeTerm bool) ExecutorOption {
|
func WithAssumeTerm(assumeTerm bool) ExecutorOption {
|
||||||
return assumeTermOption{assumeTerm}
|
return &assumeTermOption{assumeTerm}
|
||||||
}
|
}
|
||||||
|
|
||||||
type assumeTermOption struct {
|
type assumeTermOption struct {
|
||||||
assumeTerm bool
|
assumeTerm bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o assumeTermOption) ApplyToExecutor(e *Executor) {
|
func (o *assumeTermOption) ApplyToExecutor(e *Executor) {
|
||||||
e.AssumeTerm = o.assumeTerm
|
e.AssumeTerm = o.assumeTerm
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDry tells the [Executor] to output the commands that would be run without
|
// WithDry tells the [Executor] to output the commands that would be run without
|
||||||
// actually running them.
|
// actually running them.
|
||||||
func WithDry(dry bool) ExecutorOption {
|
func WithDry(dry bool) ExecutorOption {
|
||||||
return dryOption{dry}
|
return &dryOption{dry}
|
||||||
}
|
}
|
||||||
|
|
||||||
type dryOption struct {
|
type dryOption struct {
|
||||||
dry bool
|
dry bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o dryOption) ApplyToExecutor(e *Executor) {
|
func (o *dryOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Dry = o.dry
|
e.Dry = o.dry
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSummary tells the [Executor] to output a summary of the given tasks
|
// WithSummary tells the [Executor] to output a summary of the given tasks
|
||||||
// instead of running them.
|
// instead of running them.
|
||||||
func WithSummary(summary bool) ExecutorOption {
|
func WithSummary(summary bool) ExecutorOption {
|
||||||
return summaryOption{summary}
|
return &summaryOption{summary}
|
||||||
}
|
}
|
||||||
|
|
||||||
type summaryOption struct {
|
type summaryOption struct {
|
||||||
summary bool
|
summary bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o summaryOption) ApplyToExecutor(e *Executor) {
|
func (o *summaryOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Summary = o.summary
|
e.Summary = o.summary
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithParallel tells the [Executor] to run tasks given in the same call in
|
// WithParallel tells the [Executor] to run tasks given in the same call in
|
||||||
// parallel.
|
// parallel.
|
||||||
func WithParallel(parallel bool) ExecutorOption {
|
func WithParallel(parallel bool) ExecutorOption {
|
||||||
return parallelOption{parallel}
|
return ¶llelOption{parallel}
|
||||||
}
|
}
|
||||||
|
|
||||||
type parallelOption struct {
|
type parallelOption struct {
|
||||||
parallel bool
|
parallel bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o parallelOption) ApplyToExecutor(e *Executor) {
|
func (o *parallelOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Parallel = o.parallel
|
e.Parallel = o.parallel
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithColor tells the [Executor] whether or not to output using colorized
|
// WithColor tells the [Executor] whether or not to output using colorized
|
||||||
// strings.
|
// strings.
|
||||||
func WithColor(color bool) ExecutorOption {
|
func WithColor(color bool) ExecutorOption {
|
||||||
return colorOption{color}
|
return &colorOption{color}
|
||||||
}
|
}
|
||||||
|
|
||||||
type colorOption struct {
|
type colorOption struct {
|
||||||
color bool
|
color bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o colorOption) ApplyToExecutor(e *Executor) {
|
func (o *colorOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Color = o.color
|
e.Color = o.color
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithConcurrency sets the maximum number of tasks that the [Executor] can run
|
// WithConcurrency sets the maximum number of tasks that the [Executor] can run
|
||||||
// in parallel.
|
// in parallel.
|
||||||
func WithConcurrency(concurrency int) ExecutorOption {
|
func WithConcurrency(concurrency int) ExecutorOption {
|
||||||
return concurrencyOption{concurrency}
|
return &concurrencyOption{concurrency}
|
||||||
}
|
}
|
||||||
|
|
||||||
type concurrencyOption struct {
|
type concurrencyOption struct {
|
||||||
concurrency int
|
concurrency int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o concurrencyOption) ApplyToExecutor(e *Executor) {
|
func (o *concurrencyOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Concurrency = o.concurrency
|
e.Concurrency = o.concurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithInterval sets the interval at which the [Executor] will wait for
|
// WithInterval sets the interval at which the [Executor] will wait for
|
||||||
// duplicated events before running a task.
|
// duplicated events before running a task.
|
||||||
func WithInterval(interval time.Duration) ExecutorOption {
|
func WithInterval(interval time.Duration) ExecutorOption {
|
||||||
return intervalOption{interval}
|
return &intervalOption{interval}
|
||||||
}
|
}
|
||||||
|
|
||||||
type intervalOption struct {
|
type intervalOption struct {
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o intervalOption) ApplyToExecutor(e *Executor) {
|
func (o *intervalOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Interval = o.interval
|
e.Interval = o.interval
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithOutputStyle sets the output style of the [Executor]. By default, the
|
// WithOutputStyle sets the output style of the [Executor]. By default, the
|
||||||
// output style is set to the style defined in the Taskfile.
|
// output style is set to the style defined in the Taskfile.
|
||||||
func WithOutputStyle(outputStyle ast.Output) ExecutorOption {
|
func WithOutputStyle(outputStyle ast.Output) ExecutorOption {
|
||||||
return outputStyleOption{outputStyle}
|
return &outputStyleOption{outputStyle}
|
||||||
}
|
}
|
||||||
|
|
||||||
type outputStyleOption struct {
|
type outputStyleOption struct {
|
||||||
outputStyle ast.Output
|
outputStyle ast.Output
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o outputStyleOption) ApplyToExecutor(e *Executor) {
|
func (o *outputStyleOption) ApplyToExecutor(e *Executor) {
|
||||||
e.OutputStyle = o.outputStyle
|
e.OutputStyle = o.outputStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,67 +409,67 @@ func (o outputStyleOption) ApplyToExecutor(e *Executor) {
|
|||||||
// default, the sorter is set to sort tasks alphabetically, but with tasks with
|
// default, the sorter is set to sort tasks alphabetically, but with tasks with
|
||||||
// no namespace (in the root Taskfile) first.
|
// no namespace (in the root Taskfile) first.
|
||||||
func WithTaskSorter(sorter sort.Sorter) ExecutorOption {
|
func WithTaskSorter(sorter sort.Sorter) ExecutorOption {
|
||||||
return taskSorterOption{sorter}
|
return &taskSorterOption{sorter}
|
||||||
}
|
}
|
||||||
|
|
||||||
type taskSorterOption struct {
|
type taskSorterOption struct {
|
||||||
sorter sort.Sorter
|
sorter sort.Sorter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o taskSorterOption) ApplyToExecutor(e *Executor) {
|
func (o *taskSorterOption) ApplyToExecutor(e *Executor) {
|
||||||
e.TaskSorter = o.sorter
|
e.TaskSorter = o.sorter
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithStdin sets the [Executor]'s standard input [io.Reader].
|
// WithStdin sets the [Executor]'s standard input [io.Reader].
|
||||||
func WithStdin(stdin io.Reader) ExecutorOption {
|
func WithStdin(stdin io.Reader) ExecutorOption {
|
||||||
return stdinOption{stdin}
|
return &stdinOption{stdin}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stdinOption struct {
|
type stdinOption struct {
|
||||||
stdin io.Reader
|
stdin io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o stdinOption) ApplyToExecutor(e *Executor) {
|
func (o *stdinOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Stdin = o.stdin
|
e.Stdin = o.stdin
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithStdout sets the [Executor]'s standard output [io.Writer].
|
// WithStdout sets the [Executor]'s standard output [io.Writer].
|
||||||
func WithStdout(stdout io.Writer) ExecutorOption {
|
func WithStdout(stdout io.Writer) ExecutorOption {
|
||||||
return stdoutOption{stdout}
|
return &stdoutOption{stdout}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stdoutOption struct {
|
type stdoutOption struct {
|
||||||
stdout io.Writer
|
stdout io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o stdoutOption) ApplyToExecutor(e *Executor) {
|
func (o *stdoutOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Stdout = o.stdout
|
e.Stdout = o.stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithStderr sets the [Executor]'s standard error [io.Writer].
|
// WithStderr sets the [Executor]'s standard error [io.Writer].
|
||||||
func WithStderr(stderr io.Writer) ExecutorOption {
|
func WithStderr(stderr io.Writer) ExecutorOption {
|
||||||
return stderrOption{stderr}
|
return &stderrOption{stderr}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stderrOption struct {
|
type stderrOption struct {
|
||||||
stderr io.Writer
|
stderr io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o stderrOption) ApplyToExecutor(e *Executor) {
|
func (o *stderrOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Stderr = o.stderr
|
e.Stderr = o.stderr
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithIO sets the [Executor]'s standard input, output, and error to the same
|
// WithIO sets the [Executor]'s standard input, output, and error to the same
|
||||||
// [io.ReadWriter].
|
// [io.ReadWriter].
|
||||||
func WithIO(rw io.ReadWriter) ExecutorOption {
|
func WithIO(rw io.ReadWriter) ExecutorOption {
|
||||||
return ioOption{rw}
|
return &ioOption{rw}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ioOption struct {
|
type ioOption struct {
|
||||||
rw io.ReadWriter
|
rw io.ReadWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o ioOption) ApplyToExecutor(e *Executor) {
|
func (o *ioOption) ApplyToExecutor(e *Executor) {
|
||||||
e.Stdin = o.rw
|
e.Stdin = o.rw
|
||||||
e.Stdout = o.rw
|
e.Stdout = o.rw
|
||||||
e.Stderr = o.rw
|
e.Stderr = o.rw
|
||||||
@ -476,13 +477,13 @@ func (o ioOption) ApplyToExecutor(e *Executor) {
|
|||||||
|
|
||||||
// WithVersionCheck tells the [Executor] whether or not to check the version of
|
// WithVersionCheck tells the [Executor] whether or not to check the version of
|
||||||
func WithVersionCheck(enableVersionCheck bool) ExecutorOption {
|
func WithVersionCheck(enableVersionCheck bool) ExecutorOption {
|
||||||
return versionCheckOption{enableVersionCheck}
|
return &versionCheckOption{enableVersionCheck}
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionCheckOption struct {
|
type versionCheckOption struct {
|
||||||
enableVersionCheck bool
|
enableVersionCheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o versionCheckOption) ApplyToExecutor(e *Executor) {
|
func (o *versionCheckOption) ApplyToExecutor(e *Executor) {
|
||||||
e.EnableVersionCheck = o.enableVersionCheck
|
e.EnableVersionCheck = o.enableVersionCheck
|
||||||
}
|
}
|
||||||
|
14
setup.go
14
setup.go
@ -72,13 +72,13 @@ func (e *Executor) readTaskfile(node taskfile.Node) error {
|
|||||||
}
|
}
|
||||||
reader := taskfile.NewReader(
|
reader := taskfile.NewReader(
|
||||||
node,
|
node,
|
||||||
taskfile.ReaderWithInsecure(e.Insecure),
|
taskfile.WithInsecure(e.Insecure),
|
||||||
taskfile.ReaderWithDownload(e.Download),
|
taskfile.WithDownload(e.Download),
|
||||||
taskfile.ReaderWithOffline(e.Offline),
|
taskfile.WithOffline(e.Offline),
|
||||||
taskfile.ReaderWithTimeout(e.Timeout),
|
taskfile.WithTimeout(e.Timeout),
|
||||||
taskfile.ReaderWithTempDir(e.TempDir.Remote),
|
taskfile.WithTempDir(e.TempDir.Remote),
|
||||||
taskfile.ReaderWithDebugFunc(debugFunc),
|
taskfile.WithDebugFunc(debugFunc),
|
||||||
taskfile.ReaderWithPromptFunc(promptFunc),
|
taskfile.WithPromptFunc(promptFunc),
|
||||||
)
|
)
|
||||||
graph, err := reader.Read()
|
graph, err := reader.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,14 +28,14 @@ Continue?`
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// ReaderDebugFunc is a function that is called when the [Reader] wants to
|
// DebugFunc is a function that can be called to log debug messages.
|
||||||
// log debug messages
|
DebugFunc func(string)
|
||||||
ReaderDebugFunc func(string)
|
// PromptFunc is a function that can be called to prompt the user for input.
|
||||||
// ReaderPromptFunc is a function that is called when the [Reader] wants to
|
PromptFunc func(string) error
|
||||||
// prompt the user in some way
|
// A ReaderOption is any type that can apply a configuration to a [Reader].
|
||||||
ReaderPromptFunc func(string) error
|
ReaderOption interface {
|
||||||
// ReaderOption is a function that configures a [Reader].
|
ApplyToReader(*Reader)
|
||||||
ReaderOption func(*Reader)
|
}
|
||||||
// A Reader will recursively read Taskfiles from a given [Node] and build a
|
// A Reader will recursively read Taskfiles from a given [Node] and build a
|
||||||
// [ast.TaskfileGraph] from them.
|
// [ast.TaskfileGraph] from them.
|
||||||
Reader struct {
|
Reader struct {
|
||||||
@ -46,8 +46,8 @@ type (
|
|||||||
offline bool
|
offline bool
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
tempDir string
|
tempDir string
|
||||||
debugFunc ReaderDebugFunc
|
debugFunc DebugFunc
|
||||||
promptFunc ReaderPromptFunc
|
promptFunc PromptFunc
|
||||||
promptMutex sync.Mutex
|
promptMutex sync.Mutex
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -78,72 +78,113 @@ func NewReader(
|
|||||||
// the [Reader].
|
// the [Reader].
|
||||||
func (r *Reader) Options(opts ...ReaderOption) {
|
func (r *Reader) Options(opts ...ReaderOption) {
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(r)
|
opt.ApplyToReader(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithInsecure allows the [Reader] to make insecure connections when
|
// WithInsecure allows the [Reader] to make insecure connections when reading
|
||||||
// reading remote taskfiles. By default, insecure connections are rejected.
|
// remote taskfiles. By default, insecure connections are rejected.
|
||||||
func ReaderWithInsecure(insecure bool) ReaderOption {
|
func WithInsecure(insecure bool) ReaderOption {
|
||||||
return func(r *Reader) {
|
return &insecureOption{insecure: insecure}
|
||||||
r.insecure = insecure
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithDownload forces the [Reader] to download a fresh copy of the
|
type insecureOption struct {
|
||||||
// taskfile from the remote source.
|
insecure bool
|
||||||
func ReaderWithDownload(download bool) ReaderOption {
|
|
||||||
return func(r *Reader) {
|
|
||||||
r.download = download
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithOffline stops the [Reader] from being able to make network
|
func (o *insecureOption) ApplyToReader(r *Reader) {
|
||||||
// connections. It will still be able to read local files and cached copies of
|
r.insecure = o.insecure
|
||||||
// remote files.
|
|
||||||
func ReaderWithOffline(offline bool) ReaderOption {
|
|
||||||
return func(r *Reader) {
|
|
||||||
r.offline = offline
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithTimeout sets the [Reader]'s timeout for fetching remote taskfiles.
|
// WithDownload forces the [Reader] to download a fresh copy of the taskfile
|
||||||
// By default, the timeout is set to 10 seconds.
|
// from the remote source.
|
||||||
func ReaderWithTimeout(timeout time.Duration) ReaderOption {
|
func WithDownload(download bool) ReaderOption {
|
||||||
return func(r *Reader) {
|
return &downloadOption{download: download}
|
||||||
r.timeout = timeout
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithTempDir sets the temporary directory that will be used by the
|
type downloadOption struct {
|
||||||
// [Reader]. By default, the reader uses [os.TempDir].
|
download bool
|
||||||
func ReaderWithTempDir(tempDir string) ReaderOption {
|
|
||||||
return func(r *Reader) {
|
|
||||||
r.tempDir = tempDir
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithDebugFunc sets the debug function to be used by the [Reader]. If
|
func (o *downloadOption) ApplyToReader(r *Reader) {
|
||||||
// set, this function will be called with debug messages. This can be useful if
|
r.download = o.download
|
||||||
// the caller wants to log debug messages from the [Reader]. By default, no
|
|
||||||
// debug function is set and the logs are not written.
|
|
||||||
func ReaderWithDebugFunc(debugFunc ReaderDebugFunc) ReaderOption {
|
|
||||||
return func(r *Reader) {
|
|
||||||
r.debugFunc = debugFunc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithPromptFunc sets the prompt function to be used by the [Reader]. If
|
// WithOffline stops the [Reader] from being able to make network connections.
|
||||||
// set, this function will be called with prompt messages. The function should
|
// It will still be able to read local files and cached copies of remote files.
|
||||||
|
func WithOffline(offline bool) ReaderOption {
|
||||||
|
return &offlineOption{offline: offline}
|
||||||
|
}
|
||||||
|
|
||||||
|
type offlineOption struct {
|
||||||
|
offline bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *offlineOption) ApplyToReader(r *Reader) {
|
||||||
|
r.offline = o.offline
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout sets the [Reader]'s timeout for fetching remote taskfiles. By
|
||||||
|
// default, the timeout is set to 10 seconds.
|
||||||
|
func WithTimeout(timeout time.Duration) ReaderOption {
|
||||||
|
return &timeoutOption{timeout: timeout}
|
||||||
|
}
|
||||||
|
|
||||||
|
type timeoutOption struct {
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *timeoutOption) ApplyToReader(r *Reader) {
|
||||||
|
r.timeout = o.timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTempDir sets the temporary directory that will be used by the [Reader].
|
||||||
|
// By default, the reader uses [os.TempDir].
|
||||||
|
func WithTempDir(tempDir string) ReaderOption {
|
||||||
|
return &tempDirOption{tempDir: tempDir}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tempDirOption struct {
|
||||||
|
tempDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *tempDirOption) ApplyToReader(r *Reader) {
|
||||||
|
r.tempDir = o.tempDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDebugFunc sets the debug function to be used by the [Reader]. If set,
|
||||||
|
// this function will be called with debug messages. This can be useful if the
|
||||||
|
// caller wants to log debug messages from the [Reader]. By default, no debug
|
||||||
|
// function is set and the logs are not written.
|
||||||
|
func WithDebugFunc(debugFunc DebugFunc) ReaderOption {
|
||||||
|
return &debugFuncOption{debugFunc: debugFunc}
|
||||||
|
}
|
||||||
|
|
||||||
|
type debugFuncOption struct {
|
||||||
|
debugFunc DebugFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *debugFuncOption) ApplyToReader(r *Reader) {
|
||||||
|
r.debugFunc = o.debugFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPromptFunc sets the prompt function to be used by the [Reader]. If set,
|
||||||
|
// this function will be called with prompt messages. The function should
|
||||||
// optionally log the message to the user and return nil if the prompt is
|
// optionally log the message to the user and return nil if the prompt is
|
||||||
// accepted and the execution should continue. Otherwise, it should return an
|
// accepted and the execution should continue. Otherwise, it should return an
|
||||||
// error which describes why the the prompt was rejected. This can then be
|
// error which describes why the prompt was rejected. This can then be caught
|
||||||
// caught and used later when calling the [Reader.Read] method. By default, no
|
// and used later when calling the [Reader.Read] method. By default, no prompt
|
||||||
// prompt function is set and all prompts are automatically accepted.
|
// function is set and all prompts are automatically accepted.
|
||||||
func ReaderWithPromptFunc(promptFunc ReaderPromptFunc) ReaderOption {
|
func WithPromptFunc(promptFunc PromptFunc) ReaderOption {
|
||||||
return func(r *Reader) {
|
return &promptFuncOption{promptFunc: promptFunc}
|
||||||
r.promptFunc = promptFunc
|
}
|
||||||
}
|
|
||||||
|
type promptFuncOption struct {
|
||||||
|
promptFunc PromptFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *promptFuncOption) ApplyToReader(r *Reader) {
|
||||||
|
r.promptFunc = o.promptFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read will read the Taskfile defined by the [Reader]'s [Node] and recurse
|
// Read will read the Taskfile defined by the [Reader]'s [Node] and recurse
|
||||||
@ -292,9 +333,9 @@ func (r *Reader) readNode(node Node) (*ast.Taskfile, error) {
|
|||||||
taskfileDecodeErr := &errors.TaskfileDecodeError{}
|
taskfileDecodeErr := &errors.TaskfileDecodeError{}
|
||||||
if errors.As(err, &taskfileDecodeErr) {
|
if errors.As(err, &taskfileDecodeErr) {
|
||||||
snippet := NewSnippet(b,
|
snippet := NewSnippet(b,
|
||||||
SnippetWithLine(taskfileDecodeErr.Line),
|
WithLine(taskfileDecodeErr.Line),
|
||||||
SnippetWithColumn(taskfileDecodeErr.Column),
|
WithColumn(taskfileDecodeErr.Column),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
)
|
)
|
||||||
return nil, taskfileDecodeErr.WithFileInfo(node.Location(), snippet.String())
|
return nil, taskfileDecodeErr.WithFileInfo(node.Location(), snippet.String())
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// SnippetOption is a function that configures a [Snippet].
|
// A SnippetOption is any type that can apply a configuration to a [Snippet].
|
||||||
SnippetOption func(*Snippet)
|
SnippetOption interface {
|
||||||
|
ApplyToSnippet(*Snippet)
|
||||||
|
}
|
||||||
// A Snippet is a syntax highlighted snippet of a Taskfile with optional
|
// A Snippet is a syntax highlighted snippet of a Taskfile with optional
|
||||||
// padding and a line and column indicator.
|
// padding and a line and column indicator.
|
||||||
Snippet struct {
|
Snippet struct {
|
||||||
@ -55,9 +57,7 @@ type (
|
|||||||
// determines the number of lines to include before and after the chosen line.
|
// determines the number of lines to include before and after the chosen line.
|
||||||
func NewSnippet(b []byte, opts ...SnippetOption) *Snippet {
|
func NewSnippet(b []byte, opts ...SnippetOption) *Snippet {
|
||||||
snippet := &Snippet{}
|
snippet := &Snippet{}
|
||||||
for _, opt := range opts {
|
snippet.Options(opts...)
|
||||||
opt(snippet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Syntax highlight the input and split it into lines
|
// Syntax highlight the input and split it into lines
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
@ -80,40 +80,61 @@ func NewSnippet(b []byte, opts ...SnippetOption) *Snippet {
|
|||||||
// to the [Snippet].
|
// to the [Snippet].
|
||||||
func (s *Snippet) Options(opts ...SnippetOption) {
|
func (s *Snippet) Options(opts ...SnippetOption) {
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(s)
|
opt.ApplyToSnippet(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnippetWithLine specifies the line number that the [Snippet] should center
|
// WithLine specifies the line number that the [Snippet] should center around
|
||||||
// around and point to.
|
// and point to.
|
||||||
func SnippetWithLine(line int) SnippetOption {
|
func WithLine(line int) SnippetOption {
|
||||||
return func(snippet *Snippet) {
|
return &lineOption{line: line}
|
||||||
snippet.line = line
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnippetWithColumn specifies the column number that the [Snippet] should
|
type lineOption struct {
|
||||||
// point to.
|
line int
|
||||||
func SnippetWithColumn(column int) SnippetOption {
|
|
||||||
return func(snippet *Snippet) {
|
|
||||||
snippet.column = column
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnippetWithPadding specifies the number of lines to include before and after
|
func (o *lineOption) ApplyToSnippet(s *Snippet) {
|
||||||
// the selected line in the [Snippet].
|
s.line = o.line
|
||||||
func SnippetWithPadding(padding int) SnippetOption {
|
|
||||||
return func(snippet *Snippet) {
|
|
||||||
snippet.padding = padding
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnippetWithNoIndicators specifies that the [Snippet] should not include line
|
// WithColumn specifies the column number that the [Snippet] should point to.
|
||||||
// or column indicators.
|
func WithColumn(column int) SnippetOption {
|
||||||
func SnippetWithNoIndicators() SnippetOption {
|
return &columnOption{column: column}
|
||||||
return func(snippet *Snippet) {
|
}
|
||||||
snippet.noIndicators = true
|
|
||||||
}
|
type columnOption struct {
|
||||||
|
column int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *columnOption) ApplyToSnippet(s *Snippet) {
|
||||||
|
s.column = o.column
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPadding specifies the number of lines to include before and after the
|
||||||
|
// selected line in the [Snippet].
|
||||||
|
func WithPadding(padding int) SnippetOption {
|
||||||
|
return &paddingOption{padding: padding}
|
||||||
|
}
|
||||||
|
|
||||||
|
type paddingOption struct {
|
||||||
|
padding int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *paddingOption) ApplyToSnippet(s *Snippet) {
|
||||||
|
s.padding = o.padding
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNoIndicators specifies that the [Snippet] should not include line or
|
||||||
|
// column indicators.
|
||||||
|
func WithNoIndicators() SnippetOption {
|
||||||
|
return &noIndicatorsOption{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noIndicatorsOption struct{}
|
||||||
|
|
||||||
|
func (o *noIndicatorsOption) ApplyToSnippet(s *Snippet) {
|
||||||
|
s.noIndicators = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Snippet) String() string {
|
func (s *Snippet) String() string {
|
||||||
|
@ -31,8 +31,8 @@ func TestNewSnippet(t *testing.T) {
|
|||||||
name: "first line, first column",
|
name: "first line, first column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: &Snippet{
|
want: &Snippet{
|
||||||
linesRaw: []string{
|
linesRaw: []string{
|
||||||
@ -52,9 +52,9 @@ func TestNewSnippet(t *testing.T) {
|
|||||||
name: "first line, first column, padding=2",
|
name: "first line, first column, padding=2",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: &Snippet{
|
want: &Snippet{
|
||||||
linesRaw: []string{
|
linesRaw: []string{
|
||||||
@ -96,8 +96,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "empty",
|
name: "empty",
|
||||||
b: []byte{},
|
b: []byte{},
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
@ -110,7 +110,7 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "1st line, 0th column (line indicator only)",
|
name: "1st line, 0th column (line indicator only)",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
},
|
},
|
||||||
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -118,7 +118,7 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "0th line, 1st column (column indicator only)",
|
name: "0th line, 1st column (column indicator only)",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
@ -126,8 +126,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "0th line, 1st column, padding=2 (column indicator only)",
|
name: "0th line, 1st column, padding=2 (column indicator only)",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: " 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 2 | \x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: " 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 2 | \x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -135,8 +135,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "1st line, 1st column",
|
name: "1st line, 1st column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -144,8 +144,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "1st line, 10th column",
|
name: "1st line, 10th column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(10),
|
WithColumn(10),
|
||||||
},
|
},
|
||||||
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -153,9 +153,9 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "1st line, 1st column, padding=2",
|
name: "1st line, 1st column, padding=2",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 2 | \x1b[1m\x1b[30m\x1b[0m\n 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 2 | \x1b[1m\x1b[30m\x1b[0m\n 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -163,9 +163,9 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "1st line, 10th column, padding=2",
|
name: "1st line, 10th column, padding=2",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(1),
|
WithLine(1),
|
||||||
SnippetWithColumn(10),
|
WithColumn(10),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 2 | \x1b[1m\x1b[30m\x1b[0m\n 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: "> 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 2 | \x1b[1m\x1b[30m\x1b[0m\n 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -173,8 +173,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "5th line, 1st column",
|
name: "5th line, 1st column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(5),
|
WithLine(5),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: "> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: "> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -182,8 +182,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "5th line, 5th column",
|
name: "5th line, 5th column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(5),
|
WithLine(5),
|
||||||
SnippetWithColumn(5),
|
WithColumn(5),
|
||||||
},
|
},
|
||||||
want: "> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: "> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -191,9 +191,9 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "5th line, 5th column, padding=2",
|
name: "5th line, 5th column, padding=2",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(5),
|
WithLine(5),
|
||||||
SnippetWithColumn(5),
|
WithColumn(5),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: " 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 4 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mdefault\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 6 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mFOO\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mfoo\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 7 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mBAR\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mbar\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: " 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 4 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mdefault\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 6 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mFOO\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mfoo\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 7 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mBAR\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mbar\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -201,10 +201,10 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "5th line, 5th column, padding=2, no indicators",
|
name: "5th line, 5th column, padding=2, no indicators",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(5),
|
WithLine(5),
|
||||||
SnippetWithColumn(5),
|
WithColumn(5),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
SnippetWithNoIndicators(),
|
WithNoIndicators(),
|
||||||
},
|
},
|
||||||
want: " 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 4 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mdefault\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 6 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mFOO\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mfoo\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 7 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mBAR\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mbar\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: " 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 4 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mdefault\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 6 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mFOO\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mfoo\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 7 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mBAR\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mbar\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -212,8 +212,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "10th line, 1st column",
|
name: "10th line, 1st column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(10),
|
WithLine(10),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: "> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: "> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -221,8 +221,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "10th line, 23rd column",
|
name: "10th line, 23rd column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(10),
|
WithLine(10),
|
||||||
SnippetWithColumn(23),
|
WithColumn(23),
|
||||||
},
|
},
|
||||||
want: "> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: "> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -230,8 +230,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "10th line, 24th column (out of bounds)",
|
name: "10th line, 24th column (out of bounds)",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(10),
|
WithLine(10),
|
||||||
SnippetWithColumn(24),
|
WithColumn(24),
|
||||||
},
|
},
|
||||||
want: "> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: "> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -239,9 +239,9 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "10th line, 23rd column, padding=2",
|
name: "10th line, 23rd column, padding=2",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(10),
|
WithLine(10),
|
||||||
SnippetWithColumn(23),
|
WithColumn(23),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: " 8 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mcmds\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 9 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.FOO}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
want: " 8 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mcmds\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 9 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.FOO}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n> 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^",
|
||||||
},
|
},
|
||||||
@ -249,9 +249,9 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "5th line, 5th column, padding=100",
|
name: "5th line, 5th column, padding=100",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(5),
|
WithLine(5),
|
||||||
SnippetWithColumn(5),
|
WithColumn(5),
|
||||||
SnippetWithPadding(100),
|
WithPadding(100),
|
||||||
},
|
},
|
||||||
want: " 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 2 | \x1b[1m\x1b[30m\x1b[0m\n 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 4 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mdefault\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 6 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mFOO\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mfoo\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 7 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mBAR\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mbar\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 8 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mcmds\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 9 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.FOO}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: " 1 | \x1b[33mversion\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36m3\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 2 | \x1b[1m\x1b[30m\x1b[0m\n 3 | \x1b[33mtasks\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 4 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mdefault\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n> 5 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mvars\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n | ^\n 6 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mFOO\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mfoo\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 7 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mBAR\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m \x1b[0m\x1b[36mbar\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 8 | \x1b[1m\x1b[30m \x1b[0m\x1b[33mcmds\x1b[0m\x1b[1m\x1b[30m:\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 9 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.FOO}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
@ -259,8 +259,8 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "11th line (out of bounds), 1st column",
|
name: "11th line (out of bounds), 1st column",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(11),
|
WithLine(11),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
},
|
},
|
||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
@ -268,9 +268,9 @@ func TestSnippetString(t *testing.T) {
|
|||||||
name: "11th line (out of bounds), 1st column, padding=2",
|
name: "11th line (out of bounds), 1st column, padding=2",
|
||||||
b: []byte(sample),
|
b: []byte(sample),
|
||||||
opts: []SnippetOption{
|
opts: []SnippetOption{
|
||||||
SnippetWithLine(11),
|
WithLine(11),
|
||||||
SnippetWithColumn(1),
|
WithColumn(1),
|
||||||
SnippetWithPadding(2),
|
WithPadding(2),
|
||||||
},
|
},
|
||||||
want: " 9 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.FOO}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
want: " 9 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.FOO}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m\n 10 | \x1b[1m\x1b[30m \x1b[0m\x1b[1m\x1b[30m- \x1b[0m\x1b[36mecho \"{{.BAR}}\"\x1b[0m\x1b[1m\x1b[30m\x1b[0m",
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user