diff options
Diffstat (limited to 'vendor/go.step.sm/cli-utils')
30 files changed, 0 insertions, 10556 deletions
diff --git a/vendor/go.step.sm/cli-utils/LICENSE b/vendor/go.step.sm/cli-utils/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/vendor/go.step.sm/cli-utils/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/go.step.sm/cli-utils/command/command.go b/vendor/go.step.sm/cli-utils/command/command.go deleted file mode 100644 index a51c2ff..0000000 --- a/vendor/go.step.sm/cli-utils/command/command.go +++ /dev/null @@ -1,44 +0,0 @@ -package command - -import ( - "os" - - "github.com/urfave/cli" - "go.step.sm/cli-utils/step" - "go.step.sm/cli-utils/usage" -) - -var cmds []cli.Command -var currentContext *cli.Context - -func init() { - os.Unsetenv(step.IgnoreEnvVar) - cmds = []cli.Command{ - usage.HelpCommand(), - } -} - -// Register adds the given command to the global list of commands. -// It sets recursively the command Flags environment variables. -func Register(c cli.Command) { - step.SetEnvVar(&c) - cmds = append(cmds, c) -} - -// Retrieve returns all commands -func Retrieve() []cli.Command { - return cmds -} - -// ActionFunc returns a cli.ActionFunc that stores the context. -func ActionFunc(fn cli.ActionFunc) cli.ActionFunc { - return func(ctx *cli.Context) error { - currentContext = ctx - return fn(ctx) - } -} - -// IsForce returns if the force flag was passed -func IsForce() bool { - return currentContext != nil && currentContext.Bool("force") -} diff --git a/vendor/go.step.sm/cli-utils/errs/errs.go b/vendor/go.step.sm/cli-utils/errs/errs.go deleted file mode 100644 index 998c4f1..0000000 --- a/vendor/go.step.sm/cli-utils/errs/errs.go +++ /dev/null @@ -1,330 +0,0 @@ -package errs - -import ( - "fmt" - "os" - "strings" - - "errors" - - pkge "github.com/pkg/errors" - "github.com/urfave/cli" -) - -// NewError returns a new Error for the given format and arguments -func NewError(format string, args ...interface{}) error { - return fmt.Errorf(format, args...) -} - -// NewExitError returns an error that the urfave/cli package will handle and -// will show the given error and exit with the given code. -func NewExitError(err error, exitCode int) error { - return cli.NewExitError(err, exitCode) -} - -// Wrap returns a new error wrapped by the given error with the given message. -// If the given error implements the errors.Cause interface, the base error is -// used. If the given error is wrapped by a package name, the error wrapped -// will be the string after the last colon. -// -// TODO: this should be refactored to use Go's wrap facilities. -func Wrap(err error, format string, args ...interface{}) error { - if err == nil { - return nil - } - cause := pkge.Cause(err) - if errors.Is(err, cause) { - str := err.Error() - if i := strings.LastIndexByte(str, ':'); i >= 0 { - str = strings.TrimSpace(str[i:]) - return pkge.Wrapf(errors.New(str), format, args...) - } - } - return pkge.Wrapf(cause, format, args...) -} - -// InsecureCommand returns an error with a message saying that the current -// command requires the insecure flag. -func InsecureCommand(ctx *cli.Context) error { - return fmt.Errorf("'%s %s' requires the '--insecure' flag", ctx.App.Name, ctx.Command.Name) -} - -// EqualArguments returns an error saying that the given positional arguments -// cannot be equal. -func EqualArguments(ctx *cli.Context, arg1, arg2 string) error { - return fmt.Errorf("positional arguments <%s> and <%s> cannot be equal in '%s'", arg1, arg2, usage(ctx)) -} - -// MissingArguments returns an error with a missing arguments message for the -// given positional argument names. -func MissingArguments(ctx *cli.Context, argNames ...string) error { - switch len(argNames) { - case 0: - return fmt.Errorf("missing positional arguments in '%s'", usage(ctx)) - case 1: - return fmt.Errorf("missing positional argument <%s> in '%s'", argNames[0], usage(ctx)) - default: - args := make([]string, len(argNames)) - for i, name := range argNames { - args[i] = "<" + name + ">" - } - return fmt.Errorf("missing positional arguments %s in '%s'", strings.Join(args, " "), usage(ctx)) - } -} - -// NumberOfArguments returns nil if the number of positional arguments is -// equal to the required one. It will return an appropriate error if they are -// not. -func NumberOfArguments(ctx *cli.Context, required int) error { - n := ctx.NArg() - switch { - case n < required: - return TooFewArguments(ctx) - case n > required: - return TooManyArguments(ctx) - default: - return nil - } -} - -// MinMaxNumberOfArguments returns nil if the number of positional arguments -// between the min/max range. It will return an appropriate error if they are -// not. -func MinMaxNumberOfArguments(ctx *cli.Context, min, max int) error { - n := ctx.NArg() - switch { - case n < min: - return TooFewArguments(ctx) - case n > max: - return TooManyArguments(ctx) - default: - return nil - } -} - -// TooFewArguments returns an error with a few arguments were provided message. -func TooFewArguments(ctx *cli.Context) error { - return fmt.Errorf("not enough positional arguments were provided in '%s'", usage(ctx)) -} - -// TooManyArguments returns an error with a too many arguments were provided -// message. -func TooManyArguments(ctx *cli.Context) error { - return fmt.Errorf("too many positional arguments were provided in '%s'", usage(ctx)) -} - -// InsecureArgument returns an error with the given argument requiring the -// --insecure flag. -func InsecureArgument(_ *cli.Context, name string) error { - return fmt.Errorf("positional argument <%s> requires the '--insecure' flag", name) -} - -// FlagValueInsecure returns an error with the given flag and value requiring -// the --insecure flag. -func FlagValueInsecure(_ *cli.Context, flag, value string) error { - return fmt.Errorf("flag '--%s %s' requires the '--insecure' flag", flag, value) -} - -// InvalidFlagValue returns an error with the given value being missing or -// invalid for the given flag. Optionally it lists the given formatted options -// at the end. -func InvalidFlagValue(ctx *cli.Context, flag, value, options string) error { - if options != "" { - options = fmt.Sprintf("options are %s", options) - } - - return InvalidFlagValueMsg(ctx, flag, value, options) -} - -// InvalidFlagValueMsg returns an error with the given value being missing or -// invalid for the given flag. Optionally it returns an error message to aid -// in debugging. -func InvalidFlagValueMsg(_ *cli.Context, flag, value, msg string) error { - var format string - if value == "" { - format = fmt.Sprintf("missing value for flag '--%s'", flag) - } else { - format = fmt.Sprintf("invalid value '%s' for flag '--%s'", value, flag) - } - - if msg == "" { - return errors.New(format) - } - - return errors.New(format + "; " + msg) -} - -// IncompatibleFlag returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlag(_ *cli.Context, flag, value string) error { - return fmt.Errorf("flag '--%s' is incompatible with '%s'", flag, value) -} - -// IncompatibleFlagWithFlag returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlagWithFlag(_ *cli.Context, flag, withFlag string) error { - return fmt.Errorf("flag '--%s' is incompatible with '--%s'", flag, withFlag) -} - -// IncompatibleFlagValue returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlagValue(_ *cli.Context, flag, incompatibleWith, - incompatibleWithValue string) error { - return fmt.Errorf("flag '--%s' is incompatible with flag '--%s %s'", - flag, incompatibleWith, incompatibleWithValue) -} - -// IncompatibleFlagValues returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlagValues(ctx *cli.Context, flag, value, incompatibleWith, - incompatibleWithValue string) error { - return IncompatibleFlagValueWithFlagValue(ctx, flag, value, incompatibleWith, - incompatibleWithValue, "") -} - -// IncompatibleFlagValueWithFlagValue returns an error with the given value -// being missing or invalid for the given flag. Optionally it lists the given -// formatted options at the end. -func IncompatibleFlagValueWithFlagValue(_ *cli.Context, flag, value, - withFlag, withValue, options string) error { - format := fmt.Sprintf("flag '--%s %s' is incompatible with flag '--%s %s'", - flag, value, withFlag, withValue) - - if options == "" { - return errors.New(format) - } - - // TODO: check whether double space before options is intended - return fmt.Errorf("%s\n\n Option(s): --%s %s", format, withFlag, options) -} - -// RequiredFlag returns an error with the required flag message. -func RequiredFlag(ctx *cli.Context, flag string) error { - return fmt.Errorf("'%s %s' requires the '--%s' flag", ctx.App.HelpName, - ctx.Command.Name, flag) -} - -// RequiredWithFlag returns an error with the required flag message with another flag. -func RequiredWithFlag(_ *cli.Context, flag, required string) error { - return fmt.Errorf("flag '--%s' requires the '--%s' flag", flag, required) -} - -// RequiredWithFlagValue returns an error with the required flag message. -func RequiredWithFlagValue(_ *cli.Context, flag, value, required string) error { - return fmt.Errorf("'--%s %s' requires the '--%s' flag", flag, value, required) -} - -// RequiredWithProvisionerTypeFlag returns an error with the required flag message. -func RequiredWithProvisionerTypeFlag(_ *cli.Context, provisionerType, required string) error { - return fmt.Errorf("provisioner type '%s' requires the '--%s' flag", provisionerType, required) -} - -// RequiredInsecureFlag returns an error with the given flag requiring the -// insecure flag message. -func RequiredInsecureFlag(_ *cli.Context, flag string) error { - return fmt.Errorf("flag '--%s' requires the '--insecure' flag", flag) -} - -// RequiredSubtleFlag returns an error with the given flag requiring the -// subtle flag message.. -func RequiredSubtleFlag(_ *cli.Context, flag string) error { - return fmt.Errorf("flag '--%s' requires the '--subtle' flag", flag) -} - -// RequiredUnlessInsecureFlag returns an error with the required flag message unless -// the insecure flag is used. -func RequiredUnlessInsecureFlag(ctx *cli.Context, flag string) error { - return RequiredUnlessFlag(ctx, flag, "insecure") -} - -// RequiredUnlessFlag returns an error with the required flag message unless -// the specified flag is used. -func RequiredUnlessFlag(_ *cli.Context, flag, unlessFlag string) error { - return fmt.Errorf("flag '--%s' is required unless the '--%s' flag is provided", flag, unlessFlag) -} - -// RequiredUnlessSubtleFlag returns an error with the required flag message unless -// the subtle flag is used. -func RequiredUnlessSubtleFlag(ctx *cli.Context, flag string) error { - return RequiredUnlessFlag(ctx, flag, "subtle") -} - -// RequiredOrFlag returns an error with a list of flags being required messages. -func RequiredOrFlag(_ *cli.Context, flags ...string) error { - params := make([]string, len(flags)) - for i, flag := range flags { - params[i] = "--" + flag - } - return fmt.Errorf("one of flag %s is required", strings.Join(params, " or ")) -} - -// RequiredWithOrFlag returns an error with a list of flags at least one of which -// is required in conjunction with the last flag in the list. -func RequiredWithOrFlag(_ *cli.Context, withFlag string, flags ...string) error { - params := make([]string, len(flags)) - for i := 0; i < len(flags); i++ { - params[i] = "--" + flags[i] - } - return fmt.Errorf("one of flag %s is required with flag --%s", strings.Join(params, " or "), withFlag) -} - -// MinSizeFlag returns an error with a greater or equal message message for -// the given flag and size. -func MinSizeFlag(_ *cli.Context, flag, size string) error { - return fmt.Errorf("flag '--%s' must be greater than or equal to %s", flag, size) -} - -// MinSizeInsecureFlag returns an error with a requiring --insecure flag -// message with the given flag an size. -func MinSizeInsecureFlag(_ *cli.Context, flag, size string) error { - return fmt.Errorf("flag '--%s' requires at least %s unless '--insecure' flag is provided", flag, size) -} - -// MutuallyExclusiveFlags returns an error with mutually exclusive message for -// the given flags. -func MutuallyExclusiveFlags(_ *cli.Context, flag1, flag2 string) error { - return fmt.Errorf("flag '--%s' and flag '--%s' are mutually exclusive", flag1, flag2) -} - -// UnsupportedFlag returns an error with a message saying that the given flag is -// not yet supported. -func UnsupportedFlag(_ *cli.Context, flag string) error { - return fmt.Errorf("flag '--%s' is not yet supported", flag) -} - -// usage returns the command usage text if set or a default usage string. -func usage(ctx *cli.Context) string { - if ctx.Command.UsageText == "" { - return fmt.Sprintf("%s %s [command options]", ctx.App.HelpName, ctx.Command.Name) - } - // keep just the first line and remove markdown - lines := strings.Split(ctx.Command.UsageText, "\n") - return strings.ReplaceAll(lines[0], "**", "") -} - -// FileError is a wrapper for errors of the os package. -func FileError(err error, filename string) error { - if err == nil { - return nil - } - var ( - pathErr *os.PathError - linkErr *os.LinkError - syscallErr *os.SyscallError - ) - switch { - case errors.As(err, &pathErr): - return fmt.Errorf("%s %s failed: %w", pathErr.Op, pathErr.Path, pathErr.Err) - case errors.As(err, &linkErr): - return fmt.Errorf("%s %s %s failed: %w", linkErr.Op, linkErr.Old, linkErr.New, linkErr.Err) - case errors.As(err, &syscallErr): - return fmt.Errorf("%s failed: %w", syscallErr.Syscall, syscallErr.Err) - default: - return Wrap(err, "unexpected error on %s", filename) - } -} - -// FriendlyError is an interface for returning friendly error messages to the user. -type FriendlyError interface { - Message() string -} diff --git a/vendor/go.step.sm/cli-utils/fileutil/file.go b/vendor/go.step.sm/cli-utils/fileutil/file.go deleted file mode 100644 index 04e00a2..0000000 --- a/vendor/go.step.sm/cli-utils/fileutil/file.go +++ /dev/null @@ -1,121 +0,0 @@ -package fileutil - -import ( - "os" - - "github.com/pkg/errors" -) - -// File represents a wrapper on os.File that supports read, write, seek and -// close methods, but they won't be called if an error occurred before. -type File struct { - File *os.File - err error -} - -// OpenFile calls os.OpenFile method and returns the os.File wrapped. -func OpenFile(name string, flag int, perm os.FileMode) (*File, error) { - f, err := os.OpenFile(name, flag, perm) - if err != nil { - return nil, FileError(err, name) - } - return &File{ - File: f, - }, nil -} - -// error writes f.err if it's not set and returns f.err. -func (f *File) error(err error) error { - if f.err == nil && err != nil { - f.err = FileError(err, f.File.Name()) - } - return f.err -} - -// Close wraps `func (*os.File) Close` it will always call Close but the error -// return will be the first error thrown if any. -func (f *File) Close() error { - return f.error(f.File.Close()) -} - -// Read wraps `func (*os.File) Read` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) Read(b []byte) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.Read(b) - return n, f.error(err) -} - -// ReadAt wraps `func (*os.File) ReadAt` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) ReadAt(b []byte, off int64) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.ReadAt(b, off) - return n, f.error(err) -} - -// Seek wraps `func (*os.File) Seek` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) Seek(offset int64, whence int) (ret int64, err error) { - if f.err != nil { - return 0, f.err - } - ret, err = f.File.Seek(offset, whence) - return ret, f.error(err) -} - -// Write wraps `func (*os.File) Write` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) Write(b []byte) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.Write(b) - return n, f.error(err) -} - -// WriteAt wraps `func (*os.File) WriteAt` but doesn't perform the operation if -// a previous error was thrown. -func (f *File) WriteAt(b []byte, off int64) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.WriteAt(b, off) - return n, f.error(err) -} - -// WriteString wraps `func (*os.File) WriteString` but doesn't perform the -// operation if a previous error was thrown. -func (f *File) WriteString(s string) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.WriteString(s) - return n, f.error(err) -} - -// FileError is a wrapper for errors of the os package. -func FileError(err error, filename string) error { - if err == nil { - return nil - } - var ( - pathErr *os.PathError - linkErr *os.LinkError - syscallErr *os.SyscallError - ) - switch { - case errors.As(err, &pathErr): - return errors.Errorf("%s %s failed: %v", pathErr.Op, pathErr.Path, pathErr.Err) - case errors.As(err, &linkErr): - return errors.Errorf("%s %s %s failed: %v", linkErr.Op, linkErr.Old, linkErr.New, linkErr.Err) - case errors.As(err, &syscallErr): - return errors.Errorf("%s failed: %v", syscallErr.Syscall, syscallErr.Err) - default: - return errors.Wrapf(err, "unexpected error on %s", filename) - } -} diff --git a/vendor/go.step.sm/cli-utils/fileutil/write.go b/vendor/go.step.sm/cli-utils/fileutil/write.go deleted file mode 100644 index fd8b2cb..0000000 --- a/vendor/go.step.sm/cli-utils/fileutil/write.go +++ /dev/null @@ -1,231 +0,0 @@ -package fileutil - -import ( - "bufio" - "bytes" - "fmt" - "io" - "os" - "strings" - "time" - - "github.com/pkg/errors" - "go.step.sm/cli-utils/command" - "go.step.sm/cli-utils/ui" -) - -var ( - // ErrFileExists is the error returned if a file exists. - ErrFileExists = errors.New("file exists") - - // ErrIsDir is the error returned if the file is a directory. - ErrIsDir = errors.New("file is a directory") - - // SnippetHeader is the header of a step generated snippet in a - // configuration file. - SnippetHeader = "# autogenerated by step" - - // SnippetFooter is the header of a step generated snippet in a - // configuration file. - SnippetFooter = "# end" -) - -// WriteFile wraps ioutil.WriteFile with a prompt to overwrite a file if -// the file exists. It returns ErrFileExists if the user picks to not overwrite -// the file. If force is set to true, the prompt will not be presented and the -// file if exists will be overwritten. -func WriteFile(filename string, data []byte, perm os.FileMode) error { - if command.IsForce() { - return os.WriteFile(filename, data, perm) - } - - st, err := os.Stat(filename) - if err != nil { - if os.IsNotExist(err) { - return os.WriteFile(filename, data, perm) - } - return errors.Wrapf(err, "error reading information for %s", filename) - } - - if st.IsDir() { - return ErrIsDir - } - - str, err := ui.Prompt(fmt.Sprintf("Would you like to overwrite %s [y/n]", filename), ui.WithValidateYesNo()) - if err != nil { - return err - } - switch strings.ToLower(strings.TrimSpace(str)) { - case "y", "yes": - case "n", "no": - return ErrFileExists - } - - return os.WriteFile(filename, data, perm) -} - -// AppendNewLine appends the given data at the end of the file. If the last -// character of the file does not contain an LF it prepends it to the data. -func AppendNewLine(filename string, data []byte, perm os.FileMode) error { - f, err := OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, perm) - if err != nil { - return err - } - // Read last character - if st, err := f.File.Stat(); err == nil && st.Size() != 0 { - last := make([]byte, 1) - f.Seek(-1, 2) - f.Read(last) - if last[0] != '\n' { - f.WriteString("\n") - } - } - f.Write(data) - return f.Close() -} - -func writeChunk(filename string, data []byte, hasHeaderFooter bool, header, footer string, perm os.FileMode) error { - // Get file permissions - if st, err := os.Stat(filename); err == nil { - perm = st.Mode() - } else if !os.IsNotExist(err) { - return FileError(err, filename) - } - - // Read file contents - b, err := os.ReadFile(filename) - if err != nil && !os.IsNotExist(err) { - return FileError(err, filename) - } - - // Detect previous configuration - _, start, end := findConfiguration(bytes.NewReader(b), header, footer) - - // Replace previous configuration - f, err := OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, perm) - if err != nil { - return FileError(err, filename) - } - if len(b) > 0 { - f.Write(b[:start]) - if start == end { - f.WriteString("\n") - } - } - if !hasHeaderFooter { - fmt.Fprintf(f, "%s @ %s\n", header, time.Now().UTC().Format(time.RFC3339)) - } - f.Write(data) - if !bytes.HasSuffix(data, []byte("\n")) { - f.WriteString("\n") - } - if !hasHeaderFooter { - f.WriteString(footer + "\n") - } - if len(b) > 0 { - f.Write(b[end:]) - } - return f.Close() -} - -// WriteSnippet writes the given data into the given filename. It surrounds the -// data with a default header and footer, and it will replace the previous one. -func WriteSnippet(filename string, data []byte, perm os.FileMode) error { - return writeChunk(filename, data, false, SnippetHeader, SnippetFooter, perm) -} - -// PrependLine prepends the given line into the given filename and removes -// other instances of the line in the file. -func PrependLine(filename string, data []byte, perm os.FileMode) error { - // Get file permissions - if st, err := os.Stat(filename); err == nil { - perm = st.Mode() - } else if !os.IsNotExist(err) { - return FileError(err, filename) - } - - // Read file contents - b, err := os.ReadFile(filename) - if err != nil && !os.IsNotExist(err) { - return FileError(err, filename) - } - - line := string(data) - result := []string{string(data)} - for _, l := range strings.Split(string(b), "\n") { - if l != "" && !strings.HasPrefix(l, line) { - result = append(result, l) - } - } - - if err := os.WriteFile(filename, []byte(strings.Join(result, "\n")), perm); err != nil { - return FileError(err, filename) - } - return nil -} - -// RemoveLine removes a single line which contains the given substring from the -// given file. -func RemoveLine(filename, substr string) error { - var perm os.FileMode - // Get file permissions - st, err := os.Stat(filename) - switch { - case os.IsNotExist(err): - return nil - case err != nil: - return FileError(err, filename) - default: - perm = st.Mode() - } - - // Read file contents - b, err := os.ReadFile(filename) - if err != nil && !os.IsNotExist(err) { - return FileError(err, filename) - } - - old := strings.Split(string(b), "\n") - for i, l := range old { - if !strings.Contains(l, substr) { - continue - } - if err := os.WriteFile(filename, []byte(strings.Join(append(old[:i], old[i+1:]...), "\n")), perm); err != nil { - return FileError(err, filename) - } - break - } - - return nil -} - -type offsetCounter struct { - offset int64 -} - -func (o *offsetCounter) ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { - advance, token, err = bufio.ScanLines(data, atEOF) - o.offset += int64(advance) - return -} - -func findConfiguration(r io.Reader, header, footer string) (lines []string, start, end int64) { - var inConfig bool - counter := new(offsetCounter) - scanner := bufio.NewScanner(r) - scanner.Split(counter.ScanLines) - for scanner.Scan() { - line := scanner.Text() - switch { - case !inConfig && strings.HasPrefix(line, header): - inConfig = true - start = counter.offset - int64(len(line)+1) - case inConfig && strings.HasPrefix(line, footer): - return lines, start, counter.offset - case inConfig: - lines = append(lines, line) - } - } - - return lines, counter.offset, counter.offset -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/LICENSE.txt b/vendor/go.step.sm/cli-utils/pkg/blackfriday/LICENSE.txt deleted file mode 100644 index 2885af3..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/LICENSE.txt +++ /dev/null @@ -1,29 +0,0 @@ -Blackfriday is distributed under the Simplified BSD License: - -> Copyright © 2011 Russ Ross -> All rights reserved. -> -> Redistribution and use in source and binary forms, with or without -> modification, are permitted provided that the following conditions -> are met: -> -> 1. Redistributions of source code must retain the above copyright -> notice, this list of conditions and the following disclaimer. -> -> 2. Redistributions in binary form must reproduce the above -> copyright notice, this list of conditions and the following -> disclaimer in the documentation and/or other materials provided with -> the distribution. -> -> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -> POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/README.md b/vendor/go.step.sm/cli-utils/pkg/blackfriday/README.md deleted file mode 100644 index 2e0db35..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/README.md +++ /dev/null @@ -1,283 +0,0 @@ -Blackfriday [](https://travis-ci.org/russross/blackfriday) -=========== - -Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It -is paranoid about its input (so you can safely feed it user-supplied -data), it is fast, it supports common extensions (tables, smart -punctuation substitutions, etc.), and it is safe for all utf-8 -(unicode) input. - -HTML output is currently supported, along with Smartypants -extensions. - -It started as a translation from C of [Sundown][3]. - - -Installation ------------- - -Blackfriday is compatible with any modern Go release. With Go 1.7 and git -installed: - - go get gopkg.in/russross/blackfriday.v2 - -will download, compile, and install the package into your `$GOPATH` -directory hierarchy. Alternatively, you can achieve the same if you -import it into a project: - - import "gopkg.in/russross/blackfriday.v2" - -and `go get` without parameters. - - -Versions --------- - -Currently maintained and recommended version of Blackfriday is `v2`. It's being -developed on its own branch: https://github.com/russross/blackfriday/v2. You -should install and import it via [gopkg.in][6] at -`gopkg.in/russross/blackfriday.v2`. - -Version 2 offers a number of improvements over v1: - -* Cleaned up API -* A separate call to [`Parse`][4], which produces an abstract syntax tree for - the document -* Latest bug fixes -* Flexibility to easily add your own rendering extensions - -Potential drawbacks: - -* Our benchmarks show v2 to be slightly slower than v1. Currently in the - ballpark of around 15%. -* API breakage. If you can't afford modifying your code to adhere to the new API - and don't care too much about the new features, v2 is probably not for you. -* Several bug fixes are trailing behind and still need to be forward-ported to - v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for - tracking. - -Usage ------ - -For the most sensible markdown processing, it is as simple as getting your input -into a byte slice and calling: - -```go -output := blackfriday.Run(input) -``` - -Your input will be parsed and the output rendered with a set of most popular -extensions enabled. If you want the most basic feature set, corresponding with -the bare Markdown specification, use: - -```go -output := blackfriday.Run(input, blackfriday.WithNoExtensions()) -``` - -### Sanitize untrusted content - -Blackfriday itself does nothing to protect against malicious content. If you are -dealing with user-supplied markdown, we recommend running Blackfriday's output -through HTML sanitizer such as [Bluemonday][5]. - -Here's an example of simple usage of Blackfriday together with Bluemonday: - -```go -import ( - "github.com/microcosm-cc/bluemonday" - "github.com/russross/blackfriday" -) - -// ... -unsafe := blackfriday.Run(input) -html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) -``` - -### Custom options - -If you want to customize the set of options, use `blackfriday.WithExtensions`, -`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`. - -You can also check out `blackfriday-tool` for a more complete example -of how to use it. Download and install it using: - - go get github.com/russross/blackfriday-tool - -This is a simple command-line tool that allows you to process a -markdown file using a standalone program. You can also browse the -source directly on github if you are just looking for some example -code: - -* <http://github.com/russross/blackfriday-tool> - -Note that if you have not already done so, installing -`blackfriday-tool` will be sufficient to download and install -blackfriday in addition to the tool itself. The tool binary will be -installed in `$GOPATH/bin`. This is a statically-linked binary that -can be copied to wherever you need it without worrying about -dependencies and library versions. - - -Features --------- - -All features of Sundown are supported, including: - -* **Compatibility**. The Markdown v1.0.3 test suite passes with - the `--tidy` option. Without `--tidy`, the differences are - mostly in whitespace and entity escaping, where blackfriday is - more consistent and cleaner. - -* **Common extensions**, including table support, fenced code - blocks, autolinks, strikethroughs, non-strict emphasis, etc. - -* **Safety**. Blackfriday is paranoid when parsing, making it safe - to feed untrusted user input without fear of bad things - happening. The test suite stress tests this and there are no - known inputs that make it crash. If you find one, please let me - know and send me the input that does it. - - NOTE: "safety" in this context means *runtime safety only*. In order to - protect yourself against JavaScript injection in untrusted content, see - [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content). - -* **Fast processing**. It is fast enough to render on-demand in - most web applications without having to cache the output. - -* **Thread safety**. You can run multiple parsers in different - goroutines without ill effect. There is no dependence on global - shared state. - -* **Minimal dependencies**. Blackfriday only depends on standard - library packages in Go. The source code is pretty - self-contained, so it is easy to add to any project, including - Google App Engine projects. - -* **Standards compliant**. Output successfully validates using the - W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional. - - -Extensions ----------- - -In addition to the standard markdown syntax, this package -implements the following extensions: - -* **Intra-word emphasis supression**. The `_` character is - commonly used inside words when discussing code, so having - markdown interpret it as an emphasis command is usually the - wrong thing. Blackfriday lets you treat all emphasis markers as - normal characters when they occur inside a word. - -* **Tables**. Tables can be created by drawing them in the input - using a simple syntax: - - ``` - Name | Age - --------|------ - Bob | 27 - Alice | 23 - ``` - -* **Fenced code blocks**. In addition to the normal 4-space - indentation to mark code blocks, you can explicitly mark them - and supply a language (to make syntax highlighting simple). Just - mark it like this: - - ```go - func getTrue() bool { - return true - } - ``` - - You can use 3 or more backticks to mark the beginning of the - block, and the same number to mark the end of the block. - -* **Definition lists**. A simple definition list is made of a single-line - term followed by a colon and the definition for that term. - - Cat - : Fluffy animal everyone likes - - Internet - : Vector of transmission for pictures of cats - - Terms must be separated from the previous definition by a blank line. - -* **Footnotes**. A marker in the text that will become a superscript number; - a footnote definition that will be placed in a list of footnotes at the - end of the document. A footnote looks like this: - - This is a footnote.[^1] - - [^1]: the footnote text. - -* **Autolinking**. Blackfriday can find URLs that have not been - explicitly marked as links and turn them into links. - -* **Strikethrough**. Use two tildes (`~~`) to mark text that - should be crossed out. - -* **Hard line breaks**. With this extension enabled newlines in the input - translate into line breaks in the output. This extension is off by default. - -* **Smart quotes**. Smartypants-style punctuation substitution is - supported, turning normal double- and single-quote marks into - curly quotes, etc. - -* **LaTeX-style dash parsing** is an additional option, where `--` - is translated into `–`, and `---` is translated into - `—`. This differs from most smartypants processors, which - turn a single hyphen into an ndash and a double hyphen into an - mdash. - -* **Smart fractions**, where anything that looks like a fraction - is translated into suitable HTML (instead of just a few special - cases like most smartypant processors). For example, `4/5` - becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as - <sup>4</sup>⁄<sub>5</sub>. - - -Other renderers ---------------- - -Blackfriday is structured to allow alternative rendering engines. Here -are a few of note: - -* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown): - provides a GitHub Flavored Markdown renderer with fenced code block - highlighting, clickable heading anchor links. - - It's not customizable, and its goal is to produce HTML output - equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode), - except the rendering is performed locally. - -* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, - but for markdown. - -* [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex): - renders output as LaTeX. - - -Todo ----- - -* More unit testing -* Improve unicode support. It does not understand all unicode - rules (about what constitutes a letter, a punctuation symbol, - etc.), so it may fail to detect word boundaries correctly in - some instances. It is safe on all utf-8 input. - - -License -------- - -[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt) - - - [1]: https://daringfireball.net/projects/markdown/ "Markdown" - [2]: https://golang.org/ "Go Language" - [3]: https://github.com/vmg/sundown "Sundown" - [4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func" - [5]: https://github.com/microcosm-cc/bluemonday "Bluemonday" - [6]: https://labix.org/gopkg.in "gopkg.in" diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/block.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/block.go deleted file mode 100644 index 918d656..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/block.go +++ /dev/null @@ -1,1559 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// Functions to parse block-level elements. -// - -//nolint:gocritic,revive,ineffassign,gosimple,wastedassign // ignore blackfriday -package blackfriday - -import ( - "bytes" - "html" - "regexp" - - "github.com/shurcooL/sanitized_anchor_name" -) - -const ( - charEntity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});" - escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]" -) - -var ( - reBackslashOrAmp = regexp.MustCompile("[\\&]") - reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + escapable + "|" + charEntity) -) - -// Parse block-level data. -// Note: this function and many that it calls assume that -// the input buffer ends with a newline. -func (p *Markdown) block(data []byte) { - // this is called recursively: enforce a maximum depth - if p.nesting >= p.maxNesting { - return - } - p.nesting++ - - // parse out one block-level construct at a time - for len(data) > 0 { - // prefixed heading: - // - // # Heading 1 - // ## Heading 2 - // ... - // ###### Heading 6 - if p.isPrefixHeading(data) { - data = data[p.prefixHeading(data):] - continue - } - - // block of preformatted HTML: - // - // <div> - // ... - // </div> - if data[0] == '<' { - if i := p.html(data, true); i > 0 { - data = data[i:] - continue - } - } - - // title block - // - // % stuff - // % more stuff - // % even more stuff - if p.extensions&Titleblock != 0 { - if data[0] == '%' { - if i := p.titleBlock(data, true); i > 0 { - data = data[i:] - continue - } - } - } - - // blank lines. note: returns the # of bytes to skip - if i := p.isEmpty(data); i > 0 { - data = data[i:] - continue - } - - // indented code block: - // - // func max(a, b int) int { - // if a > b { - // return a - // } - // return b - // } - if p.codePrefix(data) > 0 { - data = data[p.code(data):] - continue - } - - // fenced code block: - // - // ``` go - // func fact(n int) int { - // if n <= 1 { - // return n - // } - // return n * fact(n-1) - // } - // ``` - if p.extensions&FencedCode != 0 { - if i := p.fencedCodeBlock(data, true); i > 0 { - data = data[i:] - continue - } - } - - // horizontal rule: - // - // ------ - // or - // ****** - // or - // ______ - if p.isHRule(data) { - p.addBlock(HorizontalRule, nil) - var i int - for i = 0; i < len(data) && data[i] != '\n'; i++ { - } - data = data[i:] - continue - } - - // block quote: - // - // > A big quote I found somewhere - // > on the web - if p.quotePrefix(data) > 0 { - data = data[p.quote(data):] - continue - } - - // table: - // - // Name | Age | Phone - // ------|-----|--------- - // Bob | 31 | 555-1234 - // Alice | 27 | 555-4321 - if p.extensions&Tables != 0 { - if i := p.table(data); i > 0 { - data = data[i:] - continue - } - } - - // an itemized/unordered list: - // - // * Item 1 - // * Item 2 - // - // also works with + or - - if p.uliPrefix(data) > 0 { - data = data[p.list(data, 0):] - continue - } - - // a numbered/ordered list: - // - // 1. Item 1 - // 2. Item 2 - if p.oliPrefix(data) > 0 { - data = data[p.list(data, ListTypeOrdered):] - continue - } - - // definition lists: - // - // Term 1 - // : Definition a - // : Definition b - // - // Term 2 - // : Definition c - if p.extensions&DefinitionLists != 0 { - if p.dliPrefix(data) > 0 { - data = data[p.list(data, ListTypeDefinition):] - continue - } - } - - // anything else must look like a normal paragraph - // note: this finds underlined headings, too - data = data[p.paragraph(data):] - } - - p.nesting-- -} - -func (p *Markdown) addBlock(typ NodeType, content []byte) *Node { - p.closeUnmatchedBlocks() - container := p.addChild(typ, 0) - container.content = content - return container -} - -func (p *Markdown) isPrefixHeading(data []byte) bool { - if data[0] != '#' { - return false - } - - if p.extensions&SpaceHeadings != 0 { - level := 0 - for level < 6 && level < len(data) && data[level] == '#' { - level++ - } - if level == len(data) || data[level] != ' ' { - return false - } - } - return true -} - -func (p *Markdown) prefixHeading(data []byte) int { - level := 0 - for level < 6 && level < len(data) && data[level] == '#' { - level++ - } - i := skipChar(data, level, ' ') - end := skipUntilChar(data, i, '\n') - skip := end - id := "" - if p.extensions&HeadingIDs != 0 { - j, k := 0, 0 - // find start/end of heading id - for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ { - } - for k = j + 1; k < end && data[k] != '}'; k++ { - } - // extract heading id iff found - if j < end && k < end { - id = string(data[j+2 : k]) - end = j - skip = k + 1 - for end > 0 && data[end-1] == ' ' { - end-- - } - } - } - for end > 0 && data[end-1] == '#' { - if isBackslashEscaped(data, end-1) { - break - } - end-- - } - for end > 0 && data[end-1] == ' ' { - end-- - } - if end > i { - if id == "" && p.extensions&AutoHeadingIDs != 0 { - id = sanitized_anchor_name.Create(string(data[i:end])) - } - block := p.addBlock(Heading, data[i:end]) - block.HeadingID = id - block.Level = level - } - return skip -} - -func (p *Markdown) isUnderlinedHeading(data []byte) int { - // test of level 1 heading - if data[0] == '=' { - i := skipChar(data, 1, '=') - i = skipChar(data, i, ' ') - if i < len(data) && data[i] == '\n' { - return 1 - } - return 0 - } - - // test of level 2 heading - if data[0] == '-' { - i := skipChar(data, 1, '-') - i = skipChar(data, i, ' ') - if i < len(data) && data[i] == '\n' { - return 2 - } - return 0 - } - - return 0 -} - -func (p *Markdown) titleBlock(data []byte, doRender bool) int { - if data[0] != '%' { - return 0 - } - splitData := bytes.Split(data, []byte("\n")) - var i int - for idx, b := range splitData { - if !bytes.HasPrefix(b, []byte("%")) { - i = idx // - 1 - break - } - } - - data = bytes.Join(splitData[0:i], []byte("\n")) - consumed := len(data) - data = bytes.TrimPrefix(data, []byte("% ")) - data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1) - block := p.addBlock(Heading, data) - block.Level = 1 - block.IsTitleblock = true - - return consumed -} - -func (p *Markdown) html(data []byte, doRender bool) int { - var i, j int - - // identify the opening tag - if data[0] != '<' { - return 0 - } - curtag, tagfound := p.htmlFindTag(data[1:]) - - // handle special cases - if !tagfound { - // check for an HTML comment - if size := p.htmlComment(data, doRender); size > 0 { - return size - } - - // check for an <hr> tag - if size := p.htmlHr(data, doRender); size > 0 { - return size - } - - // no special case recognized - return 0 - } - - // look for an unindented matching closing tag - // followed by a blank line - found := false - /* - closetag := []byte("\n</" + curtag + ">") - j = len(curtag) + 1 - for !found { - // scan for a closing tag at the beginning of a line - if skip := bytes.Index(data[j:], closetag); skip >= 0 { - j += skip + len(closetag) - } else { - break - } - - // see if it is the only thing on the line - if skip := p.isEmpty(data[j:]); skip > 0 { - // see if it is followed by a blank line/eof - j += skip - if j >= len(data) { - found = true - i = j - } else { - if skip := p.isEmpty(data[j:]); skip > 0 { - j += skip - found = true - i = j - } - } - } - } - */ - - // if not found, try a second pass looking for indented match - // but not if tag is "ins" or "del" (following original Markdown.pl) - if !found && curtag != "ins" && curtag != "del" { - i = 1 - for i < len(data) { - i++ - for i < len(data) && !(data[i-1] == '<' && data[i] == '/') { - i++ - } - - if i+2+len(curtag) >= len(data) { - break - } - - j = p.htmlFindEnd(curtag, data[i-1:]) - - if j > 0 { - i += j - 1 - found = true - break - } - } - } - - if !found { - return 0 - } - - // the end of the block has been found - if doRender { - // trim newlines - end := i - for end > 0 && data[end-1] == '\n' { - end-- - } - finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end])) - } - - return i -} - -func finalizeHTMLBlock(block *Node) { - block.Literal = block.content - block.content = nil -} - -// HTML comment, lax form -func (p *Markdown) htmlComment(data []byte, doRender bool) int { - i := p.inlineHTMLComment(data) - // needs to end with a blank line - if j := p.isEmpty(data[i:]); j > 0 { - size := i + j - if doRender { - // trim trailing newlines - end := size - for end > 0 && data[end-1] == '\n' { - end-- - } - block := p.addBlock(HTMLBlock, data[:end]) - finalizeHTMLBlock(block) - } - return size - } - return 0 -} - -// HR, which is the only self-closing block tag considered -func (p *Markdown) htmlHr(data []byte, doRender bool) int { - if len(data) < 4 { - return 0 - } - if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') { - return 0 - } - if data[3] != ' ' && data[3] != '/' && data[3] != '>' { - // not an <hr> tag after all; at least not a valid one - return 0 - } - i := 3 - for i < len(data) && data[i] != '>' && data[i] != '\n' { - i++ - } - if i < len(data) && data[i] == '>' { - i++ - if j := p.isEmpty(data[i:]); j > 0 { - size := i + j - if doRender { - // trim newlines - end := size - for end > 0 && data[end-1] == '\n' { - end-- - } - finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end])) - } - return size - } - } - return 0 -} - -func (p *Markdown) htmlFindTag(data []byte) (string, bool) { - i := 0 - for i < len(data) && isalnum(data[i]) { - i++ - } - key := string(data[:i]) - if _, ok := blockTags[key]; ok { - return key, true - } - return "", false -} - -func (p *Markdown) htmlFindEnd(tag string, data []byte) int { - // assume data[0] == '<' && data[1] == '/' already tested - if tag == "hr" { - return 2 - } - // check if tag is a match - closetag := []byte("</" + tag + ">") - if !bytes.HasPrefix(data, closetag) { - return 0 - } - i := len(closetag) - - // check that the rest of the line is blank - skip := 0 - if skip = p.isEmpty(data[i:]); skip == 0 { - return 0 - } - i += skip - skip = 0 - - if i >= len(data) { - return i - } - - if p.extensions&LaxHTMLBlocks != 0 { - return i - } - if skip = p.isEmpty(data[i:]); skip == 0 { - // following line must be blank - return 0 - } - - return i + skip -} - -func (*Markdown) isEmpty(data []byte) int { - // it is okay to call isEmpty on an empty buffer - if len(data) == 0 { - return 0 - } - - var i int - for i = 0; i < len(data) && data[i] != '\n'; i++ { - if data[i] != ' ' && data[i] != '\t' { - return 0 - } - } - if i < len(data) && data[i] == '\n' { - i++ - } - return i -} - -func (*Markdown) isHRule(data []byte) bool { - i := 0 - - // skip up to three spaces - for i < 3 && data[i] == ' ' { - i++ - } - - // look at the hrule char - if data[i] != '*' && data[i] != '-' && data[i] != '_' { - return false - } - c := data[i] - - // the whole line must be the char or whitespace - n := 0 - for i < len(data) && data[i] != '\n' { - switch { - case data[i] == c: - n++ - case data[i] != ' ': - return false - } - i++ - } - - return n >= 3 -} - -// isFenceLine checks if there's a fence line (e.g., ``` or ``` go) at the beginning of data, -// and returns the end index if so, or 0 otherwise. It also returns the marker found. -// If syntax is not nil, it gets set to the syntax specified in the fence line. -func isFenceLine(data []byte, syntax *string, oldmarker string) (end int, marker string) { - i, size := 0, 0 - - // skip up to three spaces - for i < len(data) && i < 3 && data[i] == ' ' { - i++ - } - - // check for the marker characters: ~ or ` - if i >= len(data) { - return 0, "" - } - if data[i] != '~' && data[i] != '`' { - return 0, "" - } - - c := data[i] - - // the whole line must be the same char or whitespace - for i < len(data) && data[i] == c { - size++ - i++ - } - - // the marker char must occur at least 3 times - if size < 3 { - return 0, "" - } - marker = string(data[i-size : i]) - - // if this is the end marker, it must match the beginning marker - if oldmarker != "" && marker != oldmarker { - return 0, "" - } - - // TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here - // into one, always get the syntax, and discard it if the caller doesn't care. - if syntax != nil { - syn := 0 - i = skipChar(data, i, ' ') - - if i >= len(data) { - if i == len(data) { - return i, marker - } - return 0, "" - } - - syntaxStart := i - - if data[i] == '{' { - i++ - syntaxStart++ - - for i < len(data) && data[i] != '}' && data[i] != '\n' { - syn++ - i++ - } - - if i >= len(data) || data[i] != '}' { - return 0, "" - } - - // strip all whitespace at the beginning and the end - // of the {} block - for syn > 0 && isspace(data[syntaxStart]) { - syntaxStart++ - syn-- - } - - for syn > 0 && isspace(data[syntaxStart+syn-1]) { - syn-- - } - - i++ - } else { - for i < len(data) && !isspace(data[i]) { - syn++ - i++ - } - } - - *syntax = string(data[syntaxStart : syntaxStart+syn]) - } - - i = skipChar(data, i, ' ') - if i >= len(data) || data[i] != '\n' { - if i == len(data) { - return i, marker - } - return 0, "" - } - return i + 1, marker // Take newline into account. -} - -// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning, -// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects. -// If doRender is true, a final newline is mandatory to recognize the fenced code block. -func (p *Markdown) fencedCodeBlock(data []byte, doRender bool) int { - var syntax string - beg, marker := isFenceLine(data, &syntax, "") - if beg == 0 || beg >= len(data) { - return 0 - } - - var work bytes.Buffer - work.Write([]byte(syntax)) - work.WriteByte('\n') - - for { - // safe to assume beg < len(data) - - // check for the end of the code block - fenceEnd, _ := isFenceLine(data[beg:], nil, marker) - if fenceEnd != 0 { - beg += fenceEnd - break - } - - // copy the current line - end := skipUntilChar(data, beg, '\n') + 1 - - // did we reach the end of the buffer without a closing marker? - if end >= len(data) { - return 0 - } - - // verbatim copy to the working buffer - if doRender { - work.Write(data[beg:end]) - } - beg = end - } - - if doRender { - block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer - block.IsFenced = true - finalizeCodeBlock(block) - } - - return beg -} - -func unescapeChar(str []byte) []byte { - if str[0] == '\\' { - return []byte{str[1]} - } - return []byte(html.UnescapeString(string(str))) -} - -func unescapeString(str []byte) []byte { - if reBackslashOrAmp.Match(str) { - return reEntityOrEscapedChar.ReplaceAllFunc(str, unescapeChar) - } - return str -} - -func finalizeCodeBlock(block *Node) { - if block.IsFenced { - newlinePos := bytes.IndexByte(block.content, '\n') - firstLine := block.content[:newlinePos] - rest := block.content[newlinePos+1:] - block.Info = unescapeString(bytes.Trim(firstLine, "\n")) - block.Literal = rest - } else { - block.Literal = block.content - } - block.content = nil -} - -func (p *Markdown) table(data []byte) int { - table := p.addBlock(Table, nil) - i, columns := p.tableHeader(data) - if i == 0 { - p.tip = table.Parent - table.Unlink() - return 0 - } - - p.addBlock(TableBody, nil) - - for i < len(data) { - pipes, rowStart := 0, i - for ; i < len(data) && data[i] != '\n'; i++ { - if data[i] == '|' { - pipes++ - } - } - - if pipes == 0 { - i = rowStart - break - } - - // include the newline in data sent to tableRow - if i < len(data) && data[i] == '\n' { - i++ - } - p.tableRow(data[rowStart:i], columns, false) - } - - return i -} - -// check if the specified position is preceded by an odd number of backslashes -func isBackslashEscaped(data []byte, i int) bool { - backslashes := 0 - for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' { - backslashes++ - } - return backslashes&1 == 1 -} - -func (p *Markdown) tableHeader(data []byte) (size int, columns []CellAlignFlags) { - i := 0 - colCount := 1 - for i = 0; i < len(data) && data[i] != '\n'; i++ { - if data[i] == '|' && !isBackslashEscaped(data, i) { - colCount++ - } - } - - // doesn't look like a table header - if colCount == 1 { - return - } - - // include the newline in the data sent to tableRow - j := i - if j < len(data) && data[j] == '\n' { - j++ - } - header := data[:j] - - // column count ignores pipes at beginning or end of line - if data[0] == '|' { - colCount-- - } - if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) { - colCount-- - } - - columns = make([]CellAlignFlags, colCount) - - // move on to the header underline - i++ - if i >= len(data) { - return - } - - if data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - } - i = skipChar(data, i, ' ') - - // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3 - // and trailing | optional on last column - col := 0 - for i < len(data) && data[i] != '\n' { - dashes := 0 - - if data[i] == ':' { - i++ - columns[col] |= TableAlignmentLeft - dashes++ - } - for i < len(data) && data[i] == '-' { - i++ - dashes++ - } - if i < len(data) && data[i] == ':' { - i++ - columns[col] |= TableAlignmentRight - dashes++ - } - for i < len(data) && data[i] == ' ' { - i++ - } - if i == len(data) { - return - } - // end of column test is messy - switch { - case dashes < 3: - // not a valid column - return - - case data[i] == '|' && !isBackslashEscaped(data, i): - // marker found, now skip past trailing whitespace - col++ - i++ - for i < len(data) && data[i] == ' ' { - i++ - } - - // trailing junk found after last column - if col >= colCount && i < len(data) && data[i] != '\n' { - return - } - - case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount: - // something else found where marker was required - return - - case data[i] == '\n': - // marker is optional for the last column - col++ - - default: - // trailing junk found after last column - return - } - } - if col != colCount { - return - } - - p.addBlock(TableHead, nil) - p.tableRow(header, columns, true) - size = i - if size < len(data) && data[size] == '\n' { - size++ - } - return -} - -func (p *Markdown) tableRow(data []byte, columns []CellAlignFlags, header bool) { - p.addBlock(TableRow, nil) - i, col := 0, 0 - - if data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - } - - for col = 0; col < len(columns) && i < len(data); col++ { - for i < len(data) && data[i] == ' ' { - i++ - } - - cellStart := i - - for i < len(data) && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' { - i++ - } - - cellEnd := i - - // skip the end-of-cell marker, possibly taking us past end of buffer - i++ - - for cellEnd > cellStart && cellEnd-1 < len(data) && data[cellEnd-1] == ' ' { - cellEnd-- - } - - cell := p.addBlock(TableCell, data[cellStart:cellEnd]) - cell.IsHeader = header - cell.Align = columns[col] - } - - // pad it out with empty columns to get the right number - for ; col < len(columns); col++ { - cell := p.addBlock(TableCell, nil) - cell.IsHeader = header - cell.Align = columns[col] - } - - // silently ignore rows with too many cells -} - -// returns blockquote prefix length -func (p *Markdown) quotePrefix(data []byte) int { - i := 0 - for i < 3 && i < len(data) && data[i] == ' ' { - i++ - } - if i < len(data) && data[i] == '>' { - if i+1 < len(data) && data[i+1] == ' ' { - return i + 2 - } - return i + 1 - } - return 0 -} - -// blockquote ends with at least one blank line -// followed by something without a blockquote prefix -func (p *Markdown) terminateBlockquote(data []byte, beg, end int) bool { - if p.isEmpty(data[beg:]) <= 0 { - return false - } - if end >= len(data) { - return true - } - return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 -} - -// parse a blockquote fragment -func (p *Markdown) quote(data []byte) int { - block := p.addBlock(BlockQuote, nil) - var raw bytes.Buffer - beg, end := 0, 0 - for beg < len(data) { - end = beg - // Step over whole lines, collecting them. While doing that, check for - // fenced code and if one's found, incorporate it altogether, - // irregardless of any contents inside it - for end < len(data) && data[end] != '\n' { - if p.extensions&FencedCode != 0 { - if i := p.fencedCodeBlock(data[end:], false); i > 0 { - // -1 to compensate for the extra end++ after the loop: - end += i - 1 - break - } - } - end++ - } - if end < len(data) && data[end] == '\n' { - end++ - } - if pre := p.quotePrefix(data[beg:]); pre > 0 { - // skip the prefix - beg += pre - } else if p.terminateBlockquote(data, beg, end) { - break - } - // this line is part of the blockquote - raw.Write(data[beg:end]) - beg = end - } - p.block(raw.Bytes()) - p.finalize(block) - return end -} - -// returns prefix length for block code -func (p *Markdown) codePrefix(data []byte) int { - if len(data) >= 1 && data[0] == '\t' { - return 1 - } - if len(data) >= 4 && data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' { - return 4 - } - return 0 -} - -func (p *Markdown) code(data []byte) int { - var work bytes.Buffer - - i := 0 - for i < len(data) { - beg := i - for i < len(data) && data[i] != '\n' { - i++ - } - if i < len(data) && data[i] == '\n' { - i++ - } - - blankline := p.isEmpty(data[beg:i]) > 0 - if pre := p.codePrefix(data[beg:i]); pre > 0 { - beg += pre - } else if !blankline { - // non-empty, non-prefixed line breaks the pre - i = beg - break - } - - // verbatim copy to the working buffer - if blankline { - work.WriteByte('\n') - } else { - work.Write(data[beg:i]) - } - } - - // trim all the \n off the end of work - workbytes := work.Bytes() - eol := len(workbytes) - for eol > 0 && workbytes[eol-1] == '\n' { - eol-- - } - if eol != len(workbytes) { - work.Truncate(eol) - } - - work.WriteByte('\n') - - block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer - block.IsFenced = false - finalizeCodeBlock(block) - - return i -} - -// returns unordered list item prefix -func (p *Markdown) uliPrefix(data []byte) int { - i := 0 - // start with up to 3 spaces - for i < len(data) && i < 3 && data[i] == ' ' { - i++ - } - if i >= len(data)-1 { - return 0 - } - // need one of {'*', '+', '-'} followed by a space or a tab - if (data[i] != '*' && data[i] != '+' && data[i] != '-') || - (data[i+1] != ' ' && data[i+1] != '\t') { - return 0 - } - return i + 2 -} - -// returns ordered list item prefix -func (p *Markdown) oliPrefix(data []byte) int { - i := 0 - - // start with up to 3 spaces - for i < 3 && i < len(data) && data[i] == ' ' { - i++ - } - - // count the digits - start := i - for i < len(data) && data[i] >= '0' && data[i] <= '9' { - i++ - } - if start == i || i >= len(data)-1 { - return 0 - } - - // we need >= 1 digits followed by a dot and a space or a tab - if data[i] != '.' || !(data[i+1] == ' ' || data[i+1] == '\t') { - return 0 - } - return i + 2 -} - -// returns definition list item prefix -func (p *Markdown) dliPrefix(data []byte) int { - if len(data) < 2 { - return 0 - } - i := 0 - // need a ':' followed by a space or a tab - if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') { - return 0 - } - for i < len(data) && data[i] == ' ' { - i++ - } - return i + 2 -} - -// parse ordered or unordered list block -func (p *Markdown) list(data []byte, flags ListType) int { - i := 0 - flags |= ListItemBeginningOfList - block := p.addBlock(List, nil) - block.ListFlags = flags - block.Tight = true - - for i < len(data) { - skip := p.listItem(data[i:], &flags) - if flags&ListItemContainsBlock != 0 { - block.ListData.Tight = false - } - i += skip - if skip == 0 || flags&ListItemEndOfList != 0 { - break - } - flags &= ^ListItemBeginningOfList - } - - above := block.Parent - finalizeList(block) - p.tip = above - return i -} - -// Returns true if block ends with a blank line, descending if needed -// into lists and sublists. -func endsWithBlankLine(block *Node) bool { - // TODO: figure this out. Always false now. - for block != nil { - //if block.lastLineBlank { - //return true - //} - t := block.Type - if t == List || t == Item { - block = block.LastChild - } else { - break - } - } - return false -} - -func finalizeList(block *Node) { - block.open = false - item := block.FirstChild - for item != nil { - // check for non-final list item ending with blank line: - if endsWithBlankLine(item) && item.Next != nil { - block.ListData.Tight = false - break - } - // recurse into children of list item, to see if there are spaces - // between any of them: - subItem := item.FirstChild - for subItem != nil { - if endsWithBlankLine(subItem) && (item.Next != nil || subItem.Next != nil) { - block.ListData.Tight = false - break - } - subItem = subItem.Next - } - item = item.Next - } -} - -// Parse a single list item. -// Assumes initial prefix is already removed if this is a sublist. -func (p *Markdown) listItem(data []byte, flags *ListType) int { - // keep track of the indentation of the first line - itemIndent := 0 - if data[0] == '\t' { - itemIndent += 4 - } else { - for itemIndent < 3 && data[itemIndent] == ' ' { - itemIndent++ - } - } - - var bulletChar byte = '*' - i := p.uliPrefix(data) - if i == 0 { - i = p.oliPrefix(data) - } else { - bulletChar = data[i-2] - } - if i == 0 { - i = p.dliPrefix(data) - // reset definition term flag - if i > 0 { - *flags &= ^ListTypeTerm - } - } - if i == 0 { - // if in definition list, set term flag and continue - if *flags&ListTypeDefinition != 0 { - *flags |= ListTypeTerm - } else { - return 0 - } - } - - // skip leading whitespace on first line - for i < len(data) && data[i] == ' ' { - i++ - } - - // find the end of the line - line := i - for i > 0 && i < len(data) && data[i-1] != '\n' { - i++ - } - - // get working buffer - var raw bytes.Buffer - - // put the first line into the working buffer - raw.Write(data[line:i]) - line = i - - // process the following lines - containsBlankLine := false - sublist := 0 - lastChunkSize := 0 - -gatherlines: - for line < len(data) { - i++ - - // find the end of this line - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // if it is an empty line, guess that it is part of this item - // and move on to the next line - if p.isEmpty(data[line:i]) > 0 { - containsBlankLine = true - line = i - continue - } - - // calculate the indentation - indent := 0 - indentIndex := 0 - if data[line] == '\t' { - indentIndex++ - indent += 4 - } else { - for indent < 4 && line+indent < i && data[line+indent] == ' ' { - indent++ - indentIndex++ - } - } - - chunk := data[line+indentIndex : i] - - // evaluate how this line fits in - switch { - // is this a nested list item? - case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) || - p.oliPrefix(chunk) > 0 || - p.dliPrefix(chunk) > 0: - - if containsBlankLine { - *flags |= ListItemContainsBlock - } - - // to be a nested list, it must be indented more - // if not, it is the next item in the same list - if indent <= itemIndent { - break gatherlines - } - - // is this the first item in the nested list? - if sublist == 0 { - if p.dliPrefix(chunk) > 0 { - sublist = raw.Len() - lastChunkSize - } else { - sublist = raw.Len() - } - } - - // is this a nested prefix heading? - case p.isPrefixHeading(chunk): - // if the heading is not indented, it is not nested in the list - // and thus ends the list - if containsBlankLine && indent < 4 { - *flags |= ListItemEndOfList - break gatherlines - } - *flags |= ListItemContainsBlock - - // anything following an empty line is only part - // of this item if it is indented 4 spaces - // (regardless of the indentation of the beginning of the item) - case containsBlankLine && indent < 4: - if *flags&ListTypeDefinition != 0 && i < len(data)-1 { - // is the next item still a part of this list? - next := i - for next < len(data) && data[next] != '\n' { - next++ - } - for next < len(data)-1 && data[next] == '\n' { - next++ - } - if i < len(data)-1 && data[i] != ':' && data[next] != ':' { - *flags |= ListItemEndOfList - } - } else { - *flags |= ListItemEndOfList - } - break gatherlines - - // a blank line means this should be parsed as a block - case containsBlankLine: - raw.WriteByte('\n') - *flags |= ListItemContainsBlock - } - - // if this line was preceded by one or more blanks, - // re-introduce the blank into the buffer - if containsBlankLine { - containsBlankLine = false - raw.WriteByte('\n') - } - - // add the line into the working buffer without prefix - raw.Write(data[line+indentIndex : i]) - - // remember how much was written into raw, if this turns out to be a - // definition list we'll need this number to know where the sublist starts - lastChunkSize = i - (line + indentIndex) - - line = i - } - - rawBytes := raw.Bytes() - - block := p.addBlock(Item, nil) - block.ListFlags = *flags - block.Tight = false - block.BulletChar = bulletChar - block.Delimiter = '.' // Only '.' is possible in Markdown, but ')' will also be possible in CommonMark - - // render the contents of the list item - if *flags&ListItemContainsBlock != 0 && *flags&ListTypeTerm == 0 { - // intermediate render of block item, except for definition term - if sublist > 0 { - p.block(rawBytes[:sublist]) - p.block(rawBytes[sublist:]) - } else { - p.block(rawBytes) - } - } else { - // intermediate render of inline item - if sublist > 0 { - child := p.addChild(Paragraph, 0) - child.content = rawBytes[:sublist] - p.block(rawBytes[sublist:]) - } else { - child := p.addChild(Paragraph, 0) - child.content = rawBytes - } - } - return line -} - -// render a single paragraph that has already been parsed out -func (p *Markdown) renderParagraph(data []byte) { - if len(data) == 0 { - return - } - - // trim leading spaces - beg := 0 - for data[beg] == ' ' { - beg++ - } - - end := len(data) - // trim trailing newline - if data[len(data)-1] == '\n' { - end-- - } - - // trim trailing spaces - for end > beg && data[end-1] == ' ' { - end-- - } - - p.addBlock(Paragraph, data[beg:end]) -} - -func (p *Markdown) paragraph(data []byte) int { - // prev: index of 1st char of previous line - // line: index of 1st char of current line - // i: index of cursor/end of current line - var prev, line, i int - tabSize := TabSizeDefault - if p.extensions&TabSizeEight != 0 { - tabSize = TabSizeDouble - } - // keep going until we find something to mark the end of the paragraph - for i < len(data) { - // mark the beginning of the current line - prev = line - current := data[i:] - line = i - - // did we find a reference or a footnote? If so, end a paragraph - // preceding it and report that we have consumed up to the end of that - // reference: - if refEnd := isReference(p, current, tabSize); refEnd > 0 { - p.renderParagraph(data[:i]) - return i + refEnd - } - - // did we find a blank line marking the end of the paragraph? - if n := p.isEmpty(current); n > 0 { - // did this blank line followed by a definition list item? - if p.extensions&DefinitionLists != 0 { - if i < len(data)-1 && data[i+1] == ':' { - return p.list(data[prev:], ListTypeDefinition) - } - } - - p.renderParagraph(data[:i]) - return i + n - } - - // an underline under some text marks a heading, so our paragraph ended on prev line - if i > 0 { - if level := p.isUnderlinedHeading(current); level > 0 { - // render the paragraph - p.renderParagraph(data[:prev]) - - // ignore leading and trailing whitespace - eol := i - 1 - for prev < eol && data[prev] == ' ' { - prev++ - } - for eol > prev && data[eol-1] == ' ' { - eol-- - } - - id := "" - if p.extensions&AutoHeadingIDs != 0 { - id = sanitized_anchor_name.Create(string(data[prev:eol])) - } - - block := p.addBlock(Heading, data[prev:eol]) - block.Level = level - block.HeadingID = id - - // find the end of the underline - for i < len(data) && data[i] != '\n' { - i++ - } - return i - } - } - - // if the next line starts a block of HTML, then the paragraph ends here - if p.extensions&LaxHTMLBlocks != 0 { - if data[i] == '<' && p.html(current, false) > 0 { - // rewind to before the HTML block - p.renderParagraph(data[:i]) - return i - } - } - - // if there's a prefixed heading or a horizontal rule after this, paragraph is over - if p.isPrefixHeading(current) || p.isHRule(current) { - p.renderParagraph(data[:i]) - return i - } - - // if there's a fenced code block, paragraph is over - if p.extensions&FencedCode != 0 { - if p.fencedCodeBlock(current, false) > 0 { - p.renderParagraph(data[:i]) - return i - } - } - - // if there's a definition list item, prev line is a definition term - if p.extensions&DefinitionLists != 0 { - if p.dliPrefix(current) != 0 { - ret := p.list(data[prev:], ListTypeDefinition) - return ret - } - } - - // if there's a list after this, paragraph is over - if p.extensions&NoEmptyLineBeforeBlock != 0 { - if p.uliPrefix(current) != 0 || - p.oliPrefix(current) != 0 || - p.quotePrefix(current) != 0 || - p.codePrefix(current) != 0 { - p.renderParagraph(data[:i]) - return i - } - } - - // otherwise, scan to the beginning of the next line - nl := bytes.IndexByte(data[i:], '\n') - if nl >= 0 { - i += nl + 1 - } else { - i += len(data[i:]) - } - } - - p.renderParagraph(data[:i]) - return i -} - -func skipChar(data []byte, start int, char byte) int { - i := start - for i < len(data) && data[i] == char { - i++ - } - return i -} - -func skipUntilChar(text []byte, start int, char byte) int { - i := start - for i < len(text) && text[i] != char { - i++ - } - return i -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/doc.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/doc.go deleted file mode 100644 index 5b3fa98..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Package blackfriday is a markdown processor. -// -// It translates plain text with simple formatting rules into an AST, which can -// then be further processed to HTML (provided by Blackfriday itself) or other -// formats (provided by the community). -// -// The simplest way to invoke Blackfriday is to call the Run function. It will -// take a text input and produce a text output in HTML (or other format). -// -// A slightly more sophisticated way to use Blackfriday is to create a Markdown -// processor and to call Parse, which returns a syntax tree for the input -// document. You can leverage Blackfriday's parsing for content extraction from -// markdown documents. You can assign a custom renderer and set various options -// to the Markdown processor. -// -// If you're interested in calling Blackfriday from command line, see -// https://github.com/russross/blackfriday-tool. -package blackfriday diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/esc.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/esc.go deleted file mode 100644 index 6385f27..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/esc.go +++ /dev/null @@ -1,34 +0,0 @@ -package blackfriday - -import ( - "html" - "io" -) - -var htmlEscaper = [256][]byte{ - '&': []byte("&"), - '<': []byte("<"), - '>': []byte(">"), - '"': []byte("""), -} - -func escapeHTML(w io.Writer, s []byte) { - var start, end int - for end < len(s) { - escSeq := htmlEscaper[s[end]] - if escSeq != nil { - w.Write(s[start:end]) - w.Write(escSeq) - start = end + 1 - } - end++ - } - if start < len(s) && end <= len(s) { - w.Write(s[start:end]) - } -} - -func escLink(w io.Writer, text []byte) { - unesc := html.UnescapeString(string(text)) - escapeHTML(w, []byte(unesc)) -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/html.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/html.go deleted file mode 100644 index 9fbf820..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/html.go +++ /dev/null @@ -1,941 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// HTML rendering backend -// -// - -//nolint:gocritic,unused,revive // ignore blackfriday -package blackfriday - -import ( - "bytes" - "fmt" - "io" - "regexp" - "strings" -) - -// HTMLFlags control optional behavior of HTML renderer. -type HTMLFlags int - -// HTML renderer configuration options. -const ( - HTMLFlagsNone HTMLFlags = 0 - SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks - SkipImages // Skip embedded images - SkipLinks // Skip all links - Safelink // Only link to trusted protocols - NofollowLinks // Only link with rel="nofollow" - NoreferrerLinks // Only link with rel="noreferrer" - HrefTargetBlank // Add a blank target - CompletePage // Generate a complete HTML page - UseXHTML // Generate XHTML output instead of HTML - FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source - Smartypants // Enable smart punctuation substitutions - SmartypantsFractions // Enable smart fractions (with Smartypants) - SmartypantsDashes // Enable smart dashes (with Smartypants) - SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants) - SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering - SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants) - TOC // Generate a table of contents -) - -var ( - htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag) -) - -const ( - htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" + - processingInstruction + "|" + declaration + "|" + cdata + ")" - closeTag = "</" + tagName + "\\s*[>]" - openTag = "<" + tagName + attribute + "*" + "\\s*/?>" - attribute = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)" - attributeValue = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")" - attributeValueSpec = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")" - attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*" - cdata = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>" - declaration = "<![A-Z]+" + "\\s+[^>]*>" - doubleQuotedValue = "\"[^\"]*\"" - htmlComment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->" - processingInstruction = "[<][?].*?[?][>]" - singleQuotedValue = "'[^']*'" - tagName = "[A-Za-z][A-Za-z0-9-]*" - unquotedValue = "[^\"'=<>`\\x00-\\x20]+" -) - -// HTMLRendererParameters is a collection of supplementary parameters tweaking -// the behavior of various parts of HTML renderer. -type HTMLRendererParameters struct { - // Prepend this text to each relative URL. - AbsolutePrefix string - // Add this text to each footnote anchor, to ensure uniqueness. - FootnoteAnchorPrefix string - // Show this text inside the <a> tag for a footnote return link, if the - // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string - // <sup>[return]</sup> is used. - FootnoteReturnLinkContents string - // If set, add this text to the front of each Heading ID, to ensure - // uniqueness. - HeadingIDPrefix string - // If set, add this text to the back of each Heading ID, to ensure uniqueness. - HeadingIDSuffix string - - Title string // Document title (used if CompletePage is set) - CSS string // Optional CSS file URL (used if CompletePage is set) - Icon string // Optional icon file URL (used if CompletePage is set) - - Flags HTMLFlags // Flags allow customizing this renderer's behavior -} - -// HTMLRenderer is a type that implements the Renderer interface for HTML output. -// -// Do not create this directly, instead use the NewHTMLRenderer function. -type HTMLRenderer struct { - HTMLRendererParameters - - closeTag string // how to end singleton tags: either " />" or ">" - - // Track heading IDs to prevent ID collision in a single generation. - headingIDs map[string]int - - lastOutputLen int - disableTags int - - sr *SPRenderer -} - -const ( - xhtmlClose = " />" - htmlClose = ">" -) - -// NewHTMLRenderer creates and configures an HTMLRenderer object, which -// satisfies the Renderer interface. -func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer { - // configure the rendering engine - closeTag := htmlClose - if params.Flags&UseXHTML != 0 { - closeTag = xhtmlClose - } - - if params.FootnoteReturnLinkContents == "" { - params.FootnoteReturnLinkContents = `<sup>[return]</sup>` - } - - return &HTMLRenderer{ - HTMLRendererParameters: params, - - closeTag: closeTag, - headingIDs: make(map[string]int), - - sr: NewSmartypantsRenderer(params.Flags), - } -} - -func isHTMLTag(tag []byte, tagname string) bool { - found, _ := findHTMLTagPos(tag, tagname) - return found -} - -// Look for a character, but ignore it when it's in any kind of quotes, it -// might be JavaScript -func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int { - inSingleQuote := false - inDoubleQuote := false - inGraveQuote := false - i := start - for i < len(html) { - switch { - case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote: - return i - case html[i] == '\'': - inSingleQuote = !inSingleQuote - case html[i] == '"': - inDoubleQuote = !inDoubleQuote - case html[i] == '`': - inGraveQuote = !inGraveQuote - } - i++ - } - return start -} - -func findHTMLTagPos(tag []byte, tagname string) (bool, int) { - i := 0 - if i < len(tag) && tag[0] != '<' { - return false, -1 - } - i++ - i = skipSpace(tag, i) - - if i < len(tag) && tag[i] == '/' { - i++ - } - - i = skipSpace(tag, i) - j := 0 - for ; i < len(tag); i, j = i+1, j+1 { - if j >= len(tagname) { - break - } - - if strings.ToLower(string(tag[i]))[0] != tagname[j] { - return false, -1 - } - } - - if i == len(tag) { - return false, -1 - } - - rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>') - if rightAngle >= i { - return true, rightAngle - } - - return false, -1 -} - -func skipSpace(tag []byte, i int) int { - for i < len(tag) && isspace(tag[i]) { - i++ - } - return i -} - -func isRelativeLink(link []byte) (yes bool) { - // a tag begin with '#' - if link[0] == '#' { - return true - } - - // link begin with '/' but not '//', the second maybe a protocol relative link - if len(link) >= 2 && link[0] == '/' && link[1] != '/' { - return true - } - - // only the root '/' - if len(link) == 1 && link[0] == '/' { - return true - } - - // current directory : begin with "./" - if bytes.HasPrefix(link, []byte("./")) { - return true - } - - // parent directory : begin with "../" - if bytes.HasPrefix(link, []byte("../")) { - return true - } - - return false -} - -func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string { - for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { - tmp := fmt.Sprintf("%s-%d", id, count+1) - - if _, tmpFound := r.headingIDs[tmp]; !tmpFound { - r.headingIDs[id] = count + 1 - id = tmp - } else { - id = id + "-1" - } - } - - if _, found := r.headingIDs[id]; !found { - r.headingIDs[id] = 0 - } - - return id -} - -func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte { - if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { - newDest := r.AbsolutePrefix - if link[0] != '/' { - newDest += "/" - } - newDest += string(link) - return []byte(newDest) - } - return link -} - -func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string { - if isRelativeLink(link) { - return attrs - } - val := []string{} - if flags&NofollowLinks != 0 { - val = append(val, "nofollow") - } - if flags&NoreferrerLinks != 0 { - val = append(val, "noreferrer") - } - if flags&HrefTargetBlank != 0 { - attrs = append(attrs, "target=\"_blank\"") - } - if len(val) == 0 { - return attrs - } - attr := fmt.Sprintf("rel=%q", strings.Join(val, " ")) - return append(attrs, attr) -} - -func isMailto(link []byte) bool { - return bytes.HasPrefix(link, []byte("mailto:")) -} - -func needSkipLink(flags HTMLFlags, dest []byte) bool { - if flags&SkipLinks != 0 { - return true - } - return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest) -} - -func isSmartypantable(node *Node) bool { - pt := node.Parent.Type - return pt != Link && pt != CodeBlock && pt != Code -} - -func appendLanguageAttr(attrs []string, info []byte) []string { - if len(info) == 0 { - return attrs - } - endOfLang := bytes.IndexAny(info, "\t ") - if endOfLang < 0 { - endOfLang = len(info) - } - return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang])) -} - -func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) { - w.Write(name) - if len(attrs) > 0 { - w.Write(spaceBytes) - w.Write([]byte(strings.Join(attrs, " "))) - } - w.Write(gtBytes) - r.lastOutputLen = 1 -} - -func footnoteRef(prefix string, node *Node) []byte { - urlFrag := prefix + string(slugify(node.Destination)) - anchor := fmt.Sprintf(`<a rel="footnote" href="#fn:%s">%d</a>`, urlFrag, node.NoteID) - return []byte(fmt.Sprintf(`<sup class="footnote-ref" id="fnref:%s">%s</sup>`, urlFrag, anchor)) -} - -func footnoteItem(prefix string, slug []byte) []byte { - return []byte(fmt.Sprintf(`<li id="fn:%s%s">`, prefix, slug)) -} - -func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte { - const format = ` <a class="footnote-return" href="#fnref:%s%s">%s</a>` - return []byte(fmt.Sprintf(format, prefix, slug, returnLink)) -} - -func itemOpenCR(node *Node) bool { - if node.Prev == nil { - return false - } - ld := node.Parent.ListData - return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0 -} - -func skipParagraphTags(node *Node) bool { - grandparent := node.Parent.Parent - if grandparent == nil || grandparent.Type != List { - return false - } - tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0 - return grandparent.Type == List && tightOrTerm -} - -func cellAlignment(align CellAlignFlags) string { - switch align { - case TableAlignmentLeft: - return "left" - case TableAlignmentRight: - return "right" - case TableAlignmentCenter: - return "center" - default: - return "" - } -} - -func (r *HTMLRenderer) out(w io.Writer, text []byte) { - if r.disableTags > 0 { - w.Write(htmlTagRe.ReplaceAll(text, []byte{})) - } else { - w.Write(text) - } - r.lastOutputLen = len(text) -} - -func (r *HTMLRenderer) cr(w io.Writer) { - if r.lastOutputLen > 0 { - r.out(w, nlBytes) - } -} - -var ( - nlBytes = []byte{'\n'} - gtBytes = []byte{'>'} - spaceBytes = []byte{' '} -) - -var ( - brTag = []byte("<br>") - brXHTMLTag = []byte("<br />") - emTag = []byte("<em>") - emCloseTag = []byte("</em>") - strongTag = []byte("<strong>") - strongCloseTag = []byte("</strong>") - delTag = []byte("<del>") - delCloseTag = []byte("</del>") - ttTag = []byte("<tt>") - ttCloseTag = []byte("</tt>") - aTag = []byte("<a") - aCloseTag = []byte("</a>") - preTag = []byte("<pre>") - preCloseTag = []byte("</pre>") - codeTag = []byte("<code>") - codeCloseTag = []byte("</code>") - pTag = []byte("<p>") - pCloseTag = []byte("</p>") - blockquoteTag = []byte("<blockquote>") - blockquoteCloseTag = []byte("</blockquote>") - hrTag = []byte("<hr>") - hrXHTMLTag = []byte("<hr />") - ulTag = []byte("<ul>") - ulCloseTag = []byte("</ul>") - olTag = []byte("<ol>") - olCloseTag = []byte("</ol>") - dlTag = []byte("<dl>") - dlCloseTag = []byte("</dl>") - liTag = []byte("<li>") - liCloseTag = []byte("</li>") - ddTag = []byte("<dd>") - ddCloseTag = []byte("</dd>") - dtTag = []byte("<dt>") - dtCloseTag = []byte("</dt>") - tableTag = []byte("<table>") - tableCloseTag = []byte("</table>") - tdTag = []byte("<td") - tdCloseTag = []byte("</td>") - thTag = []byte("<th") - thCloseTag = []byte("</th>") - theadTag = []byte("<thead>") - theadCloseTag = []byte("</thead>") - tbodyTag = []byte("<tbody>") - tbodyCloseTag = []byte("</tbody>") - trTag = []byte("<tr>") - trCloseTag = []byte("</tr>") - h1Tag = []byte("<h1") - h1CloseTag = []byte("</h1>") - h2Tag = []byte("<h2") - h2CloseTag = []byte("</h2>") - h3Tag = []byte("<h3") - h3CloseTag = []byte("</h3>") - h4Tag = []byte("<h4") - h4CloseTag = []byte("</h4>") - h5Tag = []byte("<h5") - h5CloseTag = []byte("</h5>") - h6Tag = []byte("<h6") - h6CloseTag = []byte("</h6>") - - footnotesDivBytes = []byte("\n<div class=\"footnotes\">\n\n") - footnotesCloseDivBytes = []byte("\n</div>\n") -) - -func headingTagsFromLevel(level int) ([]byte, []byte) { - switch level { - case 1: - return h1Tag, h1CloseTag - case 2: - return h2Tag, h2CloseTag - case 3: - return h3Tag, h3CloseTag - case 4: - return h4Tag, h4CloseTag - case 5: - return h5Tag, h5CloseTag - default: - return h6Tag, h6CloseTag - } -} - -func (r *HTMLRenderer) outHRTag(w io.Writer) { - if r.Flags&UseXHTML == 0 { - r.out(w, hrTag) - } else { - r.out(w, hrXHTMLTag) - } -} - -// RenderNode is a default renderer of a single node of a syntax tree. For -// block nodes it will be called twice: first time with entering=true, second -// time with entering=false, so that it could know when it's working on an open -// tag and when on close. It writes the result to w. -// -// The return value is a way to tell the calling walker to adjust its walk -// pattern: e.g. it can terminate the traversal by returning Terminate. Or it -// can ask the walker to skip a subtree of this node by returning SkipChildren. -// The typical behavior is to return GoToNext, which asks for the usual -// traversal to the next node. -func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus { - attrs := []string{} - switch node.Type { - case Text: - if r.Flags&Smartypants != 0 { - var tmp bytes.Buffer - escapeHTML(&tmp, node.Literal) - r.sr.Process(w, tmp.Bytes()) - } else { - if node.Parent.Type == Link { - escLink(w, node.Literal) - } else { - escapeHTML(w, node.Literal) - } - } - case Softbreak: - r.cr(w) - // TODO: make it configurable via out(renderer.softbreak) - case Hardbreak: - if r.Flags&UseXHTML == 0 { - r.out(w, brTag) - } else { - r.out(w, brXHTMLTag) - } - r.cr(w) - case Emph: - if entering { - r.out(w, emTag) - } else { - r.out(w, emCloseTag) - } - case Strong: - if entering { - r.out(w, strongTag) - } else { - r.out(w, strongCloseTag) - } - case Del: - if entering { - r.out(w, delTag) - } else { - r.out(w, delCloseTag) - } - case HTMLSpan: - if r.Flags&SkipHTML != 0 { - break - } - r.out(w, node.Literal) - case Link: - // mark it but don't link it if it is not a safe link: no smartypants - dest := node.LinkData.Destination - if needSkipLink(r.Flags, dest) { - if entering { - r.out(w, ttTag) - } else { - r.out(w, ttCloseTag) - } - } else { - if entering { - dest = r.addAbsPrefix(dest) - var hrefBuf bytes.Buffer - hrefBuf.WriteString("href=\"") - escLink(&hrefBuf, dest) - hrefBuf.WriteByte('"') - attrs = append(attrs, hrefBuf.String()) - if node.NoteID != 0 { - r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node)) - break - } - attrs = appendLinkAttrs(attrs, r.Flags, dest) - if len(node.LinkData.Title) > 0 { - var titleBuff bytes.Buffer - titleBuff.WriteString("title=\"") - escapeHTML(&titleBuff, node.LinkData.Title) - titleBuff.WriteByte('"') - attrs = append(attrs, titleBuff.String()) - } - r.tag(w, aTag, attrs) - } else { - if node.NoteID != 0 { - break - } - r.out(w, aCloseTag) - } - } - case Image: - if r.Flags&SkipImages != 0 { - return SkipChildren - } - if entering { - dest := node.LinkData.Destination - dest = r.addAbsPrefix(dest) - if r.disableTags == 0 { - //if options.safe && potentiallyUnsafe(dest) { - //out(w, `<img src="" alt="`) - //} else { - r.out(w, []byte(`<img src="`)) - escLink(w, dest) - r.out(w, []byte(`" alt="`)) - //} - } - r.disableTags++ - } else { - r.disableTags-- - if r.disableTags == 0 { - if node.LinkData.Title != nil { - r.out(w, []byte(`" title="`)) - escapeHTML(w, node.LinkData.Title) - } - r.out(w, []byte(`" />`)) - } - } - case Code: - r.out(w, codeTag) - escapeHTML(w, node.Literal) - r.out(w, codeCloseTag) - case Document: - break - case Paragraph: - if skipParagraphTags(node) { - break - } - if entering { - // TODO: untangle this clusterfuck about when the newlines need - // to be added and when not. - if node.Prev != nil { - switch node.Prev.Type { - case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule: - r.cr(w) - } - } - if node.Parent.Type == BlockQuote && node.Prev == nil { - r.cr(w) - } - r.out(w, pTag) - } else { - r.out(w, pCloseTag) - if !(node.Parent.Type == Item && node.Next == nil) { - r.cr(w) - } - } - case BlockQuote: - if entering { - r.cr(w) - r.out(w, blockquoteTag) - } else { - r.out(w, blockquoteCloseTag) - r.cr(w) - } - case HTMLBlock: - if r.Flags&SkipHTML != 0 { - break - } - r.cr(w) - r.out(w, node.Literal) - r.cr(w) - case Heading: - openTag, closeTag := headingTagsFromLevel(node.Level) - if entering { - if node.IsTitleblock { - attrs = append(attrs, `class="title"`) - } - if node.HeadingID != "" { - id := r.ensureUniqueHeadingID(node.HeadingID) - if r.HeadingIDPrefix != "" { - id = r.HeadingIDPrefix + id - } - if r.HeadingIDSuffix != "" { - id = id + r.HeadingIDSuffix - } - attrs = append(attrs, fmt.Sprintf(`id="%s"`, id)) - } - r.cr(w) - r.tag(w, openTag, attrs) - } else { - r.out(w, closeTag) - if !(node.Parent.Type == Item && node.Next == nil) { - r.cr(w) - } - } - case HorizontalRule: - r.cr(w) - r.outHRTag(w) - r.cr(w) - case List: - openTag := ulTag - closeTag := ulCloseTag - if node.ListFlags&ListTypeOrdered != 0 { - openTag = olTag - closeTag = olCloseTag - } - if node.ListFlags&ListTypeDefinition != 0 { - openTag = dlTag - closeTag = dlCloseTag - } - if entering { - if node.IsFootnotesList { - r.out(w, footnotesDivBytes) - r.outHRTag(w) - r.cr(w) - } - r.cr(w) - if node.Parent.Type == Item && node.Parent.Parent.Tight { - r.cr(w) - } - r.tag(w, openTag[:len(openTag)-1], attrs) - r.cr(w) - } else { - r.out(w, closeTag) - //cr(w) - //if node.parent.Type != Item { - // cr(w) - //} - if node.Parent.Type == Item && node.Next != nil { - r.cr(w) - } - if node.Parent.Type == Document || node.Parent.Type == BlockQuote { - r.cr(w) - } - if node.IsFootnotesList { - r.out(w, footnotesCloseDivBytes) - } - } - case Item: - openTag := liTag - closeTag := liCloseTag - if node.ListFlags&ListTypeDefinition != 0 { - openTag = ddTag - closeTag = ddCloseTag - } - if node.ListFlags&ListTypeTerm != 0 { - openTag = dtTag - closeTag = dtCloseTag - } - if entering { - if itemOpenCR(node) { - r.cr(w) - } - if node.ListData.RefLink != nil { - slug := slugify(node.ListData.RefLink) - r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug)) - break - } - r.out(w, openTag) - } else { - if node.ListData.RefLink != nil { - slug := slugify(node.ListData.RefLink) - if r.Flags&FootnoteReturnLinks != 0 { - r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug)) - } - } - r.out(w, closeTag) - r.cr(w) - } - case CodeBlock: - attrs = appendLanguageAttr(attrs, node.Info) - r.cr(w) - r.out(w, preTag) - r.tag(w, codeTag[:len(codeTag)-1], attrs) - escapeHTML(w, node.Literal) - r.out(w, codeCloseTag) - r.out(w, preCloseTag) - if node.Parent.Type != Item { - r.cr(w) - } - case Table: - if entering { - r.cr(w) - r.out(w, tableTag) - } else { - r.out(w, tableCloseTag) - r.cr(w) - } - case TableCell: - openTag := tdTag - closeTag := tdCloseTag - if node.IsHeader { - openTag = thTag - closeTag = thCloseTag - } - if entering { - align := cellAlignment(node.Align) - if align != "" { - attrs = append(attrs, fmt.Sprintf(`align="%s"`, align)) - } - if node.Prev == nil { - r.cr(w) - } - r.tag(w, openTag, attrs) - } else { - r.out(w, closeTag) - r.cr(w) - } - case TableHead: - if entering { - r.cr(w) - r.out(w, theadTag) - } else { - r.out(w, theadCloseTag) - r.cr(w) - } - case TableBody: - if entering { - r.cr(w) - r.out(w, tbodyTag) - // XXX: this is to adhere to a rather silly test. Should fix test. - if node.FirstChild == nil { - r.cr(w) - } - } else { - r.out(w, tbodyCloseTag) - r.cr(w) - } - case TableRow: - if entering { - r.cr(w) - r.out(w, trTag) - } else { - r.out(w, trCloseTag) - r.cr(w) - } - default: - panic("Unknown node type " + node.Type.String()) - } - return GoToNext -} - -// RenderHeader writes HTML document preamble and TOC if requested. -func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) { - r.writeDocumentHeader(w) - if r.Flags&TOC != 0 { - r.writeTOC(w, ast) - } -} - -// RenderFooter writes HTML document footer. -func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) { - if r.Flags&CompletePage == 0 { - return - } - io.WriteString(w, "\n</body>\n</html>\n") -} - -func (r *HTMLRenderer) writeDocumentHeader(w io.Writer) { - if r.Flags&CompletePage == 0 { - return - } - ending := "" - if r.Flags&UseXHTML != 0 { - io.WriteString(w, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ") - io.WriteString(w, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n") - io.WriteString(w, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n") - ending = " /" - } else { - io.WriteString(w, "<!DOCTYPE html>\n") - io.WriteString(w, "<html>\n") - } - io.WriteString(w, "<head>\n") - io.WriteString(w, " <title>") - if r.Flags&Smartypants != 0 { - r.sr.Process(w, []byte(r.Title)) - } else { - escapeHTML(w, []byte(r.Title)) - } - io.WriteString(w, "</title>\n") - io.WriteString(w, " <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v") - io.WriteString(w, Version) - io.WriteString(w, "\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - io.WriteString(w, " <meta charset=\"utf-8\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - if r.CSS != "" { - io.WriteString(w, " <link rel=\"stylesheet\" type=\"text/css\" href=\"") - escapeHTML(w, []byte(r.CSS)) - io.WriteString(w, "\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - } - if r.Icon != "" { - io.WriteString(w, " <link rel=\"icon\" type=\"image/x-icon\" href=\"") - escapeHTML(w, []byte(r.Icon)) - io.WriteString(w, "\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - } - io.WriteString(w, "</head>\n") - io.WriteString(w, "<body>\n\n") -} - -func (r *HTMLRenderer) writeTOC(w io.Writer, ast *Node) { - buf := bytes.Buffer{} - - inHeading := false - tocLevel := 0 - headingCount := 0 - - ast.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Heading && !node.HeadingData.IsTitleblock { - inHeading = entering - if entering { - node.HeadingID = fmt.Sprintf("toc_%d", headingCount) - if node.Level == tocLevel { - buf.WriteString("</li>\n\n<li>") - } else if node.Level < tocLevel { - for node.Level < tocLevel { - tocLevel-- - buf.WriteString("</li>\n</ul>") - } - buf.WriteString("</li>\n\n<li>") - } else { - for node.Level > tocLevel { - tocLevel++ - buf.WriteString("\n<ul>\n<li>") - } - } - - fmt.Fprintf(&buf, `<a href="#toc_%d">`, headingCount) - headingCount++ - } else { - buf.WriteString("</a>") - } - return GoToNext - } - - if inHeading { - return r.RenderNode(&buf, node, entering) - } - - return GoToNext - }) - - for ; tocLevel > 0; tocLevel-- { - buf.WriteString("</li>\n</ul>") - } - - if buf.Len() > 0 { - io.WriteString(w, "<nav>\n") - w.Write(buf.Bytes()) - io.WriteString(w, "\n\n</nav>\n") - } - r.lastOutputLen = buf.Len() -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/inline.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/inline.go deleted file mode 100644 index 70557d5..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/inline.go +++ /dev/null @@ -1,1217 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// Functions to parse inline elements. -// - -//nolint:gocritic,whitespace,wastedassign,revive // ignore blackfriday -package blackfriday - -import ( - "bytes" - "regexp" - "strconv" -) - -var ( - urlRe = `((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+` - anchorRe = regexp.MustCompile(`^(<a\shref="` + urlRe + `"(\stitle="[^"<>]+")?\s?>` + urlRe + `<\/a>)`) - - // TODO: improve this regexp to catch all possible entities: - htmlEntityRe = regexp.MustCompile(`&[a-z]{2,5};`) -) - -// Functions to parse text within a block -// Each function returns the number of chars taken care of -// data is the complete block being rendered -// offset is the number of valid chars before the current cursor - -func (p *Markdown) inline(currBlock *Node, data []byte) { - // handlers might call us recursively: enforce a maximum depth - if p.nesting >= p.maxNesting || len(data) == 0 { - return - } - p.nesting++ - beg, end := 0, 0 - for end < len(data) { - handler := p.inlineCallback[data[end]] - if handler != nil { - if consumed, node := handler(p, data, end); consumed == 0 { - // No action from the callback. - end++ - } else { - // Copy inactive chars into the output. - currBlock.AppendChild(text(data[beg:end])) - if node != nil { - currBlock.AppendChild(node) - } - // Skip past whatever the callback used. - beg = end + consumed - end = beg - } - } else { - end++ - } - } - if beg < len(data) { - if data[end-1] == '\n' { - end-- - } - currBlock.AppendChild(text(data[beg:end])) - } - p.nesting-- -} - -// single and double emphasis parsing -func emphasis(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - c := data[0] - - if len(data) > 2 && data[1] != c { - // whitespace cannot follow an opening emphasis; - // strikethrough only takes two characters '~~' - if c == '~' || isspace(data[1]) { - return 0, nil - } - ret, node := helperEmphasis(p, data[1:], c) - if ret == 0 { - return 0, nil - } - - return ret + 1, node - } - - if len(data) > 3 && data[1] == c && data[2] != c { - if isspace(data[2]) { - return 0, nil - } - ret, node := helperDoubleEmphasis(p, data[2:], c) - if ret == 0 { - return 0, nil - } - - return ret + 2, node - } - - if len(data) > 4 && data[1] == c && data[2] == c && data[3] != c { - if c == '~' || isspace(data[3]) { - return 0, nil - } - ret, node := helperTripleEmphasis(p, data, 3, c) - if ret == 0 { - return 0, nil - } - - return ret + 3, node - } - - return 0, nil -} - -func codeSpan(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - nb := 0 - - // count the number of backticks in the delimiter - for nb < len(data) && data[nb] == '`' { - nb++ - } - - // find the next delimiter - i, end := 0, 0 - for end = nb; end < len(data) && i < nb; end++ { - if data[end] == '`' { - i++ - } else { - i = 0 - } - } - - // no matching delimiter? - if i < nb && end >= len(data) { - return 0, nil - } - - // trim outside whitespace - fBegin := nb - for fBegin < end && data[fBegin] == ' ' { - fBegin++ - } - - fEnd := end - nb - for fEnd > fBegin && data[fEnd-1] == ' ' { - fEnd-- - } - - // render the code span - if fBegin != fEnd { - code := NewNode(Code) - code.Literal = data[fBegin:fEnd] - return end, code - } - - return end, nil -} - -// newline preceded by two spaces becomes <br> -func maybeLineBreak(p *Markdown, data []byte, offset int) (int, *Node) { - origOffset := offset - for offset < len(data) && data[offset] == ' ' { - offset++ - } - - if offset < len(data) && data[offset] == '\n' { - if offset-origOffset >= 2 { - return offset - origOffset + 1, NewNode(Hardbreak) - } - return offset - origOffset, nil - } - return 0, nil -} - -// newline without two spaces works when HardLineBreak is enabled -func lineBreak(p *Markdown, data []byte, offset int) (int, *Node) { - if p.extensions&HardLineBreak != 0 { - return 1, NewNode(Hardbreak) - } - return 0, nil -} - -type linkType int - -const ( - linkNormal linkType = iota - linkImg - linkDeferredFootnote - linkInlineFootnote -) - -func isReferenceStyleLink(data []byte, pos int, t linkType) bool { - if t == linkDeferredFootnote { - return false - } - return pos < len(data)-1 && data[pos] == '[' && data[pos+1] != '^' -} - -func maybeImage(p *Markdown, data []byte, offset int) (int, *Node) { - if offset < len(data)-1 && data[offset+1] == '[' { - return link(p, data, offset) - } - return 0, nil -} - -func maybeInlineFootnote(p *Markdown, data []byte, offset int) (int, *Node) { - if offset < len(data)-1 && data[offset+1] == '[' { - return link(p, data, offset) - } - return 0, nil -} - -// '[': parse a link or an image or a footnote -func link(p *Markdown, data []byte, offset int) (int, *Node) { - // no links allowed inside regular links, footnote, and deferred footnotes - if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') { - return 0, nil - } - - var t linkType - switch { - // special case: ![^text] == deferred footnote (that follows something with - // an exclamation point) - case p.extensions&Footnotes != 0 && len(data)-1 > offset && data[offset+1] == '^': - t = linkDeferredFootnote - // ![alt] == image - case offset >= 0 && data[offset] == '!': - t = linkImg - offset++ - // ^[text] == inline footnote - // [^refId] == deferred footnote - case p.extensions&Footnotes != 0: - if offset >= 0 && data[offset] == '^' { - t = linkInlineFootnote - offset++ - } else if len(data)-1 > offset && data[offset+1] == '^' { - t = linkDeferredFootnote - } - // [text] == regular link - default: - t = linkNormal - } - - data = data[offset:] - - var ( - i = 1 - noteID int - title, link, altContent []byte - textHasNl = false - ) - - if t == linkDeferredFootnote { - i++ - } - - // look for the matching closing bracket - for level := 1; level > 0 && i < len(data); i++ { - switch { - case data[i] == '\n': - textHasNl = true - - case data[i-1] == '\\': - continue - - case data[i] == '[': - level++ - - case data[i] == ']': - level-- - if level <= 0 { - i-- // compensate for extra i++ in for loop - } - } - } - - if i >= len(data) { - return 0, nil - } - - txtE := i - i++ - var footnoteNode *Node - - // skip any amount of whitespace or newline - // (this is much more lax than original markdown syntax) - for i < len(data) && isspace(data[i]) { - i++ - } - - // inline style link - switch { - case i < len(data) && data[i] == '(': - // skip initial whitespace - i++ - - for i < len(data) && isspace(data[i]) { - i++ - } - - linkB := i - - // look for link end: ' " ) - findlinkend: - for i < len(data) { - switch { - case data[i] == '\\': - i += 2 - - case data[i] == ')' || data[i] == '\'' || data[i] == '"': - break findlinkend - - default: - i++ - } - } - - if i >= len(data) { - return 0, nil - } - linkE := i - - // look for title end if present - titleB, titleE := 0, 0 - if data[i] == '\'' || data[i] == '"' { - i++ - titleB = i - - findtitleend: - for i < len(data) { - switch { - case data[i] == '\\': - i += 2 - - case data[i] == ')': - break findtitleend - - default: - i++ - } - } - - if i >= len(data) { - return 0, nil - } - - // skip whitespace after title - titleE = i - 1 - for titleE > titleB && isspace(data[titleE]) { - titleE-- - } - - // check for closing quote presence - if data[titleE] != '\'' && data[titleE] != '"' { - titleB, titleE = 0, 0 - linkE = i - } - } - - // remove whitespace at the end of the link - for linkE > linkB && isspace(data[linkE-1]) { - linkE-- - } - - // remove optional angle brackets around the link - if data[linkB] == '<' { - linkB++ - } - if data[linkE-1] == '>' { - linkE-- - } - - // build escaped link and title - if linkE > linkB { - link = data[linkB:linkE] - } - - if titleE > titleB { - title = data[titleB:titleE] - } - - i++ - - // reference style link - case isReferenceStyleLink(data, i, t): - var id []byte - altContentConsidered := false - - // look for the id - i++ - linkB := i - for i < len(data) && data[i] != ']' { - i++ - } - if i >= len(data) { - return 0, nil - } - linkE := i - - // find the reference - if linkB == linkE { - if textHasNl { - var b bytes.Buffer - - for j := 1; j < txtE; j++ { - switch { - case data[j] != '\n': - b.WriteByte(data[j]) - case data[j-1] != ' ': - b.WriteByte(' ') - } - } - - id = b.Bytes() - } else { - id = data[1:txtE] - altContentConsidered = true - } - } else { - id = data[linkB:linkE] - } - - // find the reference with matching id - lr, ok := p.getRef(string(id)) - if !ok { - return 0, nil - } - - // keep link and title from reference - link = lr.link - title = lr.title - if altContentConsidered { - altContent = lr.text - } - i++ - - // shortcut reference style link or reference or inline footnote - default: - var id []byte - - // craft the id - if textHasNl { - var b bytes.Buffer - - for j := 1; j < txtE; j++ { - switch { - case data[j] != '\n': - b.WriteByte(data[j]) - case data[j-1] != ' ': - b.WriteByte(' ') - } - } - - id = b.Bytes() - } else { - if t == linkDeferredFootnote { - id = data[2:txtE] // get rid of the ^ - } else { - id = data[1:txtE] - } - } - - footnoteNode = NewNode(Item) - if t == linkInlineFootnote { - // create a new reference - noteID = len(p.notes) + 1 - - var fragment []byte - if len(id) > 0 { - if len(id) < 16 { - fragment = make([]byte, len(id)) - } else { - fragment = make([]byte, 16) - } - copy(fragment, slugify(id)) - } else { - fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteID))...) - } - - ref := &reference{ - noteID: noteID, - hasBlock: false, - link: fragment, - title: id, - footnote: footnoteNode, - } - - p.notes = append(p.notes, ref) - - link = ref.link - title = ref.title - } else { - // find the reference with matching id - lr, ok := p.getRef(string(id)) - if !ok { - return 0, nil - } - - if t == linkDeferredFootnote { - lr.noteID = len(p.notes) + 1 - lr.footnote = footnoteNode - p.notes = append(p.notes, lr) - } - - // keep link and title from reference - link = lr.link - // if inline footnote, title == footnote contents - title = lr.title - noteID = lr.noteID - } - - // rewind the whitespace - i = txtE + 1 - } - - var uLink []byte - if t == linkNormal || t == linkImg { - if len(link) > 0 { - var uLinkBuf bytes.Buffer - unescapeText(&uLinkBuf, link) - uLink = uLinkBuf.Bytes() - } - - // links need something to click on and somewhere to go - if len(uLink) == 0 || (t == linkNormal && txtE <= 1) { - return 0, nil - } - } - - // call the relevant rendering function - var linkNode *Node - switch t { - case linkNormal: - linkNode = NewNode(Link) - linkNode.Destination = normalizeURI(uLink) - linkNode.Title = title - if len(altContent) > 0 { - linkNode.AppendChild(text(altContent)) - } else { - // links cannot contain other links, so turn off link parsing - // temporarily and recurse - insideLink := p.insideLink - p.insideLink = true - p.inline(linkNode, data[1:txtE]) - p.insideLink = insideLink - } - - case linkImg: - linkNode = NewNode(Image) - linkNode.Destination = uLink - linkNode.Title = title - linkNode.AppendChild(text(data[1:txtE])) - i++ - - case linkInlineFootnote, linkDeferredFootnote: - linkNode = NewNode(Link) - linkNode.Destination = link - linkNode.Title = title - linkNode.NoteID = noteID - linkNode.Footnote = footnoteNode - if t == linkInlineFootnote { - i++ - } - - default: - return 0, nil - } - - return i, linkNode -} - -func (p *Markdown) inlineHTMLComment(data []byte) int { - if len(data) < 5 { - return 0 - } - if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { - return 0 - } - i := 5 - // scan for an end-of-comment marker, across lines if necessary - for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { - i++ - } - // no end-of-comment marker - if i >= len(data) { - return 0 - } - return i + 1 -} - -func stripMailto(link []byte) []byte { - if bytes.HasPrefix(link, []byte("mailto://")) { - return link[9:] - } else if bytes.HasPrefix(link, []byte("mailto:")) { - return link[7:] - } else { - return link - } -} - -// autolinkType specifies a kind of autolink that gets detected. -type autolinkType int - -// These are the possible flag values for the autolink renderer. -const ( - notAutolink autolinkType = iota - normalAutolink - emailAutolink -) - -// '<' when tags or autolinks are allowed -func leftAngle(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - altype, end := tagLength(data) - if size := p.inlineHTMLComment(data); size > 0 { - end = size - } - if end > 2 { - if altype != notAutolink { - var uLink bytes.Buffer - unescapeText(&uLink, data[1:end+1-2]) - if uLink.Len() > 0 { - link := uLink.Bytes() - node := NewNode(Link) - node.Destination = link - if altype == emailAutolink { - node.Destination = append([]byte("mailto:"), link...) - } - node.AppendChild(text(stripMailto(link))) - return end, node - } - } else { - htmlTag := NewNode(HTMLSpan) - htmlTag.Literal = data[:end] - return end, htmlTag - } - } - - return end, nil -} - -// '\\' backslash escape -var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~") - -func escape(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - if len(data) > 1 { - if p.extensions&BackslashLineBreak != 0 && data[1] == '\n' { - return 2, NewNode(Hardbreak) - } - if bytes.IndexByte(escapeChars, data[1]) < 0 { - return 0, nil - } - - return 2, text(data[1:2]) - } - - return 2, nil -} - -func unescapeText(ob *bytes.Buffer, src []byte) { - i := 0 - for i < len(src) { - org := i - for i < len(src) && src[i] != '\\' { - i++ - } - - if i > org { - ob.Write(src[org:i]) - } - - if i+1 >= len(src) { - break - } - - ob.WriteByte(src[i+1]) - i += 2 - } -} - -// '&' escaped when it doesn't belong to an entity -// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; -func entity(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - end := 1 - - if end < len(data) && data[end] == '#' { - end++ - } - - for end < len(data) && isalnum(data[end]) { - end++ - } - - if end < len(data) && data[end] == ';' { - end++ // real entity - } else { - return 0, nil // lone '&' - } - - ent := data[:end] - // undo & escaping or it will be converted to &amp; by another - // escaper in the renderer - if bytes.Equal(ent, []byte("&")) { - ent = []byte{'&'} - } - - return end, text(ent) -} - -func linkEndsWithEntity(data []byte, linkEnd int) bool { - entityRanges := htmlEntityRe.FindAllIndex(data[:linkEnd], -1) - return entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd -} - -// hasPrefixCaseInsensitive is a custom implementation of -// -// strings.HasPrefix(strings.ToLower(s), prefix) -// -// we rolled our own because ToLower pulls in a huge machinery of lowercasing -// anything from Unicode and that's very slow. Since this func will only be -// used on ASCII protocol prefixes, we can take shortcuts. -func hasPrefixCaseInsensitive(s, prefix []byte) bool { - if len(s) < len(prefix) { - return false - } - delta := byte('a' - 'A') - for i, b := range prefix { - if b != s[i] && b != s[i]+delta { - return false - } - } - return true -} - -var protocolPrefixes = [][]byte{ - []byte("http://"), - []byte("https://"), - []byte("ftp://"), - []byte("file://"), - []byte("mailto:"), -} - -const shortestPrefix = 6 // len("ftp://"), the shortest of the above - -func maybeAutoLink(p *Markdown, data []byte, offset int) (int, *Node) { - // quick check to rule out most false hits - if p.insideLink || len(data) < offset+shortestPrefix { - return 0, nil - } - for _, prefix := range protocolPrefixes { - endOfHead := offset + 8 // 8 is the len() of the longest prefix - if endOfHead > len(data) { - endOfHead = len(data) - } - if hasPrefixCaseInsensitive(data[offset:endOfHead], prefix) { - return autoLink(p, data, offset) - } - } - return 0, nil -} - -func autoLink(p *Markdown, data []byte, offset int) (int, *Node) { - // Now a more expensive check to see if we're not inside an anchor element - anchorStart := offset - offsetFromAnchor := 0 - for anchorStart > 0 && data[anchorStart] != '<' { - anchorStart-- - offsetFromAnchor++ - } - - anchorStr := anchorRe.Find(data[anchorStart:]) - if anchorStr != nil { - anchorClose := NewNode(HTMLSpan) - anchorClose.Literal = anchorStr[offsetFromAnchor:] - return len(anchorStr) - offsetFromAnchor, anchorClose - } - - // scan backward for a word boundary - rewind := 0 - for offset-rewind > 0 && rewind <= 7 && isletter(data[offset-rewind-1]) { - rewind++ - } - if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters - return 0, nil - } - - origData := data - data = data[offset-rewind:] - - if !isSafeLink(data) { - return 0, nil - } - - linkEnd := 0 - for linkEnd < len(data) && !isEndOfLink(data[linkEnd]) { - linkEnd++ - } - - // Skip punctuation at the end of the link - if (data[linkEnd-1] == '.' || data[linkEnd-1] == ',') && data[linkEnd-2] != '\\' { - linkEnd-- - } - - // But don't skip semicolon if it's a part of escaped entity: - if data[linkEnd-1] == ';' && data[linkEnd-2] != '\\' && !linkEndsWithEntity(data, linkEnd) { - linkEnd-- - } - - // See if the link finishes with a punctuation sign that can be closed. - var copen byte - switch data[linkEnd-1] { - case '"': - copen = '"' - case '\'': - copen = '\'' - case ')': - copen = '(' - case ']': - copen = '[' - case '}': - copen = '{' - default: - copen = 0 - } - - if copen != 0 { - bufEnd := offset - rewind + linkEnd - 2 - - openDelim := 1 - - /* Try to close the final punctuation sign in this same line; - * if we managed to close it outside of the URL, that means that it's - * not part of the URL. If it closes inside the URL, that means it - * is part of the URL. - * - * Examples: - * - * foo http://www.pokemon.com/Pikachu_(Electric) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo (http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric)) - * - * (foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => foo http://www.pokemon.com/Pikachu_(Electric) - */ - - for bufEnd >= 0 && origData[bufEnd] != '\n' && openDelim != 0 { - if origData[bufEnd] == data[linkEnd-1] { - openDelim++ - } - - if origData[bufEnd] == copen { - openDelim-- - } - - bufEnd-- - } - - if openDelim == 0 { - linkEnd-- - } - } - - var uLink bytes.Buffer - unescapeText(&uLink, data[:linkEnd]) - - if uLink.Len() > 0 { - node := NewNode(Link) - node.Destination = uLink.Bytes() - node.AppendChild(text(uLink.Bytes())) - return linkEnd, node - } - - return linkEnd, nil -} - -func isEndOfLink(char byte) bool { - return isspace(char) || char == '<' -} - -var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")} -var validPaths = [][]byte{[]byte("/"), []byte("./"), []byte("../")} - -func isSafeLink(link []byte) bool { - for _, path := range validPaths { - if len(link) >= len(path) && bytes.Equal(link[:len(path)], path) { - if len(link) == len(path) { - return true - } else if isalnum(link[len(path)]) { - return true - } - } - } - - for _, prefix := range validUris { - // TODO: handle unicode here - // case-insensitive prefix test - if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) { - return true - } - } - - return false -} - -// return the length of the given tag, or 0 is it's not valid -func tagLength(data []byte) (autolink autolinkType, end int) { - var i, j int - - // a valid tag can't be shorter than 3 chars - if len(data) < 3 { - return notAutolink, 0 - } - - // begins with a '<' optionally followed by '/', followed by letter or number - if data[0] != '<' { - return notAutolink, 0 - } - if data[1] == '/' { - i = 2 - } else { - i = 1 - } - - if !isalnum(data[i]) { - return notAutolink, 0 - } - - // scheme test - autolink = notAutolink - - // try to find the beginning of an URI - for i < len(data) && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') { - i++ - } - - if i > 1 && i < len(data) && data[i] == '@' { - if j = isMailtoAutoLink(data[i:]); j != 0 { - return emailAutolink, i + j - } - } - - if i > 2 && i < len(data) && data[i] == ':' { - autolink = normalAutolink - i++ - } - - // complete autolink test: no whitespace or ' or " - switch { - case i >= len(data): - autolink = notAutolink - case autolink != notAutolink: - j = i - - for i < len(data) { - if data[i] == '\\' { - i += 2 - } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isspace(data[i]) { - break - } else { - i++ - } - - } - - if i >= len(data) { - return autolink, 0 - } - if i > j && data[i] == '>' { - return autolink, i + 1 - } - - // one of the forbidden chars has been found - autolink = notAutolink - } - i += bytes.IndexByte(data[i:], '>') - if i < 0 { - return autolink, 0 - } - return autolink, i + 1 -} - -// look for the address part of a mail autolink and '>' -// this is less strict than the original markdown e-mail address matching -func isMailtoAutoLink(data []byte) int { - nb := 0 - - // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' - for i := 0; i < len(data); i++ { - if isalnum(data[i]) { - continue - } - - switch data[i] { - case '@': - nb++ - - case '-', '.', '_': - break - - case '>': - if nb == 1 { - return i + 1 - } - return 0 - default: - return 0 - } - } - - return 0 -} - -// look for the next emph char, skipping other constructs -func helperFindEmphChar(data []byte, c byte) int { - i := 0 - - for i < len(data) { - for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' { - i++ - } - if i >= len(data) { - return 0 - } - // do not count escaped chars - if i != 0 && data[i-1] == '\\' { - i++ - continue - } - if data[i] == c { - return i - } - - if data[i] == '`' { - // skip a code span - tmpI := 0 - i++ - for i < len(data) && data[i] != '`' { - if tmpI == 0 && data[i] == c { - tmpI = i - } - i++ - } - if i >= len(data) { - return tmpI - } - i++ - } else if data[i] == '[' { - // skip a link - tmpI := 0 - i++ - for i < len(data) && data[i] != ']' { - if tmpI == 0 && data[i] == c { - tmpI = i - } - i++ - } - i++ - for i < len(data) && (data[i] == ' ' || data[i] == '\n') { - i++ - } - if i >= len(data) { - return tmpI - } - if data[i] != '[' && data[i] != '(' { // not a link - if tmpI > 0 { - return tmpI - } - continue - } - cc := data[i] - i++ - for i < len(data) && data[i] != cc { - if tmpI == 0 && data[i] == c { - return i - } - i++ - } - if i >= len(data) { - return tmpI - } - i++ - } - } - return 0 -} - -func helperEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { - i := 0 - - // skip one symbol if coming from emph3 - if len(data) > 1 && data[0] == c && data[1] == c { - i = 1 - } - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - if i >= len(data) { - return 0, nil - } - - if i+1 < len(data) && data[i+1] == c { - i++ - continue - } - - if data[i] == c && !isspace(data[i-1]) { - - if p.extensions&NoIntraEmphasis != 0 { - if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) { - continue - } - } - - emph := NewNode(Emph) - p.inline(emph, data[:i]) - return i + 1, emph - } - } - - return 0, nil -} - -func helperDoubleEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { - i := 0 - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - - if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) { - nodeType := Strong - if c == '~' { - nodeType = Del - } - node := NewNode(nodeType) - p.inline(node, data[:i]) - return i + 2, node - } - i++ - } - return 0, nil -} - -func helperTripleEmphasis(p *Markdown, data []byte, offset int, c byte) (int, *Node) { - i := 0 - origData := data - data = data[offset:] - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - - // skip whitespace preceded symbols - if data[i] != c || isspace(data[i-1]) { - continue - } - - switch { - case i+2 < len(data) && data[i+1] == c && data[i+2] == c: - // triple symbol found - strong := NewNode(Strong) - em := NewNode(Emph) - strong.AppendChild(em) - p.inline(em, data[:i]) - return i + 3, strong - case (i+1 < len(data) && data[i+1] == c): - // double symbol found, hand over to emph1 - length, node := helperEmphasis(p, origData[offset-2:], c) - if length == 0 { - return 0, nil - } - return length - 2, node - default: - // single symbol found, hand over to emph2 - length, node := helperDoubleEmphasis(p, origData[offset-1:], c) - if length == 0 { - return 0, nil - } - return length - 1, node - } - } - return 0, nil -} - -func text(s []byte) *Node { - node := NewNode(Text) - node.Literal = s - return node -} - -func normalizeURI(s []byte) []byte { - return s // TODO: implement -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/markdown.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/markdown.go deleted file mode 100644 index 4d0a831..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/markdown.go +++ /dev/null @@ -1,945 +0,0 @@ -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. - -//nolint:gocritic,wastedassign,unused,revive,govet // ignore blackfriday -package blackfriday - -import ( - "bytes" - "fmt" - "io" - "strings" - "unicode/utf8" -) - -// -// Markdown parsing and processing -// - -// Version string of the package. Appears in the rendered document when -// CompletePage flag is on. -const Version = "2.0" - -// Extensions is a bitwise or'ed collection of enabled Blackfriday's -// extensions. -type Extensions int - -// These are the supported markdown parsing extensions. -// OR these values together to select multiple extensions. -const ( - NoExtensions Extensions = 0 - NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words - Tables // Render tables - FencedCode // Render fenced code blocks - Autolink // Detect embedded URLs that are not explicitly marked - Strikethrough // Strikethrough text using ~~test~~ - LaxHTMLBlocks // Loosen up HTML block parsing rules - SpaceHeadings // Be strict about prefix heading rules - HardLineBreak // Translate newlines into line breaks - TabSizeEight // Expand tabs to eight spaces instead of four - Footnotes // Pandoc-style footnotes - NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block - HeadingIDs // specify heading IDs with {#id} - Titleblock // Titleblock ala pandoc - AutoHeadingIDs // Create the heading ID from the text - BackslashLineBreak // Translate trailing backslashes into line breaks - DefinitionLists // Render definition lists - - CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants | - SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes - - CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | - Autolink | Strikethrough | SpaceHeadings | HeadingIDs | - BackslashLineBreak | DefinitionLists -) - -// ListType contains bitwise or'ed flags for list and list item objects. -type ListType int - -// These are the possible flag values for the ListItem renderer. -// Multiple flag values may be ORed together. -// These are mostly of interest if you are writing a new output format. -const ( - ListTypeOrdered ListType = 1 << iota - ListTypeDefinition - ListTypeTerm - - ListItemContainsBlock - ListItemBeginningOfList // TODO: figure out if this is of any use now - ListItemEndOfList -) - -// CellAlignFlags holds a type of alignment in a table cell. -type CellAlignFlags int - -// These are the possible flag values for the table cell renderer. -// Only a single one of these values will be used; they are not ORed together. -// These are mostly of interest if you are writing a new output format. -const ( - TableAlignmentLeft CellAlignFlags = 1 << iota - TableAlignmentRight - TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight) -) - -// The size of a tab stop. -const ( - TabSizeDefault = 4 - TabSizeDouble = 8 -) - -// blockTags is a set of tags that are recognized as HTML block tags. -// Any of these can be included in markdown text without special escaping. -var blockTags = map[string]struct{}{ - "blockquote": {}, - "del": {}, - "div": {}, - "dl": {}, - "fieldset": {}, - "form": {}, - "h1": {}, - "h2": {}, - "h3": {}, - "h4": {}, - "h5": {}, - "h6": {}, - "iframe": {}, - "ins": {}, - "math": {}, - "noscript": {}, - "ol": {}, - "pre": {}, - "p": {}, - "script": {}, - "style": {}, - "table": {}, - "ul": {}, - - // HTML5 - "address": {}, - "article": {}, - "aside": {}, - "canvas": {}, - "figcaption": {}, - "figure": {}, - "footer": {}, - "header": {}, - "hgroup": {}, - "main": {}, - "nav": {}, - "output": {}, - "progress": {}, - "section": {}, - "video": {}, -} - -// Renderer is the rendering interface. This is mostly of interest if you are -// implementing a new rendering format. -// -// Only an HTML implementation is provided in this repository, see the README -// for external implementations. -type Renderer interface { - // RenderNode is the main rendering method. It will be called once for - // every leaf node and twice for every non-leaf node (first with - // entering=true, then with entering=false). The method should write its - // rendition of the node to the supplied writer w. - RenderNode(w io.Writer, node *Node, entering bool) WalkStatus - - // RenderHeader is a method that allows the renderer to produce some - // content preceding the main body of the output document. The header is - // understood in the broad sense here. For example, the default HTML - // renderer will write not only the HTML document preamble, but also the - // table of contents if it was requested. - // - // The method will be passed an entire document tree, in case a particular - // implementation needs to inspect it to produce output. - // - // The output should be written to the supplied writer w. If your - // implementation has no header to write, supply an empty implementation. - RenderHeader(w io.Writer, ast *Node) - - // RenderFooter is a symmetric counterpart of RenderHeader. - RenderFooter(w io.Writer, ast *Node) -} - -// Callback functions for inline parsing. One such function is defined -// for each character that triggers a response when parsing inline data. -type inlineParser func(p *Markdown, data []byte, offset int) (int, *Node) - -// Markdown is a type that holds extensions and the runtime state used by -// Parse, and the renderer. You can not use it directly, construct it with New. -type Markdown struct { - renderer Renderer - referenceOverride ReferenceOverrideFunc - refs map[string]*reference - inlineCallback [256]inlineParser - extensions Extensions - nesting int - maxNesting int - insideLink bool - - // Footnotes need to be ordered as well as available to quickly check for - // presence. If a ref is also a footnote, it's stored both in refs and here - // in notes. Slice is nil if footnotes not enabled. - notes []*reference - - doc *Node - tip *Node // = doc - oldTip *Node - lastMatchedContainer *Node // = doc - allClosed bool -} - -func (p *Markdown) getRef(refid string) (ref *reference, found bool) { - if p.referenceOverride != nil { - r, overridden := p.referenceOverride(refid) - if overridden { - if r == nil { - return nil, false - } - return &reference{ - link: []byte(r.Link), - title: []byte(r.Title), - noteID: 0, - hasBlock: false, - text: []byte(r.Text)}, true - } - } - // refs are case insensitive - ref, found = p.refs[strings.ToLower(refid)] - return ref, found -} - -func (p *Markdown) finalize(block *Node) { - above := block.Parent - block.open = false - p.tip = above -} - -func (p *Markdown) addChild(node NodeType, offset uint32) *Node { - return p.addExistingChild(NewNode(node), offset) -} - -func (p *Markdown) addExistingChild(node *Node, offset uint32) *Node { - for !p.tip.canContain(node.Type) { - p.finalize(p.tip) - } - p.tip.AppendChild(node) - p.tip = node - return node -} - -func (p *Markdown) closeUnmatchedBlocks() { - if !p.allClosed { - for p.oldTip != p.lastMatchedContainer { - parent := p.oldTip.Parent - p.finalize(p.oldTip) - p.oldTip = parent - } - p.allClosed = true - } -} - -// -// -// Public interface -// -// - -// Reference represents the details of a link. -// See the documentation in Options for more details on use-case. -type Reference struct { - // Link is usually the URL the reference points to. - Link string - // Title is the alternate text describing the link in more detail. - Title string - // Text is the optional text to override the ref with if the syntax used was - // [refid][] - Text string -} - -// ReferenceOverrideFunc is expected to be called with a reference string and -// return either a valid Reference type that the reference string maps to or -// nil. If overridden is false, the default reference logic will be executed. -// See the documentation in Options for more details on use-case. -type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool) - -// New constructs a Markdown processor. You can use the same With* functions as -// for Run() to customize parser's behavior and the renderer. -func New(opts ...Option) *Markdown { - var p Markdown - for _, opt := range opts { - opt(&p) - } - p.refs = make(map[string]*reference) - p.maxNesting = 16 - p.insideLink = false - docNode := NewNode(Document) - p.doc = docNode - p.tip = docNode - p.oldTip = docNode - p.lastMatchedContainer = docNode - p.allClosed = true - // register inline parsers - p.inlineCallback[' '] = maybeLineBreak - p.inlineCallback['*'] = emphasis - p.inlineCallback['_'] = emphasis - if p.extensions&Strikethrough != 0 { - p.inlineCallback['~'] = emphasis - } - p.inlineCallback['`'] = codeSpan - p.inlineCallback['\n'] = lineBreak - p.inlineCallback['['] = link - p.inlineCallback['<'] = leftAngle - p.inlineCallback['\\'] = escape - p.inlineCallback['&'] = entity - p.inlineCallback['!'] = maybeImage - p.inlineCallback['^'] = maybeInlineFootnote - if p.extensions&Autolink != 0 { - p.inlineCallback['h'] = maybeAutoLink - p.inlineCallback['m'] = maybeAutoLink - p.inlineCallback['f'] = maybeAutoLink - p.inlineCallback['H'] = maybeAutoLink - p.inlineCallback['M'] = maybeAutoLink - p.inlineCallback['F'] = maybeAutoLink - } - if p.extensions&Footnotes != 0 { - p.notes = make([]*reference, 0) - } - return &p -} - -// Option customizes the Markdown processor's default behavior. -type Option func(*Markdown) - -// WithRenderer allows you to override the default renderer. -func WithRenderer(r Renderer) Option { - return func(p *Markdown) { - p.renderer = r - } -} - -// WithExtensions allows you to pick some of the many extensions provided by -// Blackfriday. You can bitwise OR them. -func WithExtensions(e Extensions) Option { - return func(p *Markdown) { - p.extensions = e - } -} - -// WithNoExtensions turns off all extensions and custom behavior. -func WithNoExtensions() Option { - return func(p *Markdown) { - p.extensions = NoExtensions - p.renderer = NewHTMLRenderer(HTMLRendererParameters{ - Flags: HTMLFlagsNone, - }) - } -} - -// WithRefOverride sets an optional function callback that is called every -// time a reference is resolved. -// -// In Markdown, the link reference syntax can be made to resolve a link to -// a reference instead of an inline URL, in one of the following ways: -// -// - [link text][refid] -// - [refid][] -// -// Usually, the refid is defined at the bottom of the Markdown document. If -// this override function is provided, the refid is passed to the override -// function first, before consulting the defined refids at the bottom. If -// the override function indicates an override did not occur, the refids at -// the bottom will be used to fill in the link details. -func WithRefOverride(o ReferenceOverrideFunc) Option { - return func(p *Markdown) { - p.referenceOverride = o - } -} - -// Run is the main entry point to Blackfriday. It parses and renders a -// block of markdown-encoded text. -// -// The simplest invocation of Run takes one argument, input: -// -// output := Run(input) -// -// This will parse the input with CommonExtensions enabled and render it with -// the default HTMLRenderer (with CommonHTMLFlags). -// -// Variadic arguments opts can customize the default behavior. Since Markdown -// type does not contain exported fields, you can not use it directly. Instead, -// use the With* functions. For example, this will call the most basic -// functionality, with no extensions: -// -// output := Run(input, WithNoExtensions()) -// -// You can use any number of With* arguments, even contradicting ones. They -// will be applied in order of appearance and the latter will override the -// former: -// -// output := Run(input, WithNoExtensions(), WithExtensions(exts), -// WithRenderer(yourRenderer)) -func Run(input []byte, opts ...Option) []byte { - r := NewHTMLRenderer(HTMLRendererParameters{ - Flags: CommonHTMLFlags, - }) - optList := []Option{WithRenderer(r), WithExtensions(CommonExtensions)} - optList = append(optList, opts...) - parser := New(optList...) - ast := parser.Parse(input) - var buf bytes.Buffer - parser.renderer.RenderHeader(&buf, ast) - ast.Walk(func(node *Node, entering bool) WalkStatus { - return parser.renderer.RenderNode(&buf, node, entering) - }) - parser.renderer.RenderFooter(&buf, ast) - return buf.Bytes() -} - -// Parse is an entry point to the parsing part of Blackfriday. It takes an -// input markdown document and produces a syntax tree for its contents. This -// tree can then be rendered with a default or custom renderer, or -// analyzed/transformed by the caller to whatever non-standard needs they have. -// The return value is the root node of the syntax tree. -func (p *Markdown) Parse(input []byte) *Node { - p.block(input) - // Walk the tree and finish up some of unfinished blocks - for p.tip != nil { - p.finalize(p.tip) - } - // Walk the tree again and process inline markdown in each block - p.doc.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Paragraph || node.Type == Heading || node.Type == TableCell { - p.inline(node, node.content) - node.content = nil - } - return GoToNext - }) - p.parseRefsToAST() - return p.doc -} - -func (p *Markdown) parseRefsToAST() { - if p.extensions&Footnotes == 0 || len(p.notes) == 0 { - return - } - p.tip = p.doc - block := p.addBlock(List, nil) - block.IsFootnotesList = true - block.ListFlags = ListTypeOrdered - flags := ListItemBeginningOfList - // Note: this loop is intentionally explicit, not range-form. This is - // because the body of the loop will append nested footnotes to p.notes and - // we need to process those late additions. Range form would only walk over - // the fixed initial set. - for i := 0; i < len(p.notes); i++ { - ref := p.notes[i] - p.addExistingChild(ref.footnote, 0) - block := ref.footnote - block.ListFlags = flags | ListTypeOrdered - block.RefLink = ref.link - if ref.hasBlock { - flags |= ListItemContainsBlock - p.block(ref.title) - } else { - p.inline(block, ref.title) - } - flags &^= ListItemBeginningOfList | ListItemContainsBlock - } - above := block.Parent - finalizeList(block) - p.tip = above - block.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Paragraph || node.Type == Heading { - p.inline(node, node.content) - node.content = nil - } - return GoToNext - }) -} - -// -// Link references -// -// This section implements support for references that (usually) appear -// as footnotes in a document, and can be referenced anywhere in the document. -// The basic format is: -// -// [1]: http://www.google.com/ "Google" -// [2]: http://www.github.com/ "Github" -// -// Anywhere in the document, the reference can be linked by referring to its -// label, i.e., 1 and 2 in this example, as in: -// -// This library is hosted on [Github][2], a git hosting site. -// -// Actual footnotes as specified in Pandoc and supported by some other Markdown -// libraries such as php-markdown are also taken care of. They look like this: -// -// This sentence needs a bit of further explanation.[^note] -// -// [^note]: This is the explanation. -// -// Footnotes should be placed at the end of the document in an ordered list. -// Inline footnotes such as: -// -// Inline footnotes^[Not supported.] also exist. -// -// are not yet supported. - -// reference holds all information necessary for a reference-style links or -// footnotes. -// -// Consider this markdown with reference-style links: -// -// [link][ref] -// -// [ref]: /url/ "tooltip title" -// -// It will be ultimately converted to this HTML: -// -// <p><a href=\"/url/\" title=\"title\">link</a></p> -// -// And a reference structure will be populated as follows: -// -// p.refs["ref"] = &reference{ -// link: "/url/", -// title: "tooltip title", -// } -// -// Alternatively, reference can contain information about a footnote. Consider -// this markdown: -// -// Text needing a footnote.[^a] -// -// [^a]: This is the note -// -// A reference structure will be populated as follows: -// -// p.refs["a"] = &reference{ -// link: "a", -// title: "This is the note", -// noteID: <some positive int>, -// } -// -// TODO: As you can see, it begs for splitting into two dedicated structures -// for refs and for footnotes. -type reference struct { - link []byte - title []byte - noteID int // 0 if not a footnote ref - hasBlock bool - footnote *Node // a link to the Item node within a list of footnotes - - text []byte // only gets populated by refOverride feature with Reference.Text -} - -func (r *reference) String() string { - return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}", - r.link, r.title, r.text, r.noteID, r.hasBlock) -} - -// Check whether or not data starts with a reference link. -// If so, it is parsed and stored in the list of references -// (in the render struct). -// Returns the number of bytes to skip to move past it, -// or zero if the first line is not a reference. -func isReference(p *Markdown, data []byte, tabSize int) int { - // up to 3 optional leading spaces - if len(data) < 4 { - return 0 - } - i := 0 - for i < 3 && data[i] == ' ' { - i++ - } - - noteID := 0 - - // id part: anything but a newline between brackets - if data[i] != '[' { - return 0 - } - i++ - if p.extensions&Footnotes != 0 { - if i < len(data) && data[i] == '^' { - // we can set it to anything here because the proper noteIds will - // be assigned later during the second pass. It just has to be != 0 - noteID = 1 - i++ - } - } - idOffset := i - for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' { - i++ - } - if i >= len(data) || data[i] != ']' { - return 0 - } - idEnd := i - // footnotes can have empty ID, like this: [^], but a reference can not be - // empty like this: []. Break early if it's not a footnote and there's no ID - if noteID == 0 && idOffset == idEnd { - return 0 - } - // spacer: colon (space | tab)* newline? (space | tab)* - i++ - if i >= len(data) || data[i] != ':' { - return 0 - } - i++ - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i < len(data) && (data[i] == '\n' || data[i] == '\r') { - i++ - if i < len(data) && data[i] == '\n' && data[i-1] == '\r' { - i++ - } - } - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i >= len(data) { - return 0 - } - - var ( - linkOffset, linkEnd int - titleOffset, titleEnd int - lineEnd int - raw []byte - hasBlock bool - ) - - if p.extensions&Footnotes != 0 && noteID != 0 { - linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize) - lineEnd = linkEnd - } else { - linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i) - } - if lineEnd == 0 { - return 0 - } - - // a valid ref has been found - - ref := &reference{ - noteID: noteID, - hasBlock: hasBlock, - } - - if noteID > 0 { - // reusing the link field for the id since footnotes don't have links - ref.link = data[idOffset:idEnd] - // if footnote, it's not really a title, it's the contained text - ref.title = raw - } else { - ref.link = data[linkOffset:linkEnd] - ref.title = data[titleOffset:titleEnd] - } - - // id matches are case-insensitive - id := string(bytes.ToLower(data[idOffset:idEnd])) - - p.refs[id] = ref - - return lineEnd -} - -func scanLinkRef(p *Markdown, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) { - // link: whitespace-free sequence, optionally between angle brackets - if data[i] == '<' { - i++ - } - linkOffset = i - for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { - i++ - } - linkEnd = i - if data[linkOffset] == '<' && data[linkEnd-1] == '>' { - linkOffset++ - linkEnd-- - } - - // optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' { - return - } - - // compute end-of-line - if i >= len(data) || data[i] == '\r' || data[i] == '\n' { - lineEnd = i - } - if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' { - lineEnd++ - } - - // optional (space|tab)* spacer after a newline - if lineEnd > 0 { - i = lineEnd + 1 - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - } - - // optional title: any non-newline sequence enclosed in '"() alone on its line - if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') { - i++ - titleOffset = i - - // look for EOL - for i < len(data) && data[i] != '\n' && data[i] != '\r' { - i++ - } - if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' { - titleEnd = i + 1 - } else { - titleEnd = i - } - - // step back - i-- - for i > titleOffset && (data[i] == ' ' || data[i] == '\t') { - i-- - } - if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') { - lineEnd = titleEnd - titleEnd = i - } - } - - return -} - -// The first bit of this logic is the same as Parser.listItem, but the rest -// is much simpler. This function simply finds the entire block and shifts it -// over by one tab if it is indeed a block (just returns the line if it's not). -// blockEnd is the end of the section in the input buffer, and contents is the -// extracted text that was shifted over one tab. It will need to be rendered at -// the end of the document. -func scanFootnote(p *Markdown, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) { - if i == 0 || len(data) == 0 { - return - } - - // skip leading whitespace on first line - for i < len(data) && data[i] == ' ' { - i++ - } - - blockStart = i - - // find the end of the line - blockEnd = i - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // get working buffer - var raw bytes.Buffer - - // put the first line into the working buffer - raw.Write(data[blockEnd:i]) - blockEnd = i - - // process the following lines - containsBlankLine := false - -gatherLines: - for blockEnd < len(data) { - i++ - - // find the end of this line - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // if it is an empty line, guess that it is part of this item - // and move on to the next line - if p.isEmpty(data[blockEnd:i]) > 0 { - containsBlankLine = true - blockEnd = i - continue - } - - n := 0 - if n = isIndented(data[blockEnd:i], indentSize); n == 0 { - // this is the end of the block. - // we don't want to include this last line in the index. - break gatherLines - } - - // if there were blank lines before this one, insert a new one now - if containsBlankLine { - raw.WriteByte('\n') - containsBlankLine = false - } - - // get rid of that first tab, write to buffer - raw.Write(data[blockEnd+n : i]) - hasBlock = true - - blockEnd = i - } - - if data[blockEnd-1] != '\n' { - raw.WriteByte('\n') - } - - contents = raw.Bytes() - - return -} - -// -// -// Miscellaneous helper functions -// -// - -// Test if a character is a punctuation symbol. -// Taken from a private function in regexp in the stdlib. -func ispunct(c byte) bool { - for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") { - if c == r { - return true - } - } - return false -} - -// Test if a character is a whitespace character. -func isspace(c byte) bool { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' -} - -// Test if a character is letter. -func isletter(c byte) bool { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') -} - -// Test if a character is a letter or a digit. -// TODO: check when this is looking for ASCII alnum and when it should use unicode -func isalnum(c byte) bool { - return (c >= '0' && c <= '9') || isletter(c) -} - -// Replace tab characters with spaces, aligning to the next TAB_SIZE column. -// always ends output with a newline -func expandTabs(out *bytes.Buffer, line []byte, tabSize int) { - // first, check for common cases: no tabs, or only tabs at beginning of line - i, prefix := 0, 0 - slowcase := false - for i = 0; i < len(line); i++ { - if line[i] == '\t' { - if prefix == i { - prefix++ - } else { - slowcase = true - break - } - } - } - - // no need to decode runes if all tabs are at the beginning of the line - if !slowcase { - for i = 0; i < prefix*tabSize; i++ { - out.WriteByte(' ') - } - out.Write(line[prefix:]) - return - } - - // the slow case: we need to count runes to figure out how - // many spaces to insert for each tab - column := 0 - i = 0 - for i < len(line) { - start := i - for i < len(line) && line[i] != '\t' { - _, size := utf8.DecodeRune(line[i:]) - i += size - column++ - } - - if i > start { - out.Write(line[start:i]) - } - - if i >= len(line) { - break - } - - for { - out.WriteByte(' ') - column++ - if column%tabSize == 0 { - break - } - } - - i++ - } -} - -// Find if a line counts as indented or not. -// Returns number of characters the indent is (0 = not indented). -func isIndented(data []byte, indentSize int) int { - if len(data) == 0 { - return 0 - } - if data[0] == '\t' { - return 1 - } - if len(data) < indentSize { - return 0 - } - for i := 0; i < indentSize; i++ { - if data[i] != ' ' { - return 0 - } - } - return indentSize -} - -// Create a url-safe slug for fragments -func slugify(in []byte) []byte { - if len(in) == 0 { - return in - } - out := make([]byte, 0, len(in)) - sym := false - - for _, ch := range in { - if isalnum(ch) { - sym = false - out = append(out, ch) - } else if sym { - continue - } else { - out = append(out, '-') - sym = true - } - } - var a, b int - var ch byte - for a, ch = range out { - if ch != '-' { - break - } - } - for b = len(out) - 1; b > 0; b-- { - if out[b] != '-' { - break - } - } - return out[a : b+1] -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/node.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/node.go deleted file mode 100644 index d820b83..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/node.go +++ /dev/null @@ -1,355 +0,0 @@ -//nolint:gocritic,unused // ignore blackfriday -package blackfriday - -import ( - "bytes" - "fmt" -) - -// NodeType specifies a type of a single node of a syntax tree. Usually one -// node (and its type) corresponds to a single markdown feature, e.g. emphasis -// or code block. -type NodeType int - -// Constants for identifying different types of nodes. See NodeType. -const ( - Document NodeType = iota - BlockQuote - List - Item - Paragraph - Heading - HorizontalRule - Emph - Strong - Del - Link - Image - Text - HTMLBlock - CodeBlock - Softbreak - Hardbreak - Code - HTMLSpan - Table - TableCell - TableHead - TableBody - TableRow -) - -var nodeTypeNames = []string{ - Document: "Document", - BlockQuote: "BlockQuote", - List: "List", - Item: "Item", - Paragraph: "Paragraph", - Heading: "Heading", - HorizontalRule: "HorizontalRule", - Emph: "Emph", - Strong: "Strong", - Del: "Del", - Link: "Link", - Image: "Image", - Text: "Text", - HTMLBlock: "HTMLBlock", - CodeBlock: "CodeBlock", - Softbreak: "Softbreak", - Hardbreak: "Hardbreak", - Code: "Code", - HTMLSpan: "HTMLSpan", - Table: "Table", - TableCell: "TableCell", - TableHead: "TableHead", - TableBody: "TableBody", - TableRow: "TableRow", -} - -func (t NodeType) String() string { - return nodeTypeNames[t] -} - -// ListData contains fields relevant to a List and Item node type. -type ListData struct { - ListFlags ListType - Tight bool // Skip <p>s around list item data if true - BulletChar byte // '*', '+' or '-' in bullet lists - Delimiter byte // '.' or ')' after the number in ordered lists - RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering - IsFootnotesList bool // This is a list of footnotes -} - -// LinkData contains fields relevant to a Link node type. -type LinkData struct { - Destination []byte // Destination is what goes into a href - Title []byte // Title is the tooltip thing that goes in a title attribute - NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote - Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil. -} - -// CodeBlockData contains fields relevant to a CodeBlock node type. -type CodeBlockData struct { - IsFenced bool // Specifies whether it's a fenced code block or an indented one - Info []byte // This holds the info string - FenceChar byte - FenceLength int - FenceOffset int -} - -// TableCellData contains fields relevant to a TableCell node type. -type TableCellData struct { - IsHeader bool // This tells if it's under the header row - Align CellAlignFlags // This holds the value for align attribute -} - -// HeadingData contains fields relevant to a Heading node type. -type HeadingData struct { - Level int // This holds the heading level number - HeadingID string // This might hold heading ID, if present - IsTitleblock bool // Specifies whether it's a title block -} - -// Node is a single element in the abstract syntax tree of the parsed document. -// It holds connections to the structurally neighboring nodes and, for certain -// types of nodes, additional information that might be needed when rendering. -type Node struct { - Type NodeType // Determines the type of the node - Parent *Node // Points to the parent - FirstChild *Node // Points to the first child, if any - LastChild *Node // Points to the last child, if any - Prev *Node // Previous sibling; nil if it's the first child - Next *Node // Next sibling; nil if it's the last child - - Literal []byte // Text contents of the leaf nodes - - HeadingData // Populated if Type is Heading - ListData // Populated if Type is List - CodeBlockData // Populated if Type is CodeBlock - LinkData // Populated if Type is Link - TableCellData // Populated if Type is TableCell - - content []byte // Markdown content of the block nodes - open bool // Specifies an open block node that has not been finished to process yet -} - -// NewNode allocates a node of a specified type. -func NewNode(typ NodeType) *Node { - return &Node{ - Type: typ, - open: true, - } -} - -func (n *Node) String() string { - ellipsis := "" - snippet := n.Literal - if len(snippet) > 16 { - snippet = snippet[:16] - ellipsis = "..." - } - return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis) -} - -// Unlink removes node 'n' from the tree. -// It panics if the node is nil. -func (n *Node) Unlink() { - if n.Prev != nil { - n.Prev.Next = n.Next - } else if n.Parent != nil { - n.Parent.FirstChild = n.Next - } - if n.Next != nil { - n.Next.Prev = n.Prev - } else if n.Parent != nil { - n.Parent.LastChild = n.Prev - } - n.Parent = nil - n.Next = nil - n.Prev = nil -} - -// AppendChild adds a node 'child' as a child of 'n'. -// It panics if either node is nil. -func (n *Node) AppendChild(child *Node) { - child.Unlink() - child.Parent = n - if n.LastChild != nil { - n.LastChild.Next = child - child.Prev = n.LastChild - n.LastChild = child - } else { - n.FirstChild = child - n.LastChild = child - } -} - -// InsertBefore inserts 'sibling' immediately before 'n'. -// It panics if either node is nil. -func (n *Node) InsertBefore(sibling *Node) { - sibling.Unlink() - sibling.Prev = n.Prev - if sibling.Prev != nil { - sibling.Prev.Next = sibling - } - sibling.Next = n - n.Prev = sibling - sibling.Parent = n.Parent - if sibling.Prev == nil { - sibling.Parent.FirstChild = sibling - } -} - -func (n *Node) isContainer() bool { - switch n.Type { - case Document: - fallthrough - case BlockQuote: - fallthrough - case List: - fallthrough - case Item: - fallthrough - case Paragraph: - fallthrough - case Heading: - fallthrough - case Emph: - fallthrough - case Strong: - fallthrough - case Del: - fallthrough - case Link: - fallthrough - case Image: - fallthrough - case Table: - fallthrough - case TableHead: - fallthrough - case TableBody: - fallthrough - case TableRow: - fallthrough - case TableCell: - return true - default: - return false - } -} - -func (n *Node) canContain(t NodeType) bool { - if n.Type == List { - return t == Item - } - if n.Type == Document || n.Type == BlockQuote || n.Type == Item { - return t != Item - } - if n.Type == Table { - return t == TableHead || t == TableBody - } - if n.Type == TableHead || n.Type == TableBody { - return t == TableRow - } - if n.Type == TableRow { - return t == TableCell - } - return false -} - -// WalkStatus allows NodeVisitor to have some control over the tree traversal. -// It is returned from NodeVisitor and different values allow Node.Walk to -// decide which node to go to next. -type WalkStatus int - -const ( - // GoToNext is the default traversal of every node. - GoToNext WalkStatus = iota - // SkipChildren tells walker to skip all children of current node. - SkipChildren - // Terminate tells walker to terminate the traversal. - Terminate -) - -// NodeVisitor is a callback to be called when traversing the syntax tree. -// Called twice for every node: once with entering=true when the branch is -// first visited, then with entering=false after all the children are done. -type NodeVisitor func(node *Node, entering bool) WalkStatus - -// Walk is a convenience method that instantiates a walker and starts a -// traversal of subtree rooted at n. -func (n *Node) Walk(visitor NodeVisitor) { - w := newNodeWalker(n) - for w.current != nil { - status := visitor(w.current, w.entering) - switch status { - case GoToNext: - w.next() - case SkipChildren: - w.entering = false - w.next() - case Terminate: - return - } - } -} - -type nodeWalker struct { - current *Node - root *Node - entering bool -} - -func newNodeWalker(root *Node) *nodeWalker { - return &nodeWalker{ - current: root, - root: root, - entering: true, - } -} - -func (nw *nodeWalker) next() { - if (!nw.current.isContainer() || !nw.entering) && nw.current == nw.root { - nw.current = nil - return - } - if nw.entering && nw.current.isContainer() { - if nw.current.FirstChild != nil { - nw.current = nw.current.FirstChild - nw.entering = true - } else { - nw.entering = false - } - } else if nw.current.Next == nil { - nw.current = nw.current.Parent - nw.entering = false - } else { - nw.current = nw.current.Next - nw.entering = true - } -} - -func dump(ast *Node) { - fmt.Println(dumpString(ast)) -} - -func dumpR(ast *Node, depth int) string { - if ast == nil { - return "" - } - indent := bytes.Repeat([]byte("\t"), depth) - content := ast.Literal - if content == nil { - content = ast.content - } - result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content) - for n := ast.FirstChild; n != nil; n = n.Next { - result += dumpR(n, depth+1) - } - return result -} - -func dumpString(ast *Node) string { - return dumpR(ast, 0) -} diff --git a/vendor/go.step.sm/cli-utils/pkg/blackfriday/smartypants.go b/vendor/go.step.sm/cli-utils/pkg/blackfriday/smartypants.go deleted file mode 100644 index e5f9e19..0000000 --- a/vendor/go.step.sm/cli-utils/pkg/blackfriday/smartypants.go +++ /dev/null @@ -1,458 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// SmartyPants rendering -// -// - -//nolint:gocritic,revive // ignore blackfriday -package blackfriday - -import ( - "bytes" - "io" -) - -// SPRenderer is a struct containing state of a Smartypants renderer. -type SPRenderer struct { - inSingleQuote bool - inDoubleQuote bool - callbacks [256]smartCallback -} - -func wordBoundary(c byte) bool { - return c == 0 || isspace(c) || ispunct(c) -} - -func tolower(c byte) byte { - if c >= 'A' && c <= 'Z' { - return c - 'A' + 'a' - } - return c -} - -func isdigit(c byte) bool { - return c >= '0' && c <= '9' -} - -func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool, addNBSP bool) bool { - // edge of the buffer is likely to be a tag that we don't get to see, - // so we treat it like text sometimes - - // enumerate all sixteen possibilities for (previousChar, nextChar) - // each can be one of {0, space, punct, other} - switch { - case previousChar == 0 && nextChar == 0: - // context is not any help here, so toggle - *isOpen = !*isOpen - case isspace(previousChar) && nextChar == 0: - // [ "] might be [ "<code>foo...] - *isOpen = true - case ispunct(previousChar) && nextChar == 0: - // [!"] hmm... could be [Run!"] or [("<code>...] - *isOpen = false - case /* isnormal(previousChar) && */ nextChar == 0: - // [a"] is probably a close - *isOpen = false - case previousChar == 0 && isspace(nextChar): - // [" ] might be [...foo</code>" ] - *isOpen = false - case isspace(previousChar) && isspace(nextChar): - // [ " ] context is not any help here, so toggle - *isOpen = !*isOpen - case ispunct(previousChar) && isspace(nextChar): - // [!" ] is probably a close - *isOpen = false - case /* isnormal(previousChar) && */ isspace(nextChar): - // [a" ] this is one of the easy cases - *isOpen = false - case previousChar == 0 && ispunct(nextChar): - // ["!] hmm... could be ["$1.95] or [</code>"!...] - *isOpen = false - case isspace(previousChar) && ispunct(nextChar): - // [ "!] looks more like [ "$1.95] - *isOpen = true - case ispunct(previousChar) && ispunct(nextChar): - // [!"!] context is not any help here, so toggle - *isOpen = !*isOpen - case /* isnormal(previousChar) && */ ispunct(nextChar): - // [a"!] is probably a close - *isOpen = false - case previousChar == 0 /* && isnormal(nextChar) */ : - // ["a] is probably an open - *isOpen = true - case isspace(previousChar) /* && isnormal(nextChar) */ : - // [ "a] this is one of the easy cases - *isOpen = true - case ispunct(previousChar) /* && isnormal(nextChar) */ : - // [!"a] is probably an open - *isOpen = true - default: - // [a'b] maybe a contraction? - *isOpen = false - } - - // Note that with the limited lookahead, this non-breaking - // space will also be appended to single double quotes. - if addNBSP && !*isOpen { - out.WriteString(" ") - } - - out.WriteByte('&') - if *isOpen { - out.WriteByte('l') - } else { - out.WriteByte('r') - } - out.WriteByte(quote) - out.WriteString("quo;") - - if addNBSP && *isOpen { - out.WriteString(" ") - } - - return true -} - -func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 { - t1 := tolower(text[1]) - - if t1 == '\'' { - nextChar := byte(0) - if len(text) >= 3 { - nextChar = text[2] - } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { - return 1 - } - } - - if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) { - out.WriteString("’") - return 0 - } - - if len(text) >= 3 { - t2 := tolower(text[2]) - - if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) && - (len(text) < 4 || wordBoundary(text[3])) { - out.WriteString("’") - return 0 - } - } - } - - nextChar := byte(0) - if len(text) > 1 { - nextChar = text[1] - } - if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) { - return 0 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 { - t1 := tolower(text[1]) - t2 := tolower(text[2]) - - if t1 == 'c' && t2 == ')' { - out.WriteString("©") - return 2 - } - - if t1 == 'r' && t2 == ')' { - out.WriteString("®") - return 2 - } - - if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' { - out.WriteString("™") - return 3 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 { - if text[1] == '-' { - out.WriteString("—") - return 1 - } - - if wordBoundary(previousChar) && wordBoundary(text[1]) { - out.WriteString("–") - return 0 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 && text[1] == '-' && text[2] == '-' { - out.WriteString("—") - return 2 - } - if len(text) >= 2 && text[1] == '-' { - out.WriteString("–") - return 1 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int { - if bytes.HasPrefix(text, []byte(""")) { - nextChar := byte(0) - if len(text) >= 7 { - nextChar = text[6] - } - if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) { - return 5 - } - } - - if bytes.HasPrefix(text, []byte("�")) { - return 3 - } - - out.WriteByte('&') - return 0 -} - -func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int { - var quote byte = 'd' - if angledQuotes { - quote = 'a' - } - - return func(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartAmpVariant(out, previousChar, text, quote, addNBSP) - } -} - -func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 && text[1] == '.' && text[2] == '.' { - out.WriteString("…") - return 2 - } - - if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' { - out.WriteString("…") - return 4 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 && text[1] == '`' { - nextChar := byte(0) - if len(text) >= 3 { - nextChar = text[2] - } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { - return 1 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int { - if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { - // is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b - // note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8) - // and avoid changing dates like 1/23/2005 into fractions. - numEnd := 0 - for len(text) > numEnd && isdigit(text[numEnd]) { - numEnd++ - } - if numEnd == 0 { - out.WriteByte(text[0]) - return 0 - } - denStart := numEnd + 1 - if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 { - denStart = numEnd + 3 - } else if len(text) < numEnd+2 || text[numEnd] != '/' { - out.WriteByte(text[0]) - return 0 - } - denEnd := denStart - for len(text) > denEnd && isdigit(text[denEnd]) { - denEnd++ - } - if denEnd == denStart { - out.WriteByte(text[0]) - return 0 - } - if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' { - out.WriteString("<sup>") - out.Write(text[:numEnd]) - out.WriteString("</sup>⁄<sub>") - out.Write(text[denStart:denEnd]) - out.WriteString("</sub>") - return denEnd - 1 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int { - if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { - if text[0] == '1' && text[1] == '/' && text[2] == '2' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' { - out.WriteString("½") - return 2 - } - } - - if text[0] == '1' && text[1] == '/' && text[2] == '4' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') { - out.WriteString("¼") - return 2 - } - } - - if text[0] == '3' && text[1] == '/' && text[2] == '4' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') { - out.WriteString("¾") - return 2 - } - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int { - nextChar := byte(0) - if len(text) > 1 { - nextChar = text[1] - } - if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) { - out.WriteString(""") - } - - return 0 -} - -func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartDoubleQuoteVariant(out, previousChar, text, 'd') -} - -func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartDoubleQuoteVariant(out, previousChar, text, 'a') -} - -func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int { - i := 0 - - for i < len(text) && text[i] != '>' { - i++ - } - - out.Write(text[:i+1]) - return i -} - -type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int - -// NewSmartypantsRenderer constructs a Smartypants renderer object. -func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer { - var ( - r SPRenderer - - smartAmpAngled = r.smartAmp(true, false) - smartAmpAngledNBSP = r.smartAmp(true, true) - smartAmpRegular = r.smartAmp(false, false) - smartAmpRegularNBSP = r.smartAmp(false, true) - - addNBSP = flags&SmartypantsQuotesNBSP != 0 - ) - - if flags&SmartypantsAngledQuotes == 0 { - r.callbacks['"'] = r.smartDoubleQuote - if !addNBSP { - r.callbacks['&'] = smartAmpRegular - } else { - r.callbacks['&'] = smartAmpRegularNBSP - } - } else { - r.callbacks['"'] = r.smartAngledDoubleQuote - if !addNBSP { - r.callbacks['&'] = smartAmpAngled - } else { - r.callbacks['&'] = smartAmpAngledNBSP - } - } - r.callbacks['\''] = r.smartSingleQuote - r.callbacks['('] = r.smartParens - if flags&SmartypantsDashes != 0 { - if flags&SmartypantsLatexDashes == 0 { - r.callbacks['-'] = r.smartDash - } else { - r.callbacks['-'] = r.smartDashLatex - } - } - r.callbacks['.'] = r.smartPeriod - if flags&SmartypantsFractions == 0 { - r.callbacks['1'] = r.smartNumber - r.callbacks['3'] = r.smartNumber - } else { - for ch := '1'; ch <= '9'; ch++ { - r.callbacks[ch] = r.smartNumberGeneric - } - } - r.callbacks['<'] = r.smartLeftAngle - r.callbacks['`'] = r.smartBacktick - return &r -} - -// Process is the entry point of the Smartypants renderer. -func (r *SPRenderer) Process(w io.Writer, text []byte) { - mark := 0 - for i := 0; i < len(text); i++ { - if action := r.callbacks[text[i]]; action != nil { - if i > mark { - w.Write(text[mark:i]) - } - previousChar := byte(0) - if i > 0 { - previousChar = text[i-1] - } - var tmp bytes.Buffer - i += action(&tmp, previousChar, text[i:]) - w.Write(tmp.Bytes()) - mark = i + 1 - } - } - if mark < len(text) { - w.Write(text[mark:]) - } -} diff --git a/vendor/go.step.sm/cli-utils/step/config.go b/vendor/go.step.sm/cli-utils/step/config.go deleted file mode 100644 index 269f21a..0000000 --- a/vendor/go.step.sm/cli-utils/step/config.go +++ /dev/null @@ -1,220 +0,0 @@ -package step - -import ( - "fmt" - "os" - "os/user" - "path/filepath" - "runtime" - "strings" - "sync" - "time" -) - -// PathEnv defines the name of the environment variable that can overwrite -// the default configuration path. -const PathEnv = "STEPPATH" - -// HomeEnv defines the name of the environment variable that can overwrite the -// default home directory. -const HomeEnv = "HOME" - -var ( - // version and buildTime are filled in during build by the Makefile - name = "Smallstep CLI" - buildTime = "N/A" - version = "N/A" -) - -var cache struct { - sync.Once - err error - stepBasePath string // stepBasePath will be populated in init() with the proper STEPPATH. - homePath string // homePath will be populated in init() with the proper HOME. -} - -// Init initializes the step environment. -// -// A program calling this function should fail because the step variables would -// be undefined. -func Init() error { - if err := initStepPath(); err != nil { - return err - } - return Contexts().Init() -} - -func initStepPath() error { - cache.Do(func() { - // Get home path from environment or from the user object. - homePath := os.Getenv(HomeEnv) - if homePath == "" { - usr, err := user.Current() - if err == nil && usr.HomeDir != "" { - homePath = usr.HomeDir - } else { - cache.err = fmt.Errorf("error obtaining home directory, please define environment variable %s", HomeEnv) - return - } - } - - // Get step path from environment or relative to home. - stepBasePath := os.Getenv(PathEnv) - if stepBasePath == "" { - stepBasePath = filepath.Join(homePath, ".step") - } - - // cleanup and add paths to cache - cache.homePath = filepath.Clean(homePath) - cache.stepBasePath = filepath.Clean(stepBasePath) - }) - - return cache.err -} - -// Home returns the user home directory using the environment variable HOME or -// the os/user package. -func Home() string { - _ = initStepPath() - return cache.homePath -} - -// BasePath returns the base path for the step configuration directory. -func BasePath() string { - _ = initStepPath() - return cache.stepBasePath -} - -// Path returns the path for the step configuration directory. -// -// 1. If the base step path has a current context configured, then this method -// returns the path to the authority configured in the context. -// 2. If the base step path does not have a current context configured this -// method returns the value defined by the environment variable STEPPATH, OR -// 3. If no environment variable is set, this method returns `$HOME/.step`. -func Path() string { - c := Contexts().GetCurrent() - if c == nil { - return BasePath() - } - return filepath.Join(BasePath(), "authorities", c.Authority) -} - -// ProfilePath returns the path for the currently selected profile path. -// -// 1. If the base step path has a current context configured, then this method -// returns the path to the profile configured in the context. -// 2. If the base step path does not have a current context configured this -// method returns the value defined by the environment variable STEPPATH, OR -// 3. If no environment variable is set, this method returns `$HOME/.step`. -func ProfilePath() string { - c := Contexts().GetCurrent() - if c == nil { - return BasePath() - } - return filepath.Join(BasePath(), "profiles", c.Profile) -} - -// IdentityPath returns the location of the identity directory. -func IdentityPath() string { - return filepath.Join(Path(), "identity") -} - -// IdentityFile returns the location of the identity file. -func IdentityFile() string { - return filepath.Join(Path(), "config", "identity.json") -} - -// DefaultsFile returns the location of the defaults file at the base of the -// authority path. -func DefaultsFile() string { - return filepath.Join(Path(), "config", "defaults.json") -} - -// ProfileDefaultsFile returns the location of the defaults file at the base -// of the profile path. -func ProfileDefaultsFile() string { - return filepath.Join(ProfilePath(), "config", "defaults.json") -} - -// ConfigPath returns the location of the $(step path)/config directory. -func ConfigPath() string { - return filepath.Join(Path(), "config") -} - -// ProfileConfigPath returns the location of the $(step path --profile)/config directory. -func ProfileConfigPath() string { - return filepath.Join(ProfilePath(), "config") -} - -// CaConfigFile returns the location of the ca.json file -- configuration for -// connecting to the CA. -func CaConfigFile() string { - return filepath.Join(Path(), "config", "ca.json") -} - -// ContextsFile returns the location of the config file. -func ContextsFile() string { - return filepath.Join(BasePath(), "contexts.json") -} - -// CurrentContextFile returns the path to the file containing the current context. -func CurrentContextFile() string { - return filepath.Join(BasePath(), "current-context.json") -} - -// Abs returns the given path relative to the STEPPATH if it's not an -// absolute path, relative to the home directory using the special string "~/", -// or relative to the working directory using "./" -// -// Relative paths like 'certs/root_ca.crt' will be converted to -// '$STEPPATH/certs/root_ca.crt', but paths like './certs/root_ca.crt' will be -// relative to the current directory. Home relative paths like -// ~/certs/root_ca.crt will be converted to '$HOME/certs/root_ca.crt'. And -// absolute paths like '/certs/root_ca.crt' will remain the same. -func Abs(path string) string { - if filepath.IsAbs(path) { - return path - } - // Windows accept both \ and / - slashed := filepath.ToSlash(path) - switch { - case strings.HasPrefix(slashed, "~/"): - return filepath.Join(Home(), path[2:]) - case strings.HasPrefix(slashed, "./"), strings.HasPrefix(slashed, "../"): - if abs, err := filepath.Abs(path); err == nil { - return abs - } - return path - default: - return filepath.Join(Path(), path) - } -} - -// Set updates the name, version, and build time -func Set(n, v, t string) { - name = n - version = v - buildTime = t -} - -// Version returns the current version of the binary -func Version() string { - out := version - if version == "N/A" { - out = "0000000-dev" - } - - return fmt.Sprintf("%s/%s (%s/%s)", - name, out, runtime.GOOS, runtime.GOARCH) -} - -// ReleaseDate returns the time of when the binary was built -func ReleaseDate() string { - out := buildTime - if buildTime == "N/A" { - out = time.Now().UTC().Format("2006-01-02 15:04 MST") - } - - return out -} diff --git a/vendor/go.step.sm/cli-utils/step/context.go b/vendor/go.step.sm/cli-utils/step/context.go deleted file mode 100644 index 0372fc9..0000000 --- a/vendor/go.step.sm/cli-utils/step/context.go +++ /dev/null @@ -1,564 +0,0 @@ -package step - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "reflect" - "sort" - "strings" - - "github.com/pkg/errors" - "github.com/urfave/cli" - "go.step.sm/cli-utils/errs" - "go.step.sm/cli-utils/ui" -) - -// IgnoreEnvVar is a value added to a flag EnvVar to avoid the use of -// environment variables or configuration files. -const IgnoreEnvVar = "STEP_IGNORE_ENV_VAR" - -// Context represents a Step Path configuration context. A context is the -// combination of a profile and an authority. -type Context struct { - Name string `json:"-"` - Profile string `json:"profile"` - Authority string `json:"authority"` - config map[string]interface{} -} - -// Validate validates a context and returns an error if invalid. -func (c *Context) Validate() error { - suffix := "; check your $STEPPATH/contexts.json file" - if c == nil { - return errors.Errorf("context cannot be nil%s", suffix) - } - if c.Authority == "" { - return errors.Errorf("context cannot have an empty authority value%s", suffix) - } - if c.Profile == "" { - return errors.Errorf("context cannot have an empty profile value%s", suffix) - } - return nil -} - -// Path return the base path relative to the context. -func (c *Context) Path() string { - return filepath.Join(BasePath(), "authorities", c.Authority) -} - -// ProfilePath return the profile base path relative to the context. -func (c *Context) ProfilePath() string { - return filepath.Join(BasePath(), "profiles", c.Profile) -} - -// DefaultsFile returns the location of the defaults file for the context. -func (c *Context) DefaultsFile() string { - return filepath.Join(c.Path(), "config", "defaults.json") -} - -// ProfileDefaultsFile returns the location of the defaults file at the base -// of the profile path. -func (c *Context) ProfileDefaultsFile() string { - return filepath.Join(c.ProfilePath(), "config", "defaults.json") -} - -// Load loads the configuration for the given context. -func (c *Context) Load() error { - c.config = map[string]interface{}{} - for _, f := range []string{c.DefaultsFile(), c.ProfileDefaultsFile()} { - b, err := os.ReadFile(f) - if os.IsNotExist(err) { - continue - } else if err != nil { - return errs.FileError(err, f) - } - - values := make(map[string]interface{}) - if err := json.Unmarshal(b, &values); err != nil { - return errors.Wrapf(err, "error parsing %s", f) - } - - for k, v := range values { - c.config[k] = v - } - } - - attributesBannedFromConfig := []string{ - "context", - "profile", - "authority", - } - for _, attr := range attributesBannedFromConfig { - if _, ok := c.config[attr]; ok { - ui.Printf("cannot set '%s' attribute in config files\n", attr) - delete(c.config, attr) - } - } - - return nil -} - -// ContextMap represents the map of available Contexts that is stored -// at the base of the Step Path. -type ContextMap map[string]*Context - -type storedCurrent struct { - Context string `json:"context"` -} - -// CtxState is the type that manages context state for the cli. -type CtxState struct { - current *Context - contexts ContextMap - config map[string]interface{} -} - -var ctxState = &CtxState{} - -// Init initializes the context map and current context state. -func (cs *CtxState) Init() error { - if err := cs.initMap(); err != nil { - return err - } - if err := cs.initCurrent(); err != nil { - return err - } - return cs.load() -} - -func (cs *CtxState) initMap() error { - contextsFile := ContextsFile() - b, err := os.ReadFile(contextsFile) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return errs.FileError(err, contextsFile) - } - cs.contexts = ContextMap{} - if err := json.Unmarshal(b, &cs.contexts); err != nil { - return errors.Wrap(err, "error unmarshaling context map") - } - for k, ctx := range cs.contexts { - if err := ctx.Validate(); err != nil { - return errors.Wrapf(err, "error in context '%s'", k) - } - ctx.Name = k - } - return nil -} - -func (cs *CtxState) initCurrent() error { - currentCtxFile := CurrentContextFile() - b, err := os.ReadFile(currentCtxFile) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return errs.FileError(err, currentCtxFile) - } - - var sc storedCurrent - if err := json.Unmarshal(b, &sc); err != nil { - return errors.Wrap(err, "error unmarshaling current context") - } - - return cs.SetCurrent(sc.Context) -} - -func (cs *CtxState) load() error { - if cs.Enabled() && cs.GetCurrent() != nil { - if err := cs.GetCurrent().Load(); err != nil { - return fmt.Errorf("failed loading current context configuration: %w", err) - } - - return nil - } - - if err := cs.LoadVintage(""); err != nil { - return fmt.Errorf("failed loading context configuration: %w", err) - } - - return nil -} - -// LoadVintage loads context configuration from the vintage (non-context) path. -func (cs *CtxState) LoadVintage(f string) error { - if f == "" { - f = DefaultsFile() - } - - b, err := os.ReadFile(f) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return errs.FileError(err, f) - } - - cs.config = make(map[string]interface{}) - if err := json.Unmarshal(b, &cs.config); err != nil { - return errors.Wrapf(err, "error parsing %s", f) - } - return nil -} - -// GetConfig returns the current context configuration. -func (cs *CtxState) GetConfig() (map[string]interface{}, error) { - if cs.Enabled() { - cur := cs.GetCurrent() - if cur == nil { - return nil, errors.New("cannot get context configuration; no current context set") - } - return cur.config, nil - } - return cs.config, nil -} - -// SetCurrent sets the current context or returns an error if a context -// with the given name does not exist. -func (cs *CtxState) SetCurrent(name string) error { - var ok bool - cs.current, ok = cs.contexts[name] - if !ok { - return errors.Errorf("could not load context '%s'", name) - } - if len(cs.current.config) == 0 { - if err := cs.current.Load(); err != nil { - return err - } - } - return nil -} - -type contextSelect struct { - Name string - Context *Context -} - -// PromptContext gets user input to select a context. -func (cs *CtxState) PromptContext() error { - var items []*contextSelect - for _, context := range cs.List() { - items = append(items, &contextSelect{ - Name: context.Name, - Context: context, - }) - } - - var ctxStr string - if len(items) == 1 { - if err := ui.PrintSelected("Context", items[0].Name); err != nil { - return err - } - ctxStr = items[0].Name - } else { - i, _, err := ui.Select("Select a context for 'step':", items, - ui.WithSelectTemplates(ui.NamedSelectTemplates("Context"))) - if err != nil { - return err - } - ctxStr = items[i].Name - } - if err := cs.SetCurrent(ctxStr); err != nil { - return err - } - return cs.SaveCurrent(ctxStr) -} - -// Enabled returns true if one of the following is true: -// - there is a current context configured -// - the context map is (list of available contexts) is not empty. -func (cs *CtxState) Enabled() bool { - return cs.current != nil || len(cs.contexts) > 0 -} - -// Contexts returns an object that enables context management. -func Contexts() *CtxState { - return ctxState -} - -// Add adds a new context to the context map. If current context is not -// set then store the new context as the current context for future commands. -func (cs *CtxState) Add(ctx *Context) error { - if err := ctx.Validate(); err != nil { - return errors.Wrapf(err, "error adding context") - } - if cs.contexts == nil { - cs.contexts = map[string]*Context{ctx.Name: ctx} - } else { - cs.contexts[ctx.Name] = ctx - } - - b, err := json.MarshalIndent(cs.contexts, "", " ") - if err != nil { - return err - } - - cf := ContextsFile() - if err := os.MkdirAll(filepath.Dir(cf), 0700); err != nil { - return errs.FileError(err, cf) - } - if err := os.WriteFile(cf, b, 0600); err != nil { - return errs.FileError(err, cf) - } - - if cs.current == nil { - if err := cs.SaveCurrent(ctx.Name); err != nil { - return err - } - } - return nil -} - -// GetCurrent returns the current context. -func (cs *CtxState) GetCurrent() *Context { - return cs.current -} - -// Get returns the context with the given name. -func (cs *CtxState) Get(name string) (ctx *Context, ok bool) { - ctx, ok = cs.contexts[name] - return -} - -// Remove removes a context from the context state. -func (cs *CtxState) Remove(name string) error { - if _, ok := cs.contexts[name]; !ok { - return errors.Errorf("context '%s' not found", name) - } - if cs.current != nil && cs.current.Name == name { - return errors.New("cannot remove current context; use 'step context select' to switch contexts") - } - - delete(cs.contexts, name) - - b, err := json.MarshalIndent(cs.contexts, "", " ") - if err != nil { - return err - } - - if err := os.WriteFile(ContextsFile(), b, 0600); err != nil { - return fmt.Errorf("error writing file: %w", err) - } - return nil -} - -// List returns a list of all contexts. -func (cs *CtxState) List() []*Context { - l := make([]*Context, 0, len(cs.contexts)) - - for _, v := range cs.contexts { - l = append(l, v) - } - return l -} - -// ListAlphabetical returns a case-insensitive, alphabetically -// sorted list of all contexts. -func (cs *CtxState) ListAlphabetical() []*Context { - l := cs.List() - - sort.Slice(l, func(i, j int) bool { - return strings.ToLower(l[i].Name) < strings.ToLower(l[j].Name) - }) - - return l -} - -// SaveCurrent stores the given context name as the selected default context for -// future commands. -func (cs *CtxState) SaveCurrent(name string) error { - if _, ok := Contexts().Get(name); !ok { - return errors.Errorf("context '%s' not found", name) - } - - b, err := json.Marshal(storedCurrent{Context: name}) - if err != nil { - return err - } - //nolint:gosec // this file does not contain sensitive info - if err = os.WriteFile(CurrentContextFile(), b, 0644); err != nil { - return errs.FileError(err, CurrentContextFile()) - } - return nil -} - -// Apply the current context configuration to the command line environment. -func (cs *CtxState) Apply(ctx *cli.Context) error { - cfg, err := cs.GetConfig() - if err != nil { - return err - } - for _, f := range ctx.Command.Flags { - // Skip if EnvVar == IgnoreEnvVar - if getFlagEnvVar(f) == IgnoreEnvVar { - continue - } - - for _, name := range strings.Split(f.GetName(), ",") { - name = strings.TrimSpace(name) - if ctx.IsSet(name) { - break - } - // Set the flag for the first key that matches. - if v, ok := cfg[name]; ok { - ctx.Set(name, fmt.Sprintf("%v", v)) - break - } - } - } - return nil -} - -// getEnvVar generates the environment variable for the given flag name. -func getEnvVar(name string) string { - parts := strings.Split(name, ",") - name = strings.TrimSpace(parts[0]) - name = strings.ReplaceAll(name, "-", "_") - return "STEP_" + strings.ToUpper(name) -} - -// getFlagEnvVar returns the value of the EnvVar field of a flag. -func getFlagEnvVar(f cli.Flag) string { - v := reflect.ValueOf(f) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() == reflect.Struct { - envVar := v.FieldByName("EnvVar") - if envVar.IsValid() { - return envVar.String() - } - } - return "" -} - -// SetEnvVar sets the the EnvVar element to each flag recursively. -func SetEnvVar(c *cli.Command) { - if c == nil { - return - } - - // Enable getting the flags from a json file - if c.Before == nil && c.Action != nil { - c.Before = getConfigVars - } - - // Enable getting the flags from environment variables - for i := range c.Flags { - envVar := getEnvVar(c.Flags[i].GetName()) - switch f := c.Flags[i].(type) { - case cli.BoolFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.BoolTFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.DurationFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Float64Flag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.GenericFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Int64Flag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.IntFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.IntSliceFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Int64SliceFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.StringFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.StringSliceFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Uint64Flag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.UintFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - } - } - - for i := range c.Subcommands { - SetEnvVar(&c.Subcommands[i]) - } -} - -// GetConfigVars load the defaults.json file and sets the flags if they are not -// already set or the EnvVar is set to IgnoreEnvVar. -// -// TODO(mariano): right now it only supports parameters at first level. -func getConfigVars(ctx *cli.Context) (err error) { - if ctx.Bool("no-context") { - return nil - } - - cs := Contexts() - - // Load the the current context into memory: - // - If contexts enabled then make sure a current context is selected - // and loaded. - // - If vintage context then check if overwritten by --config flag. - if cs.Enabled() { - if ctx.IsSet("context") { - err = cs.SetCurrent(ctx.String("context")) - } else if cs.Enabled() && cs.GetCurrent() == nil { - err = cs.PromptContext() - } - if err != nil { - return err - } - } else if ctx.GlobalString("config") != "" { - // Re-load the vintage context configuration if `--config` flag supplied. - cs.LoadVintage(ctx.GlobalString("config")) - } - - // TODO: a mock detail because of "add detail/assignee to this TODO/FIXME/BUG comment" lint issue - fullCommandName := strings.ToLower(strings.TrimSpace(ctx.Command.FullName())) - if strings.EqualFold(fullCommandName, "ca bootstrap-helper") { - return nil - } - - if err := cs.Apply(ctx); err != nil { - return fmt.Errorf("error applying contexts: %w", err) - } - - return nil -} diff --git a/vendor/go.step.sm/cli-utils/ui/options.go b/vendor/go.step.sm/cli-utils/ui/options.go deleted file mode 100644 index 382c263..0000000 --- a/vendor/go.step.sm/cli-utils/ui/options.go +++ /dev/null @@ -1,172 +0,0 @@ -package ui - -import ( - "fmt" - "regexp" - "strings" - - "github.com/manifoldco/promptui" -) - -type options struct { - mask rune - defaultValue string - value string - allowEdit bool - printTemplate string - promptTemplates *promptui.PromptTemplates - selectTemplates *promptui.SelectTemplates - validateFunc promptui.ValidateFunc -} - -// apply applies the given options. -func (o *options) apply(opts []Option) *options { - for _, fn := range opts { - fn(o) - } - return o -} - -// valid returns true if the validate function passes on the value. -func (o *options) valid() bool { - if o.validateFunc == nil { - return true - } - return o.validateFunc(o.value) == nil -} - -// getValue validates the value and returns it. -func (o *options) getValue() (string, error) { - if o.validateFunc == nil { - return o.value, nil - } - if err := o.validateFunc(o.value); err != nil { - return "", err - } - return o.value, nil -} - -// getValueBytes validates the value and returns it as a byte slice. -func (o *options) getValueBytes() ([]byte, error) { - if o.validateFunc == nil { - return []byte(o.value), nil - } - if err := o.validateFunc(o.value); err != nil { - return nil, err - } - return []byte(o.value), nil -} - -// Option is the type of the functions that modify the prompt options. -type Option func(*options) - -func extractOptions(args []interface{}) (opts []Option, rest []interface{}) { - rest = args[:0] - for _, arg := range args { - if o, ok := arg.(Option); ok { - opts = append(opts, o) - } else { - rest = append(rest, arg) - } - } - return -} - -// WithMask adds a mask to a prompt. -func WithMask(r rune) Option { - return func(o *options) { - o.mask = r - } -} - -// WithDefaultValue adds a custom string as the default value. -func WithDefaultValue(s string) Option { - return func(o *options) { - o.defaultValue = s - } -} - -// WithSliceValue sets a custom string as the result of a prompt. If value is set, -// the prompt won't be displayed. -func WithSliceValue(values []string) Option { - return func(o *options) { - o.value = strings.Join(values, ",") - } -} - -// WithValue sets a custom string as the result of a prompt. If value is set, -// the prompt won't be displayed. -func WithValue(value string) Option { - return func(o *options) { - o.value = value - } -} - -// WithAllowEdit if true, let's the user edit the default value set. -func WithAllowEdit(b bool) Option { - return func(o *options) { - o.allowEdit = b - } -} - -// WithPrintTemplate sets the template to use on the print methods. -func WithPrintTemplate(template string) Option { - return func(o *options) { - o.printTemplate = template - } -} - -// WithPromptTemplates adds a custom template to a prompt. -func WithPromptTemplates(t *promptui.PromptTemplates) Option { - return func(o *options) { - o.promptTemplates = t - } -} - -// WithSelectTemplates adds a custom template to a select. -func WithSelectTemplates(t *promptui.SelectTemplates) Option { - return func(o *options) { - o.selectTemplates = t - } -} - -// WithValidateFunc adds a custom validation function to a prompt. -func WithValidateFunc(fn func(string) error) Option { - return func(o *options) { - o.validateFunc = fn - } -} - -// WithValidateNotEmpty adds a custom validation function to a prompt that -// checks that the propted string is not empty. -func WithValidateNotEmpty() Option { - return WithValidateFunc(NotEmpty()) -} - -// WithValidateYesNo adds a custom validation function to a prompt for a Yes/No -// prompt. -func WithValidateYesNo() Option { - return WithValidateFunc(YesNo()) -} - -// WithRichPrompt add the template option with rich templates. -func WithRichPrompt() Option { - return WithPromptTemplates(PromptTemplates()) -} - -// WithSimplePrompt add the template option with simple templates. -func WithSimplePrompt() Option { - return WithPromptTemplates(SimplePromptTemplates()) -} - -// WithValidateRegexp checks a prompt answer with a regular expression. If the -// regular expression is not a valid one, the option will panic. -func WithValidateRegexp(re string) Option { - rx := regexp.MustCompile(re) - return WithValidateFunc(func(s string) error { - if rx.MatchString(s) { - return nil - } - return fmt.Errorf("%s does not match the regular expresion %s", s, re) - }) -} diff --git a/vendor/go.step.sm/cli-utils/ui/templates.go b/vendor/go.step.sm/cli-utils/ui/templates.go deleted file mode 100644 index cc37891..0000000 --- a/vendor/go.step.sm/cli-utils/ui/templates.go +++ /dev/null @@ -1,93 +0,0 @@ -package ui - -import ( - "fmt" - "runtime" - - "github.com/chzyer/readline" - "github.com/manifoldco/promptui" -) - -var ( - // IconInitial is the icon used when starting in prompt mode and the icon next to the label when - // starting in select mode. - IconInitial = promptui.Styler(promptui.FGBlue)("?") - - // IconGood is the icon used when a good answer is entered in prompt mode. - IconGood = promptui.Styler(promptui.FGGreen)("✔") - - // IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode. - IconWarn = promptui.Styler(promptui.FGYellow)("⚠") - - // IconBad is the icon used when a bad answer is entered in prompt mode. - IconBad = promptui.Styler(promptui.FGRed)("✗") - - // IconSelect is the icon used to identify the currently selected item in select mode. - IconSelect = promptui.Styler(promptui.FGBold)("▸") -) - -func init() { - // Set VT100 characters for windows too - if runtime.GOOS == "windows" { - promptui.KeyEnter = readline.CharEnter - promptui.KeyBackspace = readline.CharBackspace - promptui.KeyPrev = readline.CharPrev - promptui.KeyPrevDisplay = "↑" - promptui.KeyNext = readline.CharNext - promptui.KeyNextDisplay = "↓" - promptui.KeyBackward = readline.CharBackward - promptui.KeyBackwardDisplay = "←" - promptui.KeyForward = readline.CharForward - promptui.KeyForwardDisplay = "→" - } -} - -// PrintSelectedTemplate returns the default template used in PrintSelected. -func PrintSelectedTemplate() string { - return fmt.Sprintf(`{{ %q | green }} {{ .Name | bold }}{{ ":" | bold }} {{ .Value }}`, IconGood) + "\n" -} - -// PromptTemplates is the default style for a prompt. -func PromptTemplates() *promptui.PromptTemplates { - bold := promptui.Styler(promptui.FGBold) - return &promptui.PromptTemplates{ - Prompt: fmt.Sprintf("%s {{ . | bold }}%s ", IconInitial, bold(":")), - Success: fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":")), - // Confirm: fmt.Sprintf(`{{ "%s" | bold }} {{ . | bold }}? {{ "[]" | faint }} `, IconInitial), - Valid: fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":")), - Invalid: fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconBad), bold(":")), - } -} - -// SimplePromptTemplates is a prompt with a simple style, used by default on password prompts. -func SimplePromptTemplates() *promptui.PromptTemplates { - return &promptui.PromptTemplates{ - Prompt: "{{ . }}: ", - Success: "{{ . }}: ", - Valid: "{{ . }}: ", - Invalid: "{{ . }}: ", - } -} - -// SelectTemplates returns the default promptui.SelectTemplate for string -// slices. The given name is the prompt of the selected option. -func SelectTemplates(name string) *promptui.SelectTemplates { - return &promptui.SelectTemplates{ - Label: fmt.Sprintf("%s {{ . }}: ", IconInitial), - Active: fmt.Sprintf("%s {{ . | underline }}", IconSelect), - Inactive: " {{ . }}", - Selected: fmt.Sprintf(`{{ %q | green }} {{ "%s:" | bold }} {{ .Name }}`, IconGood, name), - } -} - -// NamedSelectTemplates returns the default promptui.SelectTemplate for struct -// slices with a name property. The given name is the prompt of the selected -// option. -func NamedSelectTemplates(name string) *promptui.SelectTemplates { - return &promptui.SelectTemplates{ - Label: fmt.Sprintf("%s {{.Name}}: ", IconInitial), - Active: fmt.Sprintf("%s {{ .Name | underline }}", IconSelect), - Inactive: " {{.Name}}", - Selected: fmt.Sprintf(`{{ %q | green }} {{ "%s:" | bold }} {{ .Name }}`, IconGood, name), - } -} diff --git a/vendor/go.step.sm/cli-utils/ui/ui.go b/vendor/go.step.sm/cli-utils/ui/ui.go deleted file mode 100644 index 82dcab9..0000000 --- a/vendor/go.step.sm/cli-utils/ui/ui.go +++ /dev/null @@ -1,334 +0,0 @@ -package ui - -import ( - "fmt" - "os" - "strings" - "text/template" - - "github.com/chzyer/readline" - "github.com/manifoldco/promptui" - "github.com/pkg/errors" - "go.step.sm/crypto/randutil" -) - -// stderr implements an io.WriteCloser that skips the terminal bell character -// (ASCII code 7), and writes the rest to os.Stderr. It's used to replace -// readline.Stdout, that is the package used by promptui to display the prompts. -type stderr struct{} - -// Write implements an io.WriterCloser over os.Stderr, but it skips the terminal -// bell character. -func (s *stderr) Write(b []byte) (int, error) { - if len(b) == 1 && b[0] == readline.CharBell { - return 0, nil - } - return os.Stderr.Write(b) -} - -// Close implements an io.WriterCloser over os.Stderr. -func (s *stderr) Close() error { - return os.Stderr.Close() -} - -func init() { - readline.Stdout = &stderr{} -} - -// Init initializes the terminal to be used by this package. This is generally a -// noop except for windows. -func Init() { - setConsoleMode() -} - -// Reset sets the terminal as it was before the initialization. This is -// generally a noop except for windows. -func Reset() { - resetConsoleMode() -} - -// Print uses templates to print the arguments formated to os.Stderr. -func Print(args ...interface{}) error { - var o options - opts, args := extractOptions(args) - o.apply(opts) - - // Return with a default value. This is useful when we split the question - // and the response in two lines. - if o.value != "" && o.valid() { - return nil - } - - text := fmt.Sprint(args...) - t, err := template.New("Print").Funcs(promptui.FuncMap).Parse(text) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - if err := t.Execute(os.Stderr, nil); err != nil { - return errors.Wrap(err, "error executing template") - } - return nil -} - -// Printf uses templates to print the string formated to os.Stderr. -func Printf(format string, args ...interface{}) error { - var o options - opts, args := extractOptions(args) - o.apply(opts) - - // Return with a default value. This is useful when we split the question - // and the response in two lines. - if o.value != "" && o.valid() { - return nil - } - - text := fmt.Sprintf(format, args...) - t, err := template.New("Printf").Funcs(promptui.FuncMap).Parse(text) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - if err := t.Execute(os.Stderr, nil); err != nil { - return errors.Wrap(err, "error executing template") - } - return nil -} - -// Println uses templates to print the given arguments to os.Stderr -func Println(args ...interface{}) error { - var o options - opts, args := extractOptions(args) - o.apply(opts) - - // Return with a default value. This is useful when we split the question - // and the response in two lines. - if o.value != "" && o.valid() { - return nil - } - - text := fmt.Sprintln(args...) - t, err := template.New("Println").Funcs(promptui.FuncMap).Parse(text) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - if err := t.Execute(os.Stderr, nil); err != nil { - return errors.Wrap(err, "error executing template") - } - return nil -} - -// PrintSelected prints the given name and value as if they were selected from a -// promptui.Select. -func PrintSelected(name, value string, opts ...Option) error { - o := &options{ - printTemplate: PrintSelectedTemplate(), - } - o.apply(opts) - - t, err := template.New(name).Funcs(promptui.FuncMap).Parse(o.printTemplate) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - - data := struct { - Name string - Value string - }{name, value} - if err := t.Execute(os.Stderr, data); err != nil { - return errors.Wrap(err, "error executing template") - } - - return nil -} - -// Prompt creates and runs a promptui.Prompt with the given label. -func Prompt(label string, opts ...Option) (string, error) { - o := &options{ - promptTemplates: PromptTemplates(), - } - o.apply(opts) - - // Return value if set - if o.value != "" { - return o.getValue() - } - - // Prompt using the terminal - clean, err := preparePromptTerminal() - if err != nil { - return "", err - } - defer clean() - - prompt := &promptui.Prompt{ - Label: label, - Default: o.defaultValue, - AllowEdit: o.allowEdit, - Validate: o.validateFunc, - Templates: o.promptTemplates, - } - value, err := prompt.Run() - if err != nil { - return "", errors.Wrap(err, "error running prompt") - } - return value, nil -} - -// PromptPassword creates and runs a promptui.Prompt with the given label. This -// prompt will mask the key entries with \r. -func PromptPassword(label string, opts ...Option) ([]byte, error) { - // Using a not printable character as they work better than \r - o := &options{ - mask: 1, - promptTemplates: SimplePromptTemplates(), - } - o.apply(opts) - - // Return value if set - if o.value != "" { - return o.getValueBytes() - } - - // Prompt using the terminal - clean, err := preparePromptTerminal() - if err != nil { - return nil, err - } - defer clean() - - prompt := &promptui.Prompt{ - Label: label, - Mask: o.mask, - Default: o.defaultValue, - AllowEdit: o.allowEdit, - Validate: o.validateFunc, - Templates: o.promptTemplates, - } - pass, err := prompt.Run() - if err != nil { - return nil, errors.Wrap(err, "error reading password") - } - return []byte(pass), nil -} - -// PromptPasswordGenerate creates and runs a promptui.Prompt with the given label. -// This prompt will mask the key entries with \r. If the result password length -// is 0, it will generate a new prompt with a generated password that can be -// edited. -func PromptPasswordGenerate(label string, opts ...Option) ([]byte, error) { - pass, err := PromptPassword(label, opts...) - if err != nil || len(pass) > 0 { - return pass, err - } - passString, err := randutil.ASCII(32) - if err != nil { - return nil, err - } - passString, err = Prompt("Password", WithDefaultValue(passString), WithAllowEdit(true), WithValidateNotEmpty()) - if err != nil { - return nil, err - } - return []byte(passString), nil -} - -// PromptYesNo creates and runs a promptui.Prompt with the given label, and -// returns true if the answer is y/yes and false if the answer is n/no. -func PromptYesNo(label string, opts ...Option) (bool, error) { - opts = append([]Option{WithValidateYesNo()}, opts...) - s, err := Prompt(label, opts...) - if err != nil { - return false, err - } - switch strings.ToLower(strings.TrimSpace(s)) { - case "y", "yes": - return true, nil - case "n", "no": - return false, nil - default: - return false, fmt.Errorf("%s is not a valid answer", s) - } -} - -// Select creates and runs a promptui.Select with the given label and items. -func Select(label string, items interface{}, opts ...Option) (int, string, error) { - o := &options{ - selectTemplates: SelectTemplates(label), - } - o.apply(opts) - - clean, err := prepareSelectTerminal() - if err != nil { - return 0, "", err - } - defer clean() - - prompt := &promptui.Select{ - Label: label, - Items: items, - Templates: o.selectTemplates, - } - n, s, err := prompt.Run() - if err != nil { - return 0, "", errors.Wrap(err, "error running prompt") - } - return n, s, nil -} - -func preparePromptTerminal() (func(), error) { - nothing := func() {} - if !readline.DefaultIsTerminal() { - tty, err := os.Open("/dev/tty") - if err != nil { - return nothing, errors.Wrap(err, "error allocating terminal") - } - clean := func() { - tty.Close() - } - - fd := int(tty.Fd()) - state, err := readline.MakeRaw(fd) - if err != nil { - defer clean() - return nothing, errors.Wrap(err, "error making raw terminal") - } - stdin := readline.Stdin - readline.Stdin = tty - clean = func() { - readline.Stdin = stdin - readline.Restore(fd, state) - tty.Close() - } - return clean, nil - } - - return nothing, nil -} - -func prepareSelectTerminal() (func(), error) { - nothing := func() {} - if !readline.DefaultIsTerminal() { - tty, err := os.Open("/dev/tty") - if err != nil { - return nothing, errors.Wrap(err, "error allocating terminal") - } - clean := func() { - tty.Close() - } - - fd := int(tty.Fd()) - state, err := readline.MakeRaw(fd) - if err != nil { - defer clean() - return nothing, errors.Wrap(err, "error making raw terminal") - } - stdin := os.Stdin - os.Stdin = tty - clean = func() { - os.Stdin = stdin - readline.Restore(fd, state) - tty.Close() - } - return clean, nil - } - - return nothing, nil -} diff --git a/vendor/go.step.sm/cli-utils/ui/ui_other.go b/vendor/go.step.sm/cli-utils/ui/ui_other.go deleted file mode 100644 index f449b57..0000000 --- a/vendor/go.step.sm/cli-utils/ui/ui_other.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !windows -// +build !windows - -package ui - -func setConsoleMode() {} - -func resetConsoleMode() {} diff --git a/vendor/go.step.sm/cli-utils/ui/ui_windows.go b/vendor/go.step.sm/cli-utils/ui/ui_windows.go deleted file mode 100644 index 573bfcb..0000000 --- a/vendor/go.step.sm/cli-utils/ui/ui_windows.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build windows -// +build windows - -package ui - -import ( - "fmt" - "os" - - "golang.org/x/sys/windows" -) - -var inMode, outMode uint32 - -func init() { - var _ = windows.GetConsoleMode(windows.Stdin, &inMode) - var _ = windows.GetConsoleMode(windows.Stdout, &outMode) -} - -func setConsoleMode() { - in := inMode | windows.ENABLE_VIRTUAL_TERMINAL_INPUT - out := outMode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - - if inMode != 0 && inMode != in { - if err := windows.SetConsoleMode(windows.Stdin, in); err != nil { - fmt.Fprintf(os.Stderr, "Failed to set console mode: %v\n", err) - } - } - - if outMode != 0 && outMode != out { - if err := windows.SetConsoleMode(windows.Stdout, out); err != nil { - fmt.Fprintf(os.Stderr, "Failed to set console mode: %v\n", err) - } - } -} - -func resetConsoleMode() { - in := inMode | windows.ENABLE_VIRTUAL_TERMINAL_INPUT - out := outMode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - - if inMode != 0 && inMode != in { - if err := windows.SetConsoleMode(windows.Stdin, inMode); err != nil { - fmt.Fprintf(os.Stderr, "Failed to reset console mode: %v\n", err) - } - } - if outMode != 0 && outMode != out { - if err := windows.SetConsoleMode(windows.Stdout, outMode); err != nil { - fmt.Fprintf(os.Stderr, "Failed to reset console mode: %v\n", err) - } - } -} diff --git a/vendor/go.step.sm/cli-utils/ui/validators.go b/vendor/go.step.sm/cli-utils/ui/validators.go deleted file mode 100644 index 7d8b603..0000000 --- a/vendor/go.step.sm/cli-utils/ui/validators.go +++ /dev/null @@ -1,75 +0,0 @@ -package ui - -import ( - "errors" - "fmt" - "net" - "strings" - - "github.com/manifoldco/promptui" -) - -var errEmptyValue = errors.New("value is empty") - -// NotEmpty is a validation function that checks that the prompted string is not -// empty. -func NotEmpty() promptui.ValidateFunc { - return func(s string) error { - if strings.TrimSpace(s) == "" { - return errEmptyValue - } - return nil - } -} - -// Address is a validation function that checks that the prompted string is a -// valid TCP address. -func Address() promptui.ValidateFunc { - return func(s string) error { - if _, _, err := net.SplitHostPort(s); err != nil { - return fmt.Errorf("%s is not an TCP address", s) - } - return nil - } -} - -// IPAddress is validation function that checks that the prompted string is a -// valid IP address. -func IPAddress() promptui.ValidateFunc { - return func(s string) error { - if net.ParseIP(s) == nil { - return fmt.Errorf("%s is not an ip address", s) - } - return nil - } -} - -// DNS is a validation function that checks that the prompted string is a valid -// DNS name or IP address. -func DNS() promptui.ValidateFunc { - return func(s string) error { - if strings.TrimSpace(s) == "" { - return errEmptyValue - } - if ip := net.ParseIP(s); ip != nil { - return nil - } - if _, _, err := net.SplitHostPort(s + ":443"); err != nil { - return fmt.Errorf("%s is not a valid DNS name or IP address", s) - } - return nil - } -} - -// YesNo is a validation function that checks for a Yes/No answer. -func YesNo() promptui.ValidateFunc { - return func(s string) error { - s = strings.ToLower(strings.TrimSpace(s)) - switch s { - case "y", "yes", "n", "no": - return nil - default: - return fmt.Errorf("%s is not a valid answer", s) - } - } -} diff --git a/vendor/go.step.sm/cli-utils/usage/css.go b/vendor/go.step.sm/cli-utils/usage/css.go deleted file mode 100644 index e552534..0000000 --- a/vendor/go.step.sm/cli-utils/usage/css.go +++ /dev/null @@ -1,764 +0,0 @@ -package usage - -// CSS code replicating Github style. -// From https://github.com/sindresorhus/github-markdown-css -// MIT license -var css = `@font-face { - font-family: octicons-link; - src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); -} - -.wrapper { - margin: 0 auto; - max-width: 700px; - padding: 20px 10px; -} - -.markdown-body { - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - line-height: 1.5; - color: #24292e; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-size: 16px; - line-height: 1.5; - word-wrap: break-word; -} - -.markdown-body .pl-c { - color: #6a737d; -} - -.markdown-body .pl-c1, -.markdown-body .pl-s .pl-v { - color: #005cc5; -} - -.markdown-body .pl-e, -.markdown-body .pl-en { - color: #6f42c1; -} - -.markdown-body .pl-smi, -.markdown-body .pl-s .pl-s1 { - color: #24292e; -} - -.markdown-body .pl-ent { - color: #22863a; -} - -.markdown-body .pl-k { - color: #d73a49; -} - -.markdown-body .pl-s, -.markdown-body .pl-pds, -.markdown-body .pl-s .pl-pse .pl-s1, -.markdown-body .pl-sr, -.markdown-body .pl-sr .pl-cce, -.markdown-body .pl-sr .pl-sre, -.markdown-body .pl-sr .pl-sra { - color: #032f62; -} - -.markdown-body .pl-v, -.markdown-body .pl-smw { - color: #e36209; -} - -.markdown-body .pl-bu { - color: #b31d28; -} - -.markdown-body .pl-ii { - color: #fafbfc; - background-color: #b31d28; -} - -.markdown-body .pl-c2 { - color: #fafbfc; - background-color: #d73a49; -} - -.markdown-body .pl-c2::before { - content: "^M"; -} - -.markdown-body .pl-sr .pl-cce { - font-weight: bold; - color: #22863a; -} - -.markdown-body .pl-ml { - color: #735c0f; -} - -.markdown-body .pl-mh, -.markdown-body .pl-mh .pl-en, -.markdown-body .pl-ms { - font-weight: bold; - color: #005cc5; -} - -.markdown-body .pl-mi { - font-style: italic; - color: #24292e; -} - -.markdown-body .pl-mb { - font-weight: bold; - color: #24292e; -} - -.markdown-body .pl-md { - color: #b31d28; - background-color: #ffeef0; -} - -.markdown-body .pl-mi1 { - color: #22863a; - background-color: #f0fff4; -} - -.markdown-body .pl-mc { - color: #e36209; - background-color: #ffebda; -} - -.markdown-body .pl-mi2 { - color: #f6f8fa; - background-color: #005cc5; -} - -.markdown-body .pl-mdr { - font-weight: bold; - color: #6f42c1; -} - -.markdown-body .pl-ba { - color: #586069; -} - -.markdown-body .pl-sg { - color: #959da5; -} - -.markdown-body .pl-corl { - text-decoration: underline; - color: #032f62; -} - -.markdown-body .octicon { - display: inline-block; - vertical-align: text-top; - fill: currentColor; -} - -.markdown-body a { - background-color: transparent; -} - -.markdown-body a:active, -.markdown-body a:hover { - outline-width: 0; -} - -.markdown-body strong { - font-weight: inherit; -} - -.markdown-body strong { - font-weight: bolder; -} - -.markdown-body h1 { - font-size: 2em; - margin: 0.67em 0; -} - -.markdown-body img { - border-style: none; -} - -.markdown-body code, -.markdown-body kbd, -.markdown-body pre { - font-family: monospace, monospace; - font-size: 1em; -} - -.markdown-body hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -.markdown-body input { - font: inherit; - margin: 0; -} - -.markdown-body input { - overflow: visible; -} - -.markdown-body [type="checkbox"] { - box-sizing: border-box; - padding: 0; -} - -.markdown-body * { - box-sizing: border-box; -} - -.markdown-body input { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} - -.markdown-body a { - color: #0366d6; - text-decoration: none; -} - -.markdown-body a:hover { - text-decoration: underline; -} - -.markdown-body strong { - font-weight: 600; -} - -.markdown-body hr { - height: 0; - margin: 15px 0; - overflow: hidden; - background: transparent; - border: 0; - border-bottom: 1px solid #dfe2e5; -} - -.markdown-body hr::before { - display: table; - content: ""; -} - -.markdown-body hr::after { - display: table; - clear: both; - content: ""; -} - -.markdown-body table { - border-spacing: 0; - border-collapse: collapse; -} - -.markdown-body td, -.markdown-body th { - padding: 0; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body h1 { - font-size: 32px; - font-weight: 600; -} - -.markdown-body h2 { - font-size: 24px; - font-weight: 600; -} - -.markdown-body h3 { - font-size: 20px; - font-weight: 600; -} - -.markdown-body h4 { - font-size: 16px; - font-weight: 600; -} - -.markdown-body h5 { - font-size: 14px; - font-weight: 600; -} - -.markdown-body h6 { - font-size: 12px; - font-weight: 600; -} - -.markdown-body p { - margin-top: 0; - margin-bottom: 10px; -} - -.markdown-body blockquote { - margin: 0; -} - -.markdown-body ul, -.markdown-body ol { - padding-left: 0; - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body ol ol, -.markdown-body ul ol { - list-style-type: lower-roman; -} - -.markdown-body ul ul ol, -.markdown-body ul ol ol, -.markdown-body ol ul ol, -.markdown-body ol ol ol { - list-style-type: lower-alpha; -} - -.markdown-body dd { - margin-left: 0; -} - -.markdown-body code { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; -} - -.markdown-body pre { - margin-top: 0; - margin-bottom: 0; - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; -} - -.markdown-body .octicon { - vertical-align: text-bottom; -} - -.markdown-body .pl-0 { - padding-left: 0 !important; -} - -.markdown-body .pl-1 { - padding-left: 4px !important; -} - -.markdown-body .pl-2 { - padding-left: 8px !important; -} - -.markdown-body .pl-3 { - padding-left: 16px !important; -} - -.markdown-body .pl-4 { - padding-left: 24px !important; -} - -.markdown-body .pl-5 { - padding-left: 32px !important; -} - -.markdown-body .pl-6 { - padding-left: 40px !important; -} - -.markdown-body::before { - display: table; - content: ""; -} - -.markdown-body::after { - display: table; - clear: both; - content: ""; -} - -.markdown-body>*:first-child { - margin-top: 0 !important; -} - -.markdown-body>*:last-child { - margin-bottom: 0 !important; -} - -.markdown-body a:not([href]) { - color: inherit; - text-decoration: none; -} - -.markdown-body .anchor { - float: left; - padding-right: 4px; - margin-left: -20px; - line-height: 1; -} - -.markdown-body .anchor:focus { - outline: none; -} - -.markdown-body p, -.markdown-body blockquote, -.markdown-body ul, -.markdown-body ol, -.markdown-body dl, -.markdown-body table, -.markdown-body pre { - margin-top: 0; - margin-bottom: 16px; -} - -.markdown-body hr { - height: 0.25em; - padding: 0; - margin: 24px 0; - background-color: #e1e4e8; - border: 0; -} - -.markdown-body blockquote { - padding: 0 1em; - color: #6a737d; - border-left: 0.25em solid #dfe2e5; -} - -.markdown-body blockquote>:first-child { - margin-top: 0; -} - -.markdown-body blockquote>:last-child { - margin-bottom: 0; -} - -.markdown-body kbd { - display: inline-block; - padding: 3px 5px; - font-size: 11px; - line-height: 10px; - color: #444d56; - vertical-align: middle; - background-color: #fafbfc; - border: solid 1px #c6cbd1; - border-bottom-color: #959da5; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #959da5; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - margin-top: 24px; - margin-bottom: 16px; - font-weight: 600; - line-height: 1.25; -} - -.markdown-body h1 .octicon-link, -.markdown-body h2 .octicon-link, -.markdown-body h3 .octicon-link, -.markdown-body h4 .octicon-link, -.markdown-body h5 .octicon-link, -.markdown-body h6 .octicon-link { - color: #1b1f23; - vertical-align: middle; - visibility: hidden; -} - -.markdown-body h1:hover .anchor, -.markdown-body h2:hover .anchor, -.markdown-body h3:hover .anchor, -.markdown-body h4:hover .anchor, -.markdown-body h5:hover .anchor, -.markdown-body h6:hover .anchor { - text-decoration: none; -} - -.markdown-body h1:hover .anchor .octicon-link, -.markdown-body h2:hover .anchor .octicon-link, -.markdown-body h3:hover .anchor .octicon-link, -.markdown-body h4:hover .anchor .octicon-link, -.markdown-body h5:hover .anchor .octicon-link, -.markdown-body h6:hover .anchor .octicon-link { - visibility: visible; -} - -.markdown-body h1 { - padding-bottom: 0.3em; - font-size: 2em; - border-bottom: 1px solid #eaecef; -} - -.markdown-body h2 { - padding-bottom: 0.3em; - font-size: 1.5em; - border-bottom: 1px solid #eaecef; -} - -.markdown-body h3 { - font-size: 1.25em; -} - -.markdown-body h4 { - font-size: 1em; -} - -.markdown-body h5 { - font-size: 0.875em; -} - -.markdown-body h6 { - font-size: 0.85em; - color: #6a737d; -} - -.markdown-body ul, -.markdown-body ol { - padding-left: 2em; -} - -.markdown-body ul ul, -.markdown-body ul ol, -.markdown-body ol ol, -.markdown-body ol ul { - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body li { - word-wrap: break-all; -} - -.markdown-body li>p { - margin-top: 16px; -} - -.markdown-body li+li { - margin-top: 0.25em; -} - -.markdown-body dl { - padding: 0; -} - -.markdown-body dl dt { - padding: 0; - margin-top: 16px; - font-size: 1em; - font-style: italic; - font-weight: 600; -} - -.markdown-body dl dd { - padding: 0 16px; - margin-bottom: 16px; -} - -.markdown-body table { - display: block; - width: 100%; - overflow: auto; -} - -.markdown-body table th { - font-weight: 600; -} - -.markdown-body table th, -.markdown-body table td { - padding: 6px 13px; - border: 1px solid #dfe2e5; -} - -.markdown-body table tr { - background-color: #fff; - border-top: 1px solid #c6cbd1; -} - -.markdown-body table tr:nth-child(2n) { - background-color: #f6f8fa; -} - -.markdown-body img { - max-width: 100%; - box-sizing: content-box; - background-color: #fff; -} - -.markdown-body img[align=right] { - padding-left: 20px; -} - -.markdown-body img[align=left] { - padding-right: 20px; -} - -.markdown-body code { - padding: 0.2em 0.4em; - margin: 0; - font-size: 85%; - background-color: rgba(27,31,35,0.05); - border-radius: 3px; -} - -.markdown-body pre { - word-wrap: normal; -} - -.markdown-body pre>code { - padding: 0; - margin: 0; - font-size: 100%; - word-break: normal; - white-space: pre; - background: transparent; - border: 0; -} - -.markdown-body .highlight { - margin-bottom: 16px; -} - -.markdown-body .highlight pre { - margin-bottom: 0; - word-break: normal; -} - -.markdown-body .highlight pre, -.markdown-body pre { - padding: 16px; - overflow: auto; - font-size: 85%; - line-height: 1.45; - background-color: #f6f8fa; - border-radius: 3px; -} - -.markdown-body pre code { - display: inline; - max-width: auto; - padding: 0; - margin: 0; - overflow: visible; - line-height: inherit; - word-wrap: normal; - background-color: transparent; - border: 0; -} - -.markdown-body .full-commit .btn-outline:not(:disabled):hover { - color: #005cc5; - border-color: #005cc5; -} - -.markdown-body kbd { - display: inline-block; - padding: 3px 5px; - font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - line-height: 10px; - color: #444d56; - vertical-align: middle; - background-color: #fafbfc; - border: solid 1px #d1d5da; - border-bottom-color: #c6cbd1; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #c6cbd1; -} - -.markdown-body :checked+.radio-label { - position: relative; - z-index: 1; - border-color: #0366d6; -} - -.markdown-body .task-list-item { - list-style-type: none; -} - -.markdown-body .task-list-item+.task-list-item { - margin-top: 3px; -} - -.markdown-body .task-list-item input { - margin: 0 0.2em 0.25em -1.6em; - vertical-align: middle; -} - -.markdown-body hr { - border-bottom-color: #eee; -} - -.command { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, - monospace; - font-size: 16px; - padding-left: 40px; - -} - -.command h1 { - border: none; - margin-left: -40px; -} - -.command h2 { - border: none; - margin-top: 2em; - margin-left: -40px; - font-size: 18px; -} - -.command>ul { - padding-left: 0; -} - -.command ul { - list-style-type: none; -} - -.command table { - margin: 2em 0 1em; - display: block; - width: 100%; - overflow: auto; - border-collapse: collapse; -} - -.command table th { - font-weight: 600; -} - -.command table th, -.command table td { - padding: 6px 13px; - border: 1px solid #dfe2e5; -} - -.command table tr { - background-color: #fff; - border-top: 1px solid #c6cbd1; -} - -.command table tr:nth-child(2n) { - background-color: #f6f8fa; -} - - -` diff --git a/vendor/go.step.sm/cli-utils/usage/help.go b/vendor/go.step.sm/cli-utils/usage/help.go deleted file mode 100644 index eef3273..0000000 --- a/vendor/go.step.sm/cli-utils/usage/help.go +++ /dev/null @@ -1,191 +0,0 @@ -package usage - -import ( - "fmt" - "strings" - - "github.com/urfave/cli" -) - -// HelpCommandAction is the action function of the overwritten help command. -var HelpCommandAction = cli.ActionFunc(helpAction) - -// HelpCommand overwrites default urfvafe/cli help command to support one or -// multiple subcommands like: -// -// step help -// step help crypto -// step help crypto jwt -// step help crypto jwt sign -// ... -func HelpCommand() cli.Command { - return cli.Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "display help for the specified command or command group", - UsageText: "**step help** <command>", - Description: `**step help** command displays help for a command or command group. - -## EXAMPLES - -Display help for **step ca certificate**: -''' -$ step help ca certificate -''' - -Display help for **step ssh**: -''' -$ step help ssh -'''`, - Action: HelpCommandAction, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "http", - Usage: "HTTP service address (e.g., ':8080')", - }, - cli.StringFlag{ - Name: "html", - Usage: "The export <directory> for HTML docs.", - }, - cli.StringFlag{ - Name: "markdown", - Usage: "The export <directory> for Markdown docs.", - }, - cli.BoolFlag{ - Name: "report", - Usage: "Writes a JSON report to the HTML docs directory.", - }, - }, - } -} - -func helpAction(ctx *cli.Context) error { - // use html version - if ctx.IsSet("http") { - return httpHelpAction(ctx) - } - - if ctx.IsSet("html") { - return htmlHelpAction(ctx) - } - - if ctx.IsSet("markdown") { - return markdownHelpAction(ctx) - } - - args := ctx.Args() - if args.Present() { - last := len(args) - 1 - lastName := args[last] - subcmd := ctx.App.Commands - parent := createParentCommand(ctx) - - for _, name := range args[:last] { - for _, cmd := range subcmd { - if cmd.HasName(name) { - parent = cmd - subcmd = cmd.Subcommands - break - } - } - } - - for _, cmd := range subcmd { - if !cmd.HasName(lastName) { - continue - } - cmd.HelpName = fmt.Sprintf("%s %s", ctx.App.HelpName, strings.Join(args, " ")) - parent.HelpName = fmt.Sprintf("%s %s", ctx.App.HelpName, strings.Join(args[:last], " ")) - - ctx.Command = cmd - if len(cmd.Subcommands) == 0 { - ctx.App = createCliApp(ctx, parent) - return cli.ShowCommandHelp(ctx, lastName) - } - - ctx.App = createCliApp(ctx, cmd) - return cli.ShowCommandHelp(ctx, "") - } - - return cli.NewExitError(fmt.Sprintf("No help topic for '%s %s'", ctx.App.Name, strings.Join(args, " ")), 3) - } - - cli.ShowAppHelp(ctx) - return nil -} - -// createParentCommand returns a command representation of the app. -func createParentCommand(ctx *cli.Context) cli.Command { - return cli.Command{ - Name: ctx.App.Name, - HelpName: ctx.App.HelpName, - Usage: ctx.App.Usage, - UsageText: ctx.App.UsageText, - ArgsUsage: ctx.App.ArgsUsage, - Description: ctx.App.Description, - Subcommands: ctx.App.Commands, - Flags: ctx.App.Flags, - } -} - -// createCliApp is re-implementation of urfave/cli method (in command.go): -// -// func (c Command) startApp(ctx *Context) error -// -// It lets us show the subcommands when help is executed like: -// -// step help foo -// step help foo bar -// ... -func createCliApp(ctx *cli.Context, cmd cli.Command) *cli.App { - app := cli.NewApp() - app.Metadata = ctx.App.Metadata - - // set the name and usage - app.Name = cmd.HelpName - app.HelpName = cmd.HelpName - - app.Usage = cmd.Usage - app.UsageText = cmd.UsageText - app.Description = cmd.Description - app.ArgsUsage = cmd.ArgsUsage - - // set CommandNotFound - app.CommandNotFound = ctx.App.CommandNotFound - app.CustomAppHelpTemplate = cmd.CustomHelpTemplate - - // set the flags and commands - app.Commands = cmd.Subcommands - app.Flags = cmd.Flags - - app.Version = ctx.App.Version - app.Compiled = ctx.App.Compiled - app.Author = ctx.App.Author - app.Email = ctx.App.Email - app.Writer = ctx.App.Writer - app.ErrWriter = ctx.App.ErrWriter - - // Do not show help or version on subcommands - app.HideHelp = true - app.HideVersion = true - - // bash completion - app.EnableBashCompletion = ctx.App.EnableBashCompletion - if cmd.BashComplete != nil { - app.BashComplete = cmd.BashComplete - } - - // set the actions - app.Before = cmd.Before - app.After = cmd.After - - if cmd.Action != nil { - app.Action = cmd.Action - } else { - app.Action = helpAction - } - app.OnUsageError = cmd.OnUsageError - - app.Setup() - return app -} diff --git a/vendor/go.step.sm/cli-utils/usage/html.go b/vendor/go.step.sm/cli-utils/usage/html.go deleted file mode 100644 index 7ea8fd0..0000000 --- a/vendor/go.step.sm/cli-utils/usage/html.go +++ /dev/null @@ -1,350 +0,0 @@ -package usage - -import ( - "fmt" - "net/http" - "os" - "path" - "strings" - "time" - - "github.com/urfave/cli" - "go.step.sm/cli-utils/errs" -) - -func httpHelpAction(ctx *cli.Context) error { - addr := ctx.String("http") - if addr == "" { - return errs.RequiredFlag(ctx, "http") - } - - fmt.Printf("Serving HTTP on %s ...\n", addr) - server := http.Server{ - Addr: addr, - Handler: &htmlHelpHandler{ - cliApp: ctx.App, - }, - ReadHeaderTimeout: 15 * time.Second, - } - return server.ListenAndServe() -} - -func markdownHelpAction(ctx *cli.Context) error { - dir := path.Clean(ctx.String("markdown")) - if err := os.MkdirAll(dir, 0755); err != nil { - return errs.FileError(err, dir) - } - - // app index - index := path.Join(dir, "README.mdx") - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - markdownHelpPrinter(w, mdAppHelpTemplate, "", ctx.App) - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - // Subcommands - for _, cmd := range ctx.App.Commands { - if err := markdownHelpCommand(ctx.App, cmd, cmd, path.Join(dir, cmd.Name)); err != nil { - return err - } - } - return nil -} - -func markdownHelpCommand(app *cli.App, cmd, parent cli.Command, base string) error { - if err := os.MkdirAll(base, 0755); err != nil { - return errs.FileError(err, base) - } - - fileName := "README.mdx" - - index := path.Join(base, fileName) - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - - parentName := parent.HelpName - if cmd.HelpName == parent.HelpName { - parentName = "step" - } - - if len(cmd.Subcommands) == 0 { - markdownHelpPrinter(w, mdCommandHelpTemplate, parentName, cmd) - return errs.FileError(w.Close(), index) - } - - ctx := cli.NewContext(app, nil, nil) - ctx.App = createCliApp(ctx, cmd) - markdownHelpPrinter(w, mdSubcommandHelpTemplate, parentName, ctx.App) - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - for _, sub := range cmd.Subcommands { - sub.HelpName = fmt.Sprintf("%s %s", cmd.HelpName, sub.Name) - if err := markdownHelpCommand(app, sub, cmd, path.Join(base, sub.Name)); err != nil { - return err - } - } - - return nil -} - -func htmlHelpAction(ctx *cli.Context) error { - dir := path.Clean(ctx.String("html")) - - if err := os.MkdirAll(dir, 0755); err != nil { - return errs.FileError(err, dir) - } - - // app index - index := path.Join(dir, "index.html") - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - - tophelp := htmlHelpPrinter(w, mdAppHelpTemplate, ctx.App) - var report *Report - if ctx.IsSet("report") { - report = NewReport(ctx.App.Name, tophelp) - } - - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - // css style - cssFile := path.Join(dir, "style.css") - //nolint:gosec // not security sensitive - if err := os.WriteFile(cssFile, []byte(css), 0666); err != nil { - return errs.FileError(err, cssFile) - } - - // Subcommands - for _, cmd := range ctx.App.Commands { - if err := htmlHelpCommand(ctx.App, cmd, path.Join(dir, cmd.Name), report); err != nil { - return err - } - } - - // report - if report != nil { - repjson := path.Join(dir, "report.json") - rjw, err := os.Create(repjson) - if err != nil { - return errs.FileError(err, repjson) - } - - if err := report.Write(rjw); err != nil { - return err - } - - if err := rjw.Close(); err != nil { - return errs.FileError(err, repjson) - } - } - - return nil -} - -func htmlHelpCommand(app *cli.App, cmd cli.Command, base string, report *Report) error { - if err := os.MkdirAll(base, 0755); err != nil { - return errs.FileError(err, base) - } - - index := path.Join(base, "index.html") - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - - if len(cmd.Subcommands) == 0 { - cmdhelp := htmlHelpPrinter(w, mdCommandHelpTemplate, cmd) - - if report != nil { - report.Process(cmd.HelpName, cmdhelp) - } - - return errs.FileError(w.Close(), index) - } - - ctx := cli.NewContext(app, nil, nil) - ctx.App = createCliApp(ctx, cmd) - subhelp := htmlHelpPrinter(w, mdSubcommandHelpTemplate, ctx.App) - - if report != nil { - report.Process(cmd.HelpName, subhelp) - } - - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - for _, sub := range cmd.Subcommands { - sub.HelpName = fmt.Sprintf("%s %s", cmd.HelpName, sub.Name) - if err := htmlHelpCommand(app, sub, path.Join(base, sub.Name), report); err != nil { - return err - } - } - - return nil -} - -type htmlHelpHandler struct { - cliApp *cli.App -} - -func (h *htmlHelpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - ctx := cli.NewContext(h.cliApp, nil, nil) - - // clean request URI - requestURI := path.Clean(req.RequestURI) - if requestURI == "/" { - htmlHelpPrinter(w, mdAppHelpTemplate, ctx.App) - return - } - - if requestURI == "/style.css" { - w.Header().Set("Content-Type", `text/css; charset="utf-8"`) - w.Write([]byte(css)) - return - } - - args := strings.Split(requestURI, "/") - last := len(args) - 1 - lastName := args[last] - subcmd := ctx.App.Commands - for _, name := range args[:last] { - for _, cmd := range subcmd { - if cmd.HasName(name) { - subcmd = cmd.Subcommands - break - } - } - } - - for _, cmd := range subcmd { - if !cmd.HasName(lastName) { - continue - } - cmd.HelpName = fmt.Sprintf("%s %s", ctx.App.HelpName, strings.Join(args, " ")) - - ctx.Command = cmd - if len(cmd.Subcommands) == 0 { - htmlHelpPrinter(w, mdCommandHelpTemplate, cmd) - return - } - - ctx.App = createCliApp(ctx, cmd) - htmlHelpPrinter(w, mdSubcommandHelpTemplate, ctx.App) - return - } - - http.NotFound(w, req) -} - -// AppHelpTemplate contains the modified template for the main app -var mdAppHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -'''raw -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .Commands}} <command>{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments]{{end}}{{end}} -''' -{{- if .Description}} - -## DESCRIPTION -{{.Description}}{{end}}{{if .VisibleCommands}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -| Name | Usage | -|---|---|{{range .VisibleCommands}} -| **[{{join .Names ", "}}]({{.Name}}/)** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}}{{end}} - -## OPTIONS - -{{range $index, $option := .VisibleFlags}}{{if $index}} -{{end}}{{$option}} -{{end}}{{end}}{{if .Copyright}}{{if len .Authors}} - -## AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - -{{range $index, $author := .Authors}}{{if $index}} -{{end}}{{$author}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -## VERSION - -{{.Version}}{{end}}{{end}} - -## COPYRIGHT - -{{.Copyright}} -{{end}} -` - -// SubcommandHelpTemplate contains the modified template for a sub command -// Note that the weird "|||\n|---|---|" syntax sets up a markdown table with empty headers. -var mdSubcommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -'''raw -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}** <command>{{if .VisibleFlags}} [options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments]{{end}}{{end}} -''' -{{- if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -| Name | Usage | -|---|---|{{range .VisibleCommands}} -| **[{{join .Names ", "}}]({{.Name}}/)** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` - -// CommandHelpTemplate contains the modified template for a command -var mdCommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -'''raw -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .VisibleFlags}} [options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments]{{end}}{{end}} -''' -{{- if .Category}} - -## CATEGORY - -{{.Category}}{{end}}{{if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` diff --git a/vendor/go.step.sm/cli-utils/usage/printer.go b/vendor/go.step.sm/cli-utils/usage/printer.go deleted file mode 100644 index 2fbdeed..0000000 --- a/vendor/go.step.sm/cli-utils/usage/printer.go +++ /dev/null @@ -1,234 +0,0 @@ -package usage - -import ( - "bytes" - "fmt" - "io" - "regexp" - "strings" - "text/template" - "unicode" - - "github.com/urfave/cli" - md "go.step.sm/cli-utils/pkg/blackfriday" -) - -var sectionRe = regexp.MustCompile(`(?m:^##)`) -var sectionNameRe = regexp.MustCompile(`(?m:^## [^\n]+)`) -var indentRe = regexp.MustCompile(`(?m:^:[^\n]+)`) -var definitionListRe = regexp.MustCompile(`(?m:^[\t ]+\*\*[^\*]+\*\*[^\n]*\s+:[^\n]+)`) - -//var sectionRe = regexp.MustCompile(`^## [^\n]*$`) - -type frontmatterData struct { - Data interface{} - Parent string - Children []string -} - -// HelpPrinter overwrites cli.HelpPrinter and prints the formatted help to the terminal. -func HelpPrinter(w io.Writer, templ string, data interface{}) { - b := helpPreprocessor(w, templ, data, false) - w.Write(Render(b)) -} - -func htmlHelpPrinter(w io.Writer, templ string, data interface{}) []byte { - b := helpPreprocessor(w, templ, data, true) - w.Write([]byte(`<html><head><title>step command line documentation</title>`)) - w.Write([]byte(`<link href="/style.css" rel="stylesheet" type="text/css">`)) - w.Write([]byte(`</head><body><div class="wrapper markdown-body command">`)) - html := md.Run(b) - w.Write(html) - w.Write([]byte(`</div></body></html>`)) - - return html -} - -func markdownHelpPrinter(w io.Writer, templ, parent string, data interface{}) { - b := helpPreprocessor(w, templ, data, true) - - frontmatter := frontmatterData{ - Data: data, - Parent: parent, - } - - if app, ok := data.(*cli.App); ok { - for _, cmd := range app.Commands { - frontmatter.Children = append(frontmatter.Children, cmd.Name) - } - } - - var frontMatterTemplate = `--- -layout: auto-doc -category: reference -title: {{.Data.HelpName}} -menu: - docs: -{{- if .Parent}} - parent: {{.Parent}} -{{- end }} -{{- if .Children }} - children: -{{- range .Children }} - - {{.}} -{{- end }} -{{- end }} ---- - -` - t, err := template.New("frontmatter").Parse(frontMatterTemplate) - if err != nil { - panic(err) - } - err = t.Execute(w, frontmatter) - if err != nil { - panic(err) - } - w.Write(b) -} - -func helpPreprocessor(_ io.Writer, templ string, data interface{}, applyRx bool) []byte { - buf := new(bytes.Buffer) - cli.HelpPrinterCustom(buf, templ, data, nil) - //w.Write(buf.Bytes()) - // s := string(markdownify(buf.Bytes())) - s := markdownify(buf) - // Move the OPTIONS section to the right place. urfave puts them at the end - // of the file, we want them to be after POSITIONAL ARGUMENTS, DESCRIPTION, - // USAGE, or NAME (in that order, depending on which sections exist). - optLoc := strings.Index(s, "## OPTIONS") - if optLoc != -1 { - optEnd := findSectionEnd("OPTIONS", s) - if optEnd != -1 { - options := s[optLoc:optEnd] - s = s[:optLoc] + s[optEnd:] - if newLoc := findSectionEnd("POSITIONAL ARGUMENTS", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else if newLoc := findSectionEnd("DESCRIPTION", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else if newLoc := findSectionEnd("USAGE", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else if newLoc := findSectionEnd("NAME", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else { - // Keep it at the end I guess :/. - s += options - } - } - } - - if applyRx { - // Keep capitalized only the first letter in arguments names. - s = sectionNameRe.ReplaceAllStringFunc(s, func(s string) string { - return s[0:4] + strings.ToLower(s[4:]) - }) - // Remove `:` at the start of a line. - s = indentRe.ReplaceAllStringFunc(s, func(s string) string { - return strings.TrimSpace(s[1:]) - }) - // Convert lines like: - // **Foo** - // : Bar zar ... - // To: - // - **Foo**: Bar zar ... - s = definitionListRe.ReplaceAllStringFunc(s, func(s string) string { - i := strings.Index(s, "\n") - j := strings.Index(s, ":") - return "- " + strings.TrimSpace(s[:i]) + ": " + strings.TrimSpace(s[j+1:]) - }) - } - - return []byte(s) -} - -func findSectionEnd(h, s string) int { - start := strings.Index(s, fmt.Sprintf("## %s", h)) - if start == -1 { - return start - } - nextSection := sectionRe.FindStringIndex(s[start+2:]) - if nextSection == nil { - return len(s) - } - return start + 2 + nextSection[0] -} - -// Convert some stuff that we can't easily write in help files because -// -// backticks and raw strings don't mix: -// -// - "<foo>" to "`foo`" -// - "”'" to "```" -func markdownify(r *bytes.Buffer) string { - const escapeByte = byte('\\') - var last byte - var inCode bool - - w := new(bytes.Buffer) - for { - b, err := r.ReadByte() - if err != nil { - return w.String() - } - loop: - switch b { - case '<': - if last != escapeByte && !inCode { - w.WriteByte('`') - } else { - w.WriteByte(b) - } - case '>': - if last != escapeByte && !inCode { - w.WriteByte('`') - } else { - w.WriteByte(b) - } - case '\'': - b1, _ := r.ReadByte() - b2, _ := r.ReadByte() - if b1 == b && b2 == b { - w.WriteString("```") - if !inCode { - if n, _, err := r.ReadRune(); err == nil { - if unicode.IsSpace(n) { - w.WriteString("shell") - } - r.UnreadRune() - } - } - inCode = !inCode - } else { - // We can only unread the last one (b2) - w.WriteByte(b) - r.UnreadByte() - b = b1 - last = b - goto loop - } - case '*': - if inCode { - if b1, _ := r.ReadByte(); b1 != '*' { - w.WriteByte(b) - w.UnreadByte() - } - } else { - w.WriteByte(b) - } - case escapeByte: - if last == escapeByte { - w.WriteByte(escapeByte) - b = 0 - } else if n, _, err := r.ReadRune(); err == nil { - if unicode.IsSpace(n) { - w.WriteByte(escapeByte) - } - r.UnreadRune() - } - case 0: // probably because io.EOF - default: - w.WriteByte(b) - } - last = b - } -} diff --git a/vendor/go.step.sm/cli-utils/usage/renderer.go b/vendor/go.step.sm/cli-utils/usage/renderer.go deleted file mode 100644 index acc9766..0000000 --- a/vendor/go.step.sm/cli-utils/usage/renderer.go +++ /dev/null @@ -1,372 +0,0 @@ -package usage - -import ( - "bufio" - "bytes" - "fmt" - "io" - "regexp" - "strings" - "text/tabwriter" - "unicode" - - "github.com/mgutz/ansi" - md "go.step.sm/cli-utils/pkg/blackfriday" -) - -// Render renders the given data with a custom markdown renderer. -func Render(b []byte) []byte { - return md.Run(b, md.WithRenderer(&Renderer{6, 0, nil, nil, false})) -} - -var colorEscapeRe = regexp.MustCompile(`\033\[\d*(;\d*)?m?\]?`) -var maxLineLength = 80 - -func stripColors(b []byte) []byte { - return colorEscapeRe.ReplaceAll(b, []byte("")) -} - -type item struct { - flags md.ListType - term []byte - definitions [][]byte -} - -type list struct { - items []item - flags md.ListType - parent *list -} - -/* TODO: commented because unused -func (l *list) isUnordered() bool { - return !l.isOrdered() && !l.isDefinition() -} - -func (l *list) isOrdered() bool { - return l.flags&md.ListTypeOrdered != 0 -} - -func (l *list) containsBlock() bool { - // TODO: Not sure if we have to check every item or if it gets - // automatically set on the list? - return l.flags&md.ListItemContainsBlock != 0 -} -*/ - -func (l *list) isDefinition() bool { - return l.flags&md.ListTypeDefinition != 0 -} - -type bufqueue struct { - w io.Writer - buf *bytes.Buffer - next *bufqueue - mode RenderMode -} - -// RenderMode enumerates different line breaks modes. -type RenderMode int - -const ( - // RenderModeKeepBreaks will keep the line breaks in the docs. - RenderModeKeepBreaks RenderMode = iota - // RenderModeBreakLines will automatically wrap the lines. - RenderModeBreakLines -) - -// Renderer implements a custom markdown renderer for blackfriday. -type Renderer struct { - depth int - listdepth int - list *list - out *bufqueue - inpara bool -} - -func (r *Renderer) write(b []byte) { - r.out.w.Write(b) -} - -func (r *Renderer) printf(s string, a ...interface{}) { - fmt.Fprintf(r.out.w, s, a...) -} - -func (r *Renderer) capture(mode RenderMode) { - buf := new(bytes.Buffer) - r.out = &bufqueue{buf, buf, r.out, mode} -} - -func (r *Renderer) finishCapture() *bytes.Buffer { - buf := r.out.buf - r.out = r.out.next - return buf -} - -func (r *Renderer) inParagraph() bool { - return r.inpara -} - -/* TODO: commented because unused -func (r *Renderer) inList() bool { - return r.list != nil -} -*/ - -func (r *Renderer) renderParagraphKeepBreaks(buf *bytes.Buffer) { - scanner := bufio.NewScanner(buf) - for scanner.Scan() { - r.printf(strings.Repeat(" ", r.depth)+"%s\n", scanner.Text()) - } -} - -func (r *Renderer) renderParagraphBreakLines(buf *bytes.Buffer, maxlen int) { - maxlen -= r.depth - scanner := bufio.NewScanner(buf) - scanner.Split(bufio.ScanWords) - line := []string{} - length := 0 - for scanner.Scan() { - word := scanner.Text() - wordLength := len(stripColors([]byte(word))) - // Print the line if we've got a collection of words over 80 characters, or if - // we have a single word that is over 80 characters on an otherwise empty line. - switch { - case length+wordLength > maxlen: - r.printf(strings.Repeat(" ", r.depth)+"%s\n", strings.Join(line, " ")) - line = []string{word} - length = wordLength - case length == 0 && wordLength > maxlen: - r.printf(strings.Repeat(" ", r.depth)+"%s\n", word) - default: - line = append(line, word) - length += wordLength + 1 // Plus one for space - } - } - if len(line) > 0 { - r.printf(strings.Repeat(" ", r.depth)+"%s\n", strings.Join(line, " ")) - } -} - -func (r *Renderer) renderParagraph(buf *bytes.Buffer) { - switch r.out.mode { - case RenderModeKeepBreaks: - r.renderParagraphKeepBreaks(buf) - case RenderModeBreakLines: - r.renderParagraphBreakLines(buf, maxLineLength) - } -} - -// RenderNode implements blackfriday.Renderer interface. -func (r *Renderer) RenderNode(w io.Writer, node *md.Node, entering bool) md.WalkStatus { - if r.out == nil { - r.out = &bufqueue{w, nil, nil, RenderModeBreakLines} - } - - switch node.Type { - case md.Paragraph: - // Alternative idea here: call r.RenderNode() with our new buffer as - // `w`. In the `else` condition here render to the outter buffer and - // always return md.Terminate. So when we enter a paragraph we start - // parsing with a new output buffer and capture the output. - if entering { - if r.inParagraph() { - panic("already in paragraph") - } - r.inpara = true - //r.printf(out, "[paragraph:") - r.capture(r.out.mode) - } else { - r.renderParagraph(r.finishCapture()) - // Write a newline unless the parent node is a definition list term. - if node.Parent.Type != md.Item || node.Parent.ListFlags&md.ListTypeTerm == 0 { - r.printf("\n") - } - r.inpara = false - //r.printf(w, ":paragraph]") - } - case md.Text: - // TODO: is this necessary? I think all text is in a paragraph. - if r.inParagraph() { - r.write(node.Literal) - } else { - s := strings.ReplaceAll(string(node.Literal), "\n", "\n"+strings.Repeat(" ", r.depth)) - r.printf(s) - } - case md.Heading: - if entering { - r.printf(ansi.ColorCode("default+bh")) - } else { - r.printf(ansi.Reset) - r.printf("\n") - } - case md.Link: - if entering { - r.printf(ansi.ColorCode("default+b")) - //r.printf("\033[2m") // Dim - } else { - r.printf(ansi.Reset) - } - case md.Strong: - if entering { - r.printf(ansi.ColorCode("default+bh")) - } else { - r.printf(ansi.Reset) - } - case md.Emph: - if entering { - r.printf(ansi.ColorCode("default+u")) - } else { - r.printf(ansi.Reset) - } - case md.Code: - r.printf(ansi.ColorCode("default+u")) - r.write(node.Literal) - r.printf(ansi.Reset) - case md.List: - if entering { - r.listdepth++ - r.list = &list{[]item{}, node.ListFlags, r.list} - //r.printf("[list (type %s:", node.ListData.ListFlags) - } else { - if r.listdepth > 1 && r.list.isDefinition() { - w := new(tabwriter.Writer) - w.Init(r.out.w, 0, 8, 4, ' ', tabwriter.StripEscape) - for _, item := range r.list.items { - fmt.Fprint(w, strings.TrimRight(string(item.term), " \n")) - fmt.Fprint(w, "\n") - for _, def := range item.definitions { - fmt.Fprint(w, strings.TrimRight(string(def), " \n")) - } - fmt.Fprintf(w, "\n\n") - } - w.Flush() - } else { - ordered := (node.ListFlags&md.ListTypeOrdered != 0) - unordered := (node.ListFlags&md.ListTypeOrdered == 0 && node.ListFlags&md.ListTypeDefinition == 0) - for i, item := range r.list.items { - if ordered || unordered { - p := bytes.IndexFunc(item.term, func(r rune) bool { return !unicode.IsSpace(r) }) - switch { - case ordered: // add numbers on ordered lists - item.term = append(item.term[:p], append([]byte(fmt.Sprintf("%d. ", i+1)), item.term[p:]...)...) - case unordered: // add bullet points on unordered lists - item.term = append(item.term[:p], append([]byte("• "), item.term[p:]...)...) - } - } - - r.write(item.term) - for _, def := range item.definitions { - r.write(def) - } - } - } - r.listdepth-- - r.list = r.list.parent - //r.printf(":list]") - } - case md.Item: - incdepth := 4 - //ltype := "normal" - if node.ListFlags&md.ListTypeTerm != 0 { - // Nested definition list terms get indented two spaces. Non-nested - // definition list terms are not indented. - if r.listdepth > 1 { - incdepth = 2 - } else { - incdepth = 0 - } - //ltype = "dt" - } else if node.ListFlags&md.ListTypeDefinition != 0 { - incdepth = 4 - //ltype = "dd" - } - - if entering { - //fmt.Fprintf(out, "[list item %s:", ltype) - r.depth += incdepth - if r.listdepth > 1 && r.list.isDefinition() { - r.capture(RenderModeKeepBreaks) - } else { - r.capture(RenderModeBreakLines) - } - if !r.list.isDefinition() || node.ListFlags&md.ListTypeTerm != 0 { - r.list.items = append(r.list.items, item{node.ListFlags, nil, nil}) - } - } else { - //fmt.Fprintf(out, ":list item]") - r.depth -= incdepth - buf := r.finishCapture() - if r.list.isDefinition() && node.ListFlags&md.ListTypeTerm == 0 { - i := len(r.list.items) - 1 - r.list.items[i].definitions = append(r.list.items[i].definitions, buf.Bytes()) - } else { - r.list.items[len(r.list.items)-1].term = buf.Bytes() - } - } - case md.Table: - if entering { - r.capture(RenderModeKeepBreaks) - w := new(tabwriter.Writer) - w.Init(r.out.w, 1, 8, 2, ' ', tabwriter.StripEscape) - r.out.w = w - } else { - r.out.w.(*tabwriter.Writer).Flush() - buf := r.finishCapture() - r.renderParagraphKeepBreaks(buf) - r.printf("\n") - } - case md.TableBody: - // Do nothing. - case md.TableHead: - if entering { - r.capture(r.out.mode) - } else { - // Markdown doens't have a way to create a table without headers. - // We've opted to fix that here by not rendering headers at all if - // they're empty. - result := r.finishCapture().Bytes() - if strings.TrimSpace(string(stripColors(result))) != "" { - parts := strings.Split(strings.TrimRight(string(result), "\t\n"), "\t") - for i := 0; i < len(parts); i++ { - parts[i] = "\xff" + ansi.ColorCode("default+bh") + "\xff" + parts[i] + "\xff" + ansi.Reset + "\xff" - } - r.printf(strings.Join(parts, "\t") + "\t\n") - } - } - case md.TableRow: - if entering { - r.capture(r.out.mode) - } else { - // Escape any colors in the row before writing to the - // tabwriter, otherwise they screw up the width calculations. The - // escape character for tabwriter is \xff. - result := r.finishCapture().Bytes() - result = colorEscapeRe.ReplaceAll(result, []byte("\xff$0\xff")) - r.write(result) - r.printf("\n") - } - case md.TableCell: - if !entering { - r.printf("\t") - } - case md.CodeBlock: - r.depth += 4 - r.renderParagraphKeepBreaks(bytes.NewBuffer(node.Literal)) - r.printf("\n") - r.depth -= 4 - case md.Document: - default: - r.printf("unknown block %s:", node.Type) - r.write(node.Literal) - } - //w.Write([]byte(fmt.Sprintf("node<%s; %t>", node.Type, entering))) - //w.Write(node.Literal) - return md.GoToNext -} - -// RenderHeader implements blackfriday.Renderer interface. -func (r *Renderer) RenderHeader(io.Writer, *md.Node) {} - -// RenderFooter implements blackfriday.Renderer interface. -func (r *Renderer) RenderFooter(io.Writer, *md.Node) {} diff --git a/vendor/go.step.sm/cli-utils/usage/report.go b/vendor/go.step.sm/cli-utils/usage/report.go deleted file mode 100644 index 075fec4..0000000 --- a/vendor/go.step.sm/cli-utils/usage/report.go +++ /dev/null @@ -1,148 +0,0 @@ -package usage - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "regexp" - "strings" - - "golang.org/x/net/html" -) - -// Section keeps track of individual sections -type Section struct { - Command string `json:"command"` - Name string `json:"name"` - Text string `json:"text"` - Words int `json:"words"` - Lines int `json:"lines"` - Sections []*Section `json:"sections"` -} - -// Report holds together a report of sections -type Report struct { - Report []*Section `json:"report"` -} - -// NewReport returns report based on raw -func NewReport(command string, top []byte) *Report { - report := Report{} - report.Process(command, top) - - return &report -} - -// Write serializes the report to json -func (report *Report) Write(w io.Writer) error { - j, err := json.MarshalIndent(report, "", " ") - - if err != nil { - return err - } - - w.Write(j) - - return nil -} - -// Process adds a html based help page to the report -func (report *Report) Process(command string, raw []byte) error { - r := bytes.NewBuffer(raw) - doc, err := html.Parse(r) - - if err != nil { - return err - } - - if doc.FirstChild.Type != html.ElementNode || - doc.FirstChild.Data != "html" || - doc.FirstChild.FirstChild.NextSibling.Data != "body" { - return errors.New("error parsing raw html") - } - - body := doc.FirstChild.FirstChild.NextSibling - - report.addSection(command, body.FirstChild, nil) - - return nil -} - -func (report *Report) addSection(command string, node *html.Node, section *Section) (*html.Node, *Section) { - if node == nil || - node.Type != html.ElementNode || - node.Data != "h2" { - return nil, nil - } - - text, next := report.processNode(node) - words := strings.Fields(text) - lines := strings.Split(text, "\n") - - s := Section{ - Command: command, - Name: node.FirstChild.Data, - Text: text, - Words: len(words), - Lines: len(lines), - } - - if section == nil { - report.Report = append(report.Report, &s) - return report.addSection(command, next, &s) - } - - section.Sections = append(section.Sections, &s) - return report.addSection(command, next, section) -} - -func (report *Report) processNode(node *html.Node) (string, *html.Node) { - text := "" - current := node.NextSibling - - r := regexp.MustCompile(`<[^>]*>`) - - for current != nil { - var buf bytes.Buffer - w := io.Writer(&buf) - html.Render(w, current) - - notags := r.ReplaceAllString(buf.String(), "") - clean := strings.TrimSpace(notags) - - if len(text) > 0 && len(clean) > 0 { - text = fmt.Sprintf("%s %s", text, clean) - } else if len(clean) > 0 { - text = clean - } - - current = current.NextSibling - if current == nil { - return text, nil - } else if current.Type == html.ElementNode && - current.Data == "h2" { - node = current - current = nil - } - } - - return text, node -} - -// PerHeadline returns all sections across commands/pages with the same headline -func (report *Report) PerHeadline(headline string) []Section { - var results []Section - for _, top := range report.Report { - for _, section := range top.Sections { - if section.Name != headline { - continue - } - - results = append(results, *section) - } - } - - return results -} diff --git a/vendor/go.step.sm/cli-utils/usage/usage.go b/vendor/go.step.sm/cli-utils/usage/usage.go deleted file mode 100644 index 9ed88d9..0000000 --- a/vendor/go.step.sm/cli-utils/usage/usage.go +++ /dev/null @@ -1,214 +0,0 @@ -package usage - -import ( - "bytes" - "fmt" - "html" - "strconv" - "strings" - "text/template" -) - -var usageTextTempl = " {{.Name}}\n {{.Usage}} {{if .Required}}(Required){{else}}(Optional){{end}}{{if .Multiple}} (Multiple can be specified){{end}}\n" -var templ *template.Template - -func init() { - templ = template.Must(template.New("usageText").Parse(usageTextTempl)) -} - -// Argument specifies the Name, Usage, and whether or not an Argument is -// required or not -type Argument struct { - Required bool - Multiple bool - Name string - Usage string -} - -// Decorate returns the name of an Argument and decorates it with notation to -// indicate whether its required or not -func (a Argument) Decorate() string { - name := a.Name - if a.Multiple { - name += "(s)..." - } - if a.Required { - return fmt.Sprintf("<%s>", name) - } - - return fmt.Sprintf("[%s]", name) -} - -// Arguments is an array of Argument structs that specify which arguments are -// accepted by a Command -type Arguments []Argument - -// UsageText returns the value of the UsageText property for a cli.Command for -// these arguments -func (args Arguments) UsageText() string { - var buf bytes.Buffer - for _, a := range args { - data := map[string]interface{}{ - "Name": a.Decorate(), - "Multiple": a.Multiple, - "Required": a.Required, - "Usage": a.Usage, - } - - err := templ.Execute(&buf, data) - if err != nil { - panic(fmt.Sprintf("Could not generate args template for %s: %s", a.Name, err)) - } - } - - return "\n\n" + buf.String() -} - -// ArgsUsage returns the value of the ArgsUsage property for a cli.Command for -// these arguments -func (args Arguments) ArgsUsage() string { - out := "" - for i, a := range args { - out += a.Decorate() - if i < len(args)-1 { - out += " " - } - } - - return out -} - -// AppHelpTemplate contains the modified template for the main app -var AppHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .Commands}} <command>{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Description}} - -## DESCRIPTION -{{.Description}}{{end}}{{if .VisibleCommands}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -||| -|---|---|{{range .VisibleCommands}} -| **{{join .Names ", "}}** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}}{{end}} - -## OPTIONS - -{{range $index, $option := .VisibleFlags}}{{if $index}} -{{end}}{{$option}} -{{end}}{{end}}{{if .Copyright}}{{if len .Authors}} - -## AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - -{{range $index, $author := .Authors}}{{if $index}} -{{end}}{{$author}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -## ONLINE - -This documentation is available online at https://smallstep.com/docs/cli - -## VERSION - -{{.Version}}{{end}}{{end}} - -## COPYRIGHT - -{{.Copyright}} - -## FEEDBACK ` + - html.UnescapeString("&#"+strconv.Itoa(128525)+";") + " " + - html.UnescapeString("&#"+strconv.Itoa(127867)+";") + - ` - -The **step** utility is not instrumented for usage statistics. It does not phone home. -But your feedback is extremely valuable. Any information you can provide regarding how you’re using **step** helps. -Please send us a sentence or two, good or bad: **feedback@smallstep.com** or ask in [GitHub Discussions](https://github.com/smallstep/certificates/discussions). -{{end}} -` - -// SubcommandHelpTemplate contains the modified template for a sub command -// Note that the weird "|||\n|---|---|" syntax sets up a markdown table with empty headers. -var SubcommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}** <command>{{if .VisibleFlags}} _[options]_{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -||| -|---|---|{{range .VisibleCommands}} -| **{{join .Names ", "}}** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` - -// CommandHelpTemplate contains the modified template for a command -var CommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .VisibleFlags}} _[options]_{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Category}} - -## CATEGORY - -{{.Category}}{{end}}{{if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` - -// FlagNamePrefixer converts a full flag name and its placeholder into the help -// message flag prefix. This is used by the default FlagStringer. -// -// This method clones urflave/cli functionality but adds a new line at the end. -func FlagNamePrefixer(fullName, placeholder string) string { - var prefixed string - parts := strings.Split(fullName, ",") - for i, name := range parts { - name = strings.Trim(name, " ") - prefixed += "**" + prefixFor(name) + name + "**" - - if placeholder != "" { - prefixed += "=" + placeholder - } - if i < len(parts)-1 { - prefixed += ", " - } - } - //return "* " + prefixed + "\n" - return prefixed + "\n: " -} - -func prefixFor(name string) (prefix string) { - if len(name) == 1 { - prefix = "-" - } else { - prefix = "--" - } - - return -} |
