{"id":20355896,"url":"https://github.com/hedzr/is","last_synced_at":"2026-04-01T17:57:16.768Z","repository":{"id":205908831,"uuid":"715380826","full_name":"hedzr/is","owner":"hedzr","description":"go lib to provide a set of minimal environ container and detectors","archived":false,"fork":false,"pushed_at":"2026-03-18T23:57:13.000Z","size":578,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-19T12:53:55.432Z","etag":null,"topics":["detector","go","golang","library"],"latest_commit_sha":null,"homepage":"https://docs.hedzr.com/en/docs/cmdr.v2/howto/using-is-detectors/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hedzr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-07T02:51:05.000Z","updated_at":"2026-03-18T23:57:12.000Z","dependencies_parsed_at":"2024-02-14T03:22:51.332Z","dependency_job_id":"58ab4131-a246-41f6-b320-9c3fa5d316c6","html_url":"https://github.com/hedzr/is","commit_stats":null,"previous_names":["hedzr/is"],"tags_count":84,"template":false,"template_full_name":null,"purl":"pkg:github/hedzr/is","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Fis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Fis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Fis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Fis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hedzr","download_url":"https://codeload.github.com/hedzr/is/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Fis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290712,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["detector","go","golang","library"],"created_at":"2024-11-14T23:14:25.554Z","updated_at":"2026-04-01T17:57:16.750Z","avatar_url":"https://github.com/hedzr.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# is\n\n[![Go](https://github.com/hedzr/is/actions/workflows/go.yml/badge.svg)](https://github.com/hedzr/is/actions/workflows/go.yml)\n![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/hedzr/is)\n[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/hedzr/is.svg?label=release)](https://github.com/hedzr/is/releases)\n[![go.dev](https://img.shields.io/badge/go-dev-green)](https://pkg.go.dev/github.com/hedzr/is)\n[![deps.dev](https://img.shields.io/badge/deps-dev-green)](https://deps.dev/go/github.com%2Fhedzr%2Fis)\n\n`is` provides numerous detectors for checking the states of environment (build, executive, ...).\n\n## Features\n\n- `is.State(which) bool`: the universal detector entry - via `RegisterStateGetter(state string, getter func() bool)` to add your own ones. *Since v0.5.11*\n- `is.Env()` holds a global struct for CLI app basic states, such as: verbose/quiet/debug/trace....\n  - `DebugMode`/`DebugLevel`, `TraceMode`/`TraceLevel`, `ColorMode`, ...\n- `is.InDebugging() bool`, `is.InTesting() bool`, and `is.InTracing() bool`, ....\n- `is.DebugBuild() bool`.\n- `is.K8sBuild() bool`, `is.DockerBuild() bool`, ....\n- `is.ColoredTty() bool`, ....\n- `is.Color()` to get an indexer for the functions in our term/color subpackage, ...\n- Terminal Colorizer, Detector, unescape tools.\n  - `is/term/color.Color` interface\n- stringtool: `RandomStringPure`, case-converters ...\n- basics: closable, closer, signals.\n  - easier `Press any key to exit...` prompt: `is.Signals().Catch()`\n- exec: Run, RunWithOutput, Sudo, ...\n- ~~go1.23.7+ required since v0.7.0~~\n- ~~go 1.25.0+ required~~\n- go1.24.5 required since v0.8.55\n- go1.25.0 required since v0.9.0\n\nSee the above badge to get the exact required go toolchain version.\n\nTo using environment detecting utilities better and smoother, some terminal (and stringtool, basics) tools are bundled together.\n\nSince v0.6.0, `is.InDebugging()` checks if the running process' parent is `dlv`.\nThe old `DebugMode` and `DebugBuild` are still work:\n\n- `InDebugging`: checks this process is being debugged by `dlv`.\n- `DebugBuild`: `-tags=delve` is set at building.\n- `DebugMode`: `--debug` is specified at command line.\n\nSince v0.8.27, `basics.Signals().Catcher().WaitFor()` wants `ctx` param passed in.\n\n## Usages\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log/slog\"\n    \"os\"\n    \"sync\"\n    \"time\"\n\n    \"github.com/hedzr/is\"\n    \"github.com/hedzr/is/basics\"\n    \"github.com/hedzr/is/term/color\"\n)\n\nfunc main() {\n    // defer basics.Close() // uncomment if not using Catcher.WaitFor and/or cmdr.v2\n\n    is.RegisterStateGetter(\"custom\", func() bool { return is.InVscodeTerminal() })\n\n    println(is.InTesting())\n    println(is.State(\"in-testing\"))\n    println(is.State(\"custom\")) // detects a state with custom detector\n    println(is.Env().GetDebugLevel())\n    if is.InDebugMode() {\n        slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{AddSource: true, Level: slog.LevelDebug})))\n    }\n\n    // or:\n    //    is.Color().GetColorTranslator().Translate(\"\u003cb\u003ebold\u003c/b\u003e\")\n    fmt.Printf(\"%v\", color.GetCPT().Translate(`\u003ccode\u003ecode\u003c/code\u003e | \u003ckbd\u003eCTRL\u003c/kbd\u003e\n        \u003cb\u003ebold / strong / em\u003c/b\u003e\n        \u003ci\u003eitalic / cite\u003c/i\u003e\n        \u003cu\u003eunderline\u003c/u\u003e\n        \u003cmark\u003einverse mark\u003c/mark\u003e\n        \u003cdel\u003estrike / del \u003c/del\u003e\n        \u003cfont color=\"green\"\u003egreen text\u003c/font\u003e\n`, color.FgDefault))\n\n    var cancelled int32\n    ctx, cancel := context.WithCancel(context.Background())\n    defer cancel()\n\n    catcher := is.Signals().Catch()\n    catcher.\n        WithPrompt(\"Press CTRL-C to quit...\").\n        // WithOnLoopFunc(dbStarter, cacheStarter, mqStarter).\n        WithPeripherals(\u0026dbMgr{}).\n        WithOnSignalCaught(func(ctx context.Context, sig os.Signal, wg *sync.WaitGroup) {\n            println()\n            slog.Info(\"signal caught\", \"sig\", sig)\n            cancel() // cancel user's loop, see Wait(...)\n        }).\n        WaitFor(ctx, func(ctx context.Context, closer func()) {\n            slog.Debug(\"entering looper's loop...\")\n            defer close() // notify catcher we want to shutdown\n            // to terminate this app after a while automatically:\n            time.Sleep(10 * time.Second)\n\n            if atomic.CompareAndSwapInt32(\u0026cancelled, 0, 1) {\n                is.PressAnyKeyToContinue(os.Stdin)\n            }\n        })\n}\n\ntype dbMgr struct{}\n\nfunc (*dbMgr) Close()                           {}         // before app terminatine\nfunc (*dbMgr) Open(context.Context) (err error) { return } // ran before catcher.WaitFor()\n```\n\nResult is similar with:\n\n![image-20240113071930661](https://cdn.jsdelivr.net/gh/hzimg/blog-pics@master/uPic/image-20240113071930661.png)\n\nNOTE that `is.Signals().Catch()` will produce a prompt and enter a infinite loop to wait for user's keystroke pressed.\n\n### Lists\n\n```go\nis.Terminal(os.Stdout)\n```\n\nThe partials:\n\n- is.InDebugging / InDebugMode\n- is.DebuggerAttached (relyes on delve tag)\n- is.InTracing / InTestingT\n- is.InTesting / InTestingT\n- is.InDevelopingTime\n- is.InVscodeTerminal\n- is.InK8s\n- is.InIstio\n- is.InDocker / InDockerEnvSimple\n- Build\n  - is.K8sBuild\n  - is.IstioBuild\n  - is.DockerBuild\n  - is.VerboseBuild\n  - is.DebugBuild\n  - buildtags.IsBuildTagExists\n\n- States / Env\n  - VerboseModeEnabled\n  - GetVerboseLevel / SetVerboseMode / SetVerboseLevel\n  - QuietModeEnabled\n  - GetQuietLevel / SetQuietMode / SetQuietLevel\n  - NoColorMode\n  - GetNoColorLevel / SetNoColorMode / SetNoColorLevel\n  - DebugMode\n  - GetDebugLevel / SetDebugMode / SetDebugLevel\n  - Tracing\n  - TraceMode\n  - GetTraceLevel / SetTraceMode / SetTraceLevel\n\n- Terminal / Tty\n  - is.Terminal(file)\n  - is.TerminalFd(fd)\n  - is.Tty(wr)\n  - is.ColoredTty(wr)\n  - is.AnsiEscaped(s) (~~IsTtyEscaped(s)~~)\n  - StripEscapes(s)\n  - ReadPassword\n  - GetTtySize\n  - is.GetTtySizeByName(filename) (cols,rows,err)\n  - is.GetTtySizeByFile(file) (cols,rows,err)\n  - is.GetTtySizeByFd(fd) (cols,rows,err)\n  - StartupByDoubleClick() bool\n\n- [Special] Terminal / Color\n  - escaping tools: GetCPT()/GetCPTC()/GetCPTNC()\n  - Highlight, Dimf, Text, Dim, ToDim, ToHighlight, ToColor, ...\n  - `color.Color` interface\n  - `color.New()` return a stream-callable color object: `color.Cursor`.\n\n- Basics\n  - closers\n    - Peripheral, Closable, Closer\n    - RegisterClosable\n    - RegisterClosers\n    - RegisterCloseFns\n  - `is.Signals().Catcher()`\n  - is.FileExists(filepath)\n  - is.ToBool, StringToBool\n\n### Build Tags\n\nSome functions want special buildtags presented. These are including:\n\n- `verbose`: See VerboseBuild, ...\n- `delve`: See DebugBuild, ...\n- `k8s`: See K8sBuild\n- `istio`: See IstioBuild\n- `docker`: See DockerBuild\n- ...\n- `buildtags.IsBuildTagExists(tag) bool`\n\n### Colorizes\n\nThe test codes:\n\n```go\nimport \"github.com/hedzr/is/term/color\"\n\nfunc TestGetCPT(t *testing.T) {\nt.Logf(\"%v\", color.GetCPT().Translate(`\u003ccode\u003ecode\u003c/code\u003e | \u003ckbd\u003eCTRL\u003c/kbd\u003e\n    \u003cb\u003ebold / strong / em\u003c/b\u003e\n    \u003ci\u003eitalic / cite\u003c/i\u003e\n    \u003cu\u003eunderline\u003c/u\u003e\n    \u003cmark\u003einverse mark\u003c/mark\u003e\n    \u003cdel\u003estrike / del \u003c/del\u003e\n    \u003cfont color=\"green\"\u003egreen text\u003c/font\u003e\n    `, color.FgDefault))\n}\n```\n\nResult:\n\n![image-20231107100150520](https://cdn.jsdelivr.net/gh/hzimg/blog-pics@master/uPic/image-20231107100150520.png)\n\nAnd more:\n\n```go\nfunc TestStripLeftTabs(t *testing.T) {\nt.Logf(\"%v\", color.StripLeftTabs(`\n    \n        \u003ccode\u003ecode\u003c/code\u003e\n    NC Cool\n     But it's tight.\n      Hold On!\n    Hurry Up.\n    `))\n}\n\nfunc TestStripHTMLTags(t *testing.T) {\nt.Logf(\"%v\", color.StripHTMLTags(`\n    \n        \u003ccode\u003ecode\u003c/code\u003e\n    NC Cool\n     But it's tight.\n      Hold On!\n    Hurry Up.\n    `))\n}\n```\n\n### `Cursor`\n\nSince v0.8+, A new `color.Cursor` object can be initialized by `color.New()`, which support format the colorful text with streaming calls, for console/tty.\n\n\u003e See [the online docs](https://docs.hedzr.com/docs/is/) for more usages.\n\n\u003cdetails title=\"Expand\"\u003e\u003ccaption\u003eexpand\u003c/caption\u003e\u003cdetail\u003e\n\nThe examples are:\n\n```go\n\nfunc ExampleNew() {\n // start a color text builder\n var c = color.New()\n\n // specially for running on remote ci server\n if states.Env().IsNoColorMode() {\n  states.Env().SetNoColorMode(true)\n }\n\n // paint and get the result (with ansi-color-seq ready)\n var result = c.Println().\n  Color16(color.FgRed).\n  Printf(\"hello, %s.\", \"world\").Println().\n  SavePos().\n  Println(\"x\").\n  Color16(color.FgGreen).Printf(\"hello, %s.\\n\", \"world\").\n  Color256(160).Printf(\"[160] hello, %s.\\n\", \"world\").\n  Color256(161).Printf(\"[161] hello, %s.\\n\", \"world\").\n  Color256(162).Printf(\"[162] hello, %s.\\n\", \"world\").\n  Color256(163).Printf(\"[163] hello, %s.\\n\", \"world\").\n  Color256(164).Printf(\"[164] hello, %s.\\n\", \"world\").\n  Color256(165).Printf(\"[165] hello, %s.\\n\", \"world\").\n  Up(3).Echo(\" ERASED \").\n  RGB(211, 211, 33).Printf(\"[16m] hello, %s.\", \"world\").\n  Println().\n  RestorePos().\n  Println(\"z\").\n  Down(8).\n  Println(\"DONE\").\n  Build()\n\n  // and render the result\n fmt.Println(result)\n\n // For most of ttys, the output looks like:\n //\n // \u001b[31mhello, world.\u001b[0m\n // \u001b[sx\n // \u001b[32mhello, world.\n // \u001b[38;5;160m[160] hello, world.\n // \u001b[38;5;161m[161] hello, world.\n // \u001b[38;5;162m[162] hello, world.\n // \u001b[38;5;163m[163] hello, world.\n // \u001b[38;5;164m[164] hello, world.\n // \u001b[38;5;165m[165] hello, world.\n // \u001b[0m\u001b[3A ERASED \u001b[38;2;211;211;33m[16m] hello, world.\n // \u001b[uz\n // \u001b[8BDONE\n}\n\nfunc ExampleCursor_Color16() {\n // another colorful builfer\n var c = color.New()\n fmt.Println(c.Color16(color.FgRed).\n  Printf(\"hello, %s.\", \"world\").Println().Build())\n // Output: \u001b[31mhello, world.\u001b[0m\n}\n\nfunc ExampleCursor_Color() {\n // another colorful builfer\n var c = color.New()\n fmt.Println(c.Color(color.FgRed, \"hello, %s.\", \"world\").Build())\n // Output: \u001b[31mhello, world.\u001b[0m\n}\n\nfunc ExampleCursor_Bg() {\n // another colorful builfer\n var c = color.New()\n fmt.Println(c.Bg(color.BgRed, \"hello, %s.\", \"world\").Build())\n // Output: \u001b[41mhello, world.\u001b[0m\n}\n\nfunc ExampleCursor_Effect() {\n // another colorful builfer\n var c = color.New()\n fmt.Println(c.Effect(color.BgDim, \"hello, %s.\", \"world\").Build())\n // Output: \u001b[2mhello, world.\u001b[0m\n}\n\nfunc ExampleCursor_Color256() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c.\n  Color256(163).Printf(\"[163] hello, %s.\\n\", \"world\").\n  Color256(164).Printf(\"[164] hello, %s.\\n\", \"world\").\n  Color256(165).Printf(\"[165] hello, %s.\\n\", \"world\").\n  Build())\n // Output:\n // \u001b[38;5;163m[163] hello, world.\n // \u001b[38;5;164m[164] hello, world.\n // \u001b[38;5;165m[165] hello, world.\n}\n\nfunc ExampleCursor_RGB() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c.\n  RGB(211, 211, 33).Printf(\"[16m] hello, %s.\\n\", \"world\").\n  BgRGB(211, 211, 33).Printf(\"[16m] hello, %s.\\n\", \"world\").\n  Build())\n // Output:\n // \u001b[38;2;211;211;33m[16m] hello, world.\n // \u001b[48;2;211;211;33m[16m] hello, world.\n}\n\nfunc ExampleCursor_EDim() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c. // Color16(color.FgRed).\n   EDim(\"[DIM] hello, %s.\\n\", \"world\").String())\n // Output:\n // \u001b[2m[DIM] hello, world.\n // \u001b[0m\n}\n\nfunc ExampleCursor_Black() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c. // Color16(color.FgRed).\n   Black(\"[BLACK] hello, %s.\\n\", \"world\").String())\n // Output:\n // \u001b[30m[BLACK] hello, world.\n // \u001b[0m\n}\n\nfunc ExampleCursor_BgBlack() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c. // Color16(color.FgRed).\n   BgBlack(\"[BGBLACK] hello, %s.\\n\", \"world\").String())\n // Output:\n // \u001b[40m[BGBLACK] hello, world.\n // \u001b[0m\n}\n\nfunc ExampleCursor_Translate() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c. // Color16(color.FgRed).\n   Translate(`\u003ccode\u003ecode\u003c/code\u003e | \u003ckbd\u003eCTRL\u003c/kbd\u003e\n  \u003cb\u003ebold / strong / em\u003c/b\u003e\n  \u003ci\u003eitalic / cite\u003c/i\u003e\n  \u003cu\u003eunderline\u003c/u\u003e\n  \u003cmark\u003einverse mark\u003c/mark\u003e\n  \u003cdel\u003estrike / del \u003c/del\u003e\n  \u003cfont color=\"green\"\u003egreen text\u003c/font\u003e\n  `).String())\n // Output:\n // \u001b[51;1mcode\u001b[0m\u001b[39m | \u001b[51;1mCTRL\u001b[0m\u001b[39m\n //  \u001b[1mbold / strong / em\u001b[0m\u001b[39m\n //  \u001b[3mitalic / cite\u001b[0m\u001b[39m\n //  \u001b[4munderline\u001b[0m\u001b[39m\n //  \u001b[7minverse mark\u001b[0m\u001b[39m\n //  \u001b[9mstrike / del \u001b[0m\u001b[39m\n //  \u001b[32mgreen text\u001b[0m\u001b[39m\n}\n\nfunc ExampleCursor_StripLeftTabsColorful() {\n // another colorful builfer\n var c = color.New()\n fmt.Print(c. // Color16(color.FgRed).\n   StripLeftTabsColorful(`\n  \u003ccode\u003ecode\u003c/code\u003e | \u003ckbd\u003eCTRL\u003c/kbd\u003e\n  \u003cb\u003ebold / strong / em\u003c/b\u003e\n  \u003ci\u003eitalic / cite\u003c/i\u003e\n  \u003cu\u003eunderline\u003c/u\u003e\n  \u003cmark\u003einverse mark\u003c/mark\u003e\n  \u003cdel\u003estrike / del \u003c/del\u003e\n  \u003cfont color=\"green\"\u003egreen text\u003c/font\u003e\n  `).String())\n // Output:\n // \u001b[51;1mcode\u001b[0m\u001b[0m | \u001b[51;1mCTRL\u001b[0m\u001b[0m\n // \u001b[1mbold / strong / em\u001b[0m\u001b[0m\n // \u001b[3mitalic / cite\u001b[0m\u001b[0m\n // \u001b[4munderline\u001b[0m\u001b[0m\n // \u001b[7minverse mark\u001b[0m\u001b[0m\n // \u001b[9mstrike / del \u001b[0m\u001b[0m\n // \u001b[32mgreen text\u001b[0m\u001b[0m\n}\n```\n\n\u003c/detail\u003e\u003c/details\u003e\n\n### `color` subpackage\n\nPackage color provides a wrapped standard output device like printf but with colored enhancements.\n\nThe main types are [Cursor](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Cursor) and [Translator](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Translator).\n\n[Cursor](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Cursor) allows formatting colorful text and moving cursor to another coordinate.\n\n[New](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#New) will return a [Cursor](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Cursor) object.\n\n[RowsBlock](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#RowsBlock) is another cursor controller, which can treat the current line and following lines as a block and updating these lines repeatedly. This feature will help the progressbar writers or the continuous lines updater.\n\n[Translator](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Translator) is a text and tiny HTML tags translator to convert these markup text into colorful console text sequences. [GetCPT](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#GetCPT) can return a smart translator which translate colorful text or strip the ansi escaped sequence from result text if `states.Env().IsNoColorMode()` is true.\n\n[Color](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Color) is an interface type to represent a terminal color object, which can be serialized to ansi escaped sequence directly by [Color.Color].\n\nTo create a [Color](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Color) object, there are several ways:\n\n- by [NewColor16](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewColor16), or use [Color16](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#Color16) constants directly like [FgBlack](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#FgBlack), [BgGreen](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#BgGreen), ...\n- by [NewColor256](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewColor256) to make a 8-bit 256-colors object\n- by [NewColor16m](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewColor16m) to make a true-color object\n- by [NewControlCode](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewControlCode) or [ControlCode](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#ControlCode) constants\n- by [NewFeCode](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewFeCode) or [FeCode](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#FeCode) constants\n- by [NewSGR](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewSGR) or use [CSIsgr](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#CSIsgr) constants directly like [SGRdim](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#SGRdim), [SGRstrike](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#SGRstrike), ...\n- by [NewStyle](https://pkg.go.dev/github.com/hedzr/is@v0.8.31/term/color#NewStyle) to make a compounded object\n- ...\n\nAs to v0.8.53, a `Color` object can wrap itself arroubd the given text:\n\n```go\ncolor.BgBold.Wrap(color.FgRed.Wrap(\"ERROR!\"))\ncolor.BgDim.Wrap(color.FgDarkGray.Wrap(\"debug message here.\"))\n```\n\n## Integrated with `cmdr`\n\n### `Closers`\n\nThe `Closers()` collects all closable objects and allow shutting down them at once.\n\n```go\npackage main\n\nimport (\n    \"os\"\n\n    \"github.com/hedzr/is/basics\"\n)\n\ntype redisHub struct{}\n\nfunc (s *redisHub) Close() {\n    // close the connections to redis servers\n    println(\"redis connections closed\")\n}\n\nfunc main() {\n    defer basics.Close()\n\n    tmpFile, _ := os.CreateTemp(os.TempDir(), \"1*.log\")\n    basics.RegisterClosers(tmpFile)\n\n    basics.RegisterCloseFn(func() {\n        // do some shutdown operations here\n        println(\"close single functor\")\n    })\n\n    basics.RegisterPeripheral(\u0026redisHub{})\n}\n```\n\n### `Signals`\n\n`Signals()` could catch OS signals and entering a infinite loop.\n\nFor example, a tcp server could be:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"os\"\n    \"sync\"\n\n    \"github.com/hedzr/go-socketlib/net\"\n    \"github.com/hedzr/is\"\n    logz \"github.com/hedzr/logg/slog\"\n)\n\nfunc main() {\n    ctx, cancel := context.WithCancel(context.Background())\n    defer cancel()\n\n    logger := logz.New(\"new-dns\")\n    server := net.NewServer(\":7099\",\n        net.WithServerOnListening(func(ss net.Server, l stdnet.Listener) {\n            go runClient(ctx, ss, l)\n        }),\n        net.WithServerLogger(logger.WithSkip(1)),\n    )\n    defer server.Close()\n\n    // make a catcher so that it can catch ths signals,\n    catcher := is.Signals().Catch()\n    catcher.\n        // WithVerboseFn(func(msg string, args ...any) {\n        //     logz.WithSkip(2).Verbose(fmt.Sprintf(\"[verbose] %s\", fmt.Sprintf(msg, args...)))\n        // }).\n        WithOnSignalCaught(func(ctx context.Context, sig os.Signal, wg *sync.WaitGroup) {\n            println()\n            logz.Debug(\"signal caught\", \"sig\", sig)\n            if err := server.Shutdown(); err != nil {\n                logz.Error(\"server shutdown error\", \"err\", err)\n            }\n            cancel()\n        }).\n        WaitFor(ctx, func(ctx context.Context, closer func()) {\n            logz.Debug(\"entering looper's loop...\")\n\n            server.WithOnShutdown(func(err error, ss net.Server) { closer() })\n            err := server.ListenAndServe(ctx, nil)\n            if err != nil {\n                logz.Fatal(\"server serve failed\", \"err\", err)\n            } else {\n                closer()\n            }\n        })\n}\n\nfunc runClient(ctx context.Context, ss net.Server, l stdnet.Listener) {\n    c := net.NewClient()\n\n    if err := c.Dial(\"tcp\", \":7099\"); err != nil {\n        logz.Fatal(\"connecting to server failed\", \"err\", err, \"server-endpoint\", \":7099\")\n    }\n    logz.Info(\"[client] connected\", \"server.addr\", c.RemoteAddr())\n    c.RunDemo(ctx)\n}\n```\n\n## Contributions\n\nKindly welcome, please issue me first for keeping this repo smaller.\n\n## License\n\nunder Apache 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhedzr%2Fis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhedzr%2Fis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhedzr%2Fis/lists"}