mirror of
https://github.com/yusing/godoxy.git
synced 2026-02-21 16:27:46 +01:00
This is a large-scale refactoring across the codebase that replaces the custom `gperr.Error` type with Go's standard `error` interface. The changes include: - Replacing `gperr.Error` return types with `error` in function signatures - Using `errors.New()` and `fmt.Errorf()` instead of `gperr.New()` and `gperr.Errorf()` - Using `%w` format verb for error wrapping instead of `.With()` method - Replacing `gperr.Subject()` calls with `gperr.PrependSubject()` - Converting error logging from `gperr.Log*()` functions to zerolog's `.Err().Msg()` pattern - Update NewLogger to handle multiline error message - Updating `goutils` submodule to latest commit This refactoring aligns with Go idioms and removes the dependency on custom error handling abstractions in favor of standard library patterns.
158 lines
3.9 KiB
Go
158 lines
3.9 KiB
Go
package rules
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
gperr "github.com/yusing/goutils/errs"
|
|
"github.com/yusing/goutils/strings/ansi"
|
|
)
|
|
|
|
type Help struct {
|
|
command string
|
|
description []string
|
|
args map[string]string // args[arg] -> description
|
|
}
|
|
|
|
func makeLines(lines ...string) []string {
|
|
return lines
|
|
}
|
|
|
|
func helpExample(cmd string, args ...string) string {
|
|
var sb strings.Builder
|
|
sb.WriteString(" ")
|
|
sb.WriteString(ansi.WithANSI(cmd, ansi.HighlightGreen))
|
|
for _, arg := range args {
|
|
var out strings.Builder
|
|
pos := 0
|
|
for {
|
|
start := strings.IndexByte(arg[pos:], '$')
|
|
if start == -1 {
|
|
if pos < len(arg) {
|
|
// If no variable at all (pos == 0), cyan highlight for whole-arg
|
|
// Otherwise, for mixed strings containing variables, leave non-variable text unhighlighted
|
|
if pos == 0 {
|
|
out.WriteString(ansi.WithANSI(arg[pos:], ansi.HighlightCyan))
|
|
} else {
|
|
out.WriteString(arg[pos:])
|
|
}
|
|
}
|
|
break
|
|
}
|
|
start += pos
|
|
if start > pos {
|
|
// Non-variable text should not be highlighted
|
|
out.WriteString(arg[pos:start])
|
|
}
|
|
// Parse variable name and optional function call
|
|
end := start + 1
|
|
for end < len(arg) && (arg[end] == '_' || (arg[end] >= 'a' && arg[end] <= 'z') || (arg[end] >= 'A' && arg[end] <= 'Z') || (arg[end] >= '0' && arg[end] <= '9')) {
|
|
end++
|
|
}
|
|
// Check for function call
|
|
if end < len(arg) && arg[end] == '(' {
|
|
parenCount := 1
|
|
end++
|
|
for end < len(arg) && parenCount > 0 {
|
|
switch arg[end] {
|
|
case '(':
|
|
parenCount++
|
|
case ')':
|
|
parenCount--
|
|
}
|
|
end++
|
|
}
|
|
}
|
|
varExpr := arg[start:end]
|
|
out.WriteString(helpVar(varExpr))
|
|
pos = end
|
|
}
|
|
fmt.Fprintf(&sb, ` "%s"`, out.String())
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func helpListItem(key string, value string) string {
|
|
var sb strings.Builder
|
|
sb.WriteString(" ")
|
|
sb.WriteString(ansi.WithANSI(key, ansi.HighlightYellow))
|
|
sb.WriteString(": ")
|
|
sb.WriteString(value)
|
|
return sb.String()
|
|
}
|
|
|
|
// helpFuncCall generates a string like "fn(arg1, arg2, arg3)"
|
|
func helpFuncCall(fn string, args ...string) string {
|
|
var sb strings.Builder
|
|
sb.WriteString(ansi.WithANSI(fn, ansi.HighlightRed))
|
|
sb.WriteString("(")
|
|
for i, arg := range args {
|
|
fmt.Fprintf(&sb, `"%s"`, ansi.WithANSI(arg, ansi.HighlightCyan))
|
|
if i < len(args)-1 {
|
|
sb.WriteString(", ")
|
|
}
|
|
}
|
|
sb.WriteString(")")
|
|
return sb.String()
|
|
}
|
|
|
|
// helpVar generates a highlighted string for a variable like "$req_method" or "$header(X-Test)"
|
|
func helpVar(varExpr string) string {
|
|
if !strings.HasPrefix(varExpr, "$") {
|
|
return varExpr
|
|
}
|
|
|
|
// Check if it's a function call
|
|
parenIdx := strings.IndexByte(varExpr, '(')
|
|
if parenIdx == -1 {
|
|
// Simple variable like "$req_method"
|
|
return ansi.WithANSI(varExpr, ansi.HighlightCyan)
|
|
}
|
|
|
|
// Function call like "$header(X-Test)"
|
|
var sb strings.Builder
|
|
sb.WriteString(ansi.WithANSI(varExpr[:parenIdx], ansi.HighlightCyan))
|
|
sb.WriteString(ansi.WithANSI("(", ansi.HighlightWhite))
|
|
|
|
// Extract and highlight the arguments
|
|
argsStr := varExpr[parenIdx+1 : len(varExpr)-1]
|
|
sb.WriteString(ansi.WithANSI(argsStr, ansi.HighlightYellow))
|
|
|
|
sb.WriteString(ansi.WithANSI(")", ansi.HighlightWhite))
|
|
return sb.String()
|
|
}
|
|
|
|
/*
|
|
Generate help string as error, e.g.
|
|
|
|
rewrite <from> <to>
|
|
from: the path to rewrite, must start with /
|
|
to: the path to rewrite to, must start with /
|
|
*/
|
|
func (h *Help) Error() error {
|
|
var lines gperr.MultilineError
|
|
|
|
lines.Adds(ansi.WithANSI(h.command, ansi.HighlightGreen))
|
|
lines.AddStrings(h.description...)
|
|
lines.Adds(" args:")
|
|
|
|
argKeys := make([]string, 0, len(h.args))
|
|
longestArg := 0
|
|
for arg := range h.args {
|
|
if len(arg) > longestArg {
|
|
longestArg = len(arg)
|
|
}
|
|
argKeys = append(argKeys, arg)
|
|
}
|
|
|
|
// sort argKeys alphabetically to make output stable
|
|
slices.Sort(argKeys)
|
|
for _, arg := range argKeys {
|
|
desc := h.args[arg]
|
|
lines.Addf(" %-"+strconv.Itoa(longestArg)+"s: %s", ansi.WithANSI(arg, ansi.HighlightCyan), desc)
|
|
}
|
|
return &lines
|
|
}
|