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