Documentation
¶
Index ¶
- Constants
- Variables
- func AbsFloat(x float64) float64
- func AbsInt(x int64) int64
- func AddInternalFuncs()
- func BuildDocsFull() string
- func BuildDocsTOC() string
- func CalculateCorrectedIndex(rawIdx, length int64, clamp bool) int64
- func DiagnosticProseWidth() int
- func DocTopicSlug(topic string) string
- func ErrIndexOutOfBounds(i *Interpreter, node rl.Node, idx int64, length int64)
- func ExitCodeFor(name string) int
- func FuzzyMatchFold(source, target string) bool
- func GetDocFuncs() []string
- func GetDocPage(slug string) (string, bool)
- func GetDocTopic(topic string) (string, bool)
- func GetDocURL(topic string) (string, bool)
- func GetEmbeddedCommandSrc(name string) *string
- func GetEnumColor(value string, possibleSortedValues []string) (r, g, b int, err error)
- func GetErrorDoc(code string) string
- func GetFuncDoc(name string) (string, bool)
- func GetInvocationLogPath() string
- func GetInvocationLogsDir() string
- func GetTermHeight() int
- func GetTermWidth() int
- func InputConfirm(title string, prompt string) (bool, error)
- func IsTerminatingSignal(name string) bool
- func IsWindows() bool
- func JsonToString(jsonVal interface{}) string
- func Levenshtein(a, b string) int
- func ListErrorCodes() []string
- func LoadPickResource(i *Interpreter, callNode rl.Node, jsonPath string) (PickResource, *RadError)
- func LogInvocation(entry InvocationLogEntry)
- func MaybeRotate()
- func NormalizeLineEndings(s string) string
- func NormalizePath(path string) string
- func ParseDuration(s string) (time.Duration, error)
- func ParseDurationString(s string) (int64, error)
- func RadToJsonType(arg RadValue) interface{}
- func RegisterInvocationLogging()
- func RenderDiagnosticToString(d Diagnostic) string
- func ReplAutoIndent(buf string) string
- func ReplNeedsMore(buf string) bool
- func ReplTrimTrailingBlankLines(buf string) string
- func ResetGlobals()
- func RunRepl() error
- func SetScriptPath(path string)
- func TerminalAvailable() bool
- func ToPrintable(val interface{}) string
- func ToPrintableQuoteStr(val interface{}, quoteStrings bool) string
- func TransformRadArgs(args []RadArg, transformer func(RadArg) string) []string
- func TypeAsString(val interface{}) string
- type ArgLenConstraint
- type ArgPrompter
- type ArgRangeConstraint
- type BaseRadArg
- func (f *BaseRadArg) Configured() bool
- func (f *BaseRadArg) DefaultAsString() string
- func (f *BaseRadArg) Excludes(otherArg RadArg) bool
- func (f *BaseRadArg) GetDescription() string
- func (f *BaseRadArg) GetExternalName() string
- func (f *BaseRadArg) GetIdentifier() string
- func (f *BaseRadArg) GetShort() string
- func (f *BaseRadArg) GetSpan() *rl.Span
- func (f *BaseRadArg) HasNonZeroDefault() bool
- func (f *BaseRadArg) Hidden(hide bool)
- func (f *BaseRadArg) IsDefined() bool
- func (f *BaseRadArg) IsHidden() bool
- func (f *BaseRadArg) IsNullable() bool
- func (f *BaseRadArg) IsOptional() bool
- func (f *BaseRadArg) IsVariadic() bool
- func (f *BaseRadArg) SetBypassValidation(bypass bool)
- func (f *BaseRadArg) SetUsagePlaceholder(placeholder string)
- func (f *BaseRadArg) SetValue(_ string)
- type BoolListRadArg
- type BoolRadArg
- type BufferReader
- type BuiltInFunc
- type CallFrame
- type Capture
- type CheckableReader
- type Clock
- type CodeCtx
- type ColumnSort
- type ConstraintCtx
- type CtrlKind
- type DeferBlock
- type Delimiter
- type Diagnostic
- type DiagnosticCollector
- func (c *DiagnosticCollector) Add(d Diagnostic) bool
- func (c *DiagnosticCollector) AtLimit() bool
- func (c *DiagnosticCollector) Count() int
- func (c *DiagnosticCollector) Diagnostics() []Diagnostic
- func (c *DiagnosticCollector) HasErrors() bool
- func (c *DiagnosticCollector) IsEmpty() bool
- func (c *DiagnosticCollector) Remaining() int
- func (c *DiagnosticCollector) TotalEmitted() int
- type DiagnosticRenderer
- type DocPage
- type EmbeddedCmd
- type Env
- func (e *Env) AllVarNames() []string
- func (e *Env) FindSimilarVars(name string, maxResults int) []string
- func (e *Env) GetJsonFieldVar(name string) (*JsonFieldVar, bool)
- func (e *Env) GetVar(name string) (RadValue, bool)
- func (e *Env) GetVarElseBug(i *Interpreter, node rl.Node, name string) RadValue
- func (e *Env) NewChildEnv() Env
- func (e *Env) PrintShellExports()
- func (e *Env) SetJsonFieldVar(jsonFieldVar *JsonFieldVar)
- func (e *Env) SetVar(name string, v RadValue)
- func (e *Env) SetVarUpdatingEnclosing(name string, v RadValue, updateEnclosing bool)
- type ErrorCtx
- type EvalResult
- type ExitReason
- type ExpectedOutput
- type FakeSignalSource
- func (f *FakeSignalSource) Fire(sig os.Signal)
- func (f *FakeSignalSource) FiredCount(sig os.Signal) int
- func (f *FakeSignalSource) Ignore(sigs ...os.Signal)
- func (f *FakeSignalSource) Notify(ch chan<- os.Signal, sigs ...os.Signal)
- func (f *FakeSignalSource) Stop(ch chan<- os.Signal)
- func (f *FakeSignalSource) WasIgnored(sig os.Signal) bool
- type FileReader
- type FixedClock
- type FloatListRadArg
- type FloatRadArg
- type FuncInvocation
- func (f FuncInvocation) GetArg(name string) RadValue
- func (f FuncInvocation) GetBool(name string) bool
- func (f FuncInvocation) GetFloat(name string) float64
- func (f FuncInvocation) GetFn(name string) RadFn
- func (f FuncInvocation) GetInt(name string) int64
- func (f FuncInvocation) GetIntAllowingBool(name string) int64
- func (f FuncInvocation) GetList(name string) *RadList
- func (f FuncInvocation) GetMap(name string) *RadMap
- func (f FuncInvocation) GetStr(name string) RadString
- func (f FuncInvocation) Return(vals ...interface{}) RadValue
- func (f FuncInvocation) ReturnErrf(code rl.Error, msg string, args ...interface{}) RadValue
- type GeneralSort
- type GlobalFlagScope
- type HttpRequest
- type IntListRadArg
- type IntRadArg
- type InteractiveDriver
- type Interpreter
- func (i *Interpreter) CallStack() []CallFrame
- func (i *Interpreter) Checkpoint()
- func (i *Interpreter) EvalReplTurn(src string, root *rl.SourceFile, tree *rts.RadTree) (out RadValue, abort *RadAbort)
- func (i *Interpreter) GetScriptName() string
- func (i *Interpreter) GetSrc() string
- func (i *Interpreter) GetSrcForSpan(span rl.Span) string
- func (i *Interpreter) InitArgs(args []RadArg)
- func (i *Interpreter) InitBuiltIns()
- func (i *Interpreter) NewRadPanic(node rl.Node, err RadValue) *RadPanic
- func (i *Interpreter) RegisterWithExit()
- func (i *Interpreter) Run()
- func (i *Interpreter) Signals() *SignalManager
- func (i *Interpreter) WithTmpSrc(tmpSrc string, fn func())
- type InterpreterInput
- type InvocationLogEntry
- type InvocationLoggingConfig
- type InvocationType
- type JsonFieldVar
- type JsonPath
- type JsonPathSegment
- type JsonPathSegmentIdx
- type Label
- type MockResponse
- type MockResponseSlice
- type NullWriter
- type PickResource
- type PickResourceOpt
- type PickResourceOptionSerde
- type PickResourceSerde
- type PosArg
- type Printer
- type RadAbort
- type RadArg
- type RadArgTypeT
- type RadConfig
- type RadError
- type RadExitHandler
- func (h *RadExitHandler) AddPreExitCallback(cb func())
- func (h *RadExitHandler) Exit(code int)
- func (h *RadExitHandler) ExitWith(code int, reason ExitReason, signal string)
- func (h *RadExitHandler) ResetExiting()
- func (h *RadExitHandler) SetExecuteDeferredStmtsFunc(f func(code int))
- func (h *RadExitHandler) SetUnwinding(unwind bool)
- type RadFn
- type RadHome
- func (r *RadHome) GetStash() *string
- func (r *RadHome) GetStashForId(id string) string
- func (r *RadHome) GetStashSub(subPath string, node rl.Node) (string, *RadError)
- func (r *RadHome) LoadState(i *Interpreter, node rl.Node) (RadValue, bool, *RadError)
- func (r *RadHome) SaveState(i *Interpreter, node rl.Node, value RadValue) *RadError
- func (r *RadHome) SetStashId(id string)
- type RadIo
- type RadList
- func (l *RadList) Append(value RadValue)
- func (l *RadList) AsActualStringList(i *Interpreter, node rl.Node) []string
- func (l *RadList) AsStringList(quoteStrings bool) []string
- func (l *RadList) Contains(val RadValue) bool
- func (l *RadList) Equals(r *RadList) bool
- func (l *RadList) IndexAt(i *Interpreter, node rl.Node, idx int64) RadValue
- func (l *RadList) IsEmpty() bool
- func (l *RadList) Join(sep string, prefix string, suffix string) RadString
- func (l *RadList) JoinWith(other *RadList) RadValue
- func (l *RadList) Len() int64
- func (l *RadList) LenInt() int
- func (l *RadList) RemoveIdx(i *Interpreter, node rl.Node, idx int)
- func (l *RadList) Reverse() *RadList
- func (l *RadList) ShallowCopy() *RadList
- func (l *RadList) SortAccordingToIndices(i *Interpreter, node rl.Node, indices []int64)
- func (l *RadList) ToGoList() []interface{}
- func (l *RadList) ToString() string
- type RadMap
- func (m *RadMap) AsErrMsg(i *Interpreter, node rl.Node) string
- func (m *RadMap) ContainsKey(key RadValue) bool
- func (m *RadMap) Delete(key RadValue)
- func (l *RadMap) Equals(right *RadMap) bool
- func (m *RadMap) Get(key RadValue) (RadValue, bool)
- func (m *RadMap) GetByKey(i *Interpreter, node rl.Node, key RadValue) RadValue
- func (m *RadMap) Keys() []RadValue
- func (m *RadMap) Len() int64
- func (m *RadMap) Range(fn func(key, value RadValue) bool)
- func (m *RadMap) Set(key RadValue, value RadValue)
- func (m *RadMap) SetPrimitiveBool(key string, value bool)
- func (m *RadMap) SetPrimitiveFloat(key string, value float64)
- func (m *RadMap) SetPrimitiveInt(key string, value int)
- func (m *RadMap) SetPrimitiveInt64(key string, value int64)
- func (m *RadMap) SetPrimitiveList(key string, value *RadList)
- func (m *RadMap) SetPrimitiveMap(key string, value *RadMap)
- func (m *RadMap) SetPrimitiveStr(key string, value string)
- func (m *RadMap) ShallowCopy() *RadMap
- func (m *RadMap) ToGoMap() map[string]interface{}
- func (m *RadMap) ToString() string
- func (m *RadMap) Values() []RadValue
- type RadNull
- type RadPanic
- type RadRunner
- type RadString
- func (s *RadString) Compare(other RadString) int
- func (s RadString) Concat(other RadString) RadString
- func (s RadString) ConcatStr(other string) RadString
- func (s RadString) CopyAttrTo(otherStr string) RadString
- func (s *RadString) CopyWithAttr(attr RadTextAttr) RadString
- func (s *RadString) DeepCopy() RadString
- func (s RadString) Equals(other RadString) bool
- func (s *RadString) Hyperlink(link RadString) RadString
- func (s *RadString) IndexAt(idx int64) RadString
- func (s RadString) Len() int64
- func (s RadString) Lower() RadString
- func (s RadString) Plain() string
- func (s RadString) Repeat(multiplier int64) RadString
- func (s *RadString) Reverse() RadString
- func (s RadString) Runes() []rune
- func (s *RadString) SetAttr(attr RadTextAttr)
- func (s RadString) SetRgb(red int, green int, blue int)
- func (s RadString) SetRgb64(red int64, green int64, blue int64)
- func (s *RadString) SetSegmentsHyperlink(link RadString)
- func (s RadString) String() string
- func (s *RadString) SubSlice(startRune, endRune int64) RadString
- func (s *RadString) ToRuneList() *RadList
- func (s *RadString) Trim(chars string) RadString
- func (s *RadString) TrimLeft(chars string) RadString
- func (s *RadString) TrimPrefix(prefix string) RadString
- func (s *RadString) TrimRight(chars string) RadString
- func (s *RadString) TrimSuffix(suffix string) RadString
- func (s RadString) Upper() RadString
- type RadTextAttr
- type RadTypeVisitor
- func (v *RadTypeVisitor) ForBool(handler func(RadValue, bool)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForDefault(handler func(RadValue)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForError(handler func(RadValue, *RadError)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForFloat(handler func(RadValue, float64)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForFn(handler func(RadValue, RadFn)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForInt(handler func(RadValue, int64)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForList(handler func(RadValue, *RadList)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForMap(handler func(RadValue, *RadMap)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForNull(handler func(RadValue, RadNull)) *RadTypeVisitor
- func (v *RadTypeVisitor) ForString(handler func(RadValue, RadString)) *RadTypeVisitor
- func (v *RadTypeVisitor) UnhandledTypeError(val RadValue)
- func (v *RadTypeVisitor) Visit(acceptor RadTypeVisitorAcceptor)
- type RadTypeVisitorAcceptor
- type RadValue
- func (v RadValue) Accept(visitor *RadTypeVisitor)
- func (left RadValue) Equals(right RadValue) bool
- func (v RadValue) GoMapKey() string
- func (v RadValue) Hash() string
- func (v RadValue) Index(i *Interpreter, node rl.Node, key RadValue) RadValue
- func (v RadValue) IsError() bool
- func (v RadValue) IsNull() bool
- func (v RadValue) ModifyByKey(i *Interpreter, node rl.Node, key RadValue, rightValue RadValue)
- func (v RadValue) RequireBool(i *Interpreter, node rl.Node) bool
- func (v RadValue) RequireError(i *Interpreter, node rl.Node) *RadError
- func (v RadValue) RequireFloatAllowingInt(i *Interpreter, node rl.Node) float64
- func (v RadValue) RequireFn(i *Interpreter, node rl.Node) RadFn
- func (v RadValue) RequireInt(i *Interpreter, node rl.Node) int64
- func (v RadValue) RequireIntAllowingBool(i *Interpreter, node rl.Node) int64
- func (v RadValue) RequireList(i *Interpreter, node rl.Node) *RadList
- func (v RadValue) RequireMap(i *Interpreter, node rl.Node) *RadMap
- func (v RadValue) RequireNonVoid(i *Interpreter, node rl.Node) RadValue
- func (v RadValue) RequireNotType(i *Interpreter, node rl.Node, errPrefix string, disallowedTypes ...rl.RadType) RadValue
- func (v RadValue) RequireStr(i *Interpreter, node rl.Node) RadString
- func (v RadValue) RequireType(i *Interpreter, node rl.Node, errPrefix string, allowedTypes ...rl.RadType) RadValue
- func (v RadValue) ToCompatSubject() (out rl.TypingCompatVal)
- func (v RadValue) ToGoValue() (out interface{})
- func (v RadValue) TruthyFalsy() bool
- func (v RadValue) TryGetBool() (bool, bool)
- func (v RadValue) TryGetError() (*RadError, bool)
- func (v RadValue) TryGetFloatAllowingInt() (float64, bool)
- func (v RadValue) TryGetFn() (RadFn, bool)
- func (v RadValue) TryGetList() (*RadList, bool)
- func (v RadValue) TryGetMap() (*RadMap, bool)
- func (v RadValue) TryGetStr() (RadString, bool)
- func (v RadValue) Type() rl.RadType
- type RealClock
- type RegistrationMode
- type ReplSession
- type RequestDef
- type Requester
- func (r *Requester) AddMockedResponse(urlRegex string, jsonPath string)
- func (r *Requester) ClearMockedResponses()
- func (r *Requester) IsInsecure() bool
- func (r *Requester) Request(ctx context.Context, def RequestDef) ResponseDef
- func (r *Requester) RequestJson(ctx context.Context, url string, insecure bool, quiet bool) (interface{}, error)
- func (r *Requester) SetCaptureCallback(cb func(HttpRequest))
- func (r *Requester) SetInsecure(insecure bool)
- type ResponseDef
- type RunnerInput
- type ScopedGlobalFlag
- type ScriptArg
- type ScriptCommand
- type ScriptData
- type Severity
- type ShellExecutor
- type ShellInvocation
- type SignalManager
- func (sm *SignalManager) ClearInHandler()
- func (sm *SignalManager) Ctx() context.Context
- func (sm *SignalManager) DrainPending() (string, bool)
- func (sm *SignalManager) Handler(name string) (RadFn, bool)
- func (sm *SignalManager) Ignore(name string) error
- func (sm *SignalManager) MarkInHandler(name string)
- func (sm *SignalManager) NotifyCh() chan<- os.Signal
- func (sm *SignalManager) RefreshCtx()
- func (sm *SignalManager) Start()
- func (sm *SignalManager) Stop()
- func (sm *SignalManager) Trap(name string, fn RadFn) error
- type SignalSource
- type SortDir
- type StringListRadArg
- type StringRadArg
- type TblWriter
- type Terminal
- type TerminalSource
- type Trie
- type TrieNode
Constants ¶
const ( EmbCmdNew = "new" EmbCmdDocs = "docs" EmbCmdHome = "home" EmbCmdGenId = "gen-id" EmbCmdStash = "stash" EmbCmdCheck = "check" EmbCmdFmt = "fmt" EmbCmdExplain = "explain" )
const ( UNREACHABLE = "Bug! This should be unreachable" NOT_IMPLEMENTED = "not implemented" NO_NUM_RETURN_VALUES_CONSTRAINT = -1 USAGE_ALIGNMENT_CHAR = "\x00" PADDING_CHAR = "\x00" )
const ( WILDCARD = "*" MACRO_STASH_ID = "stash_id" MACRO_ENABLE_GLOBAL_OPTIONS = "enable_global_options" MACRO_ENABLE_ARGS_BLOCK = "enable_args_block" )
const ( COLOR_AUTO = "auto" COLOR_ALWAYS = "always" COLOR_NEVER = "never" FLAG_HELP = "help" FLAG_H = "h" FLAG_DEBUG = "debug" FLAG_D = "d" FLAG_RAD_DEBUG = "rad-debug" FLAG_COLOR = "color" FLAG_QUIET = "quiet" FLAG_Q = "q" FLAG_SHELL = "shell" FLAG_VERSION = "version" FLAG_V = "v" FLAG_CONFIRM_SHELL = "confirm-shell" FLAG_SRC = "src" FLAG_CST_TREE = "cst-tree" FLAG_AST_TREE = "ast-tree" FLAG_RAD_ARGS_DUMP = "rad-args-dump" FLAG_MOCK_RESPONSE = "mock-response" FLAG_TLS_INSECURE = "tls-insecure" FLAG_INTERACTIVE = "interactive" FLAG_I = "i" FLAG_REPLY = "reply" FLAG_REPLY_NA = "reply-na" )
const ( FUNC_PRINT = "print" FUNC_PRINT_ERR = "print_err" FUNC_PPRINT = "pprint" FUNC_DEBUG = "debug" FUNC_EXIT = "exit" FUNC_SLEEP = "sleep" FUNC_SEED_RANDOM = "seed_random" FUNC_RAND = "rand" FUNC_RAND_INT = "rand_int" FUNC_REPLACE = "replace" FUNC_LEN = "len" FUNC_SORT = "sort" FUNC_NOW = "now" FUNC_PARSE_EPOCH = "parse_epoch" FUNC_PARSE_DATE = "parse_date" FUNC_TYPE_OF = "type_of" FUNC_JOIN = "join" FUNC_UPPER = "upper" FUNC_LOWER = "lower" FUNC_STARTS_WITH = "starts_with" FUNC_ENDS_WITH = "ends_with" FUNC_PICK = "pick" FUNC_PICK_KV = "pick_kv" FUNC_PICK_FROM_RESOURCE = "pick_from_resource" FUNC_MULTIPICK = "multipick" FUNC_KEYS = "keys" FUNC_VALUES = "values" FUNC_TRUNCATE = "truncate" FUNC_SPLIT = "split" FUNC_SPLIT_LINES = "split_lines" FUNC_RANGE = "range" FUNC_UNIQUE = "unique" FUNC_INDEX_OF = "index_of" FUNC_CONFIRM = "confirm" FUNC_INPUT = "input" FUNC_PARSE_JSON = "parse_json" FUNC_TO_JSON = "to_json" FUNC_PARSE_INT = "parse_int" FUNC_PARSE_FLOAT = "parse_float" FUNC_HTTP_GET = "http_get" FUNC_HTTP_POST = "http_post" FUNC_HTTP_PUT = "http_put" FUNC_HTTP_PATCH = "http_patch" FUNC_HTTP_DELETE = "http_delete" FUNC_HTTP_HEAD = "http_head" FUNC_HTTP_OPTIONS = "http_options" FUNC_HTTP_TRACE = "http_trace" FUNC_HTTP_CONNECT = "http_connect" FUNC_ABS = "abs" FUNC_POW = "pow" FUNC_ERROR = "error" FUNC_GET_PATH = "get_path" FUNC_FIND_PATHS = "find_paths" FUNC_DELETE_PATH = "delete_path" FUNC_MKDIR = "mkdir" FUNC_BASE_NAME = "base_name" FUNC_DIR_NAME = "dir_name" FUNC_JOIN_PATHS = "join_paths" FUNC_GET_OS = "get_os" FUNC_FORMAT_EPOCH = "format_epoch" FUNC_COUNT = "count" FUNC_ZIP = "zip" FUNC_STR = "str" FUNC_INT = "int" FUNC_FLOAT = "float" FUNC_SUM = "sum" FUNC_TRIM = "trim" FUNC_TRIM_PREFIX = "trim_prefix" FUNC_TRIM_SUFFIX = "trim_suffix" FUNC_TRIM_LEFT = "trim_left" FUNC_TRIM_RIGHT = "trim_right" FUNC_READ_FILE = "read_file" FUNC_WRITE_FILE = "write_file" FUNC_READ_STDIN = "read_stdin" FUNC_HAS_STDIN = "has_stdin" FUNC_ROUND = "round" FUNC_CEIL = "ceil" FUNC_FLOOR = "floor" FUNC_MIN = "min" FUNC_MAX = "max" FUNC_MATCHES = "matches" FUNC_CLAMP = "clamp" FUNC_REVERSE = "reverse" FUNC_IS_DEFINED = "is_defined" // todo might be poorly named. should focus on vars. Or maybe just embrace works for anything, name it 'exists'? FUNC_HYPERLINK = "hyperlink" FUNC_UUID_V4 = "uuid_v4" FUNC_UUID_V7 = "uuid_v7" FUNC_GEN_FID = "gen_fid" FUNC_GET_RAD_HOME = "get_rad_home" FUNC_GET_STASH_PATH = "get_stash_path" FUNC_LOAD_STATE = "load_state" FUNC_SAVE_STATE = "save_state" FUNC_LOAD_STASH_FILE = "load_stash_file" FUNC_WRITE_STASH_FILE = "write_stash_file" FUNC_GET_ENV = "get_env" FUNC_GET_PID = "get_pid" FUNC_HASH = "hash" FUNC_ENCODE_BASE64 = "encode_base64" FUNC_DECODE_BASE64 = "decode_base64" FUNC_ENCODE_BASE16 = "encode_base16" FUNC_DECODE_BASE16 = "decode_base16" FUNC_MAP = "map" FUNC_FILTER = "filter" FUNC_FLAT_MAP = "flat_map" FUNC_LOAD = "load" FUNC_COLOR_RGB = "color_rgb" FUNC_COLORIZE = "colorize" FUNC_PARSE_DURATION = "parse_duration" FUNC_CONVERT_DURATION = "convert_duration" FUNC_GET_ARGS = "get_args" FUNC_SIGNAL_IGNORE = "signal_ignore" FUNC_SIGNAL_TRAP = "signal_trap" INTERNAL_FUNC_GET_STASH_ID = "_rad_get_stash_id" INTERNAL_FUNC_DELETE_STASH = "_rad_delete_stash" INTERNAL_FUNC_RUN_CHECK = "_rad_run_check" INTERNAL_FUNC_FMT = "_rad_fmt" INTERNAL_FUNC_CHECK_FROM_LOGS = "_rad_check_from_logs" INTERNAL_FUNC_EXPLAIN = "_rad_explain" INTERNAL_FUNC_EXPLAIN_LIST = "_rad_explain_list" INTERNAL_FUNC_DOCS_TOC = "_rad_docs_toc" INTERNAL_FUNC_DOCS_GET = "_rad_docs_get" INTERNAL_FUNC_DOCS_FULL = "_rad_docs_full" INTERNAL_FUNC_DOCS_URL = "_rad_docs_url" INTERNAL_FUNC_RENDER = "_rad_render" )
Note: when adding functions, update the docs! docs-web/docs/reference/functions.md
const DefaultDiagnosticLimit = 10
DefaultDiagnosticLimit is the default maximum number of diagnostics to collect.
const ENV_RAD_HOME = "RAD_HOME"
const (
Version = "v0.12.1"
)
Variables ¶
var ( MODES = []string{COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER} NO_CONSTRAINTS []string FlagHelp BoolRadArg FlagDebug BoolRadArg FlagRadDebug BoolRadArg FlagColor StringRadArg FlagQuiet BoolRadArg FlagShell BoolRadArg FlagVersion BoolRadArg FlagConfirmShellCommands BoolRadArg FlagSrc BoolRadArg FlagCstTree BoolRadArg FlagAstTree BoolRadArg FlagRadArgsDump BoolRadArg FlagMockResponse StringRadArg FlagTlsInsecure BoolRadArg FlagInteractive BoolRadArg FlagReply StringListRadArg FlagReplyNa StringListRadArg // GlobalFlagScopes is the single source of truth for global flag ordering // (as printed in usage) and scope. Rebuilt by CreateAndRegisterGlobalFlags. GlobalFlagScopes []ScopedGlobalFlag )
var ( RRootCmd *ra.Cmd RConfig *RadConfig RP Printer RIo RadIo RExit *RadExitHandler RForceExit func(int) // hard exit that skips defers; for double-Ctrl+C RReq *Requester RClock Clock RSleep func(ctx context.Context, duration time.Duration) RShell ShellExecutor RConfirm func(title string, prompt string) (bool, error) RSignal SignalSource RInteractive InteractiveDriver RTerminal TerminalSource // RReplies holds the answers supplied via --reply / --reply-na, bound to the // prompt sites they address. nil when the script has no prompts. RReplies *prompts.Replies RNG *rand.Rand HasScript bool ScriptPath string ScriptDir string ScriptName string IsTest bool // RawArgs is the caller's argv after the rad binary, as they typed it. A // stdin script has its `-` stripped from os.Args before the run proper, so // os.Args can't be used to reproduce the original invocation. RawArgs []string AlreadyExportedShellVars bool RTermWidth *int // nil = use real terminal width; non-nil overrides for tests RTermHeight *int // nil = use real terminal height; non-nil overrides for tests StartEpochMillis int64 )
var ATTR_STRINGS = make([]string, 0)
var COLOR_STRINGS = make([]string, 0)
var Cmds []EmbeddedCmd
var CmdsByName map[string]EmbeddedCmd
var EMPTY_STR = NewRadString("")
var ErrNoTerminal = errors.New("no terminal available")
ErrNoTerminal reports that no terminal is reachable: neither stdin nor the process's controlling terminal. This is the CI / cron / AI-agent case.
var FuncBaseName = BuiltInFunc{ Name: FUNC_BASE_NAME, Execute: func(f FuncInvocation) RadValue { path := f.GetStr("_path").Plain() return f.Return(NormalizePath(filepath.Base(path))) }, }
var FuncColorize = BuiltInFunc{ Name: FUNC_COLORIZE, Execute: func(f FuncInvocation) RadValue { strVal := ToPrintableQuoteStr(f.GetArg("_val"), false) enum := lo.Uniq(f.GetList("_enum").AsStringList(false)) skipIfSingle := f.GetBool("skip_if_single") if len(enum) == 0 { return f.ReturnErrf(rl.ErrEmptyList, "Possible values list cannot be empty, but was.") } if skipIfSingle && len(enum) == 1 { s := NewRadString(strVal) return f.Return(s) } sort.Strings(enum) if !lo.Contains(enum, strVal) { return f.ReturnErrf(rl.ErrColorizeValNotInEnum, "Value '%s' not found in the provided list of possible values: %s", strVal, enum) } r, g, b, err := GetEnumColor(strVal, enum) if err != nil { return f.ReturnErrf(rl.ErrEmptyList, "Failed to get color for value '%s': %s", strVal, err.Error()) } s := NewRadString(strVal) s.SetRgb(r, g, b) return f.Return(s) }, }
var FuncConvertDuration = BuiltInFunc{ Name: FUNC_CONVERT_DURATION, Execute: func(f FuncInvocation) RadValue { value := f.GetFloat("_value") unit := f.GetStr("_unit").Plain() var nanosFloat float64 switch unit { case "nanos": nanosFloat = value case "micros": nanosFloat = value * float64(time.Microsecond) case "millis": nanosFloat = value * float64(time.Millisecond) case "seconds": nanosFloat = value * float64(time.Second) case "minutes": nanosFloat = value * float64(time.Minute) case "hours": nanosFloat = value * float64(time.Hour) case "days": nanosFloat = value * 24 * float64(time.Hour) default: bugIncorrectTypes(FUNC_CONVERT_DURATION) panic(UNREACHABLE) } if math.IsNaN(nanosFloat) || math.IsInf(nanosFloat, 0) || math.Abs(nanosFloat) > float64(math.MaxInt64) { return f.ReturnErrf(rl.ErrNumInvalidRange, "Duration overflow: value too large for %s", unit) } return f.Return(NewDurationMap(int64(nanosFloat))) }, }
var FuncDebug = BuiltInFunc{ Name: FUNC_DEBUG, Execute: func(f FuncInvocation) RadValue { RP.ScriptDebug(resolvePrintStr(f)) return VOID_SENTINEL }, }
var FuncDirName = BuiltInFunc{ Name: FUNC_DIR_NAME, Execute: func(f FuncInvocation) RadValue { path := f.GetStr("_path").Plain() return f.Return(NormalizePath(filepath.Dir(path))) }, }
var FuncExit = BuiltInFunc{ Name: FUNC_EXIT, Execute: func(f FuncInvocation) RadValue { err := f.GetIntAllowingBool("_code") exit(f.i, err) return VOID_SENTINEL }, }
var FuncFormatEpoch = BuiltInFunc{ Name: FUNC_FORMAT_EPOCH, Execute: func(f FuncInvocation) RadValue { epoch := f.GetInt("_epoch") format := f.GetStr("_format").Plain() tz := f.GetStr("tz").Plain() unit := f.GetStr("unit").Plain() if format == "" { return f.ReturnErrf(rl.ErrCannotFormat, "Cannot format epoch with an empty format string") } isNegative := epoch < 0 absEpoch := epoch if isNegative { absEpoch = -absEpoch } second, nanoSecond, _, errVal := resolveEpochUnit(f, FUNC_FORMAT_EPOCH, absEpoch, unit) if errVal != nil { return *errVal } if isNegative { second = -second nanoSecond = -nanoSecond } location, errVal := resolveTimeLocation(f, tz) if errVal != nil { return *errVal } goTime := time.Unix(second, nanoSecond).In(location) return f.Return(goTime.Format(convertFormatToGoLayout(format))) }, }
var FuncInternalCheckFromLogs = BuiltInFunc{ Name: INTERNAL_FUNC_CHECK_FROM_LOGS, Execute: func(f FuncInvocation) RadValue { raw := strings.TrimSpace(f.GetStr("_duration").Plain()) d, err := ParseDuration(raw) if err != nil { return f.ReturnErrf(rl.ErrInvalidCheckDuration, "Invalid duration: %s", err.Error()) } if d < 0 { return f.ReturnErrf(rl.ErrInvalidCheckDuration, "Duration cannot be negative: %s", raw) } durationMillis := d.Milliseconds() verbose := f.GetBool("_verbose") strict := f.GetBool("_strict") scripts := parseInvocationLogs(f.i, f.callNode, durationMillis) sortScriptsByLastOccurrence(scripts) durationDesc := raw if durationMillis == 0 { durationDesc = "all time" } RP.Printf("Found %d scripts in invocation logs (checking within %s)...\n\n", len(scripts), durationDesc) chk, err := check.NewChecker() if err != nil { chk = nil RP.RadStderrf("Warning! Failed to init checker once, will init per file: %v\n", err) } if chk != nil { chk.SetStrict(strict) } results := make([]scriptResult, 0, len(scripts)) maxPathLen := 0 for i, script := range scripts { RP.RadDebugf("Checking script %d/%d: %s", i+1, len(scripts), script.Path) if !com.IsRegularFile(script.Path) { RP.RadDebugf(" skipped (not a regular file)") results = append(results, scriptResult{Path: script.Path, Skipped: true}) continue } checkStart := time.Now() counts, ok := checkScriptWith(script.Path, chk, strict) RP.RadDebugf(" checked in %s (ok=%t, errors=%d)", time.Since(checkStart), ok, counts.Errors) r := scriptResult{Path: script.Path, Counts: counts, Ok: ok} results = append(results, r) if len(script.Path) > maxPathLen { maxPathLen = len(script.Path) } } // Column headers and their widths type col struct { Header string Width int } cols := []col{ {"Errors", 6}, {"Warns", 5}, {"Info", 5}, {"Hints", 5}, } faint := color.New(color.Faint) green := color.New(color.FgGreen) red := color.New(color.FgRed) yellow := color.New(color.FgYellow) cyan := color.New(color.FgCyan) blue := color.New(color.FgBlue) colsWidth := 0 for _, c := range cols { colsWidth += 2 + c.Width } tableWidth := 4 + maxPathLen + colsWidth hasDataRows := false for _, r := range results { if !r.Skipped { hasDataRows = true break } } if hasDataRows { headerLine := fmt.Sprintf(" %-*s", maxPathLen, "") for _, c := range cols { headerLine += fmt.Sprintf(" %*s", c.Width, c.Header) } RP.Printf("%s\n", faint.Sprint(headerLine)) } totalChecked, passed, failed, skipped, loadErrors := 0, 0, 0, 0, 0 var totalCounts diagCounts for _, r := range results { if r.Skipped { skipped++ if verbose { RP.Printf(" %s\n", faint.Sprintf("- %s (not found or not a regular file)", r.Path)) } continue } totalChecked++ totalCounts.Errors += r.Counts.Errors totalCounts.Warnings += r.Counts.Warnings totalCounts.Infos += r.Counts.Infos totalCounts.Hints += r.Counts.Hints isFail := !r.Ok || r.Counts.Errors > 0 if isFail { failed++ } else { passed++ } if !r.Ok { loadErrors++ } // Status icon var icon string if isFail { icon = red.Sprint("✗") } else { icon = green.Sprint("✓") } line := fmt.Sprintf(" %s %-*s", icon, maxPathLen, r.Path) if r.Ok { line += formatCount(r.Counts.Errors, cols[0].Width, red, faint) line += formatCount(r.Counts.Warnings, cols[1].Width, yellow, faint) line += formatCount(r.Counts.Infos, cols[2].Width, cyan, faint) line += formatCount(r.Counts.Hints, cols[3].Width, blue, faint) } else { line += " " + faint.Sprint("(load error)") } RP.Printf("%s\n", line) } sepWidth := tableWidth if sepWidth < 40 { sepWidth = 40 } RP.Printf("\n%s\n", strings.Repeat("─", sepWidth)) bold := color.New(color.Bold) summary := fmt.Sprintf("Checked %d scripts: %s passed, %s failed", totalChecked, green.Sprintf("%d", passed), red.Sprintf("%d", failed)) // Append non-zero diagnostic/status details in a single parenthetical var detailParts []string if totalCounts.Errors > 0 { noun := "errors" if totalCounts.Errors == 1 { noun = "error" } detailParts = append(detailParts, red.Sprintf("%d %s", totalCounts.Errors, noun)) } if loadErrors > 0 { noun := "load errors" if loadErrors == 1 { noun = "load error" } detailParts = append(detailParts, faint.Sprintf("%d %s", loadErrors, noun)) } if totalCounts.Warnings > 0 { noun := "warnings" if totalCounts.Warnings == 1 { noun = "warning" } detailParts = append(detailParts, yellow.Sprintf("%d %s", totalCounts.Warnings, noun)) } if totalCounts.Infos > 0 { noun := "info diagnostics" if totalCounts.Infos == 1 { noun = "info diagnostic" } detailParts = append(detailParts, cyan.Sprintf("%d %s", totalCounts.Infos, noun)) } if totalCounts.Hints > 0 { noun := "hints" if totalCounts.Hints == 1 { noun = "hint" } detailParts = append(detailParts, blue.Sprintf("%d %s", totalCounts.Hints, noun)) } if skipped > 0 { detailParts = append(detailParts, faint.Sprintf("%d skipped", skipped)) } if len(detailParts) > 0 { summary += " (" + strings.Join(detailParts, ", ") + ")" } RP.Printf("%s.\n", bold.Sprint(summary)) if failed > 0 { RExit.Exit(1) } else { RExit.Exit(0) } return VOID_SENTINEL }, }
FuncInternalCheckFromLogs implements _rad_check_from_logs, which checks rad scripts from invocation logs for syntax/semantic errors. This is an internal function used by the rad CLI for bulk checking recently-used scripts.
var FuncJoinPaths = BuiltInFunc{ Name: FUNC_JOIN_PATHS, Execute: func(f FuncInvocation) RadValue { parts := f.GetList("_parts") strs := make([]string, 0, parts.LenInt()) for _, v := range parts.Values { strs = append(strs, v.RequireStr(f.i, f.callNode).Plain()) } return f.Return(NormalizePath(filepath.Join(strs...))) }, }
var FuncMatches = BuiltInFunc{ Name: FUNC_MATCHES, Execute: func(f FuncInvocation) RadValue { input := f.GetStr("_str").Plain() pattern := f.GetStr("_pattern").Plain() partial := f.GetBool("partial") re, err := regexp.Compile(pattern) if err != nil { return f.ReturnErrf(rl.ErrInvalidRegex, "Error compiling regex pattern: %s", err) } var matches bool if partial { matches = re.FindString(input) != "" } else { anchoredPattern := "^(?:" + pattern + ")$" anchoredRe, err := regexp.Compile(anchoredPattern) if err != nil { return f.ReturnErrf(rl.ErrInvalidRegex, "Error compiling regex pattern: %s", err) } matches = anchoredRe.MatchString(input) } return f.Return(matches) }, }
var FuncMkdir = BuiltInFunc{ Name: FUNC_MKDIR, Execute: func(f FuncInvocation) RadValue { path := com.ExpandTilde(f.GetStr("_path").Plain()) newResult := func(created bool) RadValue { resultMap := NewRadMap() resultMap.SetPrimitiveStr(constPath, NormalizePath(path)) resultMap.SetPrimitiveBool(constCreated, created) return f.Return(resultMap) } if stat, err := os.Stat(path); err == nil { if stat.IsDir() { return newResult(false) } return f.ReturnErrf(rl.ErrFileWrite, "Cannot create directory %q: path exists and is not a directory", NormalizePath(path)) } if err := os.MkdirAll(path, 0755); err != nil { if os.IsPermission(err) { return f.Return(NewErrorStr(err.Error()).SetCode(rl.ErrFileNoPermission)) } return f.Return(NewErrorStr(err.Error()).SetCode(rl.ErrFileWrite)) } return newResult(true) }, }
var FuncMultipick = BuiltInFunc{ Name: FUNC_MULTIPICK, Execute: func(f FuncInvocation) RadValue { options := f.GetList("_options").AsStringList(false) if len(options) == 0 { return f.Return(NewErrorStrf("Cannot multipick from empty options list")) } minArg := f.GetArg("min") maxArg := f.GetArg("max") promptArg := f.GetArg("prompt") min := int64(0) if !minArg.IsNull() { min = minArg.RequireInt(f.i, f.callNode) } if min < 0 { return f.Return(NewErrorStrf("min must be non-negative, got %d", min)) } // Get max value (optional) var max *int64 if !maxArg.IsNull() { maxVal := maxArg.RequireInt(f.i, f.callNode) max = &maxVal if maxVal <= 0 { return f.Return(NewErrorStrf("max must be positive, got %d", maxVal)) } if min > maxVal { return f.Return(NewErrorStrf("min (%d) cannot be greater than max (%d)", min, maxVal)) } } if min > int64(len(options)) { if min == 1 { return f.Return(NewErrorStrf("min is 1 but there are no options available")) } else { return f.Return(NewErrorStrf("min is %d but only %d options available", min, len(options))) } } // Generate smart default prompt if not provided var prompt string if promptArg.IsNull() { prompt = generateMultipickPrompt(min, max) } else { prompt = f.GetStr("prompt").Plain() } if answer, outcome := takeReply(f.callNode); outcome != prompts.NoReply { if outcome != prompts.Answered { return f.Return(unansweredPromptErr(f.callNode, outcome, fmt.Sprintf("The multipick %q", prompt))) } selected, radErr := multipickFromReply(answer.List, options, min, max, prompt) if radErr != nil { return f.Return(radErr) } return f.Return(selected) } model := radish.NewMultiSelect(). Title(prompt). Options(options...). Min(int(min)). Width(GetTermWidth()) if max != nil { model.Max(int(*max)) } res, _, err := RInteractive.Run(model) if err != nil { if errors.Is(err, radish.ErrNotInteractive) { return f.Return(unansweredPromptErr(f.callNode, prompts.NoReply, fmt.Sprintf("The multipick %q", prompt))) } return f.Return(NewErrorStrf("Error running multipick: %v", err)) } if res.Canceled { return f.Return(NewErrorStrf("multipick canceled")) } result := NewRadList() for _, item := range model.Selected() { result.Append(newRadValueStr(item)) } return f.Return(result) }, }
var FuncPPrint = BuiltInFunc{ Name: FUNC_PPRINT, Execute: func(f FuncInvocation) RadValue { item := f.GetArg("_item") jsonStruct := RadToJsonType(item) output := prettify(f.i, f.callNode, jsonStruct) RP.Print(output) return VOID_SENTINEL }, }
var FuncParseDate = BuiltInFunc{ Name: FUNC_PARSE_DATE, Execute: func(f FuncInvocation) RadValue { dateStr := f.GetStr("_date").Plain() formatArg := f.GetArg("format") tz := f.GetStr("tz").Plain() // Resolve output timezone var location *time.Location if tz == "local" { location = RClock.Local() } else { var err error location, err = time.LoadLocation(tz) if err != nil { return f.ReturnErrf(rl.ErrInvalidTimeZone, "Invalid time zone '%s'", tz) } } if dateStr == "" { return f.Return(NewErrorStr("Cannot parse an empty date string").SetCode(rl.ErrParseDate)) } var parsedTime time.Time if !formatArg.IsNull() { format := formatArg.RequireStr(f.i, f.callNode).Plain() if format == "" { return f.Return(NewErrorStr("Cannot parse date with an empty format string").SetCode(rl.ErrParseDate)) } goLayout := convertFormatToGoLayout(format) t, err := time.ParseInLocation(goLayout, dateStr, location) if err != nil { errMsg := fmt.Sprintf("Failed to parse date %q with format %q", dateStr, format) return f.Return(NewErrorStr(errMsg).SetCode(rl.ErrParseDate)) } parsedTime = t } else { // Auto-detect: try known unambiguous formats var parsed bool for _, af := range autoDetectFormats { if af.hasTz { t, err := time.Parse(af.layout, dateStr) if err == nil { parsedTime = t.In(location) parsed = true break } } else { t, err := time.ParseInLocation(af.layout, dateStr, location) if err == nil { parsedTime = t parsed = true break } } } if !parsed { errMsg := fmt.Sprintf( "Failed to parse date %q. Supported formats: YYYY-MM-DD, YYYY-MM-DDTHH:mm:ss, "+ "YYYY-MM-DD HH:mm:ss (with optional timezone offset and fractional seconds). "+ "Use 'format' to specify a custom format, e.g. parse_date(%q, format=\"DD/MM/YYYY\").", dateStr, dateStr, ) return f.Return(NewErrorStr(errMsg).SetCode(rl.ErrParseDate)) } } return f.Return(NewTimeMap(parsedTime)) }, }
var FuncParseDuration = BuiltInFunc{ Name: FUNC_PARSE_DURATION, Execute: func(f FuncInvocation) RadValue { durStr := f.GetStr("_duration").Plain() nanos, err := ParseDurationString(durStr) if err != nil { return f.ReturnErrf(rl.ErrParseDuration, "Failed to parse duration %q: %s", durStr, err) } return f.Return(NewDurationMap(nanos)) }, }
var FuncPick = BuiltInFunc{ Name: FUNC_PICK, Execute: func(f FuncInvocation) RadValue { options := f.GetList("_options").AsStringList(false) filterArg := f.GetArg("_filter") filters := make([]string, 0) if !filterArg.IsNull() { switch coerced := filterArg.Val.(type) { case RadString: filters = append(filters, coerced.Plain()) case *RadList: for _, item := range coerced.Values { filters = append(filters, item.RequireStr(f.i, f.callNode).Plain()) } default: bugIncorrectTypes(FUNC_PICK) } } keyGroups := lo.Map(options, func(key string, _ int) []string { return []string{key} }) prioExact := f.GetBool(namedArgPreferExact) str, err := pickKv(f, keyGroups, keyGroups, filters, prioExact) if err != nil { return f.Return(err) } return f.Return(str[0]) }, }
var FuncPickFromResource = BuiltInFunc{ Name: FUNC_PICK_FROM_RESOURCE, Execute: func(f FuncInvocation) RadValue { path := f.GetStr("path").Plain() filter := f.GetArg("_filter") resource, err := LoadPickResource(f.i, f.callNode, path) if err != nil { return f.Return(err) } var keyGroups [][]string var valueGroups [][]RadValue for _, opt := range resource.Opts { keyGroups = append(keyGroups, opt.Keys) valueGroups = append(valueGroups, opt.Values) } filters := make([]string, 0) if !filter.IsNull() { switch coerced := filter.Val.(type) { case RadString: filters = append(filters, coerced.Plain()) case *RadList: for _, item := range coerced.Values { filters = append(filters, item.RequireStr(f.i, f.callNode).Plain()) } default: bugIncorrectTypes(FUNC_PICK_KV) } } prioExact := f.GetBool(namedArgPreferExact) out, err := pickKv(f, keyGroups, valueGroups, filters, prioExact) if err != nil { return f.Return(err) } if len(out) == 1 { return newRadValues(f.i, f.callNode, out[0]) } else { return newRadValues(f.i, f.callNode, out) } }, }
var FuncPickKv = BuiltInFunc{ Name: FUNC_PICK_KV, Execute: func(f FuncInvocation) RadValue { keys := f.GetList("keys").AsStringList(false) values := f.GetList("values").Values filter := f.GetArg("_filter") filters := make([]string, 0) if !filter.IsNull() { switch coerced := filter.Val.(type) { case RadString: filters = append(filters, coerced.Plain()) case *RadList: for _, item := range coerced.Values { filters = append(filters, item.RequireStr(f.i, f.callNode).Plain()) } default: bugIncorrectTypes(FUNC_PICK_KV) } } keyGroups := lo.Map(keys, func(key string, _ int) []string { return []string{key} }) valueGroups := lo.Map(values, func(value RadValue, _ int) []RadValue { return []RadValue{value} }) prioExact := f.GetBool(namedArgPreferExact) out, err := pickKv(f, keyGroups, valueGroups, filters, prioExact) if err != nil { return f.Return(err) } return f.Return(out[0]) }, }
var FuncPrint = BuiltInFunc{ Name: FUNC_PRINT, Execute: func(f FuncInvocation) RadValue { RP.Print(resolvePrintStr(f)) return VOID_SENTINEL }, }
var FuncPrintErr = BuiltInFunc{ Name: FUNC_PRINT_ERR, Execute: func(f FuncInvocation) RadValue { RP.ScriptStderrf(resolvePrintStr(f)) return VOID_SENTINEL }, }
var FuncRand = BuiltInFunc{ Name: FUNC_RAND, Execute: func(f FuncInvocation) RadValue { return f.Return(RNG.Float64()) }, }
var FuncRandInt = BuiltInFunc{ Name: FUNC_RAND_INT, Execute: func(f FuncInvocation) RadValue { arg1 := f.GetInt("_arg1") arg2 := f.GetArg("_arg2") var min, max int64 if arg2.IsNull() { min = 0 max = arg1 } else { min = arg1 max = arg2.RequireInt(f.i, f.callNode) } if min >= max { return f.ReturnErrf(rl.ErrArgsContradict, "min (%d) must be less than max (%d).", min, max) } n := max - min return newRadValues(f.i, f.callNode, min+RNG.Int63n(n)) }, }
var FuncRange = BuiltInFunc{ Name: FUNC_RANGE, Execute: func(f FuncInvocation) RadValue { useFloats := false arg1 := f.GetArg("_arg1") arg2 := f.GetArg("_arg2") step := f.GetArg("_step") for _, arg := range []RadValue{arg1, arg2, step} { switch arg.Type() { case rl.RadFloatT: useFloats = true case rl.RadIntT, rl.RadNullT: default: bugIncorrectTypes(FUNC_RANGE) } } if useFloats { return runFloatRange(f, arg1, arg2, step) } else { return runIntRange(f, arg1, arg2, step) } }, }
var FuncReplace = BuiltInFunc{ Name: FUNC_REPLACE, Execute: func(f FuncInvocation) RadValue { original := f.GetStr("_original").Plain() find := f.GetStr("_find").Plain() replace := f.GetStr("_replace").Plain() if !f.GetBool("regex") { return f.Return(strings.ReplaceAll(original, find, replace)) } re, err := regexp.Compile(find) if err != nil { return f.ReturnErrf(rl.ErrInvalidRegex, "Error compiling regex pattern: %s", err) } return f.Return(replaceAllExpanding(re, original, replace)) }, }
var FuncSeedRandom = BuiltInFunc{ Name: FUNC_SEED_RANDOM, Execute: func(f FuncInvocation) RadValue { RNG = rand.New(rand.NewSource(f.GetInt("_seed"))) return VOID_SENTINEL }, }
var FuncSignalIgnore = BuiltInFunc{ Name: FUNC_SIGNAL_IGNORE, Execute: func(f FuncInvocation) RadValue { names, err := extractSignalNames(f, "_signal", FUNC_SIGNAL_IGNORE) if err != nil { return f.Return(err) } for _, name := range names { if ierr := f.i.signals.Ignore(name); ierr != nil { return f.Return(NewErrorStrf("%v", ierr).SetCode(rl.ErrGenericRuntime)) } } return VOID_SENTINEL }, }
FuncSignalIgnore installs OS-level SIG_IGN for one or more signals. Most useful for SIGPIPE: a script that pipes its output (e.g. `script | head`) will otherwise crash when the downstream consumer closes the pipe.
Distinct from `signal_trap(sig, fn(){})`: a no-op handler still wakes the process and runs Rad-side dispatch on every delivery, whereas SIG_IGN tells the kernel to drop the signal before it reaches us. For SIGPIPE in particular this also affects subprocess inheritance.
var FuncSignalTrap = BuiltInFunc{ Name: FUNC_SIGNAL_TRAP, Execute: func(f FuncInvocation) RadValue { names, err := extractSignalNames(f, "_signal", FUNC_SIGNAL_TRAP) if err != nil { return f.Return(err) } handler := f.GetFn("_handler") for _, name := range names { if terr := f.i.signals.Trap(name, handler); terr != nil { return f.Return(NewErrorStrf("%v", terr).SetCode(rl.ErrGenericRuntime)) } } return VOID_SENTINEL }, }
FuncSignalTrap registers a Rad function to run when one of the named signals is delivered to the process. The handler is invoked with a single argument: a map containing the signal name and the conventional exit code.
Replaces any previously-registered handler for the same signal. There is no current way to restore the platform default - once a signal is trapped, it stays trapped for the lifetime of the interpreter.
After the handler returns, execution always continues - the handler must explicitly call exit() if it wants to terminate. This matches Bash, Ruby, Python, and Node, which all converge on always-continue. The user pays a small ergonomic cost (every SIGINT handler needs `exit(ctx.exit_code)`) in exchange for a predictable single-rule mental model.
var FuncSleep = BuiltInFunc{ Name: FUNC_SLEEP, Execute: func(f FuncInvocation) RadValue { duration := f.GetArg("_duration") switch coerced := duration.Val.(type) { case int64: err := sleep(f.i, time.Duration(coerced)*time.Second, f.namedArgs) if err != nil { return f.Return(err) } return VOID_SENTINEL case float64: err := sleep(f.i, time.Duration(coerced*1000)*time.Millisecond, f.namedArgs) if err != nil { return f.Return(err) } return VOID_SENTINEL case RadString: durStr := coerced.Plain() floatVal, err := rts.ParseFloat(durStr) if err == nil { err := sleep(f.i, time.Duration(floatVal*1000)*time.Millisecond, f.namedArgs) if err != nil { return f.Return(err) } return VOID_SENTINEL } nanos, err := ParseDurationString(durStr) if err == nil { err := sleep(f.i, time.Duration(nanos), f.namedArgs) if err != nil { return f.Return(err) } return VOID_SENTINEL } return f.ReturnErrf(rl.ErrSleepStr, "Invalid string argument: %q", coerced.Plain()) default: bugIncorrectTypes(FUNC_SLEEP) panic(UNREACHABLE) } }, }
var FuncSplit = BuiltInFunc{ Name: FUNC_SPLIT, Execute: func(f FuncInvocation) RadValue { toSplit := f.GetStr("_val").Plain() splitter := f.GetStr("_sep").Plain() useRegex := f.GetBool("regex") limitArg := f.GetArg("limit") limit := -1 if !limitArg.IsNull() { limitVal := limitArg.RequireInt(f.i, f.callNode) if limitVal < 1 { return f.Return(NewErrorStrf("limit must be at least 1, got %d", limitVal).SetCode(rl.ErrNumInvalidRange)) } limit = int(limitVal) + 1 } var parts []string if useRegex { re, err := regexp.Compile(splitter) if err != nil { return f.ReturnErrf(rl.ErrInvalidRegex, "Error compiling regex pattern: %s", err) } parts = re.Split(toSplit, limit) } else if limit < 0 { parts = strings.Split(toSplit, splitter) } else { parts = strings.SplitN(toSplit, splitter, limit) } result := make([]RadValue, 0, len(parts)) for _, part := range parts { result = append(result, newRadValue(f.i, f.callNode, part)) } return f.Return(result) }, }
var FuncSplitLines = BuiltInFunc{ Name: FUNC_SPLIT_LINES, Execute: func(f FuncInvocation) RadValue { toSplit := f.GetStr("_val").Plain() return f.Return(splitLines(f.i, f.callNode, toSplit)) }, }
var FuncToJson = BuiltInFunc{ Name: FUNC_TO_JSON, Execute: func(f FuncInvocation) RadValue { indent := f.GetInt("indent") if indent < 0 { return f.ReturnErrf(rl.ErrNumInvalidRange, "Indent must be non-negative, got %d", indent) } jsonStruct := RadToJsonType(f.GetArg("_val")) buf := &bytes.Buffer{} enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) if indent > 0 { enc.SetIndent("", strings.Repeat(" ", int(indent))) } if err := enc.Encode(jsonStruct); err != nil { return f.ReturnErrf(rl.ErrInternalBug, "Failed to serialize to JSON: %v", err) } return f.Return(strings.TrimSuffix(buf.String(), "\n")) }, }
var FunctionsByName map[string]BuiltInFunc
var (
NO_NAMED_ARGS_INPUT = map[string]namedArg{}
)
var RAD_NULL = RadNull{}
var RAD_NULL_VAL = newRadValue(nil, nil, RAD_NULL)
var VOID_SENTINEL = RadValue{Val: 0x0}
used to internally delete things e.g. vars from env, but also empty returns. too much? subtle bugs?
var VoidBreak = NewEvalResult(VOID_SENTINEL, CtrlBreak)
var VoidContinue = NewEvalResult(VOID_SENTINEL, CtrlContinue)
var VoidNormal = NewEvalResult(VOID_SENTINEL, CtrlNormal)
Functions ¶
func AddInternalFuncs ¶
func AddInternalFuncs()
func BuildDocsFull ¶ added in v0.11.0
func BuildDocsFull() string
BuildDocsFull renders the bulk corpus: the TOC followed by the content of every page marked InAll, H1-wrapped and separated by horizontal rules. This mirrors llms-full.txt so `rad docs all` is the "load everything" mode agents reach for. Migration guides are listed in the TOC but left out of the dump - they teach syntax that no longer works.
func BuildDocsTOC ¶ added in v0.11.0
func BuildDocsTOC() string
BuildDocsTOC renders the topic index: sections, titles, the command to print each page, and an H2 preview. It's the `rad docs` (no-arg) listing and the header of `rad docs all`.
func CalculateCorrectedIndex ¶
CalculateCorrectedIndex 'corrects' negative indices into their positive equivalents
func DiagnosticProseWidth ¶ added in v0.12.0
func DiagnosticProseWidth() int
DiagnosticProseWidth reports the column budget for prose in error output. Anything hand-formatting an error message should wrap to this rather than picking its own width, so every error rad prints fits the same terminal.
func DocTopicSlug ¶ added in v0.12.1
DocTopicSlug reports the page slug a `rad docs` topic addresses, resolving the bare-section shorthand. Empty if the topic isn't a page.
func ErrIndexOutOfBounds ¶
func ErrIndexOutOfBounds(i *Interpreter, node rl.Node, idx int64, length int64)
func ExitCodeFor ¶ added in v0.11.0
ExitCodeFor returns the conventional exit code (128 + signal number) for the named signal. Returns 0 if the signal is not supported.
func FuzzyMatchFold ¶ added in v0.9.0
FuzzyMatchFold returns true if each character in source can be found in target in order, using case-insensitive matching. This is a simplified fuzzy search - not Levenshtein distance.
For example:
- FuzzyMatchFold("abc", "AbraCadabra") -> true (a...b...c found in order)
- FuzzyMatchFold("adc", "abcd") -> false (d comes before c in target)
func GetDocFuncs ¶ added in v0.11.0
func GetDocFuncs() []string
GetDocFuncs returns the names of every built-in with an embedded per-function doc page (i.e. every `rad docs <name>` that resolves).
func GetDocPage ¶ added in v0.11.0
GetDocPage returns the raw markdown for one page slug (e.g. "guide/basics"), or false if no such page is embedded.
func GetDocTopic ¶ added in v0.11.0
GetDocTopic resolves a `rad docs <topic>` argument to raw markdown. It's the single entry point, accepting (in precedence order) error codes, built-in function names, section names, and page slugs: `rad docs RAD10001` explains an error, `rad docs len` prints a function's doc, `rad docs migrations` prints a section's index, and `rad docs guide/basics` prints a page. Error codes are digits and slugs contain a "/", so the only namespace that can collide is function names against section names - gen-docs-embed rejects that at build time. Returns false if nothing matches.
func GetDocURL ¶ added in v0.12.1
GetDocURL maps a `rad docs` topic to its page on the documentation website, or false if the topic resolves to nothing. Mirrors GetDocTopic's precedence: error codes, then built-ins, then pages.
func GetEmbeddedCommandSrc ¶
func GetEnumColor ¶
GetEnumColor generates a visually distinct and appealing RGB color for a given value from a list. It returns R, G, B values (0-255) and an error if the value is not found.
func GetErrorDoc ¶ added in v0.9.0
GetErrorDoc returns the documentation for an error code, or empty string if not found. The code should be just the numeric part (e.g., "10001" not "RAD10001").
func GetFuncDoc ¶ added in v0.11.0
GetFuncDoc returns the per-function doc page for a built-in (e.g. "len"), or false if no such function is documented.
func GetInvocationLogPath ¶ added in v0.6.11
func GetInvocationLogPath() string
GetInvocationLogPath returns the path to the current invocation log file
func GetInvocationLogsDir ¶ added in v0.6.11
func GetInvocationLogsDir() string
GetInvocationLogsDir returns the directory containing invocation logs
func GetTermHeight ¶ added in v0.12.0
func GetTermHeight() int
GetTermHeight returns the terminal height to use for rendering. Unlike width, nothing truncates to it - it exists so an inline editor knows how many rows it can redraw over without scrolling its own top off the screen.
func GetTermWidth ¶ added in v0.10.0
func GetTermWidth() int
GetTermWidth returns the terminal width to use for rendering. This is the canonical way to obtain terminal width in production code - callers do not need to concern themselves with testing overrides. Tests can inject a fixed width via RunnerInput.RTermWidth.
func InputConfirm ¶
todo allow controlling 'yes' response?
func IsTerminatingSignal ¶ added in v0.11.0
IsTerminatingSignal reports whether the named signal's default action is to terminate the process. Used by the checkpoint when no handler is registered: terminating signals cause RExit.Exit(128+sig), non-terminating ones (only SIGWINCH today) are no-ops.
func IsWindows ¶ added in v0.7.1
func IsWindows() bool
IsWindows returns true if running on Windows.
func JsonToString ¶
func JsonToString(jsonVal interface{}) string
func Levenshtein ¶ added in v0.9.0
Levenshtein calculates the Levenshtein distance between two strings. Used for "did you mean?" suggestions.
func ListErrorCodes ¶ added in v0.9.0
func ListErrorCodes() []string
ListErrorCodes returns all documented error codes.
func LoadPickResource ¶
func LoadPickResource(i *Interpreter, callNode rl.Node, jsonPath string) (PickResource, *RadError)
func LogInvocation ¶ added in v0.6.11
func LogInvocation(entry InvocationLogEntry)
LogInvocation appends an invocation log entry to the JSONL log file Creates directory and file if they don't exist
func MaybeRotate ¶ added in v0.6.11
func MaybeRotate()
MaybeRotate checks if the current log file exceeds the size threshold and rotates it if necessary. Non-fatal: warns on errors but doesn't crash.
func NormalizeLineEndings ¶ added in v0.7.1
NormalizeLineEndings converts Windows-style line endings (\r\n) to Unix-style (\n). This ensures consistent text handling across platforms.
func NormalizePath ¶ added in v0.7.1
NormalizePath converts OS-specific path separators to forward slashes. This ensures Rad scripts are portable across platforms.
func ParseDuration ¶ added in v0.6.11
ParseDuration parses a human-readable duration string into time.Duration Supported formats:
- Simple: "30d", "2w", "24h", "1y"
- Combinations: "2w3d", "1y2w", "3d12h30m"
- Special: "all" returns 0 (no time filtering)
Units:
- y: years (365 days, ignores leap years)
- w: weeks (7 days)
- d: days (24 hours)
- h: hours
- m: minutes
- s: seconds
func ParseDurationString ¶ added in v0.9.0
ParseDurationString parses a human-readable duration string into nanoseconds. Extends Go's time.ParseDuration with support for "d" (days, where 1d = 24h) and "w" (weeks, where 1w = 7d). Spaces are stripped, and a leading "-" negates the whole duration.
func RadToJsonType ¶
func RadToJsonType(arg RadValue) interface{}
converts a Rad data structure to a JSON-schema-adhering structure.
func RegisterInvocationLogging ¶ added in v0.6.11
func RegisterInvocationLogging()
func RenderDiagnosticToString ¶ added in v0.12.0
func RenderDiagnosticToString(d Diagnostic) string
RenderDiagnosticToString renders d to a string, honoring the current color setting and terminal width. No trailing newline.
func ReplAutoIndent ¶ added in v0.12.0
ReplAutoIndent returns the leading whitespace for the line after buf: one level deeper following a block header, otherwise level with the line above.
func ReplNeedsMore ¶ added in v0.12.0
ReplNeedsMore reports whether a buffer is an unfinished Rad fragment that should keep accumulating.
Callers must supply their own terminator - a blank line - because the block rule below never releases on its own. That is deliberate: an indentation scoped language has no closing token, so "the user typed nothing" is the only signal available, and both input paths implement it.
func ReplTrimTrailingBlankLines ¶ added in v0.12.0
ReplTrimTrailingBlankLines drops the whitespace-only lines a submitted buffer carries - the blank line that closed a block, and any auto-indent left on it. Rad's parser would otherwise see a dangling indent and reject the whole thing.
func SetScriptPath ¶
func SetScriptPath(path string)
func TerminalAvailable ¶ added in v0.12.0
func TerminalAvailable() bool
TerminalAvailable reports whether an interactive prompt could reach a user.
func ToPrintable ¶
func ToPrintable(val interface{}) string
func ToPrintableQuoteStr ¶
func TransformRadArgs ¶
func TypeAsString ¶
func TypeAsString(val interface{}) string
Types ¶
type ArgLenConstraint ¶ added in v0.12.0
ArgLenConstraint bounds how many values a list or variadic arg takes, as opposed to what each value may be.
type ArgPrompter ¶ added in v0.11.0
type ArgPrompter interface {
Select(title string, options []string, summarize func(choice string) string) (string, error)
MultiSelect(title string, options, preselected []string, summarize func(chosen []string) string) ([]string, error)
Input(title, placeholder string, validate func(string) error, summarize func(value string) string) (string, error)
}
ArgPrompter abstracts the prompt shapes the --interactive walk needs, so the walk logic is unit-testable with a fake. The production implementation builds radish models and runs them through the RInteractive driver seam. Each prompt takes a summarize renderer producing the collapsed line left in the transcript after the prompt ends (compact flag-form, previewing the equivalent invocation); an empty result collapses to nothing.
type ArgRangeConstraint ¶
type BaseRadArg ¶
type BaseRadArg struct {
ExternalName string // User-facing arg they'll set in CLI
Identifier string // Identifier in script. If non-script arg, then equal to ExternalName
Short string
Description string
// contains filtered or unexported fields
}
func (*BaseRadArg) Configured ¶
func (f *BaseRadArg) Configured() bool
func (*BaseRadArg) DefaultAsString ¶
func (f *BaseRadArg) DefaultAsString() string
func (*BaseRadArg) Excludes ¶
func (f *BaseRadArg) Excludes(otherArg RadArg) bool
func (*BaseRadArg) GetDescription ¶
func (f *BaseRadArg) GetDescription() string
func (*BaseRadArg) GetExternalName ¶
func (f *BaseRadArg) GetExternalName() string
func (*BaseRadArg) GetIdentifier ¶
func (f *BaseRadArg) GetIdentifier() string
func (*BaseRadArg) GetShort ¶
func (f *BaseRadArg) GetShort() string
func (*BaseRadArg) GetSpan ¶ added in v0.9.0
func (f *BaseRadArg) GetSpan() *rl.Span
func (*BaseRadArg) HasNonZeroDefault ¶
func (f *BaseRadArg) HasNonZeroDefault() bool
func (*BaseRadArg) Hidden ¶
func (f *BaseRadArg) Hidden(hide bool)
func (*BaseRadArg) IsDefined ¶
func (f *BaseRadArg) IsDefined() bool
func (*BaseRadArg) IsHidden ¶
func (f *BaseRadArg) IsHidden() bool
func (*BaseRadArg) IsNullable ¶
func (f *BaseRadArg) IsNullable() bool
func (*BaseRadArg) IsOptional ¶
func (f *BaseRadArg) IsOptional() bool
func (*BaseRadArg) IsVariadic ¶ added in v0.6.0
func (f *BaseRadArg) IsVariadic() bool
func (*BaseRadArg) SetBypassValidation ¶ added in v0.5.59
func (f *BaseRadArg) SetBypassValidation(bypass bool)
func (*BaseRadArg) SetUsagePlaceholder ¶ added in v0.12.0
func (f *BaseRadArg) SetUsagePlaceholder(placeholder string)
SetUsagePlaceholder overrides the value placeholder shown in usage, e.g. "line:value" for --reply. Rad's own flags are the only callers: a script's args take ra's placeholder for their type, which is what keeps the type names in --help consistent across every arg rad registers.
func (*BaseRadArg) SetValue ¶
func (f *BaseRadArg) SetValue(_ string)
type BoolListRadArg ¶
type BoolListRadArg struct {
BaseRadArg
Value []bool
Default []bool
}
func NewBoolListRadArg ¶
func NewBoolListRadArg(name, short, description string, hasDefault bool, defaultValue []bool, requires, excludes []string, ) BoolListRadArg
func (*BoolListRadArg) GetType ¶
func (f *BoolListRadArg) GetType() RadArgTypeT
func (*BoolListRadArg) Register ¶
func (f *BoolListRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*BoolListRadArg) SetValue ¶
func (f *BoolListRadArg) SetValue(arg string)
type BoolRadArg ¶
type BoolRadArg struct {
BaseRadArg
Value bool
Default bool
}
func NewBoolRadArg ¶
func NewBoolRadArg(name, short, description string, hasDefault bool, defaultValue bool, requires, excludes []string, ) BoolRadArg
func (*BoolRadArg) GetType ¶
func (f *BoolRadArg) GetType() RadArgTypeT
func (*BoolRadArg) Register ¶
func (f *BoolRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*BoolRadArg) SetValue ¶
func (f *BoolRadArg) SetValue(arg string)
type BufferReader ¶
type BufferReader struct {
// contains filtered or unexported fields
}
func (*BufferReader) HasContent ¶
func (br *BufferReader) HasContent() bool
func (*BufferReader) SetPiped ¶ added in v0.6.10
func (br *BufferReader) SetPiped(piped bool)
func (*BufferReader) Unwrap ¶
func (br *BufferReader) Unwrap() io.Reader
type BuiltInFunc ¶
type BuiltInFunc struct {
Name string
Signature *rts.FnSignature
Execute func(FuncInvocation) RadValue
}
todo add 'usage' to each function? self-documenting errors when incorrectly using
type CallFrame ¶ added in v0.9.0
type CallFrame struct {
FunctionName string // Name of the function (or "<anonymous>" for lambdas)
CallSite *rl.Span // Where the function was called from
DefSite *rl.Span // Where the function is defined
}
CallFrame represents a function call in the Rad call stack. Used for providing stack traces in error messages.
type CheckableReader ¶
type CheckableReader interface {
Read(p []byte) (n int, err error)
HasContent() bool
Unwrap() io.Reader
}
func NewBufferReader ¶
func NewBufferReader(buffer *bytes.Buffer) CheckableReader
func NewFileReader ¶
func NewFileReader(file *os.File) CheckableReader
type ConstraintCtx ¶
func NewConstraintCtx ¶
func NewConstraintCtx(scriptArgs []RadArg) ConstraintCtx
type DeferBlock ¶
func NewDeferBlock ¶
type Diagnostic ¶ added in v0.9.0
type Diagnostic struct {
Severity Severity
Code rl.Error // From rts/rl/errors.go
Message string // One-line summary
Labels []Label // Primary + secondary spans
Hints []string // "= help: ..." lines
Source string // Complete source for rendering
CallStack []CallFrame // Rad call stack at time of error (most recent first)
}
Diagnostic represents a single diagnostic message with optional multi-span context.
func NewDiagnostic ¶ added in v0.9.0
func NewDiagnostic(severity Severity, code rl.Error, message string, source string, primarySpan rl.Span) Diagnostic
NewDiagnostic creates a diagnostic with a single primary label.
func NewDiagnosticFromCheck ¶ added in v0.9.0
func NewDiagnosticFromCheck(d check.Diagnostic, file string) Diagnostic
NewDiagnosticFromCheck converts a check.Diagnostic to a core.Diagnostic. The file parameter is used for the span's file path.
func NewDiagnosticWithLabels ¶ added in v0.9.0
func NewDiagnosticWithLabels(severity Severity, code rl.Error, message string, source string, labels []Label) Diagnostic
NewDiagnosticWithLabels creates a diagnostic with multiple labels.
func (Diagnostic) PrimarySpan ¶ added in v0.9.0
func (d Diagnostic) PrimarySpan() *rl.Span
PrimarySpan returns the first primary span, or nil if none exists.
func (Diagnostic) WithCallStack ¶ added in v0.9.0
func (d Diagnostic) WithCallStack(stack []CallFrame) Diagnostic
WithCallStack attaches a call stack to the diagnostic and returns the modified diagnostic.
func (Diagnostic) WithHint ¶ added in v0.9.0
func (d Diagnostic) WithHint(hint string) Diagnostic
WithHint adds a hint to the diagnostic and returns the modified diagnostic.
func (Diagnostic) WithHints ¶ added in v0.9.0
func (d Diagnostic) WithHints(hints ...string) Diagnostic
WithHints adds multiple hints to the diagnostic and returns the modified diagnostic.
func (Diagnostic) WithSecondaryLabel ¶ added in v0.9.0
func (d Diagnostic) WithSecondaryLabel(span rl.Span, message string) Diagnostic
WithSecondaryLabel adds a secondary label to the diagnostic and returns the modified diagnostic.
type DiagnosticCollector ¶ added in v0.9.0
type DiagnosticCollector struct {
// contains filtered or unexported fields
}
DiagnosticCollector accumulates diagnostics up to a configurable limit. Tree-sitter's error recovery can cause cascades where one real error spawns many, so limiting prevents wall-of-text noise while still showing patterns.
func NewDiagnosticCollector ¶ added in v0.9.0
func NewDiagnosticCollector() *DiagnosticCollector
NewDiagnosticCollector creates a collector with the default limit.
func NewDiagnosticCollectorWithLimit ¶ added in v0.9.0
func NewDiagnosticCollectorWithLimit(limit int) *DiagnosticCollector
NewDiagnosticCollectorWithLimit creates a collector with a custom limit.
func (*DiagnosticCollector) Add ¶ added in v0.9.0
func (c *DiagnosticCollector) Add(d Diagnostic) bool
Add adds a diagnostic to the collector. Returns false when the limit is reached, signaling that the caller should stop producing diagnostics.
func (*DiagnosticCollector) AtLimit ¶ added in v0.9.0
func (c *DiagnosticCollector) AtLimit() bool
AtLimit returns true if the collector has reached its limit.
func (*DiagnosticCollector) Count ¶ added in v0.9.0
func (c *DiagnosticCollector) Count() int
Count returns the number of diagnostics collected.
func (*DiagnosticCollector) Diagnostics ¶ added in v0.9.0
func (c *DiagnosticCollector) Diagnostics() []Diagnostic
Diagnostics returns all collected diagnostics.
func (*DiagnosticCollector) HasErrors ¶ added in v0.9.0
func (c *DiagnosticCollector) HasErrors() bool
HasErrors returns true if there are any error-severity diagnostics.
func (*DiagnosticCollector) IsEmpty ¶ added in v0.9.0
func (c *DiagnosticCollector) IsEmpty() bool
IsEmpty returns true if no diagnostics have been collected.
func (*DiagnosticCollector) Remaining ¶ added in v0.9.0
func (c *DiagnosticCollector) Remaining() int
Remaining returns how many more diagnostics were emitted beyond the limit.
func (*DiagnosticCollector) TotalEmitted ¶ added in v0.9.0
func (c *DiagnosticCollector) TotalEmitted() int
TotalEmitted returns the total number of diagnostics that were attempted to be added, including those beyond the limit.
type DiagnosticRenderer ¶ added in v0.9.0
type DiagnosticRenderer struct {
// contains filtered or unexported fields
}
DiagnosticRenderer renders diagnostics in Rust-style format, laid out to fit the terminal.
func NewDiagnosticRenderer ¶ added in v0.9.0
func NewDiagnosticRenderer(w io.Writer) *DiagnosticRenderer
NewDiagnosticRenderer creates a renderer that writes to the given writer, laid out for the current terminal.
func NewDiagnosticRendererWidth ¶ added in v0.12.0
func NewDiagnosticRendererWidth(w io.Writer, termWidth int) *DiagnosticRenderer
NewDiagnosticRendererWidth creates a renderer for an explicit terminal width.
func (*DiagnosticRenderer) Render ¶ added in v0.9.0
func (r *DiagnosticRenderer) Render(d Diagnostic)
Render renders a single diagnostic.
func (*DiagnosticRenderer) RenderAll ¶ added in v0.9.0
func (r *DiagnosticRenderer) RenderAll(c *DiagnosticCollector)
RenderAll renders all diagnostics in a collector and displays truncation message if needed.
type DocPage ¶ added in v0.11.0
type DocPage struct {
Slug string `json:"slug"`
Section string `json:"section"`
Title string `json:"title"`
H2s []string `json:"h2s"`
// InAll marks a page as part of `rad docs all`. Every embedded page
// is addressable by slug; only these join the bulk dump. Migration
// guides ship without it - see fullCorpusSections in
// tools/gen-docs-embed.
InAll bool `json:"in_all"`
}
DocPage is one entry in the embedded docs manifest.
func GetDocsManifest ¶ added in v0.11.0
func GetDocsManifest() []DocPage
GetDocsManifest returns the embedded doc pages in nav order.
type EmbeddedCmd ¶
type Env ¶
type Env struct {
Enclosing *Env
Vars map[string]RadValue
JsonFieldVars map[string]*JsonFieldVar // not pointer?
// contains filtered or unexported fields
}
func NewEnv ¶
func NewEnv(i *Interpreter) *Env
func (*Env) AllVarNames ¶ added in v0.9.0
AllVarNames returns all variable names visible from this environment.
func (*Env) FindSimilarVars ¶ added in v0.9.0
FindSimilarVars finds variable names similar to the given name. Returns at most maxResults names, sorted by similarity.
func (*Env) GetJsonFieldVar ¶
func (e *Env) GetJsonFieldVar(name string) (*JsonFieldVar, bool)
func (*Env) GetVarElseBug ¶
func (*Env) NewChildEnv ¶
func (*Env) PrintShellExports ¶
func (e *Env) PrintShellExports()
func (*Env) SetJsonFieldVar ¶
func (e *Env) SetJsonFieldVar(jsonFieldVar *JsonFieldVar)
type ErrorCtx ¶
type ErrorCtx struct {
CodeCtx
OneLiner string
Details string
Suggestion *string // Optional suggestion for fixing the error (rendered as "Try: ...")
}
TODO require RadError code? TODO perhaps include a map[node]string for multiple explanations for different parts of the code?
type EvalResult ¶
func NewEvalResult ¶
func NewEvalResult(val RadValue, ctrl CtrlKind) EvalResult
func NormalVal ¶
func NormalVal(val RadValue) EvalResult
func ReturnVal ¶
func ReturnVal(val RadValue) EvalResult
func YieldVal ¶
func YieldVal(val RadValue) EvalResult
type ExitReason ¶ added in v0.12.0
type ExitReason int
ExitReason says why execution is ending, which a REPL needs in order to decide what to do about it: an explicit exit() ends the session, a rendered error just returns you to the prompt.
const ( ExitExplicit ExitReason = iota // exit(), or the script simply finishing ExitError // a diagnostic has already been rendered ExitSignal // a terminating signal with no handler )
type ExpectedOutput ¶
type ExpectedOutput int
const ( Zero ExpectedOutput = iota One NoConstraint )
func (ExpectedOutput) Acceptable ¶
func (e ExpectedOutput) Acceptable(actual int) bool
func (ExpectedOutput) String ¶
func (e ExpectedOutput) String() string
type FakeSignalSource ¶ added in v0.11.0
type FakeSignalSource struct {
// contains filtered or unexported fields
}
FakeSignalSource is a test-only SignalSource that lets tests deliver signals deterministically rather than sending real OS signals.
Production code goes through realSignalSource (signals.go), which wraps os/signal. Tests inject a FakeSignalSource via RunnerInput.RSignal; calls to Notify record the subscription, and Fire delivers the named signal to every channel subscribed for it.
Lives in the production package (not _test.go) so test packages outside core/ can use it. Not part of the Rad public API.
func NewFakeSignalSource ¶ added in v0.11.0
func NewFakeSignalSource() *FakeSignalSource
func (*FakeSignalSource) Fire ¶ added in v0.11.0
func (f *FakeSignalSource) Fire(sig os.Signal)
Fire delivers sig to every channel currently subscribed to it.
Writes are non-blocking; if a channel's buffer is full the signal is dropped (mirrors how os/signal behaves under burst conditions). The SignalManager uses a 4-deep buffer so single-shot Fires are reliable.
Note: signal processing happens asynchronously on the SignalManager dispatch goroutine. Tests that need to observe the result should either (a) use a control flow that naturally synchronizes (e.g. assert defers ran after script exit), or (b) call FireAndWait below.
func (*FakeSignalSource) FiredCount ¶ added in v0.11.0
func (f *FakeSignalSource) FiredCount(sig os.Signal) int
FiredCount returns how many times sig has been fired since the source was created. Useful for assertions in tests.
func (*FakeSignalSource) Ignore ¶ added in v0.11.0
func (f *FakeSignalSource) Ignore(sigs ...os.Signal)
Ignore records the SIG_IGN request without touching the real process. Tests assert against WasIgnored to verify signal_ignore plumbs through to the OS seam (we can't deterministically test "process survives SIGPIPE" in-process).
func (*FakeSignalSource) Notify ¶ added in v0.11.0
func (f *FakeSignalSource) Notify(ch chan<- os.Signal, sigs ...os.Signal)
Notify records that ch wants to receive sigs. Mirrors signal.Notify, including its additive-but-idempotent semantics: subscribing the same channel+signal twice does NOT cause two deliveries on Fire. Without this dedup, Start() subscribes SIGINT then signal_trap("sigint", ...) subscribes it again, and a single Fire would deliver SIGINT twice - confusing the SignalManager's double-SIGINT detection.
func (*FakeSignalSource) Stop ¶ added in v0.11.0
func (f *FakeSignalSource) Stop(ch chan<- os.Signal)
Stop removes ch from all subscriptions.
func (*FakeSignalSource) WasIgnored ¶ added in v0.11.0
func (f *FakeSignalSource) WasIgnored(sig os.Signal) bool
WasIgnored reports whether sig was passed to Ignore since the source was created. Used by tests asserting signal_ignore behavior.
type FileReader ¶
type FileReader struct {
// contains filtered or unexported fields
}
func (*FileReader) HasContent ¶
func (fr *FileReader) HasContent() bool
func (*FileReader) Unwrap ¶
func (fr *FileReader) Unwrap() io.Reader
type FixedClock ¶
func (*FixedClock) Local ¶ added in v0.6.7
func (f *FixedClock) Local() *time.Location
func (*FixedClock) Now ¶
func (f *FixedClock) Now() time.Time
type FloatListRadArg ¶
type FloatListRadArg struct {
BaseRadArg
Value []float64
Default []float64
}
func NewFloatListRadArg ¶
func NewFloatListRadArg( name, short, description string, hasDefault bool, defaultValue []float64, requires, excludes []string, ) FloatListRadArg
func (*FloatListRadArg) GetType ¶
func (f *FloatListRadArg) GetType() RadArgTypeT
func (*FloatListRadArg) Register ¶
func (f *FloatListRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*FloatListRadArg) SetValue ¶
func (f *FloatListRadArg) SetValue(arg string)
type FloatRadArg ¶
type FloatRadArg struct {
BaseRadArg
Value float64
Default float64
RangeConstraint *ArgRangeConstraint
}
func NewFloatRadArg ¶
func NewFloatRadArg( name, short, description string, hasDefault bool, defaultValue float64, constraint *ArgRangeConstraint, requires, excludes []string, ) FloatRadArg
func (*FloatRadArg) GetType ¶
func (f *FloatRadArg) GetType() RadArgTypeT
func (*FloatRadArg) Register ¶
func (f *FloatRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*FloatRadArg) SetValue ¶
func (f *FloatRadArg) SetValue(arg string)
type FuncInvocation ¶
type FuncInvocation struct {
// contains filtered or unexported fields
}
func NewFnInvocation ¶
func NewFnInvocation( i *Interpreter, callNode rl.Node, funcName string, args []PosArg, namedArgs map[string]namedArg, isBuiltIn bool, ) FuncInvocation
func (FuncInvocation) GetArg ¶
func (f FuncInvocation) GetArg(name string) RadValue
func (FuncInvocation) GetBool ¶
func (f FuncInvocation) GetBool(name string) bool
func (FuncInvocation) GetFloat ¶
func (f FuncInvocation) GetFloat(name string) float64
func (FuncInvocation) GetFn ¶
func (f FuncInvocation) GetFn(name string) RadFn
func (FuncInvocation) GetInt ¶
func (f FuncInvocation) GetInt(name string) int64
func (FuncInvocation) GetIntAllowingBool ¶
func (f FuncInvocation) GetIntAllowingBool(name string) int64
func (FuncInvocation) GetList ¶
func (f FuncInvocation) GetList(name string) *RadList
func (FuncInvocation) GetMap ¶
func (f FuncInvocation) GetMap(name string) *RadMap
func (FuncInvocation) GetStr ¶
func (f FuncInvocation) GetStr(name string) RadString
func (FuncInvocation) Return ¶
func (f FuncInvocation) Return(vals ...interface{}) RadValue
func (FuncInvocation) ReturnErrf ¶
func (f FuncInvocation) ReturnErrf(code rl.Error, msg string, args ...interface{}) RadValue
type GeneralSort ¶
type GlobalFlagScope ¶ added in v0.11.0
type GlobalFlagScope int
GlobalFlagScope classifies which invocations a global flag applies to. Script-execution flags (e.g. --shell) and rad-level flags (e.g. --version) make no sense on embedded commands like `rad fmt`; those invocations reject them rather than silently changing behavior (issue #149).
const ( ScopeUniversal GlobalFlagScope = iota // any invocation, including embedded commands ScopeScriptOnly // configures Rad script execution ScopeRootOnly // rad itself, e.g. `rad --version` )
type HttpRequest ¶ added in v0.6.13
type HttpRequest struct {
RequestDef RequestDef
ResponseDef ResponseDef
}
type IntListRadArg ¶
type IntListRadArg struct {
BaseRadArg
Value []int64
Default []int64
}
func NewIntListRadArg ¶
func NewIntListRadArg( name, short, description string, hasDefault bool, defaultValue []int64, requires, excludes []string, ) IntListRadArg
func (*IntListRadArg) GetType ¶
func (f *IntListRadArg) GetType() RadArgTypeT
func (*IntListRadArg) Register ¶
func (f *IntListRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*IntListRadArg) SetValue ¶
func (f *IntListRadArg) SetValue(arg string)
type IntRadArg ¶
type IntRadArg struct {
BaseRadArg
Value int64
Default int64
RangeConstraint *ArgRangeConstraint
}
func NewIntRadArg ¶
func (*IntRadArg) GetType ¶
func (f *IntRadArg) GetType() RadArgTypeT
type InteractiveDriver ¶ added in v0.11.0
InteractiveDriver runs a radish prompt Model to completion. Production wraps the real terminal; tests inject a scripted driver (radish.ScriptDriver) so the real prompt logic and rendering run end-to-end without a TTY.
The no-TTY policy lives here, not in radish: the production driver resolves a terminal through RTerminal and reports radish.ErrNotInteractive when there isn't one. Callers map that to a clear, actionable error. A scripted driver never reports ErrNotInteractive, which is exactly why interactive prompts become testable.
type Interpreter ¶
type Interpreter struct {
// contains filtered or unexported fields
}
func NewInterpreter ¶
func NewInterpreter(input InterpreterInput) *Interpreter
func (*Interpreter) CallStack ¶ added in v0.9.0
func (i *Interpreter) CallStack() []CallFrame
CallStack returns a copy of the current call stack (most recent first).
func (*Interpreter) Checkpoint ¶ added in v0.11.0
func (i *Interpreter) Checkpoint()
Checkpoint is called by the interpreter between statements. If a signal is pending it dispatches according to the current policy:
If a Rad handler is registered for the signal, invoke it with a single map argument: { signal, exit_code }. After it returns, always continue execution (Bash/Python/Ruby/Node semantics). The handler must call exit() explicitly if it wants to terminate.
If no handler is registered and the signal is terminating, route through RExit.Exit(128+sig) so defer blocks run and the exit code reflects the signal.
If no handler and the signal is non-terminating (SIGWINCH), drop it.
Checkpoint runs on the main interpreter goroutine, so it can safely touch the interpreter env / call deferred blocks / invoke Rad handlers.
Drains the entire pending queue in FIFO order before returning. The dispatching guard ensures nested checkpoints (e.g. those inside runBlock while a handler body is executing) become no-ops, so handler invocations stay in queue order rather than interleaving depth-first.
func (*Interpreter) EvalReplTurn ¶ added in v0.12.0
func (i *Interpreter) EvalReplTurn(src string, root *rl.SourceFile, tree *rts.RadTree) (out RadValue, abort *RadAbort)
EvalReplTurn runs one turn's worth of source against the live session.
A turn is the REPL's unit of execution - its mini-script - so it goes through the same top-level path a real script does rather than walking statements itself. That is what gives it function hoisting (without which a named fn typed at the prompt never registers), a signal checkpoint between statements (without which Ctrl+C cannot interrupt anything), and deferred blocks.
It returns a non-nil abort when the turn ended early: an error already rendered, a signal, or an explicit exit(). The caller decides which of those ends the session.
func (*Interpreter) GetScriptName ¶ added in v0.9.0
func (i *Interpreter) GetScriptName() string
GetScriptName returns the name/path of the current script.
func (*Interpreter) GetSrc ¶
func (i *Interpreter) GetSrc() string
func (*Interpreter) GetSrcForSpan ¶ added in v0.9.0
func (i *Interpreter) GetSrcForSpan(span rl.Span) string
func (*Interpreter) InitArgs ¶
func (i *Interpreter) InitArgs(args []RadArg)
func (*Interpreter) InitBuiltIns ¶
func (i *Interpreter) InitBuiltIns()
func (*Interpreter) NewRadPanic ¶
func (i *Interpreter) NewRadPanic(node rl.Node, err RadValue) *RadPanic
func (*Interpreter) RegisterWithExit ¶
func (i *Interpreter) RegisterWithExit()
func (*Interpreter) Run ¶
func (i *Interpreter) Run()
func (*Interpreter) Signals ¶ added in v0.11.0
func (i *Interpreter) Signals() *SignalManager
Signals exposes the interpreter's SignalManager. Used by builtins (signal_trap, signal_ignore) and by blocking-op call sites that need the signal-cancellation context.
func (*Interpreter) WithTmpSrc ¶
func (i *Interpreter) WithTmpSrc(tmpSrc string, fn func())
todo this is somewhat hacky, not a fan. only use when you're extremely sure fn won't panic
type InterpreterInput ¶ added in v0.6.16
type InterpreterInput struct {
Src string
Tree *rts.RadTree
ScriptName string
InvokedCommand *ScriptCommand
}
type InvocationLogEntry ¶ added in v0.6.11
type InvocationLogEntry struct {
EpochMillis int64 `json:"epoch_millis"`
ScriptPath string `json:"script_path"`
Args []string `json:"args,omitempty"` // omitempty when include_args=false
RadVersion string `json:"rad_version"`
DurationMillis int64 `json:"duration_millis"`
}
InvocationLogEntry represents a single script execution log entry
type InvocationLoggingConfig ¶ added in v0.6.11
type InvocationType ¶ added in v0.5.59
type InvocationType int
const ( NoScript InvocationType = iota // help, version, no args ScriptFile // existing file StdinScript // "rad -" EmbeddedCommand // built-in commands )
type JsonFieldVar ¶
type JsonFieldVar struct {
Name string
Path JsonPath
Span *rl.Span // source location for error reporting
}
func NewJsonFieldVar ¶
func NewJsonFieldVar(i *Interpreter, name string, span rl.Span, segments []JsonPathSegment) *JsonFieldVar
NewJsonFieldVar creates a JsonFieldVar from explicit path segments.
func NewJsonFieldVarSimple ¶ added in v0.9.0
func NewJsonFieldVarSimple(name string, span rl.Span) *JsonFieldVar
NewJsonFieldVarSimple creates a JsonFieldVar with a simple single-segment path. Used by the AST-based rad block interpreter for plain field names.
type JsonPath ¶
type JsonPath struct {
Segments []JsonPathSegment
}
type JsonPathSegment ¶
type JsonPathSegment struct {
Identifier string
SegmentSpan rl.Span
IdxSegments []JsonPathSegmentIdx
}
type JsonPathSegmentIdx ¶
type Label ¶ added in v0.9.0
type Label struct {
Span rl.Span
Message string
Primary bool // true = ^^^^ (red), false = ---- (blue)
}
Label represents a labeled span in a diagnostic.
func NewPrimaryLabel ¶ added in v0.9.0
NewPrimaryLabel creates a primary label (shown with ^^^^ in red).
type MockResponse ¶
type MockResponseSlice ¶
type MockResponseSlice []MockResponse
func (*MockResponseSlice) Set ¶
func (m *MockResponseSlice) Set(value string) error
func (*MockResponseSlice) String ¶
func (m *MockResponseSlice) String() string
func (*MockResponseSlice) Type ¶
func (m *MockResponseSlice) Type() string
type NullWriter ¶
type NullWriter struct{}
type PickResource ¶
type PickResource struct {
Opts []PickResourceOpt
}
type PickResourceOpt ¶
type PickResourceOptionSerde ¶
type PickResourceOptionSerde struct {
Keys []string `json:"keys"`
Values []interface{} `json:"values"`
}
type PickResourceSerde ¶
type PickResourceSerde struct {
Options []PickResourceOptionSerde `json:"options"`
}
type Printer ¶
type Printer interface {
// For Rad writers to debug their scripts. They input their debug logs with debug(). Enabled with --debug.
ScriptDebug(msg string)
// For Rad (tool) developers to debug the Rad tool, not Rad scripts. Enabled with --rad-debug.
// Rad writers should generally not need to use this.
RadDebugf(format string, args ...interface{})
// For regular output to the script user (literal string, no format interpretation)
Print(msg string)
// For regular output to the script user (with format string)
Printf(format string, args ...interface{})
// For secondary output to the user from Rad, usually to give some feedback, for example querying a URL.
// Goes to stderr.
RadStderrf(format string, args ...interface{})
// Used to print messages from the Rad script to stderr.
ScriptStderrf(format string, args ...interface{})
// For output that will be evaluated by the shell, used by --SHELL.
PrintForShellEval(msg string)
// For errors related to running the Rad script, with no token available for context.
// Exits.
ErrorExit(msg string)
// Like ErrorExit but takes an error code.
ErrorExitCode(msg string, errorCode int)
// TODO
CtxErrorExit(ctx ErrorCtx)
// TODO
CtxErrorCodeExit(ctx ErrorCtx, errorCode int)
ErrorCodeExitf(errorCode int, msgFmt string, args ...interface{})
// For errors not related to the Rad script, but to rad itself and its usage (probably misuse or rad bugs).
// Exits.
RadErrorExit(msg string)
// Similar to RadErrorExit, but prints usage after errors, and before exiting.
UsageErrorExit(msg string)
// Returns the appropriate writer for regular/standard (non-error) output.
GetStdWriter() io.Writer
}
todo make global instance, rather than passing into everything For all output to the user, except perhaps pflag-handled help/parsing errors.
func NewPrinter ¶
func NewPrinter(runner *RadRunner, isShellMode bool, isQuiet bool, isScriptDebug bool, isRadDebug bool) Printer
isShellMode directs all regular output to stderr, to avoid interfering with shell evals
isQuiet suppresses all output except shell eval prints and rad usage errors, unless isDebug is true, in which case it will also print rl errors stdout, and all debug messages
isScriptDebug will enable script debug messages isRadDebug will enable rad debug messages, and include stack traces for errors
type RadAbort ¶ added in v0.12.0
type RadAbort struct {
Code int
Reason ExitReason
Signal string
}
RadAbort unwinds execution instead of ending the process. It is panicked by the exit handler when unwinding is enabled, and recovered by whoever owns the unit of execution - in practice, the REPL's per-turn boundary.
A panic rather than a return is what makes this safe to bolt onto an interpreter written for a one-shot process: only some of the ~50 error sites are followed by panic(UNREACHABLE), and the rest simply return, so an abort that returned would resume evaluation on state the error just invalidated.
type RadArg ¶
type RadArg interface {
GetExternalName() string
GetIdentifier() string
GetShort() string
GetDescription() string
DefaultAsString() string
HasNonZeroDefault() bool // todo
GetType() RadArgTypeT
Register(cmd *ra.Cmd, mode RegistrationMode)
Configured() bool // configured by the user in some way
IsDefined() bool // either configured or has a default
SetValue(value string)
IsOptional() bool
IsNullable() bool
GetSpan() *rl.Span // nil if not a script arg
Hidden(bool)
IsHidden() bool
Excludes(otherArg RadArg) bool
IsVariadic() bool
}
func CreateAndRegisterGlobalFlags ¶
func CreateAndRegisterGlobalFlags(invocationType InvocationType) []RadArg
func CreateFlag ¶
type RadArgTypeT ¶
type RadArgTypeT int
const ( ArgStringT RadArgTypeT = iota ArgIntT ArgFloatT ArgBoolT ArgStrListT ArgIntListT ArgFloatListT ArgBoolListT )
func ToRadArgTypeT ¶
func ToRadArgTypeT(str string) RadArgTypeT
type RadConfig ¶ added in v0.6.11
type RadConfig struct {
InvocationLogging *InvocationLoggingConfig `toml:"invocation_logging"`
}
func DefaultRadConfig ¶ added in v0.6.11
func DefaultRadConfig() *RadConfig
func LoadRadConfig ¶ added in v0.6.11
func LoadRadConfig() *RadConfig
LoadRadConfig loads the invocation logging configuration from ~/.rad/config.toml (configurable) Returns defaults if file doesn't exist or on parse errors (with warnings)
type RadError ¶
type RadError struct {
Span *rl.Span // source location where the error originated (nil if unknown)
Code rl.Error
// contains filtered or unexported fields
}
func NewErrorStr ¶ added in v0.11.0
NewErrorStr wraps a plain string (no format processing). Use this when the message is built upstream or comes from another error - it avoids the fmt.Sprintf pitfall where stray '%' characters in the message get treated as format directives. Use NewErrorStrf when you actually have format args.
func NewErrorStrf ¶
type RadExitHandler ¶ added in v0.6.11
type RadExitHandler struct {
// contains filtered or unexported fields
}
func NewExitHandler ¶ added in v0.6.11
func NewExitHandler(delegate func(int)) *RadExitHandler
func (*RadExitHandler) AddPreExitCallback ¶ added in v0.6.11
func (h *RadExitHandler) AddPreExitCallback(cb func())
func (*RadExitHandler) Exit ¶ added in v0.6.11
func (h *RadExitHandler) Exit(code int)
func (*RadExitHandler) ExitWith ¶ added in v0.12.0
func (h *RadExitHandler) ExitWith(code int, reason ExitReason, signal string)
ExitWith is Exit with the reason attached, for the callers that know it.
func (*RadExitHandler) ResetExiting ¶ added in v0.12.0
func (h *RadExitHandler) ResetExiting()
ResetExiting clears the one-shot latch so the next unit of execution starts fresh. Without it the first error in a session would leave every later exit short-circuiting past deferred statements and pre-exit callbacks.
func (*RadExitHandler) SetExecuteDeferredStmtsFunc ¶ added in v0.6.11
func (h *RadExitHandler) SetExecuteDeferredStmtsFunc(f func(code int))
func (*RadExitHandler) SetUnwinding ¶ added in v0.12.0
func (h *RadExitHandler) SetUnwinding(unwind bool)
SetUnwinding switches between ending the process and unwinding to whoever is hosting execution. Scripts leave it off; the REPL turns it on for the session.
type RadFn ¶
type RadFn struct {
BuiltInFunc *BuiltInFunc // if this represents a built-in function
// below for non-built-in functions
ReprSpan *rl.Span // representative span (can point at this for errors)
Typing *rl.TypingFnT
Stmts []rl.Node
IsBlock bool // if this is a block function or expr. Block functions can only return with a 'return' stmt.
Env *Env // for closures
}
func NewBuiltIn ¶
func NewBuiltIn(inFunc BuiltInFunc) RadFn
func NewFnFromAST ¶ added in v0.9.0
func NewFnFromAST(i *Interpreter, typing *rl.TypingFnT, body []rl.Node, isBlock bool, defSpan *rl.Span) RadFn
NewFnFromAST creates a RadFn from AST components (FnDef or Lambda).
func (RadFn) Execute ¶
func (fn RadFn) Execute(f FuncInvocation) (out RadValue)
func (RadFn) ParamCount ¶ added in v0.7.0
ParamCount returns the number of parameters this function accepts. Returns 0 if typing information is unavailable.
type RadHome ¶
var RadHomeInst *RadHome
func NewRadHome ¶
func (*RadHome) GetStashForId ¶
func (*RadHome) GetStashSub ¶
func (*RadHome) SetStashId ¶
type RadList ¶
type RadList struct {
Values []RadValue
}
RadList does not carry a declared element type. Type enforcement happens only at function call boundaries via TypingT.IsCompatibleWith - mutations like Append are unchecked. See docs/type_system.md.
func NewRadList ¶
func NewRadList() *RadList
func NewRadListFromGeneric ¶
func NewRadListFromGeneric[T any](i *Interpreter, node rl.Node, list []T) *RadList
func (*RadList) AsActualStringList ¶
func (l *RadList) AsActualStringList(i *Interpreter, node rl.Node) []string
requires contents to actually be strings
func (*RadList) AsStringList ¶
func (*RadList) ShallowCopy ¶ added in v0.7.0
ShallowCopy creates a shallow copy of the list (values are not deep copied)
func (*RadList) SortAccordingToIndices ¶
func (l *RadList) SortAccordingToIndices(i *Interpreter, node rl.Node, indices []int64)
type RadMap ¶
type RadMap struct {
// contains filtered or unexported fields
}
RadMap does not carry declared key/value types. Type enforcement happens only at function call boundaries via TypingT.IsCompatibleWith - mutations like Set are unchecked. See docs/type_system.md.
func NewDurationMap ¶ added in v0.9.0
NewDurationMap builds a RadMap from a nanosecond value, providing conversions to all common time units.
func NewTimeMap ¶
func (*RadMap) ContainsKey ¶
func (*RadMap) SetPrimitiveBool ¶
func (*RadMap) SetPrimitiveFloat ¶
func (*RadMap) SetPrimitiveInt ¶
func (*RadMap) SetPrimitiveInt64 ¶
func (*RadMap) SetPrimitiveList ¶
func (*RadMap) SetPrimitiveMap ¶
func (*RadMap) SetPrimitiveStr ¶
func (*RadMap) ShallowCopy ¶ added in v0.7.0
ShallowCopy creates a shallow copy of the map (keys and values are not deep copied)
type RadPanic ¶
type RadPanic struct {
ErrV RadValue
ShellResult *shellResult // For shell command errors, contains exit code/stdout/stderr
// RaiseSpan records where this panic was raised, when that differs from
// where the error was first constructed. An error that was caught, bound to
// a variable, and later returned through another call re-arms at a new
// site; reporting only its origin sends the reader to a line they already
// handled. nil means the two coincide - the ordinary first-raise case.
RaiseSpan *rl.Span
}
RadPanic vs emitError:
Use RadPanic (catchable) for recoverable runtime errors that user code can reasonably handle via ?? or catch:
- Missing map keys, index out of bounds
- Null indexing (null.x, null[0])
- Failed parsing (parse_int, parse_json)
- Shell command failures
Use emitError (hard exit) for unrecoverable programming errors:
- Indexing into non-indexable types (int, float, bool)
- Undefined variables
- Type mismatches in built-in operations
Rule of thumb: if the error stems from data (user input, missing keys, nullable values), use RadPanic. If it stems from a logic bug in the script, use emitError.
type RadRunner ¶
type RadRunner struct {
// contains filtered or unexported fields
}
func NewRadRunner ¶
func NewRadRunner(runnerInput RunnerInput) *RadRunner
type RadString ¶
type RadString struct {
Segments []radStringSegment
}
func NewRadString ¶
todo should these methods be returning *RadString?
func RenderMarkdownForTerminal ¶ added in v0.9.0
RenderMarkdownForTerminal converts markdown text to a styled RadString for terminal display. It's a simple line-by-line renderer designed for the well-structured error documentation format.
func (RadString) CopyAttrTo ¶
Copies only the attributes of the first segment. Maybe could change somehow?
func (*RadString) CopyWithAttr ¶
func (s *RadString) CopyWithAttr(attr RadTextAttr) RadString
func (*RadString) SetAttr ¶
func (s *RadString) SetAttr(attr RadTextAttr)
func (*RadString) SetSegmentsHyperlink ¶
func (*RadString) SubSlice ¶ added in v0.9.0
SubSlice returns a substring from startRune (inclusive) to endRune (exclusive), preserving per-segment attributes. Callers must ensure 0 <= startRune <= endRune.
func (*RadString) ToRuneList ¶
func (*RadString) TrimPrefix ¶
func (*RadString) TrimSuffix ¶
type RadTextAttr ¶
type RadTextAttr int
const ( PLAIN RadTextAttr = iota BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE ORANGE PINK BOLD DIM ITALIC STRIKETHROUGH UNDERLINE )
when adding color attrs, update: enum, attrEnumToStrings, ToTblColor, AddAttrTo. when adding style attrs (bold, dim, etc.), update: enum, attrEnumToStrings, AddAttrTo. Style attrs are not supported in rad block color modifiers (no ToTblColor mapping).
func AttrFromString ¶
func AttrFromString(i *Interpreter, node rl.Node, str string) RadTextAttr
func TryColorFromString ¶
func TryColorFromString(str string) (RadTextAttr, bool)
func (RadTextAttr) AddAttrTo ¶
func (a RadTextAttr) AddAttrTo(clr *color.Color)
func (RadTextAttr) Colorize ¶
func (a RadTextAttr) Colorize(str string) string
func (RadTextAttr) IsColor ¶ added in v0.10.0
func (a RadTextAttr) IsColor() bool
func (RadTextAttr) String ¶
func (a RadTextAttr) String() string
func (RadTextAttr) ToTblColor ¶
func (a RadTextAttr) ToTblColor() tblwriter.Color
type RadTypeVisitor ¶
type RadTypeVisitor struct {
// contains filtered or unexported fields
}
RadTypeVisitor is my best attempt at trying to work around the fact that Go doesn't have an exhaustive switch on sealed types/enums. This visitor is verbose, but should make it easy to update existing code when adding a new type to Rad.
func NewTypeVisitor ¶
func NewTypeVisitor(i *Interpreter, node rl.Node) *RadTypeVisitor
func NewTypeVisitorUnsafe ¶
func NewTypeVisitorUnsafe() *RadTypeVisitor
func (*RadTypeVisitor) ForBool ¶
func (v *RadTypeVisitor) ForBool(handler func(RadValue, bool)) *RadTypeVisitor
func (*RadTypeVisitor) ForDefault ¶
func (v *RadTypeVisitor) ForDefault(handler func(RadValue)) *RadTypeVisitor
func (*RadTypeVisitor) ForError ¶
func (v *RadTypeVisitor) ForError(handler func(RadValue, *RadError)) *RadTypeVisitor
func (*RadTypeVisitor) ForFloat ¶
func (v *RadTypeVisitor) ForFloat(handler func(RadValue, float64)) *RadTypeVisitor
func (*RadTypeVisitor) ForFn ¶
func (v *RadTypeVisitor) ForFn(handler func(RadValue, RadFn)) *RadTypeVisitor
func (*RadTypeVisitor) ForInt ¶
func (v *RadTypeVisitor) ForInt(handler func(RadValue, int64)) *RadTypeVisitor
func (*RadTypeVisitor) ForList ¶
func (v *RadTypeVisitor) ForList(handler func(RadValue, *RadList)) *RadTypeVisitor
func (*RadTypeVisitor) ForMap ¶
func (v *RadTypeVisitor) ForMap(handler func(RadValue, *RadMap)) *RadTypeVisitor
func (*RadTypeVisitor) ForNull ¶
func (v *RadTypeVisitor) ForNull(handler func(RadValue, RadNull)) *RadTypeVisitor
func (*RadTypeVisitor) ForString ¶
func (v *RadTypeVisitor) ForString(handler func(RadValue, RadString)) *RadTypeVisitor
func (*RadTypeVisitor) UnhandledTypeError ¶
func (v *RadTypeVisitor) UnhandledTypeError(val RadValue)
func (*RadTypeVisitor) Visit ¶
func (v *RadTypeVisitor) Visit(acceptor RadTypeVisitorAcceptor)
type RadTypeVisitorAcceptor ¶
type RadTypeVisitorAcceptor interface {
Accept(visitor *RadTypeVisitor)
}
type RadValue ¶
type RadValue struct {
// int64, float64, RadString, bool stored as values
// collections (lists, maps) stored as pointers
// lists are *RadList
// maps are *RadMap
// functions are RadFn
// nulls are RadNull
// errors are *RadError
Val interface{}
}
func ConvertToNativeTypes ¶
func ConvertToNativeTypes(i *Interpreter, node rl.Node, val interface{}) RadValue
it was originally implemented because we might capture JSON as a list of unhandled types, but now we should be able to capture json and convert it entirely to native Rad types up front
func ConvertValuesToNativeTypes ¶
func ConvertValuesToNativeTypes(i *Interpreter, node rl.Node, vals []interface{}) []RadValue
func TryConvertJsonToNativeTypes ¶
func TryConvertJsonToNativeTypes(i *Interpreter, node rl.Node, maybeJsonStr string) (RadValue, error)
Convert a json interface{} into native Rad types
func (RadValue) Accept ¶
func (v RadValue) Accept(visitor *RadTypeVisitor)
func (RadValue) GoMapKey ¶ added in v0.9.2
GoMapKey returns a plain string representation suitable for Go map keys (e.g. JSON serialization). Unlike Hash(), it has no type prefix. Note: since Go maps / JSON require string keys, maps with distinct Rad keys that share a string representation (e.g. int 1 and string "1") will collide in the Go map. This is an inherent limitation of the target format.
func (RadValue) ModifyByKey ¶ added in v0.9.0
func (RadValue) RequireBool ¶
func (v RadValue) RequireBool(i *Interpreter, node rl.Node) bool
func (RadValue) RequireError ¶
func (v RadValue) RequireError(i *Interpreter, node rl.Node) *RadError
func (RadValue) RequireFloatAllowingInt ¶
func (v RadValue) RequireFloatAllowingInt(i *Interpreter, node rl.Node) float64
func (RadValue) RequireInt ¶
func (v RadValue) RequireInt(i *Interpreter, node rl.Node) int64
func (RadValue) RequireIntAllowingBool ¶
func (v RadValue) RequireIntAllowingBool(i *Interpreter, node rl.Node) int64
func (RadValue) RequireList ¶
func (v RadValue) RequireList(i *Interpreter, node rl.Node) *RadList
func (RadValue) RequireMap ¶
func (v RadValue) RequireMap(i *Interpreter, node rl.Node) *RadMap
func (RadValue) RequireNonVoid ¶ added in v0.9.2
func (v RadValue) RequireNonVoid(i *Interpreter, node rl.Node) RadValue
RequireNonVoid emits ErrVoidValue if v is VOID_SENTINEL.
func (RadValue) RequireNotType ¶
func (RadValue) RequireStr ¶
func (v RadValue) RequireStr(i *Interpreter, node rl.Node) RadString
func (RadValue) RequireType ¶
func (RadValue) ToCompatSubject ¶
func (v RadValue) ToCompatSubject() (out rl.TypingCompatVal)
func (RadValue) TruthyFalsy ¶
func (RadValue) TryGetBool ¶
func (RadValue) TryGetError ¶
func (RadValue) TryGetFloatAllowingInt ¶
func (RadValue) TryGetList ¶
type RegistrationMode ¶ added in v0.6.16
type RegistrationMode int
RegistrationMode defines how an argument should be registered on a Ra command. These modes enforce the correct combination of positional capability and Ra global behavior.
const ( // AsScriptArg: Script args on root when NO commands exist // - Positional + flag capable (flagOnly=false) // - Not a Ra global (asRaGlobal=false) AsScriptArg RegistrationMode = iota // AsCommandArg: Command-specific args on a subcommand // - Positional + flag capable (flagOnly=false) // - Not a Ra global (asRaGlobal=false) AsCommandArg // AsScriptFlagOnly: Script args on subcommands when commands exist // - Flag-only (flagOnly=true) // - Not a Ra global (asRaGlobal=false) // - Script args are shared across commands but don't interfere with command positionals AsScriptFlagOnly // AsGlobalFlag: Rad's built-in global flags (--help, --version, --color, etc.) // - Flag-only (flagOnly=true) // - Ra global (asRaGlobal=true, inherits to all subcommands) AsGlobalFlag // every descendant. // - Flag-only (flagOnly=true) so they don't consume a sub-command's positional // - Ra global (asRaGlobal=true) so Ra cascades them, and their configured // state, to descendants - which is what lets the flag appear either side // of the sub-command on the path // // Riding Ra's globals is a means, not an end: Ra files globals under // "Global options" and hides them in short help, so a namespace's shared // args currently render in the wrong section of its own help. The fix is // upstream (render inherited flags as command args); once it lands, this // mode and AsScriptFlagOnly collapse into one - they are the same idea, // separated only because the root was never modeled as a tree node. AsSharedNamespaceArg )
type ReplSession ¶ added in v0.5.59
type ReplSession struct {
// contains filtered or unexported fields
}
ReplSession is one interactive session: a live interpreter, the parser and tree it reuses each turn, and the input history.
func NewReplSession ¶ added in v0.5.59
func NewReplSession() (*ReplSession, error)
NewReplSession wires up a session. The parser and tree are held for the whole session and reparsed in place each turn - building either per turn leaks C-heap memory, since tree-sitter trees are not garbage collected.
func (*ReplSession) Run ¶ added in v0.5.59
func (s *ReplSession) Run() error
Run is the read-eval-print loop.
func (*ReplSession) Shutdown ¶ added in v0.5.59
func (s *ReplSession) Shutdown() error
Shutdown releases the tree-sitter resources the session held open.
type RequestDef ¶
type RequestDef struct {
Method string
Url string
Headers map[string][]string
Body *string
Insecure bool
Quiet bool
}
func NewRequestDef ¶
func NewRequestDef(method, url string, headers map[string][]string, body *string) RequestDef
func (RequestDef) BodyReader ¶
func (r RequestDef) BodyReader() io.Reader
type Requester ¶
type Requester struct {
// contains filtered or unexported fields
}
func NewRequester ¶
func NewRequester() *Requester
func (*Requester) AddMockedResponse ¶
func (*Requester) ClearMockedResponses ¶ added in v0.6.18
func (r *Requester) ClearMockedResponses()
func (*Requester) IsInsecure ¶ added in v0.9.0
func (*Requester) Request ¶
func (r *Requester) Request(ctx context.Context, def RequestDef) ResponseDef
Request executes an HTTP request. ctx is the signal-cancellation context; if it fires (e.g. SIGINT), the in-flight request is aborted. Tests can pass context.Background() if signal handling is not relevant.
func (*Requester) RequestJson ¶
func (*Requester) SetCaptureCallback ¶ added in v0.6.13
func (r *Requester) SetCaptureCallback(cb func(HttpRequest))
func (*Requester) SetInsecure ¶ added in v0.9.0
type ResponseDef ¶
type ResponseDef struct {
Success bool // true if 2xx response, else false
StatusCode *int
Headers *map[string][]string
Body *string
Error *string // signifies error making request
DurationSeconds float64
}
todo we should add more e.g. reason, message
func NewResponseDef ¶
func (ResponseDef) ToRadMap ¶
func (r ResponseDef) ToRadMap(i *Interpreter, callNode rl.Node) *RadMap
type RunnerInput ¶
type RunnerInput struct {
RIo *RadIo
RExit *func(int)
// RForceExit is the raw hard-exit (no defers/callbacks), distinct from
// RExit which wraps into a RadExitHandler. Tests inject a record-only
// variant; see global RForceExit.
RForceExit *func(int)
RReq *Requester
RClock Clock
RSleep *func(ctx context.Context, duration time.Duration)
RShell *func(ctx context.Context, invocation ShellInvocation) (string, string, int)
RConfirm *func(title string, prompt string) (bool, error)
RSignal SignalSource
RadHome *string
RTermWidth *int
RTermHeight *int
// RInteractive overrides the interactive-prompt driver. nil uses the real
// terminal; tests inject a scripted driver. See InteractiveDriver.
RInteractive InteractiveDriver
// RTerminal overrides how rad decides a terminal is reachable. nil probes
// stdin then the controlling terminal; tests inject a fixed answer so
// availability doesn't depend on how `go test` was launched.
RTerminal TerminalSource
}
type ScopedGlobalFlag ¶ added in v0.11.0
type ScopedGlobalFlag struct {
Arg RadArg
Scope GlobalFlagScope
}
type ScriptArg ¶
type ScriptArg struct {
Name string // Internal (as written in script)
ExternalName string // External (hyphenated for CLI)
Span rl.Span
Src string // Full script source, for error context rendering
Short *string
Type RadArgTypeT
Description *string
IsNullable bool // aka is optional. e.g. 'string?' syntax
HasDefaultValue bool
IsVariadic bool // whether this is a variadic argument (*options str)
EnumConstraint *[]string
RegexConstraint *regexp.Regexp
RangeConstraint *ArgRangeConstraint
LenConstraint *ArgLenConstraint
RequiresConstraint []string
ExcludesConstraint []string
// first check the Type and HasDefaultValue, then get the value
DefaultString *string
DefaultStringList *[]string
DefaultInt *int64
DefaultIntList *[]int64
DefaultFloat *float64
DefaultFloatList *[]float64
DefaultBool *bool
DefaultBoolList *[]bool
}
func FromArgDecl ¶
func FromArgDecl( decl rl.ArgDecl, src string, enumConstraint *rl.ArgEnumConstraint, regexConstraint *rl.ArgRegexConstraint, rangeConstraint *rl.ArgRangeConstraint, lenConstraint *rl.ArgLenConstraint, requiresConstraint []string, excludesConstraint []string, ) *ScriptArg
type ScriptCommand ¶ added in v0.6.16
type ScriptCommand struct {
Name string // Internal (as written in script)
ExternalName string // External (hyphenated for CLI)
Description *string
Args []*ScriptArg // Command-specific arguments
HasCallback bool
IsLambdaCallback bool
CallbackName *string // For function reference callbacks
CallbackLambda *rl.Lambda // Eagerly converted AST lambda
SubCmds []*ScriptCommand
Parent *ScriptCommand // nil at the top level
// IsDefault marks the command its level runs when none is named.
IsDefault bool
}
ScriptCommand represents a command defined in a Rad script's command: block. A command is either a leaf (HasCallback, dispatches) or a namespace (SubCmds, routes); args declared on a namespace are shared with every descendant.
func FromCmdBlock ¶ added in v0.6.16
func FromCmdBlock(cmdBlock *rl.CmdBlock, src string) (*ScriptCommand, error)
func (*ScriptCommand) IsNamespace ¶ added in v0.12.0
func (c *ScriptCommand) IsNamespace() bool
IsNamespace reports whether this command routes to sub-commands rather than dispatching to a callback of its own.
type ScriptData ¶
type ScriptData struct {
ScriptName string
Args []*ScriptArg
Commands []*ScriptCommand
Description *string
Tree *rts.RadTree
// Ast and Resolved are the converted AST and its name resolution, both
// already computed during syntax validation. They're retained rather than
// recomputed because the interactive pre-flight walk needs to tell a real
// pick() call from one where a local shadows the builtin, and that answer
// lives in Resolved.Uses. Either may be nil when conversion failed.
Ast *rl.SourceFile
Resolved *check.Resolved
Src string
DisableGlobalOpts bool
DisableArgsBlock bool
HasArgsBlock bool
}
func ExtractMetadata ¶
func ExtractMetadata(src string) *ScriptData
func (*ScriptData) ValidateNoErrors ¶
func (sd *ScriptData) ValidateNoErrors()
type Severity ¶ added in v0.9.0
type Severity int
Severity indicates the severity level of a diagnostic.
type ShellExecutor ¶ added in v0.6.13
ShellExecutor is the function type for executing shell commands. Returns: (stdout, stderr, exitCode) - only returns captured output based on invocation.Capture* fields. The ctx is the interpreter's signal-cancellation context; the executor should wake up promptly when it's canceled (the subprocess shares Rad's process group, so it will have received the signal too).
type ShellInvocation ¶ added in v0.6.13
type ShellInvocation struct {
Command string
Argv []string
CaptureStdout bool
CaptureStderr bool
IsQuiet bool
// IsConfirm is informational: the confirmation prompt is handled in
// executeShellCmd before the executor runs, so executors don't act on it.
// Kept for callers/observability (e.g. test assertions).
IsConfirm bool
}
ShellInvocation captures the details of a shell command invocation.
Exactly one of Command or Argv is set, and they mean different things. Command is a shell *program*: it goes to `<shell> -c <string>` and the shell parses pipes, redirects and expansions out of it. Argv is a literal argument vector: it is exec'd directly with no shell in the path, so nothing in it can be reinterpreted as syntax.
func (ShellInvocation) Display ¶ added in v0.12.0
func (s ShellInvocation) Display() string
Display renders the invocation as a string a user could paste into their own shell. For the shell-string form that's the command verbatim; for the argv form we re-quote each element, since the argv never was shell text and has no faithful flat rendering. Used for the ⚡️ echo and the confirm prompt, never for execution.
func (ShellInvocation) IsArgv ¶ added in v0.12.0
func (s ShellInvocation) IsArgv() bool
IsArgv reports whether this invocation bypasses the shell.
type SignalManager ¶ added in v0.11.0
type SignalManager struct {
// contains filtered or unexported fields
}
SignalManager owns signal-handling state for an Interpreter.
It coordinates between the OS signal source (or a test fake) and the interpreter's per-statement checkpoint. The OS-facing side runs in a dedicated goroutine that drains signals from notifyCh and records them in pendingSig; the interpreter side reads pendingSig at safe points between statements and dispatches to the registered Rad handler.
Blocking operations (sleep, shell exec, HTTP) consult Ctx() so they can wake promptly when a signal arrives - otherwise the handler would not run until the blocking call returned on its own.
func NewSignalManager ¶ added in v0.11.0
func NewSignalManager() *SignalManager
NewSignalManager constructs an inactive SignalManager. The dispatch goroutine is started lazily by Start (called from Interpreter.Run).
func (*SignalManager) ClearInHandler ¶ added in v0.11.0
func (sm *SignalManager) ClearInHandler()
func (*SignalManager) Ctx ¶ added in v0.11.0
func (sm *SignalManager) Ctx() context.Context
Ctx returns the current signal-cancellation context. Blocking operations should pass this to select{} or http.NewRequestWithContext so they can wake up promptly when a signal arrives.
func (*SignalManager) DrainPending ¶ added in v0.11.0
func (sm *SignalManager) DrainPending() (string, bool)
DrainPending returns the next pending signal (if any) and removes it from the queue. Called by the interpreter's checkpoint between statements.
func (*SignalManager) Handler ¶ added in v0.11.0
func (sm *SignalManager) Handler(name string) (RadFn, bool)
Handler returns the registered handler for the named signal. The second return is false if no handler is registered.
func (*SignalManager) Ignore ¶ added in v0.11.0
func (sm *SignalManager) Ignore(name string) error
Ignore installs OS-level SIG_IGN for the named signal. Useful for SIGPIPE when the script pipes its output (e.g. `script | head`) and should not terminate when the downstream consumer closes the pipe.
func (*SignalManager) MarkInHandler ¶ added in v0.11.0
func (sm *SignalManager) MarkInHandler(name string)
MarkInHandler / ClearInHandler bracket handler execution for double-Ctrl+C detection.
func (*SignalManager) NotifyCh ¶ added in v0.11.0
func (sm *SignalManager) NotifyCh() chan<- os.Signal
NotifyCh returns the channel that subscribed signals are delivered to. Tests use this with FakeSignalSource to inject signals deterministically (write to this channel directly, then wait for DrainPending to observe the result). Not part of the public Rad API.
func (*SignalManager) RefreshCtx ¶ added in v0.11.0
func (sm *SignalManager) RefreshCtx()
RefreshCtx is called after a handler returns (or a default-terminate decision is made and forgone) so the next blocking op gets a fresh (non-canceled) context.
func (*SignalManager) Start ¶ added in v0.11.0
func (sm *SignalManager) Start()
Start launches the background dispatch goroutine and subscribes to the signals Rad handles by default (SIGINT, SIGTERM). Idempotent.
Other signals are subscribed lazily when the script calls signal_trap or signal_ignore. This keeps the default behavior minimal: Rad takes over SIGINT/SIGTERM so it can route them through RExit.Exit (and thereby run defer blocks); everything else inherits Go's default behavior until the script opts in.
func (*SignalManager) Stop ¶ added in v0.11.0
func (sm *SignalManager) Stop()
Stop tears down the dispatch goroutine and OS subscriptions. Safe to call multiple times. Called from Interpreter.Run's defer so embedded/test usage doesn't accumulate leaked goroutines across interpreter lifetimes.
func (*SignalManager) Trap ¶ added in v0.11.0
func (sm *SignalManager) Trap(name string, fn RadFn) error
Trap registers fn as the handler for the named signal (e.g. "sigint"). Replacing an existing handler is allowed; the previous handler is dropped. Returns an error if the signal name is not supported on the current platform.
type SignalSource ¶ added in v0.11.0
type SignalSource interface {
Notify(ch chan<- os.Signal, sigs ...os.Signal)
Stop(ch chan<- os.Signal)
Ignore(sigs ...os.Signal)
}
SignalSource is the seam between the SignalManager and the OS signal machinery. The production implementation wraps os/signal directly; tests inject a fake whose Fire method synchronously delivers a signal to the channel without involving the OS (so tests do not race against the real process signal queue).
type StringListRadArg ¶
type StringListRadArg struct {
BaseRadArg
Value []string
Default []string
}
func NewStringListRadArg ¶
func NewStringListRadArg( name, short, description string, hasDefault bool, defaultValue, requires, excludes []string, ) StringListRadArg
func (*StringListRadArg) GetType ¶
func (f *StringListRadArg) GetType() RadArgTypeT
func (*StringListRadArg) Register ¶
func (f *StringListRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*StringListRadArg) SetValue ¶
func (f *StringListRadArg) SetValue(arg string)
type StringRadArg ¶
type StringRadArg struct {
BaseRadArg
Value string
Default string
EnumConstraint *[]string
RegexConstraint *regexp.Regexp
}
func NewStringRadArg ¶
func (*StringRadArg) GetType ¶
func (f *StringRadArg) GetType() RadArgTypeT
func (*StringRadArg) Register ¶
func (f *StringRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)
func (*StringRadArg) SetValue ¶
func (f *StringRadArg) SetValue(arg string)
type TblWriter ¶
type TblWriter struct {
// contains filtered or unexported fields
}
TblWriter wraps go-tbl for Rad's table rendering, adding terminal-width-aware truncation and column coloring. Single-use: Render() mutates internal state (truncating cells/headers), so a fresh instance must be created for each table.
func NewTblWriter ¶
func NewTblWriter() *TblWriter
func (*TblWriter) SetColumnColoring ¶
func (*TblWriter) SetTranspose ¶ added in v0.10.0
type Terminal ¶ added in v0.12.0
Terminal is a resolved place to prompt: somewhere to read keystrokes from and somewhere to draw. Release it when the prompt finishes.
type TerminalSource ¶ added in v0.12.0
TerminalSource decides where interactive prompts talk to the user. It is the single authority on "can rad prompt at all" - both the production driver and the pre-flight guard ask it, so the two can never disagree.
Note com.IsTty is NOT this: it inspects stdout, which answers a different question and is only used for cosmetic rendering choices.
func NewFakeTerminalSource ¶ added in v0.12.0
func NewFakeTerminalSource(available bool) TerminalSource
NewFakeTerminalSource returns a TerminalSource that reports terminal availability without touching a real one.
type Trie ¶
type Trie struct {
// contains filtered or unexported fields
}
func CreateTrie ¶
func CreateTrie(i *Interpreter, radKeywordNode rl.Node, jsonFields []JsonFieldVar) *Trie
func (*Trie) Insert ¶
func (t *Trie) Insert(field JsonFieldVar)
func (*Trie) TraverseTrie ¶
func (t *Trie) TraverseTrie(data interface{})
Source Files
¶
- arg_types.go
- args.go
- args_helpers.go
- args_mock.go
- clock.go
- cmds.go
- command_types.go
- completion.go
- config.go
- consts.go
- defer.go
- diagnostic.go
- diagnostic_render.go
- docs.go
- env.go
- error_docs.go
- errors.go
- eval_ctx.go
- exit.go
- expr_ops.go
- flags_global.go
- func_colorize.go
- func_convert_duration.go
- func_exit.go
- func_format_epoch.go
- func_helpers.go
- func_matches.go
- func_mkdir.go
- func_multipick.go
- func_parse_date.go
- func_parse_duration.go
- func_paths.go
- func_pick.go
- func_print.go
- func_rand.go
- func_range.go
- func_replace.go
- func_signal_ignore.go
- func_signal_trap.go
- func_sleep.go
- func_split.go
- func_split_lines.go
- func_to_json.go
- funcs.go
- funcs_internal.go
- funcs_internal_check_from_logs.go
- funcs_stat_linux.go
- fuzzy.go
- global.go
- home_stash.go
- input.go
- interactive.go
- interactive_args.go
- interpreter.go
- io.go
- json_algo.go
- json_algo_trie.go
- json_path.go
- logging_invocation.go
- logging_rotation.go
- logging_rotation_unix.go
- markdown_render.go
- parsed_types.go
- platform.go
- preflight.go
- printer.go
- prompt_replies.go
- rad_block.go
- rad_duration.go
- rad_time.go
- repl.go
- repl_eval.go
- repl_meta.go
- repl_reader.go
- repl_scan.go
- repl_session.go
- requester.go
- resources.go
- runner.go
- runner_usage.go
- script_meta.go
- shell.go
- signals.go
- signals_unix.go
- slicing.go
- sorting.go
- tbl.go
- test_signals.go
- text_attr.go
- type_error.go
- type_fn.go
- type_list.go
- type_map.go
- type_null.go
- type_rad_value.go
- type_string.go
- type_visitor.go
- utils.go
- version.go