func isQCall(n *ast.CallExpr) bool {
	return isQFunction(n) || isQPackage(n)
}
isQCall returns true if the given function call expression is Q() or q.Q().
package q
import (
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"runtime"
	"strings"
	"unicode/utf8"
	"github.com/kr/pretty"
)
func argName(arg ast.Expr) string {
	name := ""
	switch a := arg.(type) {
	case *ast.Ident:
		switch {
		case a.Obj == nil:
			name = a.Name
		case a.Obj.Kind == ast.Var, a.Obj.Kind == ast.Con:
			name = a.Obj.Name
		}
	case *ast.BinaryExpr,
		*ast.CallExpr,
		*ast.IndexExpr,
		*ast.KeyValueExpr,
		*ast.ParenExpr,
		*ast.SelectorExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.UnaryExpr:
		name = exprToString(arg)
	}
	return name
}
func argNames(filename string, line int) ([]string, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to parse %q: %w", filename, err)
	}
	var names []string
	ast.Inspect(f, func(n ast.Node) bool {
		call, is := n.(*ast.CallExpr)
		if !is {
			return true  
		}
		if fset.Position(call.End()).Line != line {
			return true
		}
		if !isQCall(call) {
			return true
		}
		for _, arg := range call.Args {
			names = append(names, argName(arg))
		}
		return true
	})
	return names, nil
}
func argWidth(arg string) int {
	replacer := strings.NewReplacer(
		"\n", "",
		"\t", "",
		"\r", "",
		"\f", "",
		"\v", "",
		string(bold), "",
		string(yellow), "",
		string(cyan), "",
		string(endColor), "",
	)
	s := replacer.Replace(arg)
	return utf8.RuneCountInString(s)
}
func colorize(text string, c color) string {
	return string(c) + text + string(endColor)
}
func exprToString(arg ast.Expr) string {
	var buf strings.Builder
	fset := token.NewFileSet()
	if err := printer.Fprint(&buf, fset, arg); err != nil {
		return ""
	}
	return strings.ReplaceAll(buf.String(), "\t", "    ")
}
func formatArgs(args ...interface{}) []string {
	formatted := make([]string, 0, len(args))
	for _, a := range args {
		s := colorize(pretty.Sprint(a), cyan)
		formatted = append(formatted, s)
	}
	return formatted
}
func getCallerInfo() (funcName, file string, line int, err error) {
	const callDepth = 2  
	pc, file, line, ok := runtime.Caller(callDepth)
	if !ok {
		return "", "", 0, errors.New("failed to get info about the function calling q.Q")  
	}
	funcName = runtime.FuncForPC(pc).Name()
	return funcName, file, line, nil
}
func prependArgName(names, values []string) []string {
	prepended := make([]string, len(values))
	for i, value := range values {
		name := ""
		if i < len(names) {
			name = names[i]
		}
		if name == "" {
			prepended[i] = value
			continue
		}
		name = colorize(name, bold)
		prepended[i] = fmt.Sprintf("%s=%s", name, value)
	}
	return prepended
}