core

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2026 License: Apache-2.0 Imports: 44 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EmbCmdNew     = "new"
	EmbCmdDocs    = "docs"
	EmbCmdHome    = "home"
	EmbCmdGenId   = "gen-id"
	EmbCmdStash   = "stash"
	EmbCmdCheck   = "check"
	EmbCmdExplain = "explain"
)
View Source
const (
	UNREACHABLE                     = "Bug! This should be unreachable"
	NOT_IMPLEMENTED                 = "not implemented"
	NO_NUM_RETURN_VALUES_CONSTRAINT = -1
	USAGE_ALIGNMENT_CHAR            = "\x00"
	PADDING_CHAR                    = "\x00"
)
View Source
const (
	WILDCARD                    = "*"
	MACRO_STASH_ID              = "stash_id"
	MACRO_ENABLE_GLOBAL_OPTIONS = "enable_global_options"
	MACRO_ENABLE_ARGS_BLOCK     = "enable_args_block"
)
View Source
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_REPL          = "repl"
	FLAG_R             = "r"
	FLAG_TLS_INSECURE  = "tls-insecure"
)
View Source
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_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_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_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_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"

	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_CHECK_FROM_LOGS = "_rad_check_from_logs"
	INTERNAL_FUNC_EXPLAIN         = "_rad_explain"
	INTERNAL_FUNC_EXPLAIN_LIST    = "_rad_explain_list"
)

Note: when adding functions, update the docs! docs-web/docs/reference/functions.md

View Source
const DefaultDiagnosticLimit = 10

DefaultDiagnosticLimit is the default maximum number of diagnostics to collect.

View Source
const ENV_RAD_HOME = "RAD_HOME"
View Source
const (
	Version = "v0.9.0"
)

Variables

View Source
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
	FlagRepl                 BoolRadArg
	FlagTlsInsecure          BoolRadArg
)
View Source
var (
	RRootCmd                 *ra.Cmd
	RConfig                  *RadConfig
	RP                       Printer
	RIo                      RadIo
	RExit                    *RadExitHandler
	RReq                     *Requester
	RClock                   Clock
	RSleep                   func(duration time.Duration)
	RShell                   ShellExecutor
	RNG                      *rand.Rand
	HasScript                bool
	ScriptPath               string
	ScriptDir                string
	ScriptName               string
	IsTest                   bool
	AlreadyExportedShellVars bool

	StartEpochMillis int64
)
View Source
var ATTR_STRINGS = make([]string, 0)
View Source
var CmdsByName map[string]EmbeddedCmd
View Source
var EMPTY_STR = NewRadString("")
View Source
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)
	},
}
View Source
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)))
	},
}
View Source
var FuncDebug = BuiltInFunc{
	Name: FUNC_DEBUG,
	Execute: func(f FuncInvocation) RadValue {
		RP.ScriptDebug(resolvePrintStr(f))
		return VOID_SENTINEL
	},
}
View Source
var FuncExit = BuiltInFunc{
	Name: FUNC_EXIT,
	Execute: func(f FuncInvocation) RadValue {
		err := f.GetIntAllowingBool("_code")
		exit(f.i, err)
		return VOID_SENTINEL
	},
}
View Source
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")

		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)
		}

		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)
			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.

View Source
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)
	},
}
View Source
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 prompt == "" {

				prompt = " "
			}
		}

		opts := make([]huh.Option[string], len(options))
		for i, opt := range options {
			opts[i] = huh.NewOption(opt, opt)
		}

		multiSelect := huh.NewMultiSelect[string]().
			Title(prompt).
			Options(opts...).
			Validate(func(selected []string) error {
				count := int64(len(selected))

				if max != nil && min == *max {
					if count != min {
						if min == 1 {
							return fmt.Errorf("Must select exactly 1 option, but selected %d", count)
						} else {
							return fmt.Errorf("Must select exactly %d options, but selected %d", min, count)
						}
					}
					return nil
				}

				if count < min {
					if min == 1 {
						return fmt.Errorf("Must select at least 1 option, but only selected %d", count)
					} else {
						return fmt.Errorf("Must select at least %d options, but only selected %d", min, count)
					}
				}

				if max != nil && count > *max {
					if *max == 1 {
						return fmt.Errorf("Must select at most 1 option, but selected %d", count)
					} else {
						return fmt.Errorf("Must select at most %d options, but selected %d", *max, count)
					}
				}

				return nil
			})

		if max != nil {
			multiSelect = multiSelect.Limit(int(*max))
		}

		// Execute the selection
		var selected []string
		multiSelect = multiSelect.Value(&selected)

		if err := multiSelect.Run(); err != nil {
			return f.Return(NewErrorStrf("Error running multipick: %v", err))
		}

		result := NewRadList()
		for _, item := range selected {
			result.Append(newRadValueStr(item))
		}

		return f.Return(result)
	},
}
View Source
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
	},
}
View Source
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))
	},
}
View Source
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])
	},
}
View Source
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)
		}
	},
}
View Source
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])
	},
}
View Source
var FuncPrint = BuiltInFunc{
	Name: FUNC_PRINT,
	Execute: func(f FuncInvocation) RadValue {
		RP.Print(resolvePrintStr(f))
		return VOID_SENTINEL
	},
}
View Source
var FuncPrintErr = BuiltInFunc{
	Name: FUNC_PRINT_ERR,
	Execute: func(f FuncInvocation) RadValue {
		RP.ScriptStderrf(resolvePrintStr(f))
		return VOID_SENTINEL
	},
}
View Source
var FuncRand = BuiltInFunc{
	Name: FUNC_RAND,
	Execute: func(f FuncInvocation) RadValue {
		return f.Return(RNG.Float64())
	},
}
View Source
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))
	},
}
View Source
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)
		}
	},
}
View Source
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()

		re, err := regexp.Compile(find)
		if err != nil {
			return f.ReturnErrf(rl.ErrInvalidRegex, "Error compiling regex pattern: %s", err)
		}

		replacementFunc := func(match string) string {
			submatches := re.FindStringSubmatch(match)

			if len(submatches) == 0 {
				return match
			}

			result := replace
			for i, submatch := range submatches {
				placeholder := fmt.Sprintf("$%d", i)
				result = strings.ReplaceAll(result, placeholder, submatch)
			}

			return result
		}

		newString := re.ReplaceAllStringFunc(original, replacementFunc)

		return f.Return(newString)
	},
}

Allows capture group replacing, for example replace("Name: abc", "a(b)c", "$1o$1") will return "Name: bobby"

View Source
var FuncSeedRandom = BuiltInFunc{
	Name: FUNC_SEED_RANDOM,
	Execute: func(f FuncInvocation) RadValue {
		RNG = rand.New(rand.NewSource(f.GetInt("_seed")))
		return VOID_SENTINEL
	},
}
View Source
var FuncSleep = BuiltInFunc{
	Name: FUNC_SLEEP,
	Execute: func(f FuncInvocation) RadValue {
		duration := f.GetArg("_duration")
		switch coerced := duration.Val.(type) {
		case int64:
			err := sleep(time.Duration(coerced)*time.Second, f.namedArgs)
			if err != nil {
				return f.Return(err)
			}
			return VOID_SENTINEL
		case float64:
			err := sleep(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(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(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)
		}
	},
}
View Source
var FuncSplit = BuiltInFunc{
	Name: FUNC_SPLIT,
	Execute: func(f FuncInvocation) RadValue {
		toSplit := f.GetStr("_val").Plain()
		splitter := f.GetStr("_sep").Plain()

		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
		}

		return f.Return(regexSplit(f.i, f.callNode, toSplit, splitter, limit))
	},
}
View Source
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))
	},
}
View Source
var FunctionsByName map[string]BuiltInFunc
View Source
var (
	NO_NAMED_ARGS_INPUT = map[string]namedArg{}
)
View Source
var RAD_NULL = RadNull{}
View Source
var RAD_NULL_VAL = newRadValue(nil, nil, RAD_NULL)
View Source
var VOID_SENTINEL = RadValue{Val: 0x0}

used to internally delete things e.g. vars from env, but also empty returns. too much? subtle bugs?

Functions

func AbsFloat

func AbsFloat(x float64) float64

func AbsInt

func AbsInt(x int64) int64

func AddInternalFuncs

func AddInternalFuncs()

func CalculateCorrectedIndex

func CalculateCorrectedIndex(rawIdx, length int64, clamp bool) int64

CalculateCorrectedIndex 'corrects' negative indices into their positive equivalents

func ErrIndexOutOfBounds

func ErrIndexOutOfBounds(i *Interpreter, node rl.Node, idx int64, length int64)

func FuzzyMatchFold added in v0.9.0

func FuzzyMatchFold(source, target string) bool

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 GetEmbeddedCommandSrc

func GetEmbeddedCommandSrc(name string) *string

func GetEnumColor

func GetEnumColor(value string, possibleSortedValues []string) (r, g, b int, err error)

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

func GetErrorDoc(code string) string

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 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 InputConfirm

func InputConfirm(title string, prompt string) (bool, error)

todo allow controlling 'yes' response?

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

func Levenshtein(a, b string) int

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

func NormalizeLineEndings(s string) string

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

func NormalizePath(path string) string

NormalizePath converts OS-specific path separators to forward slashes. This ensures Rad scripts are portable across platforms.

func ParseDuration added in v0.6.11

func ParseDuration(s string) (time.Duration, error)

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

func ParseDurationString(s string) (int64, error)

ParseDurationString parses a human-readable duration string into nanoseconds. Extends Go's time.ParseDuration with support for "d" (days, where 1d = 24h). 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 ResetGlobals

func ResetGlobals()

primarily for tests

func RunRepl added in v0.5.59

func RunRepl() error

RunRepl is the main entry point for REPL mode

func SetScriptPath

func SetScriptPath(path string)

func ToPrintable

func ToPrintable(val interface{}) string

func ToPrintableQuoteStr

func ToPrintableQuoteStr(val interface{}, quoteStrings bool) string

func TransformRadArgs

func TransformRadArgs(args []RadArg, transformer func(RadArg) string) []string

func TypeAsString

func TypeAsString(val interface{}) string

Types

type ArgRangeConstraint

type ArgRangeConstraint struct {
	Min          *float64
	MinInclusive bool
	Max          *float64
	MaxInclusive bool
}

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
	ArgUsage     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) GetArgUsage

func (f *BaseRadArg) GetArgUsage() string

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) SetValue

func (f *BaseRadArg) SetValue(_ string)

type BoolListRadArg

type BoolListRadArg struct {
	BaseRadArg
	Value   []bool
	Default []bool
}

func NewBoolListRadArg

func NewBoolListRadArg(name,
	short,
	argUsage,
	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) Read

func (br *BufferReader) Read(p []byte) (n int, err error)

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 Capture

type Capture struct {
	// contains filtered or unexported fields
}

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 Clock

type Clock interface {
	Now() time.Time
	Local() *time.Location
}

func NewFixedClock

func NewFixedClock(year, month, day, hour, minute, second, nano int64, tz *time.Location) Clock

func NewRealClock

func NewRealClock() Clock

type CodeCtx

type CodeCtx struct {
	Src string // The whole source code script.
	// Human-friendly i.e. 1-indexed
	RowStart int
	RowEnd   int // inclusive
	ColStart int
	ColEnd   int // inclusive
}

type ColumnSort

type ColumnSort struct {
	ColName string
	Span    rl.Span
	Dir     SortDir
}

type ConstraintCtx

type ConstraintCtx struct {
	ScriptArgs map[string]RadArg // Identifier -> RadArg
}

func NewConstraintCtx

func NewConstraintCtx(scriptArgs []RadArg) ConstraintCtx

type CtrlKind

type CtrlKind int
const (
	CtrlNormal CtrlKind = iota
	CtrlBreak
	CtrlContinue
	CtrlReturn
	CtrlYield
)

type DefaultReplSession added in v0.5.59

type DefaultReplSession struct {
	// contains filtered or unexported fields
}

DefaultReplSession implements the ReplSession interface

func (*DefaultReplSession) ExecuteStatement added in v0.5.59

func (s *DefaultReplSession) ExecuteStatement(input string) (*ExecutionResult, error)

ExecuteStatement executes a single statement and returns the result

func (*DefaultReplSession) GetEnvironment added in v0.5.59

func (s *DefaultReplSession) GetEnvironment() *Env

GetEnvironment returns the current interpreter environment

func (*DefaultReplSession) Run added in v0.5.59

func (s *DefaultReplSession) Run() error

Run starts the main REPL loop

func (*DefaultReplSession) Shutdown added in v0.5.59

func (s *DefaultReplSession) Shutdown() error

Shutdown performs cleanup when REPL session ends

type DeferBlock

type DeferBlock struct {
	Span       rl.Span
	Body       []rl.Node
	IsErrDefer bool
}

func NewDeferBlock

func NewDeferBlock(span rl.Span, body []rl.Node, isErrDefer bool) *DeferBlock

type Delimiter

type Delimiter struct {
	Open string
}

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

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.

func NewDiagnosticRenderer added in v0.9.0

func NewDiagnosticRenderer(w io.Writer) *DiagnosticRenderer

NewDiagnosticRenderer creates a renderer that writes to the given writer.

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 EmbeddedCmd

type EmbeddedCmd struct {
	Name        string
	Src         string
	Description string
}

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

func (e *Env) AllVarNames() []string

AllVarNames returns all variable names visible from this environment.

func (*Env) FindSimilarVars added in v0.9.0

func (e *Env) FindSimilarVars(name string, maxResults int) []string

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) GetVar

func (e *Env) GetVar(name string) (RadValue, bool)

func (*Env) GetVarElseBug

func (e *Env) GetVarElseBug(i *Interpreter, node rl.Node, name string) RadValue

func (*Env) NewChildEnv

func (e *Env) NewChildEnv() Env

func (*Env) PrintShellExports

func (e *Env) PrintShellExports()

func (*Env) SetJsonFieldVar

func (e *Env) SetJsonFieldVar(jsonFieldVar *JsonFieldVar)

func (*Env) SetVar

func (e *Env) SetVar(name string, v RadValue)

func (*Env) SetVarUpdatingEnclosing

func (e *Env) SetVarUpdatingEnclosing(name string, v RadValue, updateEnclosing bool)

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?

func NewCtxFromSpan added in v0.9.0

func NewCtxFromSpan(src string, span rl.Span, oneLiner string, details string) ErrorCtx

type EvalResult

type EvalResult struct {
	Val  RadValue
	Ctrl CtrlKind
}

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 ExecutionResult added in v0.5.59

type ExecutionResult struct {
	Value       RadValue
	ShouldPrint bool
	Error       *RadError
}

ExecutionResult represents the result of executing a statement

func NewExecutionResult added in v0.5.59

func NewExecutionResult(value RadValue, shouldPrint bool, err *RadError) *ExecutionResult

NewExecutionResult creates a new execution result

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 FileReader

type FileReader struct {
	// contains filtered or unexported fields
}

func (*FileReader) HasContent

func (fr *FileReader) HasContent() bool

func (*FileReader) Read

func (fr *FileReader) Read(p []byte) (n int, err error)

func (*FileReader) Unwrap

func (fr *FileReader) Unwrap() io.Reader

type FixedClock

type FixedClock struct {
	NowTime time.Time
}

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,
	argUsage,
	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,
	argUsage,
	description string,
	hasDefault bool,
	defaultValue float64,
	constraint *ArgRangeConstraint,
	requires,
	excludes []string,
) FloatRadArg

func (*FloatRadArg) GetDescription

func (f *FloatRadArg) GetDescription() string

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 GeneralSort struct {
	Span rl.Span
	Dir  SortDir
}

type HttpRequest added in v0.6.13

type HttpRequest struct {
	RequestDef  RequestDef
	ResponseDef ResponseDef
}

type InputReader added in v0.5.59

type InputReader interface {
	ReadStatement() (string, error)
	SupportsMultiLine() bool
	SetPrompt(primary, continuation string)
	Shutdown() error
}

InputReader abstracts input handling (designed for future multi-line extension)

func NewSingleLineInputReader added in v0.5.59

func NewSingleLineInputReader() InputReader

NewSingleLineInputReader creates a new single-line input reader using RadIo

type IntListRadArg

type IntListRadArg struct {
	BaseRadArg
	Value   []int64
	Default []int64
}

func NewIntListRadArg

func NewIntListRadArg(
	name,
	short,
	argUsage,
	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 NewIntRadArg(
	name,
	short,
	argUsage,
	description string,
	hasDefault bool,
	defaultValue int64,
	rangeConstraint *ArgRangeConstraint,
	requires,
	excludes []string,
) IntRadArg

func (*IntRadArg) GetDescription

func (f *IntRadArg) GetDescription() string

func (*IntRadArg) GetType

func (f *IntRadArg) GetType() RadArgTypeT

func (*IntRadArg) Register

func (f *IntRadArg) Register(cmd *ra.Cmd, mode RegistrationMode)

func (*IntRadArg) SetValue

func (f *IntRadArg) SetValue(arg string)

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) EvaluateStatement added in v0.5.59

func (i *Interpreter) EvaluateStatement(input string) (RadValue, error)

EvaluateStatement evaluates a single statement string and returns the result This is designed for REPL use where individual statements are evaluated against a persistent interpreter environment

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) 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 InvocationLoggingConfig struct {
	Enabled        bool `toml:"enabled"`
	IncludeArgs    bool `toml:"include_args"`
	MaxSizeMB      int  `toml:"max_size_mb"` // make float64?
	KeepRolledLogs int  `toml:"keep_rolled_logs"`
}

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
	Repl                                  // interactive REPL mode
)

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 JsonPathSegmentIdx struct {
	Span rl.Span
	Idx  *RadValue // e.g. json.names[0]; nil = wildcard []
}

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

func NewPrimaryLabel(span rl.Span, message string) Label

NewPrimaryLabel creates a primary label (shown with ^^^^ in red).

func NewSecondaryLabel added in v0.9.0

func NewSecondaryLabel(span rl.Span, message string) Label

NewSecondaryLabel creates a secondary label (shown with ---- in blue).

type MockResponse

type MockResponse struct {
	Pattern  string
	FilePath string
}

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{}

func (NullWriter) Write

func (nw NullWriter) Write(p []byte) (int, error)

Write implements the io.Writer interface for NullWriter. It accepts data but does nothing with it, effectively discarding it.

type PickResource

type PickResource struct {
	Opts []PickResourceOpt
}

type PickResourceOpt

type PickResourceOpt struct {
	Keys   []string
	Values []RadValue
}

type PickResourceOptionSerde

type PickResourceOptionSerde struct {
	Keys   []string      `json:"keys"`
	Values []interface{} `json:"values"`
}

type PickResourceSerde

type PickResourceSerde struct {
	Options []PickResourceOptionSerde `json:"options"`
}

type PosArg

type PosArg struct {
	// contains filtered or unexported fields
}

func NewPosArg

func NewPosArg(node rl.Node, value RadValue) PosArg

func NewPosArgs

func NewPosArgs(args ...PosArg) []PosArg

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 RadArg

type RadArg interface {
	GetExternalName() string
	GetIdentifier() string
	GetShort() string
	GetArgUsage() 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() []RadArg

func CreateFlag

func CreateFlag(arg *ScriptArg) RadArg

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 NewError

func NewError(msg RadString) *RadError

func NewErrorStrf

func NewErrorStrf(msg string, args ...interface{}) *RadError

func (*RadError) Equals

func (e *RadError) Equals(other *RadError) bool

func (*RadError) Hash

func (e *RadError) Hash() string

func (*RadError) Msg

func (e *RadError) Msg() RadString

func (*RadError) SetCode

func (e *RadError) SetCode(code rl.Error) *RadError

func (*RadError) SetSpan added in v0.9.0

func (e *RadError) SetSpan(span *rl.Span) *RadError

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) SetExecuteDeferredStmtsFunc added in v0.6.11

func (h *RadExitHandler) SetExecuteDeferredStmtsFunc(f func(code int))

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) IsBuiltIn

func (fn RadFn) IsBuiltIn() bool

func (RadFn) Name

func (fn RadFn) Name() string

func (RadFn) ParamCount added in v0.7.0

func (fn RadFn) ParamCount() int

ParamCount returns the number of parameters this function accepts. Returns 0 if typing information is unavailable.

func (RadFn) ToString

func (fn RadFn) ToString() string

type RadHome

type RadHome struct {
	HomeDir string
	StashId *string
}
var RadHomeInst *RadHome

func NewRadHome

func NewRadHome(home string) *RadHome

func (*RadHome) GetStash

func (r *RadHome) GetStash() *string

func (*RadHome) GetStashForId

func (r *RadHome) GetStashForId(id string) string

func (*RadHome) GetStashSub

func (r *RadHome) GetStashSub(subPath string, node rl.Node) (string, *RadError)

func (*RadHome) LoadState

func (r *RadHome) LoadState(i *Interpreter, node rl.Node) (RadValue, bool, *RadError)

func (*RadHome) SaveState

func (r *RadHome) SaveState(i *Interpreter, node rl.Node, value RadValue) *RadError

func (*RadHome) SetStashId

func (r *RadHome) SetStashId(id string)

type RadIo

type RadIo struct {
	StdIn  CheckableReader
	StdOut io.Writer
	StdErr io.Writer
}

type RadList

type RadList struct {
	Values []RadValue
}

func NewRadList

func NewRadList() *RadList

func NewRadListFromGeneric

func NewRadListFromGeneric[T any](i *Interpreter, node rl.Node, list []T) *RadList

func (*RadList) Append

func (l *RadList) Append(value RadValue)

func (*RadList) AsActualStringList

func (l *RadList) AsActualStringList(i *Interpreter, node rl.Node) []string

requires contents to actually be strings

func (*RadList) AsStringList

func (l *RadList) AsStringList(quoteStrings bool) []string

func (*RadList) Contains

func (l *RadList) Contains(val RadValue) bool

func (*RadList) Equals

func (l *RadList) Equals(r *RadList) bool

func (*RadList) IndexAt

func (l *RadList) IndexAt(i *Interpreter, node rl.Node, idx int64) RadValue

IndexAt is intended for internal use

func (*RadList) IsEmpty

func (l *RadList) IsEmpty() bool

func (*RadList) Join

func (l *RadList) Join(sep string, prefix string, suffix string) RadString

func (*RadList) JoinWith

func (l *RadList) JoinWith(other *RadList) RadValue

func (*RadList) Len

func (l *RadList) Len() int64

func (*RadList) LenInt

func (l *RadList) LenInt() int

func (*RadList) RemoveIdx

func (l *RadList) RemoveIdx(i *Interpreter, node rl.Node, idx int)

func (*RadList) Reverse added in v0.8.0

func (l *RadList) Reverse() *RadList

func (*RadList) ShallowCopy added in v0.7.0

func (l *RadList) ShallowCopy() *RadList

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)

func (*RadList) ToGoList

func (l *RadList) ToGoList() []interface{}

func (*RadList) ToString

func (l *RadList) ToString() string

type RadMap

type RadMap struct {
	// contains filtered or unexported fields
}

func NewDurationMap added in v0.9.0

func NewDurationMap(nanos int64) *RadMap

NewDurationMap builds a RadMap from a nanosecond value, providing conversions to all common time units.

func NewRadMap

func NewRadMap() *RadMap

func NewTimeMap

func NewTimeMap(time time.Time) *RadMap

func (*RadMap) AsErrMsg

func (m *RadMap) AsErrMsg(i *Interpreter, node rl.Node) string

func (*RadMap) ContainsKey

func (m *RadMap) ContainsKey(key RadValue) bool

func (*RadMap) Delete

func (m *RadMap) Delete(key RadValue)

func (*RadMap) Equals

func (l *RadMap) Equals(right *RadMap) bool

func (*RadMap) Get

func (m *RadMap) Get(key RadValue) (RadValue, bool)

func (*RadMap) GetByKey added in v0.9.0

func (m *RadMap) GetByKey(i *Interpreter, node rl.Node, key RadValue) RadValue

func (*RadMap) Keys

func (m *RadMap) Keys() []RadValue

func (*RadMap) Len

func (m *RadMap) Len() int64

func (*RadMap) Range

func (m *RadMap) Range(fn func(key, value RadValue) bool)

fn should return false when it wants to stop. True to continue.

func (*RadMap) Set

func (m *RadMap) Set(key RadValue, value RadValue)

func (*RadMap) SetPrimitiveBool

func (m *RadMap) SetPrimitiveBool(key string, value bool)

func (*RadMap) SetPrimitiveFloat

func (m *RadMap) SetPrimitiveFloat(key string, value float64)

func (*RadMap) SetPrimitiveInt

func (m *RadMap) SetPrimitiveInt(key string, value int)

func (*RadMap) SetPrimitiveInt64

func (m *RadMap) SetPrimitiveInt64(key string, value int64)

func (*RadMap) SetPrimitiveList

func (m *RadMap) SetPrimitiveList(key string, value *RadList)

func (*RadMap) SetPrimitiveMap

func (m *RadMap) SetPrimitiveMap(key string, value *RadMap)

func (*RadMap) SetPrimitiveStr

func (m *RadMap) SetPrimitiveStr(key string, value string)

func (*RadMap) ShallowCopy added in v0.7.0

func (m *RadMap) ShallowCopy() *RadMap

ShallowCopy creates a shallow copy of the map (keys and values are not deep copied)

func (*RadMap) ToGoMap

func (m *RadMap) ToGoMap() map[string]interface{}

func (*RadMap) ToString

func (m *RadMap) ToString() string

func (*RadMap) Values

func (m *RadMap) Values() []RadValue

type RadNull

type RadNull struct{}

type RadPanic

type RadPanic struct {
	ErrV        RadValue
	ShellResult *shellResult // For shell command errors, contains exit code/stdout/stderr
}

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.

func (*RadPanic) Err

func (p *RadPanic) Err() *RadError

func (*RadPanic) Panic

func (p *RadPanic) Panic()

type RadRunner

type RadRunner struct {
	// contains filtered or unexported fields
}

func NewRadRunner

func NewRadRunner(runnerInput RunnerInput) *RadRunner

func (*RadRunner) Run

func (r *RadRunner) Run() error

func (*RadRunner) RunUsage

func (r *RadRunner) RunUsage(shortHelp, isErr bool)

type RadString

type RadString struct {
	Segments []radStringSegment
}

func InputText

func InputText(prompt, hint, default_ string, secret bool) (RadString, error)

func NewRadString

func NewRadString(str string) RadString

todo should these methods be returning *RadString?

func RenderMarkdownForTerminal added in v0.9.0

func RenderMarkdownForTerminal(markdown string) RadString

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) Compare

func (s *RadString) Compare(other RadString) int

func (RadString) Concat

func (s RadString) Concat(other RadString) RadString

func (RadString) ConcatStr

func (s RadString) ConcatStr(other string) RadString

func (RadString) CopyAttrTo

func (s RadString) CopyAttrTo(otherStr string) RadString

Copies only the attributes of the first segment. Maybe could change somehow?

func (*RadString) CopyWithAttr

func (s *RadString) CopyWithAttr(attr RadTextAttr) RadString

func (*RadString) DeepCopy

func (s *RadString) DeepCopy() RadString

func (RadString) Equals

func (s RadString) Equals(other RadString) bool
func (s *RadString) Hyperlink(link RadString) RadString

func (*RadString) IndexAt

func (s *RadString) IndexAt(idx int64) RadString

assumes idx is valid for this string

func (RadString) Len

func (s RadString) Len() int64

func (RadString) Lower

func (s RadString) Lower() RadString

func (RadString) Plain

func (s RadString) Plain() string

does not apply any attributes

func (RadString) Repeat

func (s RadString) Repeat(multiplier int64) RadString

func (*RadString) Reverse

func (s *RadString) Reverse() RadString

func (RadString) Runes added in v0.9.0

func (s RadString) Runes() []rune

func (*RadString) SetAttr

func (s *RadString) SetAttr(attr RadTextAttr)

func (RadString) SetRgb

func (s RadString) SetRgb(red int, green int, blue int)

func (RadString) SetRgb64

func (s RadString) SetRgb64(red int64, green int64, blue int64)
func (s *RadString) SetSegmentsHyperlink(link RadString)

func (RadString) String

func (s RadString) String() string

applies all the attributes

func (*RadString) SubSlice added in v0.9.0

func (s *RadString) SubSlice(startRune, endRune int64) RadString

SubSlice returns a substring from startRune (inclusive) to endRune (exclusive), preserving per-segment attributes. Callers must ensure 0 <= startRune <= endRune.

func (*RadString) ToRuneList

func (s *RadString) ToRuneList() *RadList

func (*RadString) Trim

func (s *RadString) Trim(chars string) RadString

func (*RadString) TrimLeft added in v0.9.0

func (s *RadString) TrimLeft(chars string) RadString

func (*RadString) TrimPrefix

func (s *RadString) TrimPrefix(prefix string) RadString

func (*RadString) TrimRight added in v0.9.0

func (s *RadString) TrimRight(chars string) RadString

func (*RadString) TrimSuffix

func (s *RadString) TrimSuffix(suffix string) RadString

func (RadString) Upper

func (s RadString) Upper() RadString

type RadTextAttr

type RadTextAttr int
const (
	PLAIN RadTextAttr = iota
	BLACK
	RED
	GREEN
	YELLOW
	BLUE
	MAGENTA
	CYAN
	WHITE
	ORANGE
	PINK

	BOLD
	ITALIC
	UNDERLINE
)

when adding attrs, add 1) here, 2) attrEnumToStrings, 3) ToTblColor, and 4) ToFatihAttr

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) 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) Equals

func (left RadValue) Equals(right RadValue) bool

func (RadValue) Hash

func (v RadValue) Hash() string

func (RadValue) Index

func (v RadValue) Index(i *Interpreter, node rl.Node, key RadValue) RadValue

func (RadValue) IsError

func (v RadValue) IsError() bool

func (RadValue) IsNull

func (v RadValue) IsNull() bool

func (RadValue) ModifyByKey added in v0.9.0

func (v RadValue) ModifyByKey(i *Interpreter, node rl.Node, key RadValue, rightValue RadValue)

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) RequireFn

func (v RadValue) RequireFn(i *Interpreter, node rl.Node) RadFn

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) RequireNotType

func (v RadValue) RequireNotType(
	i *Interpreter,
	node rl.Node,
	errPrefix string,
	disallowedTypes ...rl.RadType,
) RadValue

func (RadValue) RequireStr

func (v RadValue) RequireStr(i *Interpreter, node rl.Node) RadString

func (RadValue) RequireType

func (v RadValue) RequireType(i *Interpreter, node rl.Node, errPrefix string, allowedTypes ...rl.RadType) RadValue

func (RadValue) ToCompatSubject

func (v RadValue) ToCompatSubject() (out rl.TypingCompatVal)

func (RadValue) ToGoValue

func (v RadValue) ToGoValue() (out interface{})

func (RadValue) TruthyFalsy

func (v RadValue) TruthyFalsy() bool

func (RadValue) TryGetBool

func (v RadValue) TryGetBool() (bool, bool)

func (RadValue) TryGetError

func (v RadValue) TryGetError() (*RadError, bool)

func (RadValue) TryGetFloatAllowingInt

func (v RadValue) TryGetFloatAllowingInt() (float64, bool)

func (RadValue) TryGetFn

func (v RadValue) TryGetFn() (RadFn, bool)

func (RadValue) TryGetList

func (v RadValue) TryGetList() (*RadList, bool)

func (RadValue) TryGetMap

func (v RadValue) TryGetMap() (*RadMap, bool)

func (RadValue) TryGetStr

func (v RadValue) TryGetStr() (RadString, bool)

func (RadValue) Type

func (v RadValue) Type() rl.RadType

type ReadlineInputReader added in v0.5.59

type ReadlineInputReader struct {
}

Future: ReadlineInputReader for enhanced input with history This interface design allows us to swap in a readline-based implementation later

type RealClock

type RealClock struct {
}

func (*RealClock) Local added in v0.6.7

func (r *RealClock) Local() *time.Location

func (*RealClock) Now

func (r *RealClock) Now() time.Time

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
)

type ReplSession added in v0.5.59

type ReplSession interface {
	Run() error
	ExecuteStatement(input string) (*ExecutionResult, error)
	GetEnvironment() *Env
	Shutdown() error
}

ReplSession represents the main REPL session contract

func CreateReplSession added in v0.5.59

func CreateReplSession() (ReplSession, error)

CreateReplSession creates a new REPL session with default configuration

func NewReplSession added in v0.5.59

func NewReplSession(interpreter *Interpreter, inputReader InputReader) ReplSession

NewReplSession creates a new REPL session with the given interpreter and input reader

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 (r *Requester) AddMockedResponse(urlRegex string, jsonPath string)

func (*Requester) ClearMockedResponses added in v0.6.18

func (r *Requester) ClearMockedResponses()

func (*Requester) IsInsecure added in v0.9.0

func (r *Requester) IsInsecure() bool

func (*Requester) Request

func (r *Requester) Request(def RequestDef) ResponseDef

func (*Requester) RequestJson

func (r *Requester) RequestJson(url string, insecure bool, quiet bool) (interface{}, error)

func (*Requester) SetCaptureCallback added in v0.6.13

func (r *Requester) SetCaptureCallback(cb func(HttpRequest))

func (*Requester) SetInsecure added in v0.9.0

func (r *Requester) SetInsecure(insecure bool)

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 NewResponseDef(
	statusCode *int,
	headers *map[string][]string,
	body *string,
	error *string,
	durationSeconds float64,
) ResponseDef

func (ResponseDef) ToRadMap

func (r ResponseDef) ToRadMap(i *Interpreter, callNode rl.Node) *RadMap

type RunnerInput

type RunnerInput struct {
	RIo     *RadIo
	RExit   *func(int)
	RReq    *Requester
	RClock  Clock
	RSleep  *func(duration time.Duration)
	RShell  *func(invocation ShellInvocation) (string, string, int)
	RadHome *string
}

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
	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,
	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
	IsLambdaCallback bool
	CallbackName     *string    // For function reference callbacks
	CallbackLambda   *rl.Lambda // Eagerly converted AST lambda
}

ScriptCommand represents a command defined in a Rad script's command: block

func FromCmdBlock added in v0.6.16

func FromCmdBlock(cmdBlock *rl.CmdBlock, src string) (*ScriptCommand, error)

type ScriptData

type ScriptData struct {
	ScriptName        string
	Args              []*ScriptArg
	Commands          []*ScriptCommand
	Description       *string
	Tree              *rts.RadTree
	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.

const (
	SeverityError Severity = iota
	SeverityWarning
	SeverityNote
)

func (Severity) String added in v0.9.0

func (s Severity) String() string

type ShellExecutor added in v0.6.13

type ShellExecutor func(invocation ShellInvocation) (string, string, int)

ShellExecutor is the function type for executing shell commands Returns: (stdout, stderr, exitCode) - only returns captured output based on invocation.Capture* fields

type ShellInvocation added in v0.6.13

type ShellInvocation struct {
	Command       string
	CaptureStdout bool
	CaptureStderr bool
	IsQuiet       bool
	IsConfirm     bool
}

ShellInvocation captures the details of a shell command invocation

type SingleLineInputReader added in v0.5.59

type SingleLineInputReader struct {
	// contains filtered or unexported fields
}

SingleLineInputReader implements InputReader for single-line input (MVP) Uses RadIo abstractions for full testability

func (*SingleLineInputReader) ReadStatement added in v0.5.59

func (r *SingleLineInputReader) ReadStatement() (string, error)

ReadStatement reads a single line of input from the user

func (*SingleLineInputReader) SetPrompt added in v0.5.59

func (r *SingleLineInputReader) SetPrompt(primary, continuation string)

SetPrompt allows customizing the prompts

func (*SingleLineInputReader) Shutdown added in v0.5.59

func (r *SingleLineInputReader) Shutdown() error

Shutdown cleans up resources

func (*SingleLineInputReader) SupportsMultiLine added in v0.5.59

func (r *SingleLineInputReader) SupportsMultiLine() bool

SupportsMultiLine returns false for MVP (single-line only)

type SortDir

type SortDir int
const (
	Asc SortDir = iota
	Desc
)

type StringListRadArg

type StringListRadArg struct {
	BaseRadArg
	Value   []string
	Default []string
}

func NewStringListRadArg

func NewStringListRadArg(
	name,
	short,
	argUsage,
	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 NewStringRadArg(
	name,
	short,
	argUsage,
	description string,
	hasDefault bool,
	defaultValue string,
	enum *[]string,
	regex *regexp.Regexp,
	requires,
	excludes []string,
) StringRadArg

func (*StringRadArg) GetDescription

func (f *StringRadArg) GetDescription() string

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
}

func NewTblWriter

func NewTblWriter() *TblWriter

func (*TblWriter) Append

func (w *TblWriter) Append(row []RadString)

func (*TblWriter) Render

func (w *TblWriter) Render()

func (*TblWriter) SetColumnColoring

func (w *TblWriter) SetColumnColoring(colToMods map[string]*radFieldMods)

func (*TblWriter) SetHeader

func (w *TblWriter) SetHeader(headers []string)

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{})

type TrieNode

type TrieNode struct {
	// contains filtered or unexported fields
}

func NewNode

func NewNode(parent *TrieNode, key string, isListWildcard bool, idx *int64) *TrieNode

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL