diff --git a/go.mod b/go.mod index 58aefd19..9895d79e 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.22 require ( github.com/adrg/xdg v0.4.0 github.com/charmbracelet/bubbles v0.18.0 - github.com/charmbracelet/bubbletea v0.25.0 + github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/glamour v0.6.0 - github.com/charmbracelet/lipgloss v0.10.0 + github.com/charmbracelet/lipgloss v0.13.0 github.com/getkin/kin-openapi v0.124.0 github.com/google/uuid v1.6.0 github.com/gorilla/handlers v1.5.2 @@ -40,9 +40,11 @@ require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.4.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect @@ -69,7 +71,7 @@ require ( github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect @@ -93,8 +95,8 @@ require ( golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.22.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index cada5711..2c3fe83b 100644 --- a/go.sum +++ b/go.sum @@ -51,19 +51,21 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= -github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= -github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= +github.com/charmbracelet/bubbletea v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c= +github.com/charmbracelet/bubbletea v1.1.0/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc= github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc= -github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= -github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= +github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= +github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -75,6 +77,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -232,8 +236,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= @@ -413,8 +417,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -441,13 +445,14 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= diff --git a/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml b/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml index ef456e06..1b6824bb 100644 --- a/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml +++ b/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml @@ -23,7 +23,6 @@ linters: - gomnd - gomoddirectives - goprintffuncname - - ifshort # - lll - misspell - nakedret diff --git a/vendor/github.com/charmbracelet/bubbletea/.golangci.yml b/vendor/github.com/charmbracelet/bubbletea/.golangci.yml index a5a91d0d..3affce91 100644 --- a/vendor/github.com/charmbracelet/bubbletea/.golangci.yml +++ b/vendor/github.com/charmbracelet/bubbletea/.golangci.yml @@ -16,6 +16,7 @@ linters: enable: - bodyclose - exportloopref + - gofumpt - goimports - gosec - nilerr diff --git a/vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml b/vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml new file mode 100644 index 00000000..40d9f298 --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml @@ -0,0 +1,6 @@ +includes: + - from_url: + url: charmbracelet/meta/main/goreleaser-lib.yaml + +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json + diff --git a/vendor/github.com/charmbracelet/bubbletea/README.md b/vendor/github.com/charmbracelet/bubbletea/README.md index 0834246c..9a8d93e2 100644 --- a/vendor/github.com/charmbracelet/bubbletea/README.md +++ b/vendor/github.com/charmbracelet/bubbletea/README.md @@ -1,10 +1,11 @@ # Bubble Tea

- Bubble Tea Title Treatment
+ Bubble Tea Title Treatment
Latest Release GoDoc Build Status + phorm.ai

The fun, functional and stateful way to build terminal apps. A Go framework @@ -266,15 +267,21 @@ delve in headless mode and then connect to it: ```bash # Start the debugger -$ dlv debug --headless . -API server listening at: 127.0.0.1:34241 +$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 . +API server listening at: 127.0.0.1:43000 # Connect to it from another terminal -$ dlv connect 127.0.0.1:34241 +$ dlv connect 127.0.0.1:43000 ``` -Note that the default port used will vary on your system and per run, so -actually watch out what address the first `dlv` run tells you to connect to. +If you do not explicitly supply the `--listen` flag, the port used will vary +per run, so passing this in makes the debugger easier to use from a script +or your IDE of choice. + +Additionally, we pass in `--api-version=2` because delve defaults to version 1 +for backwards compatibility reasons. However, delve recommends using version 2 +for all new development and some clients may no longer work with version 1. +For more information, see the [Delve documentation](https://github.com/go-delve/delve/tree/master/Documentation/api). ### Logging Stuff @@ -302,6 +309,7 @@ your program in another window. * [Lip Gloss][lipgloss]: Style, format and layout tools for terminal applications * [Harmonica][harmonica]: A spring animation library for smooth, natural motion * [BubbleZone][bubblezone]: Easy mouse event tracking for Bubble Tea components +* [ntcharts][ntcharts]: A terminal charting library built for Bubble Tea and [Lip Gloss][lipgloss] * [Termenv][termenv]: Advanced ANSI styling for terminal applications * [Reflow][reflow]: Advanced ANSI-aware methods for working with text @@ -309,6 +317,7 @@ your program in another window. [lipgloss]: https://github.com/charmbracelet/lipgloss [harmonica]: https://github.com/charmbracelet/harmonica [bubblezone]: https://github.com/lrstanley/bubblezone +[ntcharts]: https://github.com/NimbleMarkets/ntcharts [termenv]: https://github.com/muesli/termenv [reflow]: https://github.com/muesli/reflow @@ -316,25 +325,36 @@ your program in another window. For some Bubble Tea programs in production, see: +* [ASCII Movie](https://github.com/gabe565/ascii-movie): a Star Wars ASCII art movie player * [AT CLI](https://github.com/daskycodes/at_cli): execute AT Commands via serial port connections * [Aztify](https://github.com/Azure/aztfy): bring Microsoft Azure resources under Terraform * [brows](https://github.com/rubysolo/brows): a GitHub release browser * [Canard](https://github.com/mrusme/canard): an RSS client * [charm](https://github.com/charmbracelet/charm): the official Charm user account manager +* [chatgpt-cli](https://github.com/j178/chatgpt): a CLI for ChatGPT +* [chatgpt-tui](https://github.com/tearingItUp786/chatgpt-tui): a TUI for ChatGPT with SQLite sessions +* [ChatGPTUI](https://github.com/dwisiswant0/chatgptui): a TUI for ChatGPT * [chezmoi](https://github.com/twpayne/chezmoi): securely manage your dotfiles across multiple machines -* [chtop](https://github.com/chhetripradeep/chtop): monitor your ClickHouse node without leaving terminal +* [chip-8](https://github.com/braheezy/chip-8): a CHIP-8 interpreter +* [chtop](https://github.com/chhetripradeep/chtop): monitor your ClickHouse node without leaving the terminal * [circumflex](https://github.com/bensadeh/circumflex): read Hacker News in the terminal * [clidle](https://github.com/ajeetdsouza/clidle): a Wordle clone * [cLive](https://github.com/koki-develop/clive): automate terminal operations and view them live in a browser * [container-canary](https://github.com/NVIDIA/container-canary): a container validator * [countdown](https://github.com/aldernero/countdown): a multi-event countdown timer -* [dns53](https://github.com/purpleclay/dns53): dynamic DNS with Amazon Route53. Expose your EC2 quickly, securely and privately -* [eks-node-viewer](https://github.com/awslabs/eks-node-viewer): a tool for visualizing dynamic node usage within an eks cluster -* [enola](https://github.com/sherlock-project/enola): hunt down social media accounts by username across social networks +* [CRT](https://github.com/BigJk/crt): a simple terminal emulator for running Bubble Tea in a dedicated window, with optional shaders +* [cueitup](https://github.com/dhth/cueitup): inspect messages in an AWS SQS queue in a simple and deliberate manner +* [Daytona](https://github.com/daytonaio/daytona): an development environment manager +* [dns53](https://github.com/purpleclay/dns53): dynamic DNS with Amazon Route53; expose your EC2 quickly, securely and privately +* [eks-node-viewer](https://github.com/awslabs/eks-node-viewer): a tool for visualizing dynamic node usage within an EKS cluster +* [End Of Eden](https://github.com/BigJk/end_of_eden): a "Slay the Spire"-like, roguelike deck-builder game +* [enola](https://github.com/sherlock-project/enola): find social media accounts by username across social networks * [flapioca](https://github.com/kbrgl/flapioca): Flappy Bird on the CLI! * [fm](https://github.com/knipferrc/fm): a terminal-based file manager * [fork-cleaner](https://github.com/caarlos0/fork-cleaner): clean up old and inactive forks in your GitHub account +* [fractals-cli](https://github.com/MicheleFiladelfia/fractals-cli): a multiplatform terminal fractal explorer * [fztea](https://github.com/jon4hz/fztea): a Flipper Zero TUI +* [gama](https://github.com/termkit/gama): manage GitHub Actions from the terminal * [gambit](https://github.com/maaslalani/gambit): chess in the terminal * [gembro](https://git.sr.ht/~rafael/gembro): a mouse-driven Gemini browser * [gh-b](https://github.com/joaom00/gh-b): a GitHub CLI extension for managing branches @@ -343,37 +363,56 @@ For some Bubble Tea programs in production, see: * [Glow](https://github.com/charmbracelet/glow): a markdown reader, browser, and online markdown stash * [go-sweep](https://github.com/maxpaulus43/go-sweep): Minesweeper in the terminal * [gocovsh](https://github.com/orlangure/gocovsh): explore Go coverage reports from the CLI -* [got](https://github.com/fedeztk/got): a simple translator and text-to-speech app build on top of simplytranslate's APIs -* [hiSHtory](https://github.com/ddworken/hishtory): your shell history in context, synced, and queryable +* [got](https://github.com/fedeztk/got): a simple translator and text-to-speech app built on simplytranslate's APIs +* [gum](https://github.com/charmbracelet/gum): interactivity and styling for shells and shell scripts +* [hiSHtory](https://github.com/ddworken/hishtory): your shell history in context: synced, and queryable * [httpit](https://github.com/gonetx/httpit): a rapid http(s) benchmark tool +* [Huh?](https://github.com/charmbracelet/huh): an interactive prompt and form toolkit * [IDNT](https://github.com/r-darwish/idnt): a batch software uninstaller +* [json-log-viewer](https://github.com/hedhyw/json-log-viewer): an interactive JSON log viewer * [kboard](https://github.com/CamiloGarciaLaRotta/kboard): a typing game -* [mandelbrot-cli](https://github.com/MicheleFiladelfia/mandelbrot-cli): a multiplatform terminal mandelbrot set explorer +* [kplay](https://github.com/dhth/kplay): inspect messages in a Kafka topic +* [laboon](https://github.com/arisnacg/laboon): a Docker-desktop-style container manager * [mc](https://github.com/minio/mc): the official [MinIO](https://min.io) client * [mergestat](https://github.com/mergestat/mergestat): run SQL queries on git repositories +* [meteor](https://github.com/stefanlogue/meteor): a highly customizable conventional commit message tool +* [mods](https://github.com/charmbracelet/mods): AI on the CLI, built for pipelines +* [nachrichten](https://github.com/zMoooooritz/nachrichten): access up-to-date news in German provided by the [Tagesschau](https://www.tagesschau.de/) * [Neon Modem Overdrive](https://github.com/mrusme/neonmodem): a BBS-style TUI client for Discourse, Lemmy, Lobste.rs and Hacker News +* [nom](https://github.com/guyfedwards/nom): an RSS reader and manager * [Noted](https://github.com/torbratsberg/noted): a note viewer and manager -* [nom](https://github.com/guyfedwards/nom): RSS reader and manager -* [pathos](https://github.com/chip/pathos): a PATH env variable editor +* [outtasync](https://github.com/dhth/outtasync): identify CloudFormation stacks that are out of sync with their template files +* [pathos](https://github.com/chip/pathos): a PATH environment variable editor +* [Plandex](https://github.com/plandex-ai/plandex): a terminal-based AI coding engine for complex tasks * [portal](https://github.com/ZinoKader/portal): secure transfers between computers -* [redis-viewer](https://github.com/SaltFishPr/redis-viewer): a Redis databases browser -* [scrabbler](https://github.com/wI2L/scrabbler): Automatic draw TUI for your duplicate Scrabble games +* [prs](https://github.com/dhth/prs): stay up to date with your PRs +* [puffin](https://github.com/siddhantac/puffin): a TUI for hledger to manage your finances +* [pug](https://github.com/leg100/pug): terraform task manager +* [punchout](https://github.com/dhth/punchout): takes the suck out of logging time on JIRA +* [redis-viewer](https://github.com/SaltFishPr/redis-viewer): a Redis database browser +* [redis_tui](https://github.com/mat2cc/redis_tui): a Redis database browser +* [schemas](https://github.com/dhth/schemas): lets you inspect postgres schemas in the terminal +* [scrabbler](https://github.com/wI2L/scrabbler): an automatic draw tool for your duplicate Scrabble games * [sku](https://github.com/fedeztk/sku): Sudoku on the CLI * [Slides](https://github.com/maaslalani/slides): a markdown-based presentation tool -* [SlurmCommander](https://github.com/CLIP-HPC/SlurmCommander): a Slurm workload manager TUI +* [SlurmCommander](https://github.com/CLIP-HPC/SlurmCommander): a Slurm workload manager * [Soft Serve](https://github.com/charmbracelet/soft-serve): a command-line-first Git server that runs a TUI over SSH * [solitaire-tui](https://github.com/brianstrauch/solitaire-tui): Klondike Solitaire for the terminal * [StormForge Optimize Controller](https://github.com/thestormforge/optimize-controller): a tool for experimenting with application configurations in Kubernetes -* [Storydb](https://github.com/grrlopes/storydb): a bash/zsh ctrl+r improved command history finder. +* [Storydb](https://github.com/grrlopes/storydb): an improved bash/zsh-style ctrl+r command history finder * [STTG](https://github.com/wille1101/sttg): a teletext client for SVT, Sweden’s national public television station * [sttr](https://github.com/abhimanyu003/sttr): a general-purpose text transformer +* [superfile](https://github.com/MHNightCat/superfile) a fancy, modern terminal-based file manager * [tasktimer](https://github.com/caarlos0/tasktimer): a dead-simple task timer * [termdbms](https://github.com/mathaou/termdbms): a keyboard and mouse driven database browser +* [tgpt](https://github.com/aandrew-me/tgpt): conversational AI for the CLI; no API keys necessary * [ticker](https://github.com/achannarasappa/ticker): a terminal stock viewer and stock position tracker +* [trainer](https://github.com/rusinikita/trainer): a Go concurrency coding interview simulator with learning materials * [tran](https://github.com/abdfnx/tran): securely transfer stuff between computers (based on [portal](https://github.com/ZinoKader/portal)) +* [Trufflehog](https://github.com/trufflesecurity/trufflehog): find leaked credentials * [Typer](https://github.com/maaslalani/typer): a typing test -* [typioca](https://github.com/bloznelis/typioca): Cozy typing speed tester in terminal -* [tz](https://github.com/oz/tz): an aid for scheduling across multiple time zones +* [typioca](https://github.com/bloznelis/typioca): a typing test +* [tz](https://github.com/oz/tz): a scheduling aid for people in multiple time zones * [ugm](https://github.com/ariasmn/ugm): a unix user and group browser * [walk](https://github.com/antonmedv/walk): a terminal navigator * [wander](https://github.com/robinovitch61/wander): a HashiCorp Nomad terminal client diff --git a/vendor/github.com/charmbracelet/bubbletea/commands.go b/vendor/github.com/charmbracelet/bubbletea/commands.go index 7b139b88..bfa3b704 100644 --- a/vendor/github.com/charmbracelet/bubbletea/commands.go +++ b/vendor/github.com/charmbracelet/bubbletea/commands.go @@ -20,11 +20,15 @@ func Batch(cmds ...Cmd) Cmd { } validCmds = append(validCmds, c) } - if len(validCmds) == 0 { + switch len(validCmds) { + case 0: return nil - } - return func() Msg { - return BatchMsg(validCmds) + case 1: + return validCmds[0] + default: + return func() Msg { + return BatchMsg(validCmds) + } } } @@ -90,11 +94,16 @@ type sequenceMsg []Cmd // // Every is analogous to Tick in the Elm Architecture. func Every(duration time.Duration, fn func(time.Time) Msg) Cmd { + n := time.Now() + d := n.Truncate(duration).Add(duration).Sub(n) + t := time.NewTimer(d) return func() Msg { - n := time.Now() - d := n.Truncate(duration).Add(duration).Sub(n) - t := time.NewTimer(d) - return fn(<-t.C) + ts := <-t.C + t.Stop() + for len(t.C) > 0 { + <-t.C + } + return fn(ts) } } @@ -137,9 +146,14 @@ func Every(duration time.Duration, fn func(time.Time) Msg) Cmd { // return m, nil // } func Tick(d time.Duration, fn func(time.Time) Msg) Cmd { + t := time.NewTimer(d) return func() Msg { - t := time.NewTimer(d) - return fn(<-t.C) + ts := <-t.C + t.Stop() + for len(t.C) > 0 { + <-t.C + } + return fn(ts) } } @@ -187,3 +201,16 @@ func SetWindowTitle(title string) Cmd { return setWindowTitleMsg(title) } } + +type windowSizeMsg struct{} + +// WindowSize is a command that queries the terminal for its current size. It +// delivers the results to Update via a [WindowSizeMsg]. Keep in mind that +// WindowSizeMsgs will automatically be delivered to Update when the [Program] +// starts and when the window dimensions change so in many cases you will not +// need to explicitly invoke this command. +func WindowSize() Cmd { + return func() Msg { + return windowSizeMsg{} + } +} diff --git a/vendor/github.com/charmbracelet/bubbletea/exec.go b/vendor/github.com/charmbracelet/bubbletea/exec.go index fb6d91ed..7a14d2a7 100644 --- a/vendor/github.com/charmbracelet/bubbletea/exec.go +++ b/vendor/github.com/charmbracelet/bubbletea/exec.go @@ -109,7 +109,7 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) { } c.SetStdin(p.input) - c.SetStdout(p.output.TTY()) + c.SetStdout(p.output) c.SetStderr(os.Stderr) // Execute system command. diff --git a/vendor/github.com/charmbracelet/bubbletea/focus.go b/vendor/github.com/charmbracelet/bubbletea/focus.go new file mode 100644 index 00000000..4d34bea6 --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/focus.go @@ -0,0 +1,9 @@ +package tea + +// FocusMsg represents a terminal focus message. +// This occurs when the terminal gains focus. +type FocusMsg struct{} + +// BlurMsg represents a terminal blur message. +// This occurs when the terminal loses focus. +type BlurMsg struct{} diff --git a/vendor/github.com/charmbracelet/bubbletea/inputreader_other.go b/vendor/github.com/charmbracelet/bubbletea/inputreader_other.go new file mode 100644 index 00000000..8e63a87d --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/inputreader_other.go @@ -0,0 +1,14 @@ +//go:build !windows +// +build !windows + +package tea + +import ( + "io" + + "github.com/muesli/cancelreader" +) + +func newInputReader(r io.Reader) (cancelreader.CancelReader, error) { + return cancelreader.NewReader(r) +} diff --git a/vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go b/vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go new file mode 100644 index 00000000..449df479 --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go @@ -0,0 +1,107 @@ +//go:build windows +// +build windows + +package tea + +import ( + "fmt" + "io" + "os" + "sync" + + "github.com/charmbracelet/x/term" + "github.com/erikgeiser/coninput" + "github.com/muesli/cancelreader" + "golang.org/x/sys/windows" +) + +type conInputReader struct { + cancelMixin + + conin windows.Handle + + originalMode uint32 +} + +var _ cancelreader.CancelReader = &conInputReader{} + +func newInputReader(r io.Reader) (cancelreader.CancelReader, error) { + fallback := func(io.Reader) (cancelreader.CancelReader, error) { + return cancelreader.NewReader(r) + } + if f, ok := r.(term.File); !ok || f.Fd() != os.Stdin.Fd() { + return fallback(r) + } + + conin, err := coninput.NewStdinHandle() + if err != nil { + return fallback(r) + } + + originalMode, err := prepareConsole(conin, + windows.ENABLE_MOUSE_INPUT, + windows.ENABLE_WINDOW_INPUT, + windows.ENABLE_EXTENDED_FLAGS, + ) + if err != nil { + return nil, fmt.Errorf("failed to prepare console input: %w", err) + } + + return &conInputReader{ + conin: conin, + originalMode: originalMode, + }, nil +} + +// Cancel implements cancelreader.CancelReader. +func (r *conInputReader) Cancel() bool { + r.setCanceled() + + return windows.CancelIo(r.conin) == nil +} + +// Close implements cancelreader.CancelReader. +func (r *conInputReader) Close() error { + if r.originalMode != 0 { + err := windows.SetConsoleMode(r.conin, r.originalMode) + if err != nil { + return fmt.Errorf("reset console mode: %w", err) + } + } + + return nil +} + +// Read implements cancelreader.CancelReader. +func (*conInputReader) Read(_ []byte) (n int, err error) { + return 0, nil +} + +func prepareConsole(input windows.Handle, modes ...uint32) (originalMode uint32, err error) { + err = windows.GetConsoleMode(input, &originalMode) + if err != nil { + return 0, fmt.Errorf("get console mode: %w", err) + } + + newMode := coninput.AddInputModes(0, modes...) + + err = windows.SetConsoleMode(input, newMode) + if err != nil { + return 0, fmt.Errorf("set console mode: %w", err) + } + + return originalMode, nil +} + +// cancelMixin represents a goroutine-safe cancelation status. +type cancelMixin struct { + unsafeCanceled bool + lock sync.Mutex +} + +func (c *cancelMixin) setCanceled() { + c.lock.Lock() + defer c.lock.Unlock() + + c.unsafeCanceled = true +} diff --git a/vendor/github.com/charmbracelet/bubbletea/key.go b/vendor/github.com/charmbracelet/bubbletea/key.go index f851490a..ab4792ac 100644 --- a/vendor/github.com/charmbracelet/bubbletea/key.go +++ b/vendor/github.com/charmbracelet/bubbletea/key.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "regexp" + "strings" "unicode/utf8" ) @@ -54,6 +55,7 @@ type Key struct { Type KeyType Runes []rune Alt bool + Paste bool } // String returns a friendly string representation for a key. It's safe (and @@ -63,15 +65,28 @@ type Key struct { // fmt.Println(k) // // Output: enter func (k Key) String() (str string) { + var buf strings.Builder if k.Alt { - str += "alt+" + buf.WriteString("alt+") } if k.Type == KeyRunes { - str += string(k.Runes) - return str + if k.Paste { + // Note: bubbles/keys bindings currently do string compares to + // recognize shortcuts. Since pasted text should never activate + // shortcuts, we need to ensure that the binding code doesn't + // match Key events that result from pastes. We achieve this + // here by enclosing pastes in '[...]' so that the string + // comparison in Matches() fails in that case. + buf.WriteByte('[') + } + buf.WriteString(string(k.Runes)) + if k.Paste { + buf.WriteByte(']') + } + return buf.String() } else if s, ok := keyNames[k.Type]; ok { - str += s - return str + buf.WriteString(s) + return buf.String() } return "" } @@ -538,9 +553,9 @@ func (u unknownCSISequenceMsg) String() string { var spaceRunes = []rune{' '} -// readInputs reads keypress and mouse inputs from a TTY and produces messages +// readAnsiInputs reads keypress and mouse inputs from a TTY and produces messages // containing information about the key or mouse events accordingly. -func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error { +func readAnsiInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error { var buf [256]byte var leftOverFromPrevIteration []byte @@ -566,7 +581,7 @@ loop: canHaveMoreData := numBytes == len(buf) var i, w int - for i, w = 0, 07; i < len(b); i += w { + for i, w = 0, 0; i < len(b); i += w { var msg Msg w, msg = detectOneMsg(b[i:], canHaveMoreData) if w == 0 { @@ -607,19 +622,33 @@ func detectOneMsg(b []byte, canHaveMoreData bool) (w int, msg Msg) { case '<': if matchIndices := mouseSGRRegex.FindSubmatchIndex(b[3:]); matchIndices != nil { // SGR mouse events length is the length of the match plus the length of the escape sequence - mouseEventSGRLen := matchIndices[1] + 3 + mouseEventSGRLen := matchIndices[1] + 3 //nolint:gomnd return mouseEventSGRLen, MouseMsg(parseSGRMouseEvent(b)) } } } + // Detect focus events. + var foundRF bool + foundRF, w, msg = detectReportFocus(b) + if foundRF { + return w, msg + } + + // Detect bracketed paste. + var foundbp bool + foundbp, w, msg = detectBracketedPaste(b) + if foundbp { + return w, msg + } + // Detect escape sequence and control characters other than NUL, // possibly with an escape character in front to mark the Alt // modifier. var foundSeq bool foundSeq, w, msg = detectSequence(b) if foundSeq { - return + return w, msg } // No non-NUL control character or escape sequence. diff --git a/vendor/github.com/charmbracelet/bubbletea/key_other.go b/vendor/github.com/charmbracelet/bubbletea/key_other.go new file mode 100644 index 00000000..b8c46082 --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/key_other.go @@ -0,0 +1,13 @@ +//go:build !windows +// +build !windows + +package tea + +import ( + "context" + "io" +) + +func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error { + return readAnsiInputs(ctx, msgs, input) +} diff --git a/vendor/github.com/charmbracelet/bubbletea/key_sequences.go b/vendor/github.com/charmbracelet/bubbletea/key_sequences.go index cc200f8d..15483ef5 100644 --- a/vendor/github.com/charmbracelet/bubbletea/key_sequences.go +++ b/vendor/github.com/charmbracelet/bubbletea/key_sequences.go @@ -1,6 +1,10 @@ package tea -import "sort" +import ( + "bytes" + "sort" + "unicode/utf8" +) // extSequences is used by the map-based algorithm below. It contains // the sequences plus their alternatives with an escape character @@ -69,3 +73,59 @@ func detectSequence(input []byte) (hasSeq bool, width int, msg Msg) { return false, 0, nil } + +// detectBracketedPaste detects an input pasted while bracketed +// paste mode was enabled. +// +// Note: this function is a no-op if bracketed paste was not enabled +// on the terminal, since in that case we'd never see this +// particular escape sequence. +func detectBracketedPaste(input []byte) (hasBp bool, width int, msg Msg) { + // Detect the start sequence. + const bpStart = "\x1b[200~" + if len(input) < len(bpStart) || string(input[:len(bpStart)]) != bpStart { + return false, 0, nil + } + + // Skip over the start sequence. + input = input[len(bpStart):] + + // If we saw the start sequence, then we must have an end sequence + // as well. Find it. + const bpEnd = "\x1b[201~" + idx := bytes.Index(input, []byte(bpEnd)) + inputLen := len(bpStart) + idx + len(bpEnd) + if idx == -1 { + // We have encountered the end of the input buffer without seeing + // the marker for the end of the bracketed paste. + // Tell the outer loop we have done a short read and we want more. + return true, 0, nil + } + + // The paste is everything in-between. + paste := input[:idx] + + // All there is in-between is runes, not to be interpreted further. + k := Key{Type: KeyRunes, Paste: true} + for len(paste) > 0 { + r, w := utf8.DecodeRune(paste) + if r != utf8.RuneError { + k.Runes = append(k.Runes, r) + } + paste = paste[w:] + } + + return true, inputLen, KeyMsg(k) +} + +// detectReportFocus detects a focus report sequence. +// nolint: gomnd +func detectReportFocus(input []byte) (hasRF bool, width int, msg Msg) { + switch { + case bytes.Equal(input, []byte("\x1b[I")): + return true, 3, FocusMsg{} + case bytes.Equal(input, []byte("\x1b[O")): + return true, 3, BlurMsg{} + } + return false, 0, nil +} diff --git a/vendor/github.com/charmbracelet/bubbletea/key_windows.go b/vendor/github.com/charmbracelet/bubbletea/key_windows.go new file mode 100644 index 00000000..b693efd6 --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/key_windows.go @@ -0,0 +1,351 @@ +//go:build windows +// +build windows + +package tea + +import ( + "context" + "fmt" + "io" + + "github.com/erikgeiser/coninput" + localereader "github.com/mattn/go-localereader" + "golang.org/x/sys/windows" +) + +func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error { + if coninReader, ok := input.(*conInputReader); ok { + return readConInputs(ctx, msgs, coninReader.conin) + } + + return readAnsiInputs(ctx, msgs, localereader.NewReader(input)) +} + +func readConInputs(ctx context.Context, msgsch chan<- Msg, con windows.Handle) error { + var ps coninput.ButtonState // keep track of previous mouse state + var ws coninput.WindowBufferSizeEventRecord // keep track of the last window size event + for { + events, err := coninput.ReadNConsoleInputs(con, 16) + if err != nil { + return fmt.Errorf("read coninput events: %w", err) + } + + for _, event := range events { + var msgs []Msg + switch e := event.Unwrap().(type) { + case coninput.KeyEventRecord: + if !e.KeyDown || e.VirtualKeyCode == coninput.VK_SHIFT { + continue + } + + for i := 0; i < int(e.RepeatCount); i++ { + eventKeyType := keyType(e) + var runes []rune + + // Add the character only if the key type is an actual character and not a control sequence. + // This mimics the behavior in readAnsiInputs where the character is also removed. + // We don't need to handle KeySpace here. See the comment in keyType(). + if eventKeyType == KeyRunes { + runes = []rune{e.Char} + } + + msgs = append(msgs, KeyMsg{ + Type: eventKeyType, + Runes: runes, + Alt: e.ControlKeyState.Contains(coninput.LEFT_ALT_PRESSED | coninput.RIGHT_ALT_PRESSED), + }) + } + case coninput.WindowBufferSizeEventRecord: + if e != ws { + ws = e + msgs = append(msgs, WindowSizeMsg{ + Width: int(e.Size.X), + Height: int(e.Size.Y), + }) + } + case coninput.MouseEventRecord: + event := mouseEvent(ps, e) + if event.Type != MouseUnknown { + msgs = append(msgs, event) + } + ps = e.ButtonState + case coninput.FocusEventRecord, coninput.MenuEventRecord: + // ignore + default: // unknown event + continue + } + + // Send all messages to the channel + for _, msg := range msgs { + select { + case msgsch <- msg: + case <-ctx.Done(): + err := ctx.Err() + if err != nil { + return fmt.Errorf("coninput context error: %w", err) + } + return err + } + } + } + } +} + +func mouseEventButton(p, s coninput.ButtonState) (button MouseButton, action MouseAction) { + btn := p ^ s + action = MouseActionPress + if btn&s == 0 { + action = MouseActionRelease + } + + if btn == 0 { + switch { + case s&coninput.FROM_LEFT_1ST_BUTTON_PRESSED > 0: + button = MouseButtonLeft + case s&coninput.FROM_LEFT_2ND_BUTTON_PRESSED > 0: + button = MouseButtonMiddle + case s&coninput.RIGHTMOST_BUTTON_PRESSED > 0: + button = MouseButtonRight + case s&coninput.FROM_LEFT_3RD_BUTTON_PRESSED > 0: + button = MouseButtonBackward + case s&coninput.FROM_LEFT_4TH_BUTTON_PRESSED > 0: + button = MouseButtonForward + } + return + } + + switch { + case btn == coninput.FROM_LEFT_1ST_BUTTON_PRESSED: // left button + button = MouseButtonLeft + case btn == coninput.RIGHTMOST_BUTTON_PRESSED: // right button + button = MouseButtonRight + case btn == coninput.FROM_LEFT_2ND_BUTTON_PRESSED: // middle button + button = MouseButtonMiddle + case btn == coninput.FROM_LEFT_3RD_BUTTON_PRESSED: // unknown (possibly mouse backward) + button = MouseButtonBackward + case btn == coninput.FROM_LEFT_4TH_BUTTON_PRESSED: // unknown (possibly mouse forward) + button = MouseButtonForward + } + + return button, action +} + +func mouseEvent(p coninput.ButtonState, e coninput.MouseEventRecord) MouseMsg { + ev := MouseMsg{ + X: int(e.MousePositon.X), + Y: int(e.MousePositon.Y), + Alt: e.ControlKeyState.Contains(coninput.LEFT_ALT_PRESSED | coninput.RIGHT_ALT_PRESSED), + Ctrl: e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED | coninput.RIGHT_CTRL_PRESSED), + Shift: e.ControlKeyState.Contains(coninput.SHIFT_PRESSED), + } + switch e.EventFlags { + case coninput.CLICK, coninput.DOUBLE_CLICK: + ev.Button, ev.Action = mouseEventButton(p, e.ButtonState) + if ev.Action == MouseActionRelease { + ev.Type = MouseRelease + } + switch ev.Button { + case MouseButtonLeft: + ev.Type = MouseLeft + case MouseButtonMiddle: + ev.Type = MouseMiddle + case MouseButtonRight: + ev.Type = MouseRight + case MouseButtonBackward: + ev.Type = MouseBackward + case MouseButtonForward: + ev.Type = MouseForward + } + case coninput.MOUSE_WHEELED: + if e.WheelDirection > 0 { + ev.Button = MouseButtonWheelUp + ev.Type = MouseWheelUp + } else { + ev.Button = MouseButtonWheelDown + ev.Type = MouseWheelDown + } + case coninput.MOUSE_HWHEELED: + if e.WheelDirection > 0 { + ev.Button = MouseButtonWheelRight + ev.Type = MouseWheelRight + } else { + ev.Button = MouseButtonWheelLeft + ev.Type = MouseWheelLeft + } + case coninput.MOUSE_MOVED: + ev.Button, _ = mouseEventButton(p, e.ButtonState) + ev.Action = MouseActionMotion + ev.Type = MouseMotion + } + + return ev +} + +func keyType(e coninput.KeyEventRecord) KeyType { + code := e.VirtualKeyCode + + shiftPressed := e.ControlKeyState.Contains(coninput.SHIFT_PRESSED) + ctrlPressed := e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED | coninput.RIGHT_CTRL_PRESSED) + + switch code { + case coninput.VK_RETURN: + return KeyEnter + case coninput.VK_BACK: + return KeyBackspace + case coninput.VK_TAB: + if shiftPressed { + return KeyShiftTab + } + return KeyTab + case coninput.VK_SPACE: + return KeyRunes // this could be KeySpace but on unix space also produces KeyRunes + case coninput.VK_ESCAPE: + return KeyEscape + case coninput.VK_UP: + switch { + case shiftPressed && ctrlPressed: + return KeyCtrlShiftUp + case shiftPressed: + return KeyShiftUp + case ctrlPressed: + return KeyCtrlUp + default: + return KeyUp + } + case coninput.VK_DOWN: + switch { + case shiftPressed && ctrlPressed: + return KeyCtrlShiftDown + case shiftPressed: + return KeyShiftDown + case ctrlPressed: + return KeyCtrlDown + default: + return KeyDown + } + case coninput.VK_RIGHT: + switch { + case shiftPressed && ctrlPressed: + return KeyCtrlShiftRight + case shiftPressed: + return KeyShiftRight + case ctrlPressed: + return KeyCtrlRight + default: + return KeyRight + } + case coninput.VK_LEFT: + switch { + case shiftPressed && ctrlPressed: + return KeyCtrlShiftLeft + case shiftPressed: + return KeyShiftLeft + case ctrlPressed: + return KeyCtrlLeft + default: + return KeyLeft + } + case coninput.VK_HOME: + switch { + case shiftPressed && ctrlPressed: + return KeyCtrlShiftHome + case shiftPressed: + return KeyShiftHome + case ctrlPressed: + return KeyCtrlHome + default: + return KeyHome + } + case coninput.VK_END: + switch { + case shiftPressed && ctrlPressed: + return KeyCtrlShiftEnd + case shiftPressed: + return KeyShiftEnd + case ctrlPressed: + return KeyCtrlEnd + default: + return KeyEnd + } + case coninput.VK_PRIOR: + return KeyPgUp + case coninput.VK_NEXT: + return KeyPgDown + case coninput.VK_DELETE: + return KeyDelete + default: + if e.ControlKeyState&(coninput.LEFT_CTRL_PRESSED|coninput.RIGHT_CTRL_PRESSED) == 0 { + return KeyRunes + } + + switch e.Char { + case '@': + return KeyCtrlAt + case '\x01': + return KeyCtrlA + case '\x02': + return KeyCtrlB + case '\x03': + return KeyCtrlC + case '\x04': + return KeyCtrlD + case '\x05': + return KeyCtrlE + case '\x06': + return KeyCtrlF + case '\a': + return KeyCtrlG + case '\b': + return KeyCtrlH + case '\t': + return KeyCtrlI + case '\n': + return KeyCtrlJ + case '\v': + return KeyCtrlK + case '\f': + return KeyCtrlL + case '\r': + return KeyCtrlM + case '\x0e': + return KeyCtrlN + case '\x0f': + return KeyCtrlO + case '\x10': + return KeyCtrlP + case '\x11': + return KeyCtrlQ + case '\x12': + return KeyCtrlR + case '\x13': + return KeyCtrlS + case '\x14': + return KeyCtrlT + case '\x15': + return KeyCtrlU + case '\x16': + return KeyCtrlV + case '\x17': + return KeyCtrlW + case '\x18': + return KeyCtrlX + case '\x19': + return KeyCtrlY + case '\x1a': + return KeyCtrlZ + case '\x1b': + return KeyCtrlCloseBracket + case '\x1c': + return KeyCtrlBackslash + case '\x1f': + return KeyCtrlUnderscore + } + + switch code { + case coninput.VK_OEM_4: + return KeyCtrlOpenBracket + } + + return KeyRunes + } +} diff --git a/vendor/github.com/charmbracelet/bubbletea/mouse.go b/vendor/github.com/charmbracelet/bubbletea/mouse.go index add8d029..6ec51cc0 100644 --- a/vendor/github.com/charmbracelet/bubbletea/mouse.go +++ b/vendor/github.com/charmbracelet/bubbletea/mouse.go @@ -45,7 +45,7 @@ func (m MouseEvent) String() (s string) { s += "shift+" } - if m.Button == MouseButtonNone { + if m.Button == MouseButtonNone { //nolint:nestif if m.Action == MouseActionMotion || m.Action == MouseActionRelease { s += mouseActions[m.Action] } else { @@ -172,7 +172,7 @@ const ( func parseSGRMouseEvent(buf []byte) MouseEvent { str := string(buf[3:]) matches := mouseSGRRegex.FindStringSubmatch(str) - if len(matches) != 5 { + if len(matches) != 5 { //nolint:gomnd // Unreachable, we already checked the regex in `detectOneMsg`. panic("invalid mouse event") } @@ -288,7 +288,7 @@ func parseMouseButton(b int, isSGR bool) MouseEvent { m.Type = MouseForward case m.Action == MouseActionMotion: m.Type = MouseMotion - switch m.Button { + switch m.Button { //nolint:exhaustive case MouseButtonLeft: m.Type = MouseLeft case MouseButtonMiddle: diff --git a/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go b/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go index 1b1d4409..0bc4a172 100644 --- a/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go +++ b/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go @@ -2,20 +2,27 @@ package tea type nilRenderer struct{} -func (n nilRenderer) start() {} -func (n nilRenderer) stop() {} -func (n nilRenderer) kill() {} -func (n nilRenderer) write(_ string) {} -func (n nilRenderer) repaint() {} -func (n nilRenderer) clearScreen() {} -func (n nilRenderer) altScreen() bool { return false } -func (n nilRenderer) enterAltScreen() {} -func (n nilRenderer) exitAltScreen() {} -func (n nilRenderer) showCursor() {} -func (n nilRenderer) hideCursor() {} -func (n nilRenderer) enableMouseCellMotion() {} -func (n nilRenderer) disableMouseCellMotion() {} -func (n nilRenderer) enableMouseAllMotion() {} -func (n nilRenderer) disableMouseAllMotion() {} -func (n nilRenderer) enableMouseSGRMode() {} -func (n nilRenderer) disableMouseSGRMode() {} +func (n nilRenderer) start() {} +func (n nilRenderer) stop() {} +func (n nilRenderer) kill() {} +func (n nilRenderer) write(_ string) {} +func (n nilRenderer) repaint() {} +func (n nilRenderer) clearScreen() {} +func (n nilRenderer) altScreen() bool { return false } +func (n nilRenderer) enterAltScreen() {} +func (n nilRenderer) exitAltScreen() {} +func (n nilRenderer) showCursor() {} +func (n nilRenderer) hideCursor() {} +func (n nilRenderer) enableMouseCellMotion() {} +func (n nilRenderer) disableMouseCellMotion() {} +func (n nilRenderer) enableMouseAllMotion() {} +func (n nilRenderer) disableMouseAllMotion() {} +func (n nilRenderer) enableBracketedPaste() {} +func (n nilRenderer) disableBracketedPaste() {} +func (n nilRenderer) enableMouseSGRMode() {} +func (n nilRenderer) disableMouseSGRMode() {} +func (n nilRenderer) bracketedPasteActive() bool { return false } +func (n nilRenderer) setWindowTitle(_ string) {} +func (n nilRenderer) reportFocus() bool { return false } +func (n nilRenderer) enableReportFocus() {} +func (n nilRenderer) disableReportFocus() {} diff --git a/vendor/github.com/charmbracelet/bubbletea/options.go b/vendor/github.com/charmbracelet/bubbletea/options.go index 71e94493..4a56fc81 100644 --- a/vendor/github.com/charmbracelet/bubbletea/options.go +++ b/vendor/github.com/charmbracelet/bubbletea/options.go @@ -4,8 +4,6 @@ import ( "context" "io" "sync/atomic" - - "github.com/muesli/termenv" ) // ProgramOption is used to set options when initializing a Program. Program can @@ -29,11 +27,7 @@ func WithContext(ctx context.Context) ProgramOption { // won't need to use this. func WithOutput(output io.Writer) ProgramOption { return func(p *Program) { - if o, ok := output.(*termenv.Output); ok { - p.output = o - } else { - p.output = termenv.NewOutput(output, termenv.WithColorCache(true)) - } + p.output = output } } @@ -55,6 +49,23 @@ func WithInputTTY() ProgramOption { } } +// WithEnvironment sets the environment variables that the program will use. +// This useful when the program is running in a remote session (e.g. SSH) and +// you want to pass the environment variables from the remote session to the +// program. +// +// Example: +// +// var sess ssh.Session // ssh.Session is a type from the github.com/charmbracelet/ssh package +// pty, _, _ := sess.Pty() +// environ := append(sess.Environ(), "TERM="+pty.Term) +// p := tea.NewProgram(model, tea.WithEnvironment(environ) +func WithEnvironment(env []string) ProgramOption { + return func(p *Program) { + p.environ = env + } +} + // WithoutSignalHandler disables the signal handler that Bubble Tea sets up for // Programs. This is useful if you want to handle signals yourself. func WithoutSignalHandler() ProgramOption { @@ -101,6 +112,13 @@ func WithAltScreen() ProgramOption { } } +// WithoutBracketedPaste starts the program with bracketed paste disabled. +func WithoutBracketedPaste() ProgramOption { + return func(p *Program) { + p.startupOptions |= withoutBracketedPaste + } +} + // WithMouseCellMotion starts the program with the mouse enabled in "cell // motion" mode. // @@ -216,3 +234,12 @@ func WithFPS(fps int) ProgramOption { p.fps = fps } } + +// WithReportFocus enables reporting when the terminal gains and lost focus. +// +// You can then check for FocusMsg and BlurMsg in your model's Update method. +func WithReportFocus() ProgramOption { + return func(p *Program) { + p.startupOptions |= withReportFocus + } +} diff --git a/vendor/github.com/charmbracelet/bubbletea/renderer.go b/vendor/github.com/charmbracelet/bubbletea/renderer.go index 5a3ee3c4..9eb7943b 100644 --- a/vendor/github.com/charmbracelet/bubbletea/renderer.go +++ b/vendor/github.com/charmbracelet/bubbletea/renderer.go @@ -56,6 +56,29 @@ type renderer interface { // disableMouseSGRMode disables mouse extended mode (SGR). disableMouseSGRMode() + + // enableBracketedPaste enables bracketed paste, where characters + // inside the input are not interpreted when pasted as a whole. + enableBracketedPaste() + + // disableBracketedPaste disables bracketed paste. + disableBracketedPaste() + + // bracketedPasteActive reports whether bracketed paste mode is + // currently enabled. + bracketedPasteActive() bool + + // setWindowTitle sets the terminal window title. + setWindowTitle(string) + + // reportFocus returns whether reporting focus events is enabled. + reportFocus() bool + + // enableReportFocus reports focus events to the program. + enableReportFocus() + + // disableReportFocus stops reporting focus events to the program. + disableReportFocus() } // repaintMsg forces a full repaint. diff --git a/vendor/github.com/charmbracelet/bubbletea/screen.go b/vendor/github.com/charmbracelet/bubbletea/screen.go index d064222f..dfec48f0 100644 --- a/vendor/github.com/charmbracelet/bubbletea/screen.go +++ b/vendor/github.com/charmbracelet/bubbletea/screen.go @@ -116,6 +116,54 @@ func ShowCursor() Msg { // this message with ShowCursor. type showCursorMsg struct{} +// EnableBracketedPaste is a special command that tells the Bubble Tea program +// to accept bracketed paste input. +// +// Note that bracketed paste will be automatically disabled when the +// program quits. +func EnableBracketedPaste() Msg { + return enableBracketedPasteMsg{} +} + +// enableBracketedPasteMsg in an internal message signals that +// bracketed paste should be enabled. You can send an +// enableBracketedPasteMsg with EnableBracketedPaste. +type enableBracketedPasteMsg struct{} + +// DisableBracketedPaste is a special command that tells the Bubble Tea program +// to accept bracketed paste input. +// +// Note that bracketed paste will be automatically disabled when the +// program quits. +func DisableBracketedPaste() Msg { + return disableBracketedPasteMsg{} +} + +// disableBracketedPasteMsg in an internal message signals that +// bracketed paste should be disabled. You can send an +// disableBracketedPasteMsg with DisableBracketedPaste. +type disableBracketedPasteMsg struct{} + +// enableReportFocusMsg is an internal message that signals to enable focus +// reporting. You can send an enableReportFocusMsg with EnableReportFocus. +type enableReportFocusMsg struct{} + +// EnableReportFocus is a special command that tells the Bubble Tea program to +// report focus events to the program. +func EnableReportFocus() Msg { + return enableReportFocusMsg{} +} + +// disableReportFocusMsg is an internal message that signals to disable focus +// reporting. You can send an disableReportFocusMsg with DisableReportFocus. +type disableReportFocusMsg struct{} + +// DisableReportFocus is a special command that tells the Bubble Tea program to +// stop reporting focus events to the program. +func DisableReportFocus() Msg { + return disableReportFocusMsg{} +} + // EnterAltScreen enters the alternate screen buffer, which consumes the entire // terminal window. ExitAltScreen will return the terminal to its former state. // @@ -123,6 +171,8 @@ type showCursorMsg struct{} func (p *Program) EnterAltScreen() { if p.renderer != nil { p.renderer.enterAltScreen() + } else { + p.startupOptions |= withAltScreen } } @@ -132,6 +182,8 @@ func (p *Program) EnterAltScreen() { func (p *Program) ExitAltScreen() { if p.renderer != nil { p.renderer.exitAltScreen() + } else { + p.startupOptions &^= withAltScreen } } @@ -140,7 +192,11 @@ func (p *Program) ExitAltScreen() { // // Deprecated: Use the WithMouseCellMotion ProgramOption instead. func (p *Program) EnableMouseCellMotion() { - p.renderer.enableMouseCellMotion() + if p.renderer != nil { + p.renderer.enableMouseCellMotion() + } else { + p.startupOptions |= withMouseCellMotion + } } // DisableMouseCellMotion disables Mouse Cell Motion tracking. This will be @@ -148,7 +204,11 @@ func (p *Program) EnableMouseCellMotion() { // // Deprecated: The mouse will automatically be disabled when the program exits. func (p *Program) DisableMouseCellMotion() { - p.renderer.disableMouseCellMotion() + if p.renderer != nil { + p.renderer.disableMouseCellMotion() + } else { + p.startupOptions &^= withMouseCellMotion + } } // EnableMouseAllMotion enables mouse click, release, wheel and motion events, @@ -157,7 +217,11 @@ func (p *Program) DisableMouseCellMotion() { // // Deprecated: Use the WithMouseAllMotion ProgramOption instead. func (p *Program) EnableMouseAllMotion() { - p.renderer.enableMouseAllMotion() + if p.renderer != nil { + p.renderer.enableMouseAllMotion() + } else { + p.startupOptions |= withMouseAllMotion + } } // DisableMouseAllMotion disables All Motion mouse tracking. This will be @@ -165,10 +229,20 @@ func (p *Program) EnableMouseAllMotion() { // // Deprecated: The mouse will automatically be disabled when the program exits. func (p *Program) DisableMouseAllMotion() { - p.renderer.disableMouseAllMotion() + if p.renderer != nil { + p.renderer.disableMouseAllMotion() + } else { + p.startupOptions &^= withMouseAllMotion + } } // SetWindowTitle sets the terminal window title. +// +// Deprecated: Use the SetWindowTitle command instead. func (p *Program) SetWindowTitle(title string) { - p.output.SetWindowTitle(title) + if p.renderer != nil { + p.renderer.setWindowTitle(title) + } else { + p.startupTitle = title + } } diff --git a/vendor/github.com/charmbracelet/bubbletea/signals_unix.go b/vendor/github.com/charmbracelet/bubbletea/signals_unix.go index 826f58b9..40954038 100644 --- a/vendor/github.com/charmbracelet/bubbletea/signals_unix.go +++ b/vendor/github.com/charmbracelet/bubbletea/signals_unix.go @@ -1,5 +1,5 @@ -//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix -// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos +// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix zos package tea diff --git a/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go b/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go index 1573a1c2..59448e1d 100644 --- a/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go +++ b/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go @@ -8,9 +8,8 @@ import ( "sync" "time" + "github.com/charmbracelet/x/ansi" "github.com/muesli/ansi/compressor" - "github.com/muesli/reflow/truncate" - "github.com/muesli/termenv" ) const ( @@ -27,7 +26,7 @@ const ( // to exclude ranges of lines, allowing them to be written to directly. type standardRenderer struct { mtx *sync.Mutex - out *termenv.Output + out io.Writer buf bytes.Buffer queuedMessageLines []string @@ -45,6 +44,12 @@ type standardRenderer struct { // essentially whether or not we're using the full size of the terminal altScreenActive bool + // whether or not we're currently using bracketed paste + bpActive bool + + // reportingFocus whether reporting focus events is enabled + reportingFocus bool + // renderer dimensions; usually the size of the window width int height int @@ -55,7 +60,7 @@ type standardRenderer struct { // newRenderer creates a new renderer. Normally you'll want to initialize it // with os.Stdout as the first argument. -func newRenderer(out *termenv.Output, useANSICompressor bool, fps int) renderer { +func newRenderer(out io.Writer, useANSICompressor bool, fps int) renderer { if fps < 1 { fps = defaultFPS } else if fps > maxFPS { @@ -70,7 +75,7 @@ func newRenderer(out *termenv.Output, useANSICompressor bool, fps int) renderer queuedMessageLines: []string{}, } if r.useANSICompressor { - r.out = termenv.NewOutput(&compressor.Writer{Forward: out}) + r.out = &compressor.Writer{Forward: out} } return r } @@ -105,15 +110,22 @@ func (r *standardRenderer) stop() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.ClearLine() + r.execute(ansi.EraseEntireLine) + // Move the cursor back to the beginning of the line + r.execute("\r") if r.useANSICompressor { - if w, ok := r.out.TTY().(io.WriteCloser); ok { + if w, ok := r.out.(io.WriteCloser); ok { _ = w.Close() } } } +// execute writes a sequence to the terminal. +func (r *standardRenderer) execute(seq string) { + _, _ = io.WriteString(r.out, seq) +} + // kill halts the renderer. The final frame will not be rendered. func (r *standardRenderer) kill() { // Stop the renderer before acquiring the mutex to avoid a deadlock. @@ -124,7 +136,9 @@ func (r *standardRenderer) kill() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.ClearLine() + r.execute(ansi.EraseEntireLine) + // Move the cursor back to the beginning of the line + r.execute("\r") } // listen waits for ticks on the ticker, or a signal to stop the renderer. @@ -153,7 +167,6 @@ func (r *standardRenderer) flush() { // Output buffer buf := &bytes.Buffer{} - out := termenv.NewOutput(buf) newLines := strings.Split(r.buf.String(), "\n") @@ -170,25 +183,24 @@ func (r *standardRenderer) flush() { skipLines := make(map[int]struct{}) flushQueuedMessages := len(r.queuedMessageLines) > 0 && !r.altScreenActive - // Add any queued messages to this render - if flushQueuedMessages { - newLines = append(r.queuedMessageLines, newLines...) - r.queuedMessageLines = []string{} - } - // Clear any lines we painted in the last render. if r.linesRendered > 0 { for i := r.linesRendered - 1; i > 0; i-- { - // If the number of lines we want to render hasn't increased and - // new line is the same as the old line we can skip rendering for - // this line as a performance optimization. - if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) { + // if we are clearing queued messages, we want to clear all lines, since + // printing messages allows for native terminal word-wrap, we + // don't have control over the queued lines + if flushQueuedMessages { + buf.WriteString(ansi.EraseEntireLine) + } else if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) { + // If the number of lines we want to render hasn't increased and + // new line is the same as the old line we can skip rendering for + // this line as a performance optimization. skipLines[i] = struct{}{} } else if _, exists := r.ignoreLines[i]; !exists { - out.ClearLine() + buf.WriteString(ansi.EraseEntireLine) } - out.CursorUp(1) + buf.WriteString(ansi.CursorUp1) } if _, exists := r.ignoreLines[0]; !exists { @@ -201,8 +213,8 @@ func (r *standardRenderer) flush() { // standard (whereas others are proprietary to, say, VT100/VT52). // If cursor previous line (ESC[ + + F) were better supported // we could use that above to eliminate this step. - out.CursorBack(r.width) - out.ClearLine() + buf.WriteString(ansi.CursorLeft(r.width)) + buf.WriteString(ansi.EraseEntireLine) } } @@ -212,14 +224,30 @@ func (r *standardRenderer) flush() { skipLines[k] = v } + if flushQueuedMessages { + // Dump the lines we've queued up for printing + for _, line := range r.queuedMessageLines { + _, _ = buf.WriteString(line) + _, _ = buf.WriteString("\r\n") + } + // clear the queued message lines + r.queuedMessageLines = []string{} + } + // Paint new lines for i := 0; i < len(newLines); i++ { if _, skip := skipLines[i]; skip { // Unless this is the last line, move the cursor down. if i < len(newLines)-1 { - out.CursorDown(1) + buf.WriteString(ansi.CursorDown1) } } else { + if i == 0 && r.lastRender == "" { + // On first render, reset the cursor to the start of the line + // before writing anything. + buf.WriteByte('\r') + } + line := newLines[i] // Truncate lines wider than the width of the window to avoid @@ -230,13 +258,13 @@ func (r *standardRenderer) flush() { // program initialization, so after a resize this won't perform // correctly (signal SIGWINCH is not supported on Windows). if r.width > 0 { - line = truncate.String(line, uint(r.width)) + line = ansi.Truncate(line, r.width, "") } - _, _ = out.WriteString(line) + _, _ = buf.WriteString(line) if i < len(newLines)-1 { - _, _ = out.WriteString("\r\n") + _, _ = buf.WriteString("\r\n") } } } @@ -248,9 +276,9 @@ func (r *standardRenderer) flush() { // This case fixes a bug in macOS terminal. In other terminals the // other case seems to do the job regardless of whether or not we're // using the full terminal window. - out.MoveCursor(r.linesRendered, 0) + buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) } else { - out.CursorBack(r.width) + buf.WriteString(ansi.CursorLeft(r.width)) } _, _ = r.out.Write(buf.Bytes()) @@ -284,8 +312,8 @@ func (r *standardRenderer) clearScreen() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.ClearScreen() - r.out.MoveCursor(1, 1) + r.execute(ansi.EraseEntireDisplay) + r.execute(ansi.MoveCursorOrigin) r.repaint() } @@ -306,7 +334,7 @@ func (r *standardRenderer) enterAltScreen() { } r.altScreenActive = true - r.out.AltScreen() + r.execute(ansi.EnableAltScreenBuffer) // Ensure that the terminal is cleared, even when it doesn't support // alt screen (or alt screen support is disabled, like GNU screen by @@ -314,16 +342,16 @@ func (r *standardRenderer) enterAltScreen() { // // Note: we can't use r.clearScreen() here because the mutex is already // locked. - r.out.ClearScreen() - r.out.MoveCursor(1, 1) + r.execute(ansi.EraseEntireDisplay) + r.execute(ansi.MoveCursorOrigin) // cmd.exe and other terminals keep separate cursor states for the AltScreen // and the main buffer. We have to explicitly reset the cursor visibility // whenever we enter AltScreen. if r.cursorHidden { - r.out.HideCursor() + r.execute(ansi.HideCursor) } else { - r.out.ShowCursor() + r.execute(ansi.ShowCursor) } r.repaint() @@ -338,15 +366,15 @@ func (r *standardRenderer) exitAltScreen() { } r.altScreenActive = false - r.out.ExitAltScreen() + r.execute(ansi.DisableAltScreenBuffer) // cmd.exe and other terminals keep separate cursor states for the AltScreen // and the main buffer. We have to explicitly reset the cursor visibility // whenever we exit AltScreen. if r.cursorHidden { - r.out.HideCursor() + r.execute(ansi.HideCursor) } else { - r.out.ShowCursor() + r.execute(ansi.ShowCursor) } r.repaint() @@ -357,7 +385,7 @@ func (r *standardRenderer) showCursor() { defer r.mtx.Unlock() r.cursorHidden = false - r.out.ShowCursor() + r.execute(ansi.ShowCursor) } func (r *standardRenderer) hideCursor() { @@ -365,49 +393,100 @@ func (r *standardRenderer) hideCursor() { defer r.mtx.Unlock() r.cursorHidden = true - r.out.HideCursor() + r.execute(ansi.HideCursor) } func (r *standardRenderer) enableMouseCellMotion() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.EnableMouseCellMotion() + r.execute(ansi.EnableMouseCellMotion) } func (r *standardRenderer) disableMouseCellMotion() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.DisableMouseCellMotion() + r.execute(ansi.DisableMouseCellMotion) } func (r *standardRenderer) enableMouseAllMotion() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.EnableMouseAllMotion() + r.execute(ansi.EnableMouseAllMotion) } func (r *standardRenderer) disableMouseAllMotion() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.DisableMouseAllMotion() + r.execute(ansi.DisableMouseAllMotion) } func (r *standardRenderer) enableMouseSGRMode() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.EnableMouseExtendedMode() + r.execute(ansi.EnableMouseSgrExt) } func (r *standardRenderer) disableMouseSGRMode() { r.mtx.Lock() defer r.mtx.Unlock() - r.out.DisableMouseExtendedMode() + r.execute(ansi.DisableMouseSgrExt) +} + +func (r *standardRenderer) enableBracketedPaste() { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.execute(ansi.EnableBracketedPaste) + r.bpActive = true +} + +func (r *standardRenderer) disableBracketedPaste() { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.execute(ansi.DisableBracketedPaste) + r.bpActive = false +} + +func (r *standardRenderer) bracketedPasteActive() bool { + r.mtx.Lock() + defer r.mtx.Unlock() + + return r.bpActive +} + +func (r *standardRenderer) enableReportFocus() { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.execute(ansi.EnableReportFocus) + r.reportingFocus = true +} + +func (r *standardRenderer) disableReportFocus() { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.execute(ansi.DisableReportFocus) + r.reportingFocus = false +} + +func (r *standardRenderer) reportFocus() bool { + r.mtx.Lock() + defer r.mtx.Unlock() + + return r.reportingFocus +} + +// setWindowTitle sets the terminal window title. +func (r *standardRenderer) setWindowTitle(title string) { + r.execute(ansi.SetWindowTitle(title)) } // setIgnoredLines specifies lines not to be touched by the standard Bubble Tea @@ -430,15 +509,14 @@ func (r *standardRenderer) setIgnoredLines(from int, to int) { // Erase ignored lines if r.linesRendered > 0 { buf := &bytes.Buffer{} - out := termenv.NewOutput(buf) for i := r.linesRendered - 1; i >= 0; i-- { if _, exists := r.ignoreLines[i]; exists { - out.ClearLine() + buf.WriteString(ansi.EraseEntireLine) } - out.CursorUp(1) + buf.WriteString(ansi.CursorUp1) } - out.MoveCursor(r.linesRendered, 0) // put cursor back + buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) // put cursor back _, _ = r.out.Write(buf.Bytes()) } } @@ -473,16 +551,15 @@ func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary defer r.mtx.Unlock() buf := &bytes.Buffer{} - out := termenv.NewOutput(buf) - out.ChangeScrollingRegion(topBoundary, bottomBoundary) - out.MoveCursor(topBoundary, 0) - out.InsertLines(len(lines)) - _, _ = out.WriteString(strings.Join(lines, "\r\n")) - out.ChangeScrollingRegion(0, r.height) + buf.WriteString(ansi.SetScrollingRegion(topBoundary, bottomBoundary)) + buf.WriteString(ansi.MoveCursor(topBoundary, 0)) + buf.WriteString(ansi.InsertLine(len(lines))) + _, _ = buf.WriteString(strings.Join(lines, "\r\n")) + buf.WriteString(ansi.SetScrollingRegion(0, r.height)) // Move cursor back to where the main rendering routine expects it to be - out.MoveCursor(r.linesRendered, 0) + buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) _, _ = r.out.Write(buf.Bytes()) } @@ -501,15 +578,14 @@ func (r *standardRenderer) insertBottom(lines []string, topBoundary, bottomBound defer r.mtx.Unlock() buf := &bytes.Buffer{} - out := termenv.NewOutput(buf) - out.ChangeScrollingRegion(topBoundary, bottomBoundary) - out.MoveCursor(bottomBoundary, 0) - _, _ = out.WriteString("\r\n" + strings.Join(lines, "\r\n")) - out.ChangeScrollingRegion(0, r.height) + buf.WriteString(ansi.SetScrollingRegion(topBoundary, bottomBoundary)) + buf.WriteString(ansi.MoveCursor(bottomBoundary, 0)) + _, _ = buf.WriteString("\r\n" + strings.Join(lines, "\r\n")) + buf.WriteString(ansi.SetScrollingRegion(0, r.height)) // Move cursor back to where the main rendering routine expects it to be - out.MoveCursor(r.linesRendered, 0) + buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) _, _ = r.out.Write(buf.Bytes()) } diff --git a/vendor/github.com/charmbracelet/bubbletea/tea.go b/vendor/github.com/charmbracelet/bubbletea/tea.go index f18cb87c..5ed97076 100644 --- a/vendor/github.com/charmbracelet/bubbletea/tea.go +++ b/vendor/github.com/charmbracelet/bubbletea/tea.go @@ -21,10 +21,8 @@ import ( "sync/atomic" "syscall" - "github.com/containerd/console" - isatty "github.com/mattn/go-isatty" + "github.com/charmbracelet/x/term" "github.com/muesli/cancelreader" - "github.com/muesli/termenv" "golang.org/x/sync/errgroup" ) @@ -81,7 +79,7 @@ func (i inputType) String() string { // generally set with ProgramOptions. // // The options here are treated as bits. -type startupOptions byte +type startupOptions int16 func (s startupOptions) has(option startupOptions) bool { return s&option != 0 @@ -93,26 +91,28 @@ const ( withMouseAllMotion withANSICompressor withoutSignalHandler - // Catching panics is incredibly useful for restoring the terminal to a // usable state after a panic occurs. When this is set, Bubble Tea will // recover from panics, print the stack trace, and disable raw mode. This // feature is on by default. withoutCatchPanics + withoutBracketedPaste + withReportFocus ) -// handlers manages series of channels returned by various processes. It allows -// us to wait for those processes to terminate before exiting the program. -type handlers []chan struct{} +// channelHandlers manages the series of channels returned by various processes. +// It allows us to wait for those processes to terminate before exiting the +// program. +type channelHandlers []chan struct{} // Adds a channel to the list of handlers. We wait for all handlers to terminate // gracefully on shutdown. -func (h *handlers) add(ch chan struct{}) { +func (h *channelHandlers) add(ch chan struct{}) { *h = append(*h, ch) } // shutdown waits for all handlers to terminate. -func (h handlers) shutdown() { +func (h channelHandlers) shutdown() { var wg sync.WaitGroup for _, ch := range h { wg.Add(1) @@ -132,6 +132,10 @@ type Program struct { // treated as bits. These options can be set via various ProgramOptions. startupOptions startupOptions + // startupTitle is the title that will be set on the terminal when the + // program starts. + startupTitle string + inputType inputType ctx context.Context @@ -142,28 +146,29 @@ type Program struct { finished chan struct{} // where to send output, this will usually be os.Stdout. - output *termenv.Output - restoreOutput func() error - renderer renderer + output io.Writer + // ttyOutput is null if output is not a TTY. + ttyOutput term.File + previousOutputState *term.State + renderer renderer + + // the environment variables for the program, defaults to os.Environ(). + environ []string // where to read inputs from, this will usually be os.Stdin. - input io.Reader - cancelReader cancelreader.CancelReader - readLoopDone chan struct{} - console console.Console + input io.Reader + // ttyInput is null if input is not a TTY. + ttyInput term.File + previousTtyInputState *term.State + cancelReader cancelreader.CancelReader + readLoopDone chan struct{} // was the altscreen active before releasing the terminal? altScreenWasActive bool ignoreSignals uint32 - // Stores the original reference to stdin for cases where input is not a - // TTY on windows and we've automatically opened CONIN$ to receive input. - // When the program exits this will be restored. - // - // Lint ignore note: the linter will find false positive on unix systems - // as this value only comes into play on Windows, hence the ignore comment - // below. - windowsStdin *os.File //nolint:golint,structcheck,unused + bpWasActive bool // was the bracketed paste mode active before releasing the terminal? + reportFocus bool // was focus reporting active before releasing the terminal? filter func(Model, Msg) Msg @@ -181,6 +186,22 @@ func Quit() Msg { // Quit. type QuitMsg struct{} +// Suspend is a special command that tells the Bubble Tea program to suspend. +func Suspend() Msg { + return SuspendMsg{} +} + +// SuspendMsg signals the program should suspend. +// This usually happens when ctrl+z is pressed on common programs, but since +// bubbletea puts the terminal in raw mode, we need to handle it in a +// per-program basis. +// You can send this message with Suspend. +type SuspendMsg struct{} + +// ResumeMsg can be listen to to do something once a program is resumed back +// from a suspend state. +type ResumeMsg struct{} + // NewProgram creates a new Program. func NewProgram(model Model, opts ...ProgramOption) *Program { p := &Program{ @@ -203,13 +224,13 @@ func NewProgram(model Model, opts ...ProgramOption) *Program { // if no output was set, set it to stdout if p.output == nil { - p.output = termenv.DefaultOutput() - - // cache detected color values - termenv.WithColorCache(true)(p.output) + p.output = os.Stdout } - p.restoreOutput, _ = termenv.EnableVirtualTerminalProcessing(p.output) + // if no environment was set, set it to os.Environ() + if p.environ == nil { + p.environ = os.Environ() + } return p } @@ -254,7 +275,7 @@ func (p *Program) handleSignals() chan struct{} { func (p *Program) handleResize() chan struct{} { ch := make(chan struct{}) - if f, ok := p.output.TTY().(*os.File); ok && isatty.IsTerminal(f.Fd()) { + if p.ttyOutput != nil { // Get the initial terminal size and send it to the program. go p.checkResize() @@ -332,6 +353,11 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { case QuitMsg: return model, nil + case SuspendMsg: + if suspendSupported { + p.suspend() + } + case clearScreenMsg: p.renderer.clearScreen() @@ -360,6 +386,18 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { case hideCursorMsg: p.renderer.hideCursor() + case enableBracketedPasteMsg: + p.renderer.enableBracketedPaste() + + case disableBracketedPasteMsg: + p.renderer.disableBracketedPaste() + + case enableReportFocusMsg: + p.renderer.enableReportFocus() + + case disableReportFocusMsg: + p.renderer.disableReportFocus() + case execMsg: // NB: this blocks. p.exec(msg.cmd, msg.fn) @@ -400,6 +438,9 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { case setWindowTitleMsg: p.SetWindowTitle(string(msg)) + + case windowSizeMsg: + go p.checkResize() } // Process internal messages for the renderer. @@ -419,7 +460,7 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { // terminated by either [Program.Quit], [Program.Kill], or its signal handler. // Returns the final model. func (p *Program) Run() (Model, error) { - handlers := handlers{} + handlers := channelHandlers{} cmds := make(chan Cmd) p.errs = make(chan error) p.finished = make(chan struct{}, 1) @@ -436,11 +477,11 @@ func (p *Program) Run() (Model, error) { // piped in or redirected to the application. // // To disable input entirely pass nil to the [WithInput] program option. - f, isFile := p.input.(*os.File) + f, isFile := p.input.(term.File) if !isFile { break } - if isatty.IsTerminal(f.Fd()) { + if term.IsTerminal(f.Fd()) { break } @@ -493,9 +534,15 @@ func (p *Program) Run() (Model, error) { } // Honor program startup options. + if p.startupTitle != "" { + p.renderer.setWindowTitle(p.startupTitle) + } if p.startupOptions&withAltScreen != 0 { p.renderer.enterAltScreen() } + if p.startupOptions&withoutBracketedPaste == 0 { + p.renderer.enableBracketedPaste() + } if p.startupOptions&withMouseCellMotion != 0 { p.renderer.enableMouseCellMotion() p.renderer.enableMouseSGRMode() @@ -503,6 +550,12 @@ func (p *Program) Run() (Model, error) { p.renderer.enableMouseAllMotion() p.renderer.enableMouseSGRMode() } + if p.startupOptions&withReportFocus != 0 { + p.renderer.enableReportFocus() + } + + // Start the renderer. + p.renderer.start() // Initialize the program. model := p.initialModel @@ -520,9 +573,6 @@ func (p *Program) Run() (Model, error) { }() } - // Start the renderer. - p.renderer.start() - // Render the initial view. p.renderer.write(model.View()) @@ -543,7 +593,7 @@ func (p *Program) Run() (Model, error) { model, err := p.eventLoop(model, cmds) killed := p.ctx.Err() != nil if killed { - err = ErrProgramKilled + err = fmt.Errorf("%w: %s", ErrProgramKilled, p.ctx.Err()) } else { // Ensure we rendered the final state of the model. p.renderer.write(model.View()) @@ -638,9 +688,6 @@ func (p *Program) shutdown(kill bool) { } _ = p.restoreTerminalState() - if p.restoreOutput != nil { - _ = p.restoreOutput() - } p.finished <- struct{}{} } @@ -648,14 +695,19 @@ func (p *Program) shutdown(kill bool) { // reader. You can return control to the Program with RestoreTerminal. func (p *Program) ReleaseTerminal() error { atomic.StoreUint32(&p.ignoreSignals, 1) - p.cancelReader.Cancel() + if p.cancelReader != nil { + p.cancelReader.Cancel() + } + p.waitForReadLoop() if p.renderer != nil { p.renderer.stop() + p.altScreenWasActive = p.renderer.altScreen() + p.bpWasActive = p.renderer.bracketedPasteActive() + p.reportFocus = p.renderer.reportFocus() } - p.altScreenWasActive = p.renderer.altScreen() return p.restoreTerminalState() } @@ -671,7 +723,6 @@ func (p *Program) RestoreTerminal() error { if err := p.initCancelReader(); err != nil { return err } - if p.altScreenWasActive { p.renderer.enterAltScreen() } else { @@ -681,6 +732,12 @@ func (p *Program) RestoreTerminal() error { if p.renderer != nil { p.renderer.start() } + if p.bpWasActive { + p.renderer.enableBracketedPaste() + } + if p.reportFocus { + p.renderer.enableReportFocus() + } // If the output is a terminal, it may have been resized while another // process was at the foreground, in which case we may not have received diff --git a/vendor/github.com/charmbracelet/bubbletea/tea_init.go b/vendor/github.com/charmbracelet/bubbletea/tea_init.go new file mode 100644 index 00000000..19b6cc39 --- /dev/null +++ b/vendor/github.com/charmbracelet/bubbletea/tea_init.go @@ -0,0 +1,22 @@ +package tea + +import ( + "github.com/charmbracelet/lipgloss" +) + +func init() { + // XXX: This is a workaround to make assure that Lip Gloss and Termenv + // query the terminal before any Bubble Tea Program runs and acquires the + // terminal. Without this, Programs that use Lip Gloss/Termenv might hang + // while waiting for a a [termenv.OSCTimeout] while querying the terminal + // for its background/foreground colors. + // + // This happens because Bubble Tea acquires the terminal before termenv + // reads any responses. + // + // Note that this will only affect programs running on the default IO i.e. + // [os.Stdout] and [os.Stdin]. + // + // This workaround will be removed in v2. + _ = lipgloss.HasDarkBackground() +} diff --git a/vendor/github.com/charmbracelet/bubbletea/tty.go b/vendor/github.com/charmbracelet/bubbletea/tty.go index 01f084d4..02507782 100644 --- a/vendor/github.com/charmbracelet/bubbletea/tty.go +++ b/vendor/github.com/charmbracelet/bubbletea/tty.go @@ -4,26 +4,32 @@ import ( "errors" "fmt" "io" - "os" "time" - isatty "github.com/mattn/go-isatty" - localereader "github.com/mattn/go-localereader" + "github.com/charmbracelet/x/term" "github.com/muesli/cancelreader" - "golang.org/x/term" ) +func (p *Program) suspend() { + if err := p.ReleaseTerminal(); err != nil { + // If we can't release input, abort. + return + } + + suspendProcess() + + _ = p.RestoreTerminal() + go p.Send(ResumeMsg{}) +} + func (p *Program) initTerminal() error { - err := p.initInput() - if err != nil { - return err + if _, ok := p.renderer.(*nilRenderer); ok { + // No need to initialize the terminal if we're not rendering + return nil } - if p.console != nil { - err = p.console.SetRaw() - if err != nil { - return fmt.Errorf("error entering raw mode: %w", err) - } + if err := p.initInput(); err != nil { + return err } p.renderer.hideCursor() @@ -34,9 +40,14 @@ func (p *Program) initTerminal() error { // Bubble Tea program. func (p *Program) restoreTerminalState() error { if p.renderer != nil { + p.renderer.disableBracketedPaste() p.renderer.showCursor() p.disableMouse() + if p.renderer.reportFocus() { + p.renderer.disableReportFocus() + } + if p.renderer.altScreen() { p.renderer.exitAltScreen() @@ -45,20 +56,28 @@ func (p *Program) restoreTerminalState() error { } } - if p.console != nil { - err := p.console.Reset() - if err != nil { - return fmt.Errorf("error restoring terminal state: %w", err) + return p.restoreInput() +} + +// restoreInput restores the tty input to its original state. +func (p *Program) restoreInput() error { + if p.ttyInput != nil && p.previousTtyInputState != nil { + if err := term.Restore(p.ttyInput.Fd(), p.previousTtyInputState); err != nil { + return fmt.Errorf("error restoring console: %w", err) } } - - return p.restoreInput() + if p.ttyOutput != nil && p.previousOutputState != nil { + if err := term.Restore(p.ttyOutput.Fd(), p.previousOutputState); err != nil { + return fmt.Errorf("error restoring console: %w", err) + } + } + return nil } // initCancelReader (re)commences reading inputs. func (p *Program) initCancelReader() error { var err error - p.cancelReader, err = cancelreader.NewReader(p.input) + p.cancelReader, err = newInputReader(p.input) if err != nil { return fmt.Errorf("error creating cancelreader: %w", err) } @@ -72,8 +91,7 @@ func (p *Program) initCancelReader() error { func (p *Program) readLoop() { defer close(p.readLoopDone) - input := localereader.NewReader(p.cancelReader) - err := readInputs(p.ctx, p.msgs, input) + err := readInputs(p.ctx, p.msgs, p.cancelReader) if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) { select { case <-p.ctx.Done(): @@ -96,13 +114,12 @@ func (p *Program) waitForReadLoop() { // checkResize detects the current size of the output and informs the program // via a WindowSizeMsg. func (p *Program) checkResize() { - f, ok := p.output.TTY().(*os.File) - if !ok || !isatty.IsTerminal(f.Fd()) { + if p.ttyOutput == nil { // can't query window size return } - w, h, err := term.GetSize(int(f.Fd())) + w, h, err := term.GetSize(p.ttyOutput.Fd()) if err != nil { select { case <-p.ctx.Done(): diff --git a/vendor/github.com/charmbracelet/bubbletea/tty_unix.go b/vendor/github.com/charmbracelet/bubbletea/tty_unix.go index a3a25b8f..5cbb4fe1 100644 --- a/vendor/github.com/charmbracelet/bubbletea/tty_unix.go +++ b/vendor/github.com/charmbracelet/bubbletea/tty_unix.go @@ -1,38 +1,31 @@ -//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix -// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos +// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix zos package tea import ( "fmt" "os" + "os/signal" + "syscall" - "github.com/containerd/console" + "github.com/charmbracelet/x/term" ) -func (p *Program) initInput() error { - // If input's a file, use console to manage it - if f, ok := p.input.(*os.File); ok { - c, err := console.ConsoleFromFile(f) +func (p *Program) initInput() (err error) { + // Check if input is a terminal + if f, ok := p.input.(term.File); ok && term.IsTerminal(f.Fd()) { + p.ttyInput = f + p.previousTtyInputState, err = term.MakeRaw(p.ttyInput.Fd()) if err != nil { - return nil //nolint:nilerr // ignore error, this was just a test + return fmt.Errorf("error entering raw mode: %w", err) } - p.console = c } - return nil -} - -// On unix systems, RestoreInput closes any TTYs we opened for input. Note that -// we don't do this on Windows as it causes the prompt to not be drawn until -// the terminal receives a keypress rather than appearing promptly after the -// program exits. -func (p *Program) restoreInput() error { - if p.console != nil { - if err := p.console.Reset(); err != nil { - return fmt.Errorf("error restoring console: %w", err) - } + if f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) { + p.ttyOutput = f } + return nil } @@ -43,3 +36,14 @@ func openInputTTY() (*os.File, error) { } return f, nil } + +const suspendSupported = true + +// Send SIGTSTP to the entire process group. +func suspendProcess() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGCONT) + _ = syscall.Kill(0, syscall.SIGTSTP) + // blocks until a CONT happens... + <-c +} diff --git a/vendor/github.com/charmbracelet/bubbletea/tty_windows.go b/vendor/github.com/charmbracelet/bubbletea/tty_windows.go index be415aef..a3a2525b 100644 --- a/vendor/github.com/charmbracelet/bubbletea/tty_windows.go +++ b/vendor/github.com/charmbracelet/bubbletea/tty_windows.go @@ -4,44 +4,65 @@ package tea import ( + "fmt" "os" - "github.com/containerd/console" + "github.com/charmbracelet/x/term" + "golang.org/x/sys/windows" ) -func (p *Program) initInput() error { - // If input's a file, use console to manage it - if f, ok := p.input.(*os.File); ok { - // Save a reference to the current stdin then replace stdin with our - // input. We do this so we can hand input off to containerd/console to - // set raw mode, and do it in this fashion because the method - // console.ConsoleFromFile isn't supported on Windows. - p.windowsStdin = os.Stdin - os.Stdin = f - - // Note: this will panic if it fails. - c := console.Current() - p.console = c +func (p *Program) initInput() (err error) { + // Save stdin state and enable VT input + // We also need to enable VT + // input here. + if f, ok := p.input.(term.File); ok && term.IsTerminal(f.Fd()) { + p.ttyInput = f + p.previousTtyInputState, err = term.MakeRaw(p.ttyInput.Fd()) + if err != nil { + return err + } + + // Enable VT input + var mode uint32 + if err := windows.GetConsoleMode(windows.Handle(p.ttyInput.Fd()), &mode); err != nil { + return fmt.Errorf("error getting console mode: %w", err) + } + + if err := windows.SetConsoleMode(windows.Handle(p.ttyInput.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil { + return fmt.Errorf("error setting console mode: %w", err) + } } - return nil -} + // Save output screen buffer state and enable VT processing. + if f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) { + p.ttyOutput = f + p.previousOutputState, err = term.GetState(f.Fd()) + if err != nil { + return err + } -// restoreInput restores stdout in the event that we placed it aside to handle -// input with CONIN$, above. -func (p *Program) restoreInput() error { - if p.windowsStdin != nil { - os.Stdin = p.windowsStdin + var mode uint32 + if err := windows.GetConsoleMode(windows.Handle(p.ttyOutput.Fd()), &mode); err != nil { + return fmt.Errorf("error getting console mode: %w", err) + } + + if err := windows.SetConsoleMode(windows.Handle(p.ttyOutput.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil { + return fmt.Errorf("error setting console mode: %w", err) + } } - return nil + return } // Open the Windows equivalent of a TTY. func openInputTTY() (*os.File, error) { - f, err := os.OpenFile("CONIN$", os.O_RDWR, 0644) + f, err := os.OpenFile("CONIN$", os.O_RDWR, 0o644) if err != nil { return nil, err } return f, nil } + +const suspendSupported = false + +func suspendProcess() {} diff --git a/vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml b/vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml index ef456e06..1b6824bb 100644 --- a/vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml +++ b/vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml @@ -23,7 +23,6 @@ linters: - gomnd - gomoddirectives - goprintffuncname - - ifshort # - lll - misspell - nakedret diff --git a/vendor/github.com/charmbracelet/lipgloss/.golangci.yml b/vendor/github.com/charmbracelet/lipgloss/.golangci.yml index a5a91d0d..3affce91 100644 --- a/vendor/github.com/charmbracelet/lipgloss/.golangci.yml +++ b/vendor/github.com/charmbracelet/lipgloss/.golangci.yml @@ -16,6 +16,7 @@ linters: enable: - bodyclose - exportloopref + - gofumpt - goimports - gosec - nilerr diff --git a/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml b/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml new file mode 100644 index 00000000..c61970e0 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml @@ -0,0 +1,5 @@ +includes: + - from_url: + url: charmbracelet/meta/main/goreleaser-lib.yaml +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json + diff --git a/vendor/github.com/charmbracelet/lipgloss/README.md b/vendor/github.com/charmbracelet/lipgloss/README.md index 21bc40c2..42661d6c 100644 --- a/vendor/github.com/charmbracelet/lipgloss/README.md +++ b/vendor/github.com/charmbracelet/lipgloss/README.md @@ -1,11 +1,11 @@ -Lip Gloss -========= +# Lip Gloss

- Lip Gloss Title Treatment
+ Lip Gloss title treatment
Latest Release GoDoc Build Status + phorm.ai

Style definitions for nice terminal layouts. Built with TUIs in mind. @@ -64,7 +64,6 @@ The terminal's color profile will be automatically detected, and colors outside the gamut of the current palette will be automatically coerced to their closest available value. - ### Adaptive Colors You can also specify color options for light and dark backgrounds: @@ -78,11 +77,11 @@ appropriate color will be chosen at runtime. ### Complete Colors -CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color +CompleteColor specifies exact values for True Color, ANSI256, and ANSI color profiles. ```go -lipgloss.CompleteColor{True: "#0000FF", ANSI256: "86", ANSI: "5"} +lipgloss.CompleteColor{TrueColor: "#0000FF", ANSI256: "86", ANSI: "5"} ``` Automatic color degradation will not be performed in this case and it will be @@ -90,7 +89,7 @@ based on the color specified. ### Complete Adaptive Colors -You can use CompleteColor with AdaptiveColor to specify the exact values for +You can use `CompleteColor` with `AdaptiveColor` to specify the exact values for light and dark backgrounds without automatic color degradation. ```go @@ -115,7 +114,6 @@ var style = lipgloss.NewStyle(). Reverse(true) ``` - ## Block-Level Formatting Lip Gloss also supports rules for block-level formatting: @@ -154,7 +152,6 @@ lipgloss.NewStyle().Padding(1, 4, 2) lipgloss.NewStyle().Margin(2, 4, 3, 1) ``` - ## Aligning Text You can align paragraphs of text to the left, right, or center. @@ -167,7 +164,6 @@ var style = lipgloss.NewStyle(). Align(lipgloss.Center) // just kidding, align it in the center ``` - ## Width and Height Setting a minimum width and height is simple and straightforward. @@ -180,7 +176,6 @@ var style = lipgloss.NewStyle(). Foreground(lipgloss.Color("63")) ``` - ## Borders Adding borders is easy: @@ -228,21 +223,22 @@ lipgloss.NewStyle(). For more on borders see [the docs][docs]. - ## Copying Styles -Just use `Copy()`: +Just use assignment: ```go -var style = lipgloss.NewStyle().Foreground(lipgloss.Color("219")) +style := lipgloss.NewStyle().Foreground(lipgloss.Color("219")) -var wildStyle = style.Copy().Blink(true) -``` +copiedStyle := style // this is a true copy -`Copy()` performs a copy on the underlying data structure ensuring that you get -a true, dereferenced copy of a style. Without copying, it's possible to mutate -styles. +wildStyle := style.Blink(true) // this is also true copy, with blink added +``` + +Since `Style` data structures contains only primitive types, assigning a style +to another effectively creates a new copy of the style without mutating the +original. ## Inheritance @@ -261,7 +257,6 @@ var styleB = lipgloss.NewStyle(). Inherit(styleA) ``` - ## Unsetting Rules All rules can be unset: @@ -276,7 +271,6 @@ var style = lipgloss.NewStyle(). When a rule is unset, it won't be inherited or copied. - ## Enforcing Rules Sometimes, such as when developing a component, you want to make sure style @@ -353,7 +347,6 @@ For an example on using a custom renderer over SSH with [Wish][wish] see the In addition to pure styling, Lip Gloss also ships with some utilities to help assemble your layouts. - ### Joining Paragraphs Horizontally and vertically joining paragraphs is a cinch. @@ -370,7 +363,6 @@ lipgloss.JoinVertical(lipgloss.Center, paragraphA, paragraphB) lipgloss.JoinHorizontal(0.2, paragraphA, paragraphB, paragraphC) ``` - ### Measuring Width and Height Sometimes you’ll want to know the width and height of text blocks when building @@ -463,7 +455,207 @@ fmt.Println(t) For more on tables see [the docs](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc) and [examples](https://github.com/charmbracelet/lipgloss/tree/master/examples/table). -*** +## Rendering Lists + +Lip Gloss ships with a list rendering sub-package. + +```go +import "github.com/charmbracelet/lipgloss/list" +``` + +Define a new list. + +```go +l := list.New("A", "B", "C") +``` + +Print the list. + +```go +fmt.Println(l) + +// • A +// • B +// • C +``` + +Lists have the ability to nest. + +```go +l := list.New( + "A", list.New("Artichoke"), + "B", list.New("Baking Flour", "Bananas", "Barley", "Bean Sprouts"), + "C", list.New("Cashew Apple", "Cashews", "Coconut Milk", "Curry Paste", "Currywurst"), + "D", list.New("Dill", "Dragonfruit", "Dried Shrimp"), + "E", list.New("Eggs"), + "F", list.New("Fish Cake", "Furikake"), + "J", list.New("Jicama"), + "K", list.New("Kohlrabi"), + "L", list.New("Leeks", "Lentils", "Licorice Root"), +) +``` + +Print the list. + +```go +fmt.Println(l) +``` + +

+image +

+ +Lists can be customized via their enumeration function as well as using +`lipgloss.Style`s. + +```go +enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1) +itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1) + +l := list.New( + "Glossier", + "Claire’s Boutique", + "Nyx", + "Mac", + "Milk", +). + Enumerator(list.Roman). + EnumeratorStyle(enumeratorStyle). + ItemStyle(itemStyle) +``` + +Print the list. + +

+List example +

+ +In addition to the predefined enumerators (`Arabic`, `Alphabet`, `Roman`, `Bullet`, `Tree`), +you may also define your own custom enumerator: + +```go +l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck") + +func DuckDuckGooseEnumerator(l list.Items, i int) string { + if l.At(i).Value() == "Goose" { + return "Honk →" + } + return "" +} + +l = l.Enumerator(DuckDuckGooseEnumerator) +``` + +Print the list: + +

+image +

+ +If you need, you can also build lists incrementally: + +```go +l := list.New() + +for i := 0; i < repeat; i++ { + l.Item("Lip Gloss") +} +``` + +## Rendering Trees + +Lip Gloss ships with a tree rendering sub-package. + +```go +import "github.com/charmbracelet/lipgloss/tree" +``` + +Define a new tree. + +```go +t := tree.Root("."). + Child("A", "B", "C") +``` + +Print the tree. + +```go +fmt.Println(t) + +// . +// ├── A +// ├── B +// └── C +``` + +Trees have the ability to nest. + +```go +t := tree.Root("."). + Child("Item 1"). + Child( + tree.Root("Item 2"). + Child("Item 2.1"). + Child("Item 2.2"). + Child("Item 2.3"), + ). + Child( + tree.Root("Item 3"). + Child("Item 3.1"). + Child("Item 3.2"), + ) +``` + +Print the tree. + +```go +fmt.Println(t) +``` + +

+Tree Example (simple) +

+ +Trees can be customized via their enumeration function as well as using +`lipgloss.Style`s. + +```go +enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1) +itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1) + +t := tree.Root("Makeup"). + Child( + "Glossier", + "Claire’s Boutique", + "Nyx", + "Mac", + "Milk", + ). + Enumerator(tree.RoundedEnumerator). + EnumeratorStyle(enumeratorStyle). + ItemStyle(itemStyle). + RootStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575"))) +``` + +Print the tree. + +

+Tree Example (makeup) +

+ +The predefined enumerators for trees are `DefaultEnumerator` and `RoundedEnumerator`. + +If you need, you can also build trees incrementally: + +```go +t := tree.New() + +for i := 0; i < repeat; i++ { + t.Child("Lip Gloss") +} +``` + +--- ## FAQ @@ -499,10 +691,11 @@ import ( lipgloss.SetColorProfile(termenv.TrueColor) ``` -*Note:* this option limits the flexibility of your application and can cause +_Note:_ this option limits the flexibility of your application and can cause ANSI escape codes to be output in cases where that might not be desired. Take careful note of your use case and environment before choosing to force a color profile. + ## What about [Bubble Tea][tea]? @@ -516,7 +709,6 @@ In simple terms, you can use Lip Gloss to help build your Bubble Tea views. [tea]: https://github.com/charmbracelet/tea - ## Under the Hood Lip Gloss is built on the excellent [Termenv][termenv] and [Reflow][reflow] @@ -526,7 +718,6 @@ For many use cases Termenv and Reflow will be sufficient for your needs. [termenv]: https://github.com/muesli/termenv [reflow]: https://github.com/muesli/reflow - ## Rendering Markdown For a more document-centric rendering solution with support for things like @@ -535,20 +726,19 @@ the stylesheet-based Markdown renderer. [glamour]: https://github.com/charmbracelet/glamour - ## Feedback We’d love to hear your thoughts on this project. Feel free to drop us a note! -* [Twitter](https://twitter.com/charmcli) -* [The Fediverse](https://mastodon.social/@charmcli) -* [Discord](https://charm.sh/chat) +- [Twitter](https://twitter.com/charmcli) +- [The Fediverse](https://mastodon.social/@charmcli) +- [Discord](https://charm.sh/chat) ## License [MIT](https://github.com/charmbracelet/lipgloss/raw/master/LICENSE) -*** +--- Part of [Charm](https://charm.sh). @@ -556,7 +746,6 @@ Part of [Charm](https://charm.sh). Charm热爱开源 • Charm loves open source - [docs]: https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc [wish]: https://github.com/charmbracelet/wish [ssh-example]: examples/ssh diff --git a/vendor/github.com/charmbracelet/lipgloss/align.go b/vendor/github.com/charmbracelet/lipgloss/align.go index 7ee549fc..805d1e0d 100644 --- a/vendor/github.com/charmbracelet/lipgloss/align.go +++ b/vendor/github.com/charmbracelet/lipgloss/align.go @@ -3,7 +3,7 @@ package lipgloss import ( "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" "github.com/muesli/termenv" ) @@ -15,7 +15,7 @@ func alignTextHorizontal(str string, pos Position, width int, style *termenv.Sty var b strings.Builder for i, l := range lines { - lineWidth := ansi.PrintableRuneWidth(l) + lineWidth := ansi.StringWidth(l) shortAmount := widestLine - lineWidth // difference from the widest line shortAmount += max(0, width-(shortAmount+lineWidth)) // difference from the total width, if set diff --git a/vendor/github.com/charmbracelet/lipgloss/borders.go b/vendor/github.com/charmbracelet/lipgloss/borders.go index 6ef90d56..deb6b35a 100644 --- a/vendor/github.com/charmbracelet/lipgloss/borders.go +++ b/vendor/github.com/charmbracelet/lipgloss/borders.go @@ -3,7 +3,7 @@ package lipgloss import ( "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" "github.com/muesli/termenv" "github.com/rivo/uniseg" ) @@ -376,16 +376,12 @@ func (s Style) applyBorder(str string) string { // Render the horizontal (top or bottom) portion of a border. func renderHorizontalEdge(left, middle, right string, width int) string { - if width < 1 { - return "" - } - if middle == "" { middle = " " } - leftWidth := ansi.PrintableRuneWidth(left) - rightWidth := ansi.PrintableRuneWidth(right) + leftWidth := ansi.StringWidth(left) + rightWidth := ansi.StringWidth(right) runes := []rune(middle) j := 0 @@ -398,7 +394,7 @@ func renderHorizontalEdge(left, middle, right string, width int) string { if j >= len(runes) { j = 0 } - i += ansi.PrintableRuneWidth(string(runes[j])) + i += ansi.StringWidth(string(runes[j])) } out.WriteString(right) diff --git a/vendor/github.com/charmbracelet/lipgloss/color.go b/vendor/github.com/charmbracelet/lipgloss/color.go index 43f5b434..5dfb3cfe 100644 --- a/vendor/github.com/charmbracelet/lipgloss/color.go +++ b/vendor/github.com/charmbracelet/lipgloss/color.go @@ -20,7 +20,7 @@ var noColor = NoColor{} // // Example usage: // -// var style = someStyle.Copy().Background(lipgloss.NoColor{}) +// var style = someStyle.Background(lipgloss.NoColor{}) type NoColor struct{} func (NoColor) color(*Renderer) termenv.Color { diff --git a/vendor/github.com/charmbracelet/lipgloss/get.go b/vendor/github.com/charmbracelet/lipgloss/get.go index 9be3d64d..9c2f06fe 100644 --- a/vendor/github.com/charmbracelet/lipgloss/get.go +++ b/vendor/github.com/charmbracelet/lipgloss/get.go @@ -3,7 +3,7 @@ package lipgloss import ( "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" ) // GetBold returns the style's bold value. If no value is set false is returned. @@ -416,74 +416,114 @@ func (s Style) GetTransform() func(string) string { // Returns whether or not the given property is set. func (s Style) isSet(k propKey) bool { - _, exists := s.rules[k] - return exists + return s.props.has(k) } func (s Style) getAsBool(k propKey, defaultVal bool) bool { - v, ok := s.rules[k] - if !ok { + if !s.isSet(k) { return defaultVal } - if b, ok := v.(bool); ok { - return b - } - return defaultVal + return s.attrs&int(k) != 0 } func (s Style) getAsColor(k propKey) TerminalColor { - v, ok := s.rules[k] - if !ok { + if !s.isSet(k) { return noColor } - if c, ok := v.(TerminalColor); ok { + + var c TerminalColor + switch k { //nolint:exhaustive + case foregroundKey: + c = s.fgColor + case backgroundKey: + c = s.bgColor + case marginBackgroundKey: + c = s.marginBgColor + case borderTopForegroundKey: + c = s.borderTopFgColor + case borderRightForegroundKey: + c = s.borderRightFgColor + case borderBottomForegroundKey: + c = s.borderBottomFgColor + case borderLeftForegroundKey: + c = s.borderLeftFgColor + case borderTopBackgroundKey: + c = s.borderTopBgColor + case borderRightBackgroundKey: + c = s.borderRightBgColor + case borderBottomBackgroundKey: + c = s.borderBottomBgColor + case borderLeftBackgroundKey: + c = s.borderLeftBgColor + } + + if c != nil { return c } + return noColor } func (s Style) getAsInt(k propKey) int { - v, ok := s.rules[k] - if !ok { + if !s.isSet(k) { return 0 } - if i, ok := v.(int); ok { - return i + switch k { //nolint:exhaustive + case widthKey: + return s.width + case heightKey: + return s.height + case paddingTopKey: + return s.paddingTop + case paddingRightKey: + return s.paddingRight + case paddingBottomKey: + return s.paddingBottom + case paddingLeftKey: + return s.paddingLeft + case marginTopKey: + return s.marginTop + case marginRightKey: + return s.marginRight + case marginBottomKey: + return s.marginBottom + case marginLeftKey: + return s.marginLeft + case maxWidthKey: + return s.maxWidth + case maxHeightKey: + return s.maxHeight + case tabWidthKey: + return s.tabWidth } return 0 } func (s Style) getAsPosition(k propKey) Position { - v, ok := s.rules[k] - if !ok { + if !s.isSet(k) { return Position(0) } - if p, ok := v.(Position); ok { - return p + switch k { //nolint:exhaustive + case alignHorizontalKey: + return s.alignHorizontal + case alignVerticalKey: + return s.alignVertical } return Position(0) } func (s Style) getBorderStyle() Border { - v, ok := s.rules[borderStyleKey] - if !ok { + if !s.isSet(borderStyleKey) { return noBorder } - if b, ok := v.(Border); ok { - return b - } - return noBorder + return s.borderStyle } -func (s Style) getAsTransform(k propKey) func(string) string { - v, ok := s.rules[k] - if !ok { +func (s Style) getAsTransform(propKey) func(string) string { + if !s.isSet(transformKey) { return nil } - if fn, ok := v.(func(string) string); ok { - return fn - } - return nil + return s.transform } // Split a string into lines, additionally returning the size of the widest @@ -492,7 +532,7 @@ func getLines(s string) (lines []string, widest int) { lines = strings.Split(s, "\n") for _, l := range lines { - w := ansi.PrintableRuneWidth(l) + w := ansi.StringWidth(l) if widest < w { widest = w } diff --git a/vendor/github.com/charmbracelet/lipgloss/join.go b/vendor/github.com/charmbracelet/lipgloss/join.go index f265976e..b0a23a54 100644 --- a/vendor/github.com/charmbracelet/lipgloss/join.go +++ b/vendor/github.com/charmbracelet/lipgloss/join.go @@ -4,7 +4,7 @@ import ( "math" "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" ) // JoinHorizontal is a utility function for horizontally joining two @@ -12,7 +12,7 @@ import ( // the position, with 0 being all the way at the top and 1 being all the way // at the bottom. // -// If you just want to align to the left, right or center you may as well just +// If you just want to align to the top, center or bottom you may as well just // use the helper constants Top, Center, and Bottom. // // Example: @@ -85,7 +85,7 @@ func JoinHorizontal(pos Position, strs ...string) string { b.WriteString(block[i]) // Also make lines the same length - b.WriteString(strings.Repeat(" ", maxWidths[j]-ansi.PrintableRuneWidth(block[i]))) + b.WriteString(strings.Repeat(" ", maxWidths[j]-ansi.StringWidth(block[i]))) } if i < len(blocks[0])-1 { b.WriteRune('\n') @@ -137,7 +137,7 @@ func JoinVertical(pos Position, strs ...string) string { var b strings.Builder for i, block := range blocks { for j, line := range block { - w := maxWidth - ansi.PrintableRuneWidth(line) + w := maxWidth - ansi.StringWidth(line) switch pos { //nolint:exhaustive case Left: diff --git a/vendor/github.com/charmbracelet/lipgloss/position.go b/vendor/github.com/charmbracelet/lipgloss/position.go index 7d229e03..185f5af3 100644 --- a/vendor/github.com/charmbracelet/lipgloss/position.go +++ b/vendor/github.com/charmbracelet/lipgloss/position.go @@ -4,7 +4,7 @@ import ( "math" "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" ) // Position represents a position along a horizontal or vertical axis. It's in @@ -66,7 +66,7 @@ func (r *Renderer) PlaceHorizontal(width int, pos Position, str string, opts ... var b strings.Builder for i, l := range lines { // Is this line shorter than the longest line? - short := max(0, contentWidth-ansi.PrintableRuneWidth(l)) + short := max(0, contentWidth-ansi.StringWidth(l)) switch pos { //nolint:exhaustive case Left: diff --git a/vendor/github.com/charmbracelet/lipgloss/renderer.go b/vendor/github.com/charmbracelet/lipgloss/renderer.go index 85ffd254..233aa7c0 100644 --- a/vendor/github.com/charmbracelet/lipgloss/renderer.go +++ b/vendor/github.com/charmbracelet/lipgloss/renderer.go @@ -28,9 +28,6 @@ type Renderer struct { mtx sync.RWMutex } -// RendererOption is a function that can be used to configure a [Renderer]. -type RendererOption func(r *Renderer) - // DefaultRenderer returns the default renderer. func DefaultRenderer() *Renderer { return renderer diff --git a/vendor/github.com/charmbracelet/lipgloss/set.go b/vendor/github.com/charmbracelet/lipgloss/set.go index 5846b598..ed6e272c 100644 --- a/vendor/github.com/charmbracelet/lipgloss/set.go +++ b/vendor/github.com/charmbracelet/lipgloss/set.go @@ -1,36 +1,163 @@ package lipgloss -// This could (should) probably just be moved into NewStyle(). We've broken it -// out, so we can call it in a lazy way. -func (s *Style) init() { - if s.rules == nil { - s.rules = make(rules) - } -} - // Set a value on the underlying rules map. func (s *Style) set(key propKey, value interface{}) { - s.init() - - switch v := value.(type) { - case int: + // We don't allow negative integers on any of our other values, so just keep + // them at zero or above. We could use uints instead, but the + // conversions are a little tedious, so we're sticking with ints for + // sake of usability. + switch key { //nolint:exhaustive + case foregroundKey: + s.fgColor = colorOrNil(value) + case backgroundKey: + s.bgColor = colorOrNil(value) + case widthKey: + s.width = max(0, value.(int)) + case heightKey: + s.height = max(0, value.(int)) + case alignHorizontalKey: + s.alignHorizontal = value.(Position) + case alignVerticalKey: + s.alignVertical = value.(Position) + case paddingTopKey: + s.paddingTop = max(0, value.(int)) + case paddingRightKey: + s.paddingRight = max(0, value.(int)) + case paddingBottomKey: + s.paddingBottom = max(0, value.(int)) + case paddingLeftKey: + s.paddingLeft = max(0, value.(int)) + case marginTopKey: + s.marginTop = max(0, value.(int)) + case marginRightKey: + s.marginRight = max(0, value.(int)) + case marginBottomKey: + s.marginBottom = max(0, value.(int)) + case marginLeftKey: + s.marginLeft = max(0, value.(int)) + case marginBackgroundKey: + s.marginBgColor = colorOrNil(value) + case borderStyleKey: + s.borderStyle = value.(Border) + case borderTopForegroundKey: + s.borderTopFgColor = colorOrNil(value) + case borderRightForegroundKey: + s.borderRightFgColor = colorOrNil(value) + case borderBottomForegroundKey: + s.borderBottomFgColor = colorOrNil(value) + case borderLeftForegroundKey: + s.borderLeftFgColor = colorOrNil(value) + case borderTopBackgroundKey: + s.borderTopBgColor = colorOrNil(value) + case borderRightBackgroundKey: + s.borderRightBgColor = colorOrNil(value) + case borderBottomBackgroundKey: + s.borderBottomBgColor = colorOrNil(value) + case borderLeftBackgroundKey: + s.borderLeftBgColor = colorOrNil(value) + case maxWidthKey: + s.maxWidth = max(0, value.(int)) + case maxHeightKey: + s.maxHeight = max(0, value.(int)) + case tabWidthKey: // TabWidth is the only property that may have a negative value (and // that negative value can be no less than -1). - if key == tabWidthKey { - s.rules[key] = v - break + s.tabWidth = value.(int) + case transformKey: + s.transform = value.(func(string) string) + default: + if v, ok := value.(bool); ok { //nolint:nestif + if v { + s.attrs |= int(key) + } else { + s.attrs &^= int(key) + } + } else if attrs, ok := value.(int); ok { + // bool attrs + if attrs&int(key) != 0 { + s.attrs |= int(key) + } else { + s.attrs &^= int(key) + } } + } - // We don't allow negative integers on any of our other values, so just keep - // them at zero or above. We could use uints instead, but the - // conversions are a little tedious, so we're sticking with ints for - // sake of usability. - s.rules[key] = max(0, v) + // Set the prop on + s.props = s.props.set(key) +} + +// setFrom sets the property from another style. +func (s *Style) setFrom(key propKey, i Style) { + switch key { //nolint:exhaustive + case foregroundKey: + s.set(foregroundKey, i.fgColor) + case backgroundKey: + s.set(backgroundKey, i.bgColor) + case widthKey: + s.set(widthKey, i.width) + case heightKey: + s.set(heightKey, i.height) + case alignHorizontalKey: + s.set(alignHorizontalKey, i.alignHorizontal) + case alignVerticalKey: + s.set(alignVerticalKey, i.alignVertical) + case paddingTopKey: + s.set(paddingTopKey, i.paddingTop) + case paddingRightKey: + s.set(paddingRightKey, i.paddingRight) + case paddingBottomKey: + s.set(paddingBottomKey, i.paddingBottom) + case paddingLeftKey: + s.set(paddingLeftKey, i.paddingLeft) + case marginTopKey: + s.set(marginTopKey, i.marginTop) + case marginRightKey: + s.set(marginRightKey, i.marginRight) + case marginBottomKey: + s.set(marginBottomKey, i.marginBottom) + case marginLeftKey: + s.set(marginLeftKey, i.marginLeft) + case marginBackgroundKey: + s.set(marginBackgroundKey, i.marginBgColor) + case borderStyleKey: + s.set(borderStyleKey, i.borderStyle) + case borderTopForegroundKey: + s.set(borderTopForegroundKey, i.borderTopFgColor) + case borderRightForegroundKey: + s.set(borderRightForegroundKey, i.borderRightFgColor) + case borderBottomForegroundKey: + s.set(borderBottomForegroundKey, i.borderBottomFgColor) + case borderLeftForegroundKey: + s.set(borderLeftForegroundKey, i.borderLeftFgColor) + case borderTopBackgroundKey: + s.set(borderTopBackgroundKey, i.borderTopBgColor) + case borderRightBackgroundKey: + s.set(borderRightBackgroundKey, i.borderRightBgColor) + case borderBottomBackgroundKey: + s.set(borderBottomBackgroundKey, i.borderBottomBgColor) + case borderLeftBackgroundKey: + s.set(borderLeftBackgroundKey, i.borderLeftBgColor) + case maxWidthKey: + s.set(maxWidthKey, i.maxWidth) + case maxHeightKey: + s.set(maxHeightKey, i.maxHeight) + case tabWidthKey: + s.set(tabWidthKey, i.tabWidth) + case transformKey: + s.set(transformKey, i.transform) default: - s.rules[key] = v + // Set attributes for set bool properties + s.set(key, i.attrs) } } +func colorOrNil(c interface{}) TerminalColor { + if c, ok := c.(TerminalColor); ok { + return c + } + return nil +} + // Bold sets a bold formatting rule. func (s Style) Bold(v bool) Style { s.set(boldKey, v) @@ -194,6 +321,8 @@ func (s Style) PaddingBottom(i int) Style { // applied to the padding. This is true by default as it's more than likely the // desired and expected behavior, but it can be disabled for certain graphic // effects. +// +// Deprecated: Just use margins and padding. func (s Style) ColorWhitespace(v bool) Style { s.set(colorWhitespaceKey, v) return s @@ -476,7 +605,7 @@ func (s Style) BorderLeftBackground(c TerminalColor) Style { // var userStyle = text.Style{ /* ... */ } // fmt.Println(userStyle.Inline(true).Render(userInput)) func (s Style) Inline(v bool) Style { - o := s.Copy() + o := s // copy o.set(inlineKey, v) return o } @@ -494,7 +623,7 @@ func (s Style) Inline(v bool) Style { // var userStyle = text.Style{ /* ... */ } // fmt.Println(userStyle.MaxWidth(16).Render(userInput)) func (s Style) MaxWidth(n int) Style { - o := s.Copy() + o := s // copy o.set(maxWidthKey, n) return o } @@ -506,7 +635,7 @@ func (s Style) MaxWidth(n int) Style { // Because this in intended to be used at the time of render, this method will // not mutate the style and instead returns a copy. func (s Style) MaxHeight(n int) Style { - o := s.Copy() + o := s // copy o.set(maxHeightKey, n) return o } diff --git a/vendor/github.com/charmbracelet/lipgloss/size.go b/vendor/github.com/charmbracelet/lipgloss/size.go index 439a5cb8..e169ff5e 100644 --- a/vendor/github.com/charmbracelet/lipgloss/size.go +++ b/vendor/github.com/charmbracelet/lipgloss/size.go @@ -3,7 +3,7 @@ package lipgloss import ( "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" ) // Width returns the cell width of characters in the string. ANSI sequences are @@ -14,7 +14,7 @@ import ( // will give you accurate results. func Width(str string) (width int) { for _, l := range strings.Split(str, "\n") { - w := ansi.PrintableRuneWidth(l) + w := ansi.StringWidth(l) if w > width { width = w } diff --git a/vendor/github.com/charmbracelet/lipgloss/style.go b/vendor/github.com/charmbracelet/lipgloss/style.go index 58dcc0fa..4343d3cd 100644 --- a/vendor/github.com/charmbracelet/lipgloss/style.go +++ b/vendor/github.com/charmbracelet/lipgloss/style.go @@ -4,26 +4,30 @@ import ( "strings" "unicode" - "github.com/muesli/reflow/truncate" - "github.com/muesli/reflow/wordwrap" - "github.com/muesli/reflow/wrap" + "github.com/charmbracelet/x/ansi" "github.com/muesli/termenv" ) const tabWidthDefault = 4 // Property for a key. -type propKey int +type propKey int64 // Available properties. const ( - boldKey propKey = iota + // Boolean props come first. + boldKey propKey = 1 << iota italicKey underlineKey strikethroughKey reverseKey blinkKey faintKey + underlineSpacesKey + strikethroughSpacesKey + colorWhitespaceKey + + // Non-boolean props. foregroundKey backgroundKey widthKey @@ -37,8 +41,6 @@ const ( paddingBottomKey paddingLeftKey - colorWhitespaceKey - // Margins. marginTopKey marginRightKey @@ -71,14 +73,27 @@ const ( maxWidthKey maxHeightKey tabWidthKey - underlineSpacesKey - strikethroughSpacesKey transformKey ) -// A set of properties. -type rules map[propKey]interface{} +// props is a set of properties. +type props int64 + +// set sets a property. +func (p props) set(k propKey) props { + return p | props(k) +} + +// unset unsets a property. +func (p props) unset(k propKey) props { + return p &^ props(k) +} + +// has checks if a property is set. +func (p props) has(k propKey) bool { + return p&props(k) != 0 +} // NewStyle returns a new, empty Style. While it's syntactic sugar for the // Style{} primitive, it's recommended to use this function for creating styles @@ -100,8 +115,48 @@ func (r *Renderer) NewStyle() Style { // Style contains a set of rules that comprise a style as a whole. type Style struct { r *Renderer - rules map[propKey]interface{} + props props value string + + // we store bool props values here + attrs int + + // props that have values + fgColor TerminalColor + bgColor TerminalColor + + width int + height int + + alignHorizontal Position + alignVertical Position + + paddingTop int + paddingRight int + paddingBottom int + paddingLeft int + + marginTop int + marginRight int + marginBottom int + marginLeft int + marginBgColor TerminalColor + + borderStyle Border + borderTopFgColor TerminalColor + borderRightFgColor TerminalColor + borderBottomFgColor TerminalColor + borderLeftFgColor TerminalColor + borderTopBgColor TerminalColor + borderRightBgColor TerminalColor + borderBottomBgColor TerminalColor + borderLeftBgColor TerminalColor + + maxWidth int + maxHeight int + tabWidth int + + transform func(string) string } // joinString joins a list of strings into a single string separated with a @@ -133,15 +188,11 @@ func (s Style) String() string { } // Copy returns a copy of this style, including any underlying string values. +// +// Deprecated: to copy just use assignment (i.e. a := b). All methods also +// return a new style. func (s Style) Copy() Style { - o := NewStyle() - o.init() - for k, v := range s.rules { - o.rules[k] = v - } - o.r = s.r - o.value = s.value - return o + return s } // Inherit overlays the style in the argument onto this style by copying each explicitly @@ -150,9 +201,11 @@ func (s Style) Copy() Style { // // Margins, padding, and underlying string values are not inherited. func (s Style) Inherit(i Style) Style { - s.init() + for k := boldKey; k <= transformKey; k <<= 1 { + if !i.isSet(k) { + continue + } - for k, v := range i.rules { switch k { //nolint:exhaustive case marginTopKey, marginRightKey, marginBottomKey, marginLeftKey: // Margins are not inherited @@ -163,14 +216,15 @@ func (s Style) Inherit(i Style) Style { case backgroundKey: // The margins also inherit the background color if !s.isSet(marginBackgroundKey) && !i.isSet(marginBackgroundKey) { - s.rules[marginBackgroundKey] = v + s.set(marginBackgroundKey, i.bgColor) } } - if _, exists := s.rules[k]; exists { + if s.isSet(k) { continue } - s.rules[k] = v + + s.setFrom(k, i) } return s } @@ -218,20 +272,24 @@ func (s Style) Render(strs ...string) string { maxWidth = s.getAsInt(maxWidthKey) maxHeight = s.getAsInt(maxHeightKey) - underlineSpaces = underline && s.getAsBool(underlineSpacesKey, true) - strikethroughSpaces = strikethrough && s.getAsBool(strikethroughSpacesKey, true) + underlineSpaces = s.getAsBool(underlineSpacesKey, false) || (underline && s.getAsBool(underlineSpacesKey, true)) + strikethroughSpaces = s.getAsBool(strikethroughSpacesKey, false) || (strikethrough && s.getAsBool(strikethroughSpacesKey, true)) // Do we need to style whitespace (padding and space outside // paragraphs) separately? styleWhitespace = reverse // Do we need to style spaces separately? - useSpaceStyler = underlineSpaces || strikethroughSpaces + useSpaceStyler = (underline && !underlineSpaces) || (strikethrough && !strikethroughSpaces) || underlineSpaces || strikethroughSpaces transform = s.getAsTransform(transformKey) ) - if len(s.rules) == 0 { + if transform != nil { + str = transform(str) + } + + if s.props == 0 { return s.maybeConvertTabs(str) } @@ -249,9 +307,7 @@ func (s Style) Render(strs ...string) string { te = te.Underline() } if reverse { - if reverse { - teWhitespace = teWhitespace.Reverse() - } + teWhitespace = teWhitespace.Reverse() te = te.Reverse() } if blink { @@ -306,8 +362,7 @@ func (s Style) Render(strs ...string) string { // Word wrap if !inline && width > 0 { wrapAt := width - leftPadding - rightPadding - str = wordwrap.String(str, wrapAt) - str = wrap.String(str, wrapAt) // force-wrap long strings + str = ansi.Wrap(str, wrapAt, "") } // Render core text @@ -337,7 +392,7 @@ func (s Style) Render(strs ...string) string { } // Padding - if !inline { + if !inline { //nolint:nestif if leftPadding > 0 { var st *termenv.Style if colorWhitespace || styleWhitespace { @@ -393,7 +448,7 @@ func (s Style) Render(strs ...string) string { lines := strings.Split(str, "\n") for i := range lines { - lines[i] = truncate.String(lines[i], uint(maxWidth)) + lines[i] = ansi.Truncate(lines[i], maxWidth, "") } str = strings.Join(lines, "\n") @@ -402,11 +457,10 @@ func (s Style) Render(strs ...string) string { // Truncate according to MaxHeight if maxHeight > 0 { lines := strings.Split(str, "\n") - str = strings.Join(lines[:min(maxHeight, len(lines))], "\n") - } - - if transform != nil { - return transform(str) + height := min(maxHeight, len(lines)) + if len(lines) > 0 { + str = strings.Join(lines[:height], "\n") + } } return str @@ -508,7 +562,7 @@ func pad(str string, n int, style *termenv.Style) string { return b.String() } -func max(a, b int) int { +func max(a, b int) int { //nolint:unparam if a > b { return a } diff --git a/vendor/github.com/charmbracelet/lipgloss/unset.go b/vendor/github.com/charmbracelet/lipgloss/unset.go index 5387bcf7..1086e722 100644 --- a/vendor/github.com/charmbracelet/lipgloss/unset.go +++ b/vendor/github.com/charmbracelet/lipgloss/unset.go @@ -1,159 +1,164 @@ package lipgloss +// unset unsets a property from a style. +func (s *Style) unset(key propKey) { + s.props = s.props.unset(key) +} + // UnsetBold removes the bold style rule, if set. func (s Style) UnsetBold() Style { - delete(s.rules, boldKey) + s.unset(boldKey) return s } // UnsetItalic removes the italic style rule, if set. func (s Style) UnsetItalic() Style { - delete(s.rules, italicKey) + s.unset(italicKey) return s } // UnsetUnderline removes the underline style rule, if set. func (s Style) UnsetUnderline() Style { - delete(s.rules, underlineKey) + s.unset(underlineKey) return s } // UnsetStrikethrough removes the strikethrough style rule, if set. func (s Style) UnsetStrikethrough() Style { - delete(s.rules, strikethroughKey) + s.unset(strikethroughKey) return s } // UnsetReverse removes the reverse style rule, if set. func (s Style) UnsetReverse() Style { - delete(s.rules, reverseKey) + s.unset(reverseKey) return s } // UnsetBlink removes the blink style rule, if set. func (s Style) UnsetBlink() Style { - delete(s.rules, blinkKey) + s.unset(blinkKey) return s } // UnsetFaint removes the faint style rule, if set. func (s Style) UnsetFaint() Style { - delete(s.rules, faintKey) + s.unset(faintKey) return s } // UnsetForeground removes the foreground style rule, if set. func (s Style) UnsetForeground() Style { - delete(s.rules, foregroundKey) + s.unset(foregroundKey) return s } // UnsetBackground removes the background style rule, if set. func (s Style) UnsetBackground() Style { - delete(s.rules, backgroundKey) + s.unset(backgroundKey) return s } // UnsetWidth removes the width style rule, if set. func (s Style) UnsetWidth() Style { - delete(s.rules, widthKey) + s.unset(widthKey) return s } // UnsetHeight removes the height style rule, if set. func (s Style) UnsetHeight() Style { - delete(s.rules, heightKey) + s.unset(heightKey) return s } // UnsetAlign removes the horizontal and vertical text alignment style rule, if set. func (s Style) UnsetAlign() Style { - delete(s.rules, alignHorizontalKey) - delete(s.rules, alignVerticalKey) + s.unset(alignHorizontalKey) + s.unset(alignVerticalKey) return s } // UnsetAlignHorizontal removes the horizontal text alignment style rule, if set. func (s Style) UnsetAlignHorizontal() Style { - delete(s.rules, alignHorizontalKey) + s.unset(alignHorizontalKey) return s } // UnsetAlignVertical removes the vertical text alignment style rule, if set. func (s Style) UnsetAlignVertical() Style { - delete(s.rules, alignVerticalKey) + s.unset(alignVerticalKey) return s } // UnsetPadding removes all padding style rules. func (s Style) UnsetPadding() Style { - delete(s.rules, paddingLeftKey) - delete(s.rules, paddingRightKey) - delete(s.rules, paddingTopKey) - delete(s.rules, paddingBottomKey) + s.unset(paddingLeftKey) + s.unset(paddingRightKey) + s.unset(paddingTopKey) + s.unset(paddingBottomKey) return s } // UnsetPaddingLeft removes the left padding style rule, if set. func (s Style) UnsetPaddingLeft() Style { - delete(s.rules, paddingLeftKey) + s.unset(paddingLeftKey) return s } // UnsetPaddingRight removes the right padding style rule, if set. func (s Style) UnsetPaddingRight() Style { - delete(s.rules, paddingRightKey) + s.unset(paddingRightKey) return s } // UnsetPaddingTop removes the top padding style rule, if set. func (s Style) UnsetPaddingTop() Style { - delete(s.rules, paddingTopKey) + s.unset(paddingTopKey) return s } // UnsetPaddingBottom removes the bottom padding style rule, if set. func (s Style) UnsetPaddingBottom() Style { - delete(s.rules, paddingBottomKey) + s.unset(paddingBottomKey) return s } // UnsetColorWhitespace removes the rule for coloring padding, if set. func (s Style) UnsetColorWhitespace() Style { - delete(s.rules, colorWhitespaceKey) + s.unset(colorWhitespaceKey) return s } // UnsetMargins removes all margin style rules. func (s Style) UnsetMargins() Style { - delete(s.rules, marginLeftKey) - delete(s.rules, marginRightKey) - delete(s.rules, marginTopKey) - delete(s.rules, marginBottomKey) + s.unset(marginLeftKey) + s.unset(marginRightKey) + s.unset(marginTopKey) + s.unset(marginBottomKey) return s } // UnsetMarginLeft removes the left margin style rule, if set. func (s Style) UnsetMarginLeft() Style { - delete(s.rules, marginLeftKey) + s.unset(marginLeftKey) return s } // UnsetMarginRight removes the right margin style rule, if set. func (s Style) UnsetMarginRight() Style { - delete(s.rules, marginRightKey) + s.unset(marginRightKey) return s } // UnsetMarginTop removes the top margin style rule, if set. func (s Style) UnsetMarginTop() Style { - delete(s.rules, marginTopKey) + s.unset(marginTopKey) return s } // UnsetMarginBottom removes the bottom margin style rule, if set. func (s Style) UnsetMarginBottom() Style { - delete(s.rules, marginBottomKey) + s.unset(marginBottomKey) return s } @@ -161,153 +166,161 @@ func (s Style) UnsetMarginBottom() Style { // margin's background color can be set from the background color of another // style during inheritance. func (s Style) UnsetMarginBackground() Style { - delete(s.rules, marginBackgroundKey) + s.unset(marginBackgroundKey) return s } // UnsetBorderStyle removes the border style rule, if set. func (s Style) UnsetBorderStyle() Style { - delete(s.rules, borderStyleKey) + s.unset(borderStyleKey) return s } // UnsetBorderTop removes the border top style rule, if set. func (s Style) UnsetBorderTop() Style { - delete(s.rules, borderTopKey) + s.unset(borderTopKey) return s } // UnsetBorderRight removes the border right style rule, if set. func (s Style) UnsetBorderRight() Style { - delete(s.rules, borderRightKey) + s.unset(borderRightKey) return s } // UnsetBorderBottom removes the border bottom style rule, if set. func (s Style) UnsetBorderBottom() Style { - delete(s.rules, borderBottomKey) + s.unset(borderBottomKey) return s } // UnsetBorderLeft removes the border left style rule, if set. func (s Style) UnsetBorderLeft() Style { - delete(s.rules, borderLeftKey) + s.unset(borderLeftKey) return s } // UnsetBorderForeground removes all border foreground color styles, if set. func (s Style) UnsetBorderForeground() Style { - delete(s.rules, borderTopForegroundKey) - delete(s.rules, borderRightForegroundKey) - delete(s.rules, borderBottomForegroundKey) - delete(s.rules, borderLeftForegroundKey) + s.unset(borderTopForegroundKey) + s.unset(borderRightForegroundKey) + s.unset(borderBottomForegroundKey) + s.unset(borderLeftForegroundKey) return s } // UnsetBorderTopForeground removes the top border foreground color rule, // if set. func (s Style) UnsetBorderTopForeground() Style { - delete(s.rules, borderTopForegroundKey) + s.unset(borderTopForegroundKey) return s } // UnsetBorderRightForeground removes the right border foreground color rule, // if set. func (s Style) UnsetBorderRightForeground() Style { - delete(s.rules, borderRightForegroundKey) + s.unset(borderRightForegroundKey) return s } // UnsetBorderBottomForeground removes the bottom border foreground color // rule, if set. func (s Style) UnsetBorderBottomForeground() Style { - delete(s.rules, borderBottomForegroundKey) + s.unset(borderBottomForegroundKey) return s } // UnsetBorderLeftForeground removes the left border foreground color rule, // if set. func (s Style) UnsetBorderLeftForeground() Style { - delete(s.rules, borderLeftForegroundKey) + s.unset(borderLeftForegroundKey) return s } // UnsetBorderBackground removes all border background color styles, if // set. func (s Style) UnsetBorderBackground() Style { - delete(s.rules, borderTopBackgroundKey) - delete(s.rules, borderRightBackgroundKey) - delete(s.rules, borderBottomBackgroundKey) - delete(s.rules, borderLeftBackgroundKey) + s.unset(borderTopBackgroundKey) + s.unset(borderRightBackgroundKey) + s.unset(borderBottomBackgroundKey) + s.unset(borderLeftBackgroundKey) return s } // UnsetBorderTopBackgroundColor removes the top border background color rule, // if set. +// +// Deprecated: This function simply calls Style.UnsetBorderTopBackground. func (s Style) UnsetBorderTopBackgroundColor() Style { - delete(s.rules, borderTopBackgroundKey) + return s.UnsetBorderTopBackground() +} + +// UnsetBorderTopBackground removes the top border background color rule, +// if set. +func (s Style) UnsetBorderTopBackground() Style { + s.unset(borderTopBackgroundKey) return s } // UnsetBorderRightBackground removes the right border background color // rule, if set. func (s Style) UnsetBorderRightBackground() Style { - delete(s.rules, borderRightBackgroundKey) + s.unset(borderRightBackgroundKey) return s } // UnsetBorderBottomBackground removes the bottom border background color // rule, if set. func (s Style) UnsetBorderBottomBackground() Style { - delete(s.rules, borderBottomBackgroundKey) + s.unset(borderBottomBackgroundKey) return s } // UnsetBorderLeftBackground removes the left border color rule, if set. func (s Style) UnsetBorderLeftBackground() Style { - delete(s.rules, borderLeftBackgroundKey) + s.unset(borderLeftBackgroundKey) return s } // UnsetInline removes the inline style rule, if set. func (s Style) UnsetInline() Style { - delete(s.rules, inlineKey) + s.unset(inlineKey) return s } // UnsetMaxWidth removes the max width style rule, if set. func (s Style) UnsetMaxWidth() Style { - delete(s.rules, maxWidthKey) + s.unset(maxWidthKey) return s } // UnsetMaxHeight removes the max height style rule, if set. func (s Style) UnsetMaxHeight() Style { - delete(s.rules, maxHeightKey) + s.unset(maxHeightKey) return s } // UnsetTabWidth removes the tab width style rule, if set. func (s Style) UnsetTabWidth() Style { - delete(s.rules, tabWidthKey) + s.unset(tabWidthKey) return s } // UnsetUnderlineSpaces removes the value set by UnderlineSpaces. func (s Style) UnsetUnderlineSpaces() Style { - delete(s.rules, underlineSpacesKey) + s.unset(underlineSpacesKey) return s } // UnsetStrikethroughSpaces removes the value set by StrikethroughSpaces. func (s Style) UnsetStrikethroughSpaces() Style { - delete(s.rules, strikethroughSpacesKey) + s.unset(strikethroughSpacesKey) return s } // UnsetTransform removes the value set by Transform. func (s Style) UnsetTransform() Style { - delete(s.rules, transformKey) + s.unset(transformKey) return s } diff --git a/vendor/github.com/charmbracelet/lipgloss/whitespace.go b/vendor/github.com/charmbracelet/lipgloss/whitespace.go index 78815fed..040dc98e 100644 --- a/vendor/github.com/charmbracelet/lipgloss/whitespace.go +++ b/vendor/github.com/charmbracelet/lipgloss/whitespace.go @@ -3,7 +3,7 @@ package lipgloss import ( "strings" - "github.com/muesli/reflow/ansi" + "github.com/charmbracelet/x/ansi" "github.com/muesli/termenv" ) @@ -45,12 +45,12 @@ func (w whitespace) render(width int) string { if j >= len(r) { j = 0 } - i += ansi.PrintableRuneWidth(string(r[j])) + i += ansi.StringWidth(string(r[j])) } // Fill any extra gaps white spaces. This might be necessary if any runes // are more than one cell wide, which could leave a one-rune gap. - short := width - ansi.PrintableRuneWidth(b.String()) + short := width - ansi.StringWidth(b.String()) if short > 0 { b.WriteString(strings.Repeat(" ", short)) } diff --git a/vendor/github.com/charmbracelet/x/ansi/LICENSE b/vendor/github.com/charmbracelet/x/ansi/LICENSE new file mode 100644 index 00000000..65a5654e --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Charmbracelet, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/x/ansi/ansi.go b/vendor/github.com/charmbracelet/x/ansi/ansi.go new file mode 100644 index 00000000..48d873c3 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/ansi.go @@ -0,0 +1,11 @@ +package ansi + +import "io" + +// Execute is a function that "execute" the given escape sequence by writing it +// to the provided output writter. +// +// This is a syntactic sugar over [io.WriteString]. +func Execute(w io.Writer, s string) (int, error) { + return io.WriteString(w, s) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/ascii.go b/vendor/github.com/charmbracelet/x/ansi/ascii.go new file mode 100644 index 00000000..188582f7 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/ascii.go @@ -0,0 +1,8 @@ +package ansi + +const ( + // SP is the space character (Char: \x20). + SP = 0x20 + // DEL is the delete character (Caret: ^?, Char: \x7f). + DEL = 0x7F +) diff --git a/vendor/github.com/charmbracelet/x/ansi/background.go b/vendor/github.com/charmbracelet/x/ansi/background.go new file mode 100644 index 00000000..f519af08 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/background.go @@ -0,0 +1,61 @@ +package ansi + +import ( + "image/color" +) + +// SetForegroundColor returns a sequence that sets the default terminal +// foreground color. +// +// OSC 10 ; color ST +// OSC 10 ; color BEL +// +// Where color is the encoded color number. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetForegroundColor(c color.Color) string { + return "\x1b]10;" + colorToHexString(c) + "\x07" +} + +// RequestForegroundColor is a sequence that requests the current default +// terminal foreground color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const RequestForegroundColor = "\x1b]10;?\x07" + +// SetBackgroundColor returns a sequence that sets the default terminal +// background color. +// +// OSC 11 ; color ST +// OSC 11 ; color BEL +// +// Where color is the encoded color number. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetBackgroundColor(c color.Color) string { + return "\x1b]11;" + colorToHexString(c) + "\x07" +} + +// RequestBackgroundColor is a sequence that requests the current default +// terminal background color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const RequestBackgroundColor = "\x1b]11;?\x07" + +// SetCursorColor returns a sequence that sets the terminal cursor color. +// +// OSC 12 ; color ST +// OSC 12 ; color BEL +// +// Where color is the encoded color number. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetCursorColor(c color.Color) string { + return "\x1b]12;" + colorToHexString(c) + "\x07" +} + +// RequestCursorColor is a sequence that requests the current terminal cursor +// color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const RequestCursorColor = "\x1b]12;?\x07" diff --git a/vendor/github.com/charmbracelet/x/ansi/c0.go b/vendor/github.com/charmbracelet/x/ansi/c0.go new file mode 100644 index 00000000..13e3c6c3 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/c0.go @@ -0,0 +1,72 @@ +package ansi + +// C0 control characters. +// +// These range from (0x00-0x1F) as defined in ISO 646 (ASCII). +// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes +const ( + // NUL is the null character (Caret: ^@, Char: \0). + NUL = 0x00 + // SOH is the start of heading character (Caret: ^A). + SOH = 0x01 + // STX is the start of text character (Caret: ^B). + STX = 0x02 + // ETX is the end of text character (Caret: ^C). + ETX = 0x03 + // EOT is the end of transmission character (Caret: ^D). + EOT = 0x04 + // ENQ is the enquiry character (Caret: ^E). + ENQ = 0x05 + // ACK is the acknowledge character (Caret: ^F). + ACK = 0x06 + // BEL is the bell character (Caret: ^G, Char: \a). + BEL = 0x07 + // BS is the backspace character (Caret: ^H, Char: \b). + BS = 0x08 + // HT is the horizontal tab character (Caret: ^I, Char: \t). + HT = 0x09 + // LF is the line feed character (Caret: ^J, Char: \n). + LF = 0x0A + // VT is the vertical tab character (Caret: ^K, Char: \v). + VT = 0x0B + // FF is the form feed character (Caret: ^L, Char: \f). + FF = 0x0C + // CR is the carriage return character (Caret: ^M, Char: \r). + CR = 0x0D + // SO is the shift out character (Caret: ^N). + SO = 0x0E + // SI is the shift in character (Caret: ^O). + SI = 0x0F + // DLE is the data link escape character (Caret: ^P). + DLE = 0x10 + // DC1 is the device control 1 character (Caret: ^Q). + DC1 = 0x11 + // DC2 is the device control 2 character (Caret: ^R). + DC2 = 0x12 + // DC3 is the device control 3 character (Caret: ^S). + DC3 = 0x13 + // DC4 is the device control 4 character (Caret: ^T). + DC4 = 0x14 + // NAK is the negative acknowledge character (Caret: ^U). + NAK = 0x15 + // SYN is the synchronous idle character (Caret: ^V). + SYN = 0x16 + // ETB is the end of transmission block character (Caret: ^W). + ETB = 0x17 + // CAN is the cancel character (Caret: ^X). + CAN = 0x18 + // EM is the end of medium character (Caret: ^Y). + EM = 0x19 + // SUB is the substitute character (Caret: ^Z). + SUB = 0x1A + // ESC is the escape character (Caret: ^[, Char: \e). + ESC = 0x1B + // FS is the file separator character (Caret: ^\). + FS = 0x1C + // GS is the group separator character (Caret: ^]). + GS = 0x1D + // RS is the record separator character (Caret: ^^). + RS = 0x1E + // US is the unit separator character (Caret: ^_). + US = 0x1F +) diff --git a/vendor/github.com/charmbracelet/x/ansi/c1.go b/vendor/github.com/charmbracelet/x/ansi/c1.go new file mode 100644 index 00000000..71058f53 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/c1.go @@ -0,0 +1,72 @@ +package ansi + +// C1 control characters. +// +// These range from (0x80-0x9F) as defined in ISO 6429 (ECMA-48). +// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes +const ( + // PAD is the padding character. + PAD = 0x80 + // HOP is the high octet preset character. + HOP = 0x81 + // BPH is the break permitted here character. + BPH = 0x82 + // NBH is the no break here character. + NBH = 0x83 + // IND is the index character. + IND = 0x84 + // NEL is the next line character. + NEL = 0x85 + // SSA is the start of selected area character. + SSA = 0x86 + // ESA is the end of selected area character. + ESA = 0x87 + // HTS is the horizontal tab set character. + HTS = 0x88 + // HTJ is the horizontal tab with justification character. + HTJ = 0x89 + // VTS is the vertical tab set character. + VTS = 0x8A + // PLD is the partial line forward character. + PLD = 0x8B + // PLU is the partial line backward character. + PLU = 0x8C + // RI is the reverse index character. + RI = 0x8D + // SS2 is the single shift 2 character. + SS2 = 0x8E + // SS3 is the single shift 3 character. + SS3 = 0x8F + // DCS is the device control string character. + DCS = 0x90 + // PU1 is the private use 1 character. + PU1 = 0x91 + // PU2 is the private use 2 character. + PU2 = 0x92 + // STS is the set transmit state character. + STS = 0x93 + // CCH is the cancel character. + CCH = 0x94 + // MW is the message waiting character. + MW = 0x95 + // SPA is the start of guarded area character. + SPA = 0x96 + // EPA is the end of guarded area character. + EPA = 0x97 + // SOS is the start of string character. + SOS = 0x98 + // SGCI is the single graphic character introducer character. + SGCI = 0x99 + // SCI is the single character introducer character. + SCI = 0x9A + // CSI is the control sequence introducer character. + CSI = 0x9B + // ST is the string terminator character. + ST = 0x9C + // OSC is the operating system command character. + OSC = 0x9D + // PM is the privacy message character. + PM = 0x9E + // APC is the application program command character. + APC = 0x9F +) diff --git a/vendor/github.com/charmbracelet/x/ansi/clipboard.go b/vendor/github.com/charmbracelet/x/ansi/clipboard.go new file mode 100644 index 00000000..94d26c36 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/clipboard.go @@ -0,0 +1,75 @@ +package ansi + +import "encoding/base64" + +// Clipboard names. +const ( + SystemClipboard = 'c' + PrimaryClipboard = 'p' +) + +// SetClipboard returns a sequence for manipulating the clipboard. +// +// OSC 52 ; Pc ; Pd ST +// OSC 52 ; Pc ; Pd BEL +// +// Where Pc is the clipboard name and Pd is the base64 encoded data. +// Empty data or invalid base64 data will reset the clipboard. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetClipboard(c byte, d string) string { + if d != "" { + d = base64.StdEncoding.EncodeToString([]byte(d)) + } + return "\x1b]52;" + string(c) + ";" + d + "\x07" +} + +// SetSystemClipboard returns a sequence for setting the system clipboard. +// +// This is equivalent to SetClipboard(SystemClipboard, d). +func SetSystemClipboard(d string) string { + return SetClipboard(SystemClipboard, d) +} + +// SetPrimaryClipboard returns a sequence for setting the primary clipboard. +// +// This is equivalent to SetClipboard(PrimaryClipboard, d). +func SetPrimaryClipboard(d string) string { + return SetClipboard(PrimaryClipboard, d) +} + +// ResetClipboard returns a sequence for resetting the clipboard. +// +// This is equivalent to SetClipboard(c, ""). +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func ResetClipboard(c byte) string { + return SetClipboard(c, "") +} + +// ResetSystemClipboard is a sequence for resetting the system clipboard. +// +// This is equivalent to ResetClipboard(SystemClipboard). +const ResetSystemClipboard = "\x1b]52;c;\x07" + +// ResetPrimaryClipboard is a sequence for resetting the primary clipboard. +// +// This is equivalent to ResetClipboard(PrimaryClipboard). +const ResetPrimaryClipboard = "\x1b]52;p;\x07" + +// RequestClipboard returns a sequence for requesting the clipboard. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func RequestClipboard(c byte) string { + return "\x1b]52;" + string(c) + ";?\x07" +} + +// RequestSystemClipboard is a sequence for requesting the system clipboard. +// +// This is equivalent to RequestClipboard(SystemClipboard). +const RequestSystemClipboard = "\x1b]52;c;?\x07" + +// RequestPrimaryClipboard is a sequence for requesting the primary clipboard. +// +// This is equivalent to RequestClipboard(PrimaryClipboard). +const RequestPrimaryClipboard = "\x1b]52;p;?\x07" diff --git a/vendor/github.com/charmbracelet/x/ansi/color.go b/vendor/github.com/charmbracelet/x/ansi/color.go new file mode 100644 index 00000000..2ff78bd7 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/color.go @@ -0,0 +1,196 @@ +package ansi + +import ( + "image/color" +) + +// Technically speaking, the 16 basic ANSI colors are arbitrary and can be +// customized at the terminal level. Given that, we're returning what we feel +// are good defaults. +// +// This could also be a slice, but we use a map to make the mappings very +// explicit. +// +// See: https://www.ditig.com/publications/256-colors-cheat-sheet +var lowANSI = map[uint32]uint32{ + 0: 0x000000, // black + 1: 0x800000, // red + 2: 0x008000, // green + 3: 0x808000, // yellow + 4: 0x000080, // blue + 5: 0x800080, // magenta + 6: 0x008080, // cyan + 7: 0xc0c0c0, // white + 8: 0x808080, // bright black + 9: 0xff0000, // bright red + 10: 0x00ff00, // bright green + 11: 0xffff00, // bright yellow + 12: 0x0000ff, // bright blue + 13: 0xff00ff, // bright magenta + 14: 0x00ffff, // bright cyan + 15: 0xffffff, // bright white +} + +// Color is a color that can be used in a terminal. ANSI (including +// ANSI256) and 24-bit "true colors" fall under this category. +type Color interface { + color.Color +} + +// BasicColor is an ANSI 3-bit or 4-bit color with a value from 0 to 15. +type BasicColor uint8 + +var _ Color = BasicColor(0) + +const ( + // Black is the ANSI black color. + Black BasicColor = iota + + // Red is the ANSI red color. + Red + + // Green is the ANSI green color. + Green + + // Yellow is the ANSI yellow color. + Yellow + + // Blue is the ANSI blue color. + Blue + + // Magenta is the ANSI magenta color. + Magenta + + // Cyan is the ANSI cyan color. + Cyan + + // White is the ANSI white color. + White + + // BrightBlack is the ANSI bright black color. + BrightBlack + + // BrightRed is the ANSI bright red color. + BrightRed + + // BrightGreen is the ANSI bright green color. + BrightGreen + + // BrightYellow is the ANSI bright yellow color. + BrightYellow + + // BrightBlue is the ANSI bright blue color. + BrightBlue + + // BrightMagenta is the ANSI bright magenta color. + BrightMagenta + + // BrightCyan is the ANSI bright cyan color. + BrightCyan + + // BrightWhite is the ANSI bright white color. + BrightWhite +) + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c BasicColor) RGBA() (uint32, uint32, uint32, uint32) { + ansi := uint32(c) + if ansi > 15 { + return 0, 0, 0, 0xffff + } + + r, g, b := ansiToRGB(ansi) + return toRGBA(r, g, b) +} + +// ExtendedColor is an ANSI 256 (8-bit) color with a value from 0 to 255. +type ExtendedColor uint8 + +var _ Color = ExtendedColor(0) + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c ExtendedColor) RGBA() (uint32, uint32, uint32, uint32) { + r, g, b := ansiToRGB(uint32(c)) + return toRGBA(r, g, b) +} + +// TrueColor is a 24-bit color that can be used in the terminal. +// This can be used to represent RGB colors. +// +// For example, the color red can be represented as: +// +// TrueColor(0xff0000) +type TrueColor uint32 + +var _ Color = TrueColor(0) + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c TrueColor) RGBA() (uint32, uint32, uint32, uint32) { + r, g, b := hexToRGB(uint32(c)) + return toRGBA(r, g, b) +} + +// ansiToRGB converts an ANSI color to a 24-bit RGB color. +// +// r, g, b := ansiToRGB(57) +func ansiToRGB(ansi uint32) (uint32, uint32, uint32) { + // For out-of-range values return black. + if ansi > 255 { + return 0, 0, 0 + } + + // Low ANSI. + if ansi < 16 { + h, ok := lowANSI[ansi] + if !ok { + return 0, 0, 0 + } + r, g, b := hexToRGB(h) + return r, g, b + } + + // Grays. + if ansi > 231 { + s := (ansi-232)*10 + 8 + return s, s, s + } + + // ANSI256. + n := ansi - 16 + b := n % 6 + g := (n - b) / 6 % 6 + r := (n - b - g*6) / 36 % 6 + for _, v := range []*uint32{&r, &g, &b} { + if *v > 0 { + c := *v*40 + 55 + *v = c + } + } + + return r, g, b +} + +// hexToRGB converts a number in hexadecimal format to red, green, and blue +// values. +// +// r, g, b := hexToRGB(0x0000FF) +func hexToRGB(hex uint32) (uint32, uint32, uint32) { + return hex >> 16, hex >> 8 & 0xff, hex & 0xff +} + +// toRGBA converts an RGB 8-bit color values to 32-bit color values suitable +// for color.Color. +// +// color.Color requires 16-bit color values, so we duplicate the 8-bit values +// to fill the 16-bit values. +// +// This always returns 0xffff (opaque) for the alpha channel. +func toRGBA(r, g, b uint32) (uint32, uint32, uint32, uint32) { + r |= r << 8 + g |= g << 8 + b |= b << 8 + return r, g, b, 0xffff +} diff --git a/vendor/github.com/charmbracelet/x/ansi/csi.go b/vendor/github.com/charmbracelet/x/ansi/csi.go new file mode 100644 index 00000000..b7e5bd2d --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/csi.go @@ -0,0 +1,141 @@ +package ansi + +import ( + "bytes" + "strconv" + + "github.com/charmbracelet/x/ansi/parser" +) + +// CsiSequence represents a control sequence introducer (CSI) sequence. +// +// The sequence starts with a CSI sequence, CSI (0x9B) in a 8-bit environment +// or ESC [ (0x1B 0x5B) in a 7-bit environment, followed by any number of +// parameters in the range of 0x30-0x3F, then by any number of intermediate +// byte in the range of 0x20-0x2F, then finally with a single final byte in the +// range of 0x20-0x7E. +// +// CSI P..P I..I F +// +// See ECMA-48 § 5.4. +type CsiSequence struct { + // Params contains the raw parameters of the sequence. + // This is a slice of integers, where each integer is a 32-bit integer + // containing the parameter value in the lower 31 bits and a flag in the + // most significant bit indicating whether there are more sub-parameters. + Params []int + + // Cmd contains the raw command of the sequence. + // The command is a 32-bit integer containing the CSI command byte in the + // lower 8 bits, the private marker in the next 8 bits, and the intermediate + // byte in the next 8 bits. + // + // CSI ? u + // + // Is represented as: + // + // 'u' | '?' << 8 + Cmd int +} + +var _ Sequence = CsiSequence{} + +// Marker returns the marker byte of the CSI sequence. +// This is always gonna be one of the following '<' '=' '>' '?' and in the +// range of 0x3C-0x3F. +// Zero is returned if the sequence does not have a marker. +func (s CsiSequence) Marker() int { + return parser.Marker(s.Cmd) +} + +// Intermediate returns the intermediate byte of the CSI sequence. +// An intermediate byte is in the range of 0x20-0x2F. This includes these +// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+', +// ',', '-', '.', '/'. +// Zero is returned if the sequence does not have an intermediate byte. +func (s CsiSequence) Intermediate() int { + return parser.Intermediate(s.Cmd) +} + +// Command returns the command byte of the CSI sequence. +func (s CsiSequence) Command() int { + return parser.Command(s.Cmd) +} + +// Param returns the parameter at the given index. +// It returns -1 if the parameter does not exist. +func (s CsiSequence) Param(i int) int { + return parser.Param(s.Params, i) +} + +// HasMore returns true if the parameter has more sub-parameters. +func (s CsiSequence) HasMore(i int) bool { + return parser.HasMore(s.Params, i) +} + +// Subparams returns the sub-parameters of the given parameter. +// It returns nil if the parameter does not exist. +func (s CsiSequence) Subparams(i int) []int { + return parser.Subparams(s.Params, i) +} + +// Len returns the number of parameters in the sequence. +// This will return the number of parameters in the sequence, excluding any +// sub-parameters. +func (s CsiSequence) Len() int { + return parser.Len(s.Params) +} + +// Range iterates over the parameters of the sequence and calls the given +// function for each parameter. +// The function should return false to stop the iteration. +func (s CsiSequence) Range(fn func(i int, param int, hasMore bool) bool) { + parser.Range(s.Params, fn) +} + +// Clone returns a copy of the CSI sequence. +func (s CsiSequence) Clone() Sequence { + return CsiSequence{ + Params: append([]int(nil), s.Params...), + Cmd: s.Cmd, + } +} + +// String returns a string representation of the sequence. +// The string will always be in the 7-bit format i.e (ESC [ P..P I..I F). +func (s CsiSequence) String() string { + return s.buffer().String() +} + +// buffer returns a buffer containing the sequence. +func (s CsiSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteString("\x1b[") + if m := s.Marker(); m != 0 { + b.WriteByte(byte(m)) + } + s.Range(func(i, param int, hasMore bool) bool { + if param >= 0 { + b.WriteString(strconv.Itoa(param)) + } + if i < len(s.Params)-1 { + if hasMore { + b.WriteByte(':') + } else { + b.WriteByte(';') + } + } + return true + }) + if i := s.Intermediate(); i != 0 { + b.WriteByte(byte(i)) + } + b.WriteByte(byte(s.Command())) + return &b +} + +// Bytes returns the byte representation of the sequence. +// The bytes will always be in the 7-bit format i.e (ESC [ P..P I..I F). +func (s CsiSequence) Bytes() []byte { + return s.buffer().Bytes() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/ctrl.go b/vendor/github.com/charmbracelet/x/ansi/ctrl.go new file mode 100644 index 00000000..21beb9cd --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/ctrl.go @@ -0,0 +1,17 @@ +package ansi + +// RequestXTVersion is a control sequence that requests the terminal's XTVERSION. It responds with a DSR sequence identifying the version. +// +// CSI > Ps q +// DCS > | text ST +// +// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys +const RequestXTVersion = "\x1b[>0q" + +// RequestPrimaryDeviceAttributes is a control sequence that requests the +// terminal's primary device attributes (DA1). +// +// CSI c +// +// See https://vt100.net/docs/vt510-rm/DA1.html +const RequestPrimaryDeviceAttributes = "\x1b[c" diff --git a/vendor/github.com/charmbracelet/x/ansi/cursor.go b/vendor/github.com/charmbracelet/x/ansi/cursor.go new file mode 100644 index 00000000..ec1fc4d2 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/cursor.go @@ -0,0 +1,235 @@ +package ansi + +import "strconv" + +// SaveCursor (DECSC) is an escape sequence that saves the current cursor +// position. +// +// ESC 7 +// +// See: https://vt100.net/docs/vt510-rm/DECSC.html +const SaveCursor = "\x1b7" + +// RestoreCursor (DECRC) is an escape sequence that restores the cursor +// position. +// +// ESC 8 +// +// See: https://vt100.net/docs/vt510-rm/DECRC.html +const RestoreCursor = "\x1b8" + +// RequestCursorPosition (CPR) is an escape sequence that requests the current +// cursor position. +// +// CSI 6 n +// +// The terminal will report the cursor position as a CSI sequence in the +// following format: +// +// CSI Pl ; Pc R +// +// Where Pl is the line number and Pc is the column number. +// See: https://vt100.net/docs/vt510-rm/CPR.html +const RequestCursorPosition = "\x1b[6n" + +// RequestExtendedCursorPosition (DECXCPR) is a sequence for requesting the +// cursor position report including the current page number. +// +// CSI ? 6 n +// +// The terminal will report the cursor position as a CSI sequence in the +// following format: +// +// CSI ? Pl ; Pc ; Pp R +// +// Where Pl is the line number, Pc is the column number, and Pp is the page +// number. +// See: https://vt100.net/docs/vt510-rm/DECXCPR.html +const RequestExtendedCursorPosition = "\x1b[?6n" + +// CursorUp (CUU) returns a sequence for moving the cursor up n cells. +// +// CSI n A +// +// See: https://vt100.net/docs/vt510-rm/CUU.html +func CursorUp(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "A" +} + +// CursorUp1 is a sequence for moving the cursor up one cell. +// +// This is equivalent to CursorUp(1). +const CursorUp1 = "\x1b[A" + +// CursorDown (CUD) returns a sequence for moving the cursor down n cells. +// +// CSI n B +// +// See: https://vt100.net/docs/vt510-rm/CUD.html +func CursorDown(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "B" +} + +// CursorDown1 is a sequence for moving the cursor down one cell. +// +// This is equivalent to CursorDown(1). +const CursorDown1 = "\x1b[B" + +// CursorRight (CUF) returns a sequence for moving the cursor right n cells. +// +// CSI n C +// +// See: https://vt100.net/docs/vt510-rm/CUF.html +func CursorRight(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "C" +} + +// CursorRight1 is a sequence for moving the cursor right one cell. +// +// This is equivalent to CursorRight(1). +const CursorRight1 = "\x1b[C" + +// CursorLeft (CUB) returns a sequence for moving the cursor left n cells. +// +// CSI n D +// +// See: https://vt100.net/docs/vt510-rm/CUB.html +func CursorLeft(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "D" +} + +// CursorLeft1 is a sequence for moving the cursor left one cell. +// +// This is equivalent to CursorLeft(1). +const CursorLeft1 = "\x1b[D" + +// CursorNextLine (CNL) returns a sequence for moving the cursor to the +// beginning of the next line n times. +// +// CSI n E +// +// See: https://vt100.net/docs/vt510-rm/CNL.html +func CursorNextLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "E" +} + +// CursorPreviousLine (CPL) returns a sequence for moving the cursor to the +// beginning of the previous line n times. +// +// CSI n F +// +// See: https://vt100.net/docs/vt510-rm/CPL.html +func CursorPreviousLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "F" +} + +// MoveCursor (CUP) returns a sequence for moving the cursor to the given row +// and column. +// +// CSI n ; m H +// +// See: https://vt100.net/docs/vt510-rm/CUP.html +func MoveCursor(row, col int) string { + if row < 0 { + row = 0 + } + if col < 0 { + col = 0 + } + return "\x1b[" + strconv.Itoa(row) + ";" + strconv.Itoa(col) + "H" +} + +// MoveCursorOrigin is a sequence for moving the cursor to the upper left +// corner of the screen. This is equivalent to MoveCursor(1, 1). +const MoveCursorOrigin = "\x1b[1;1H" + +// SaveCursorPosition (SCP or SCOSC) is a sequence for saving the cursor +// position. +// +// CSI s +// +// This acts like Save, except the page number where the cursor is located is +// not saved. +// +// See: https://vt100.net/docs/vt510-rm/SCOSC.html +const SaveCursorPosition = "\x1b[s" + +// RestoreCursorPosition (RCP or SCORC) is a sequence for restoring the cursor +// position. +// +// CSI u +// +// This acts like Restore, except the cursor stays on the same page where the +// cursor was saved. +// +// See: https://vt100.net/docs/vt510-rm/SCORC.html +const RestoreCursorPosition = "\x1b[u" + +// SetCursorStyle (DECSCUSR) returns a sequence for changing the cursor style. +// +// CSI Ps SP q +// +// Where Ps is the cursor style: +// +// 0: Blinking block +// 1: Blinking block (default) +// 2: Steady block +// 3: Blinking underline +// 4: Steady underline +// 5: Blinking bar (xterm) +// 6: Steady bar (xterm) +// +// See: https://vt100.net/docs/vt510-rm/DECSCUSR.html +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 +func SetCursorStyle(style int) string { + if style < 0 { + style = 0 + } + return "\x1b[" + strconv.Itoa(style) + " q" +} + +// SetPointerShape returns a sequence for changing the mouse pointer cursor +// shape. Use "default" for the default pointer shape. +// +// OSC 22 ; Pt ST +// OSC 22 ; Pt BEL +// +// Where Pt is the pointer shape name. The name can be anything that the +// operating system can understand. Some common names are: +// +// - copy +// - crosshair +// - default +// - ew-resize +// - n-resize +// - text +// - wait +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetPointerShape(shape string) string { + return "\x1b]22;" + shape + "\x07" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/dcs.go b/vendor/github.com/charmbracelet/x/ansi/dcs.go new file mode 100644 index 00000000..185f0b52 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/dcs.go @@ -0,0 +1,148 @@ +package ansi + +import ( + "bytes" + "strconv" + + "github.com/charmbracelet/x/ansi/parser" +) + +// DcsSequence represents a Device Control String (DCS) escape sequence. +// +// The DCS sequence is used to send device control strings to the terminal. The +// sequence starts with the C1 control code character DCS (0x9B) or ESC P in +// 7-bit environments, followed by parameter bytes, intermediate bytes, a +// command byte, followed by data bytes, and ends with the C1 control code +// character ST (0x9C) or ESC \ in 7-bit environments. +// +// This follows the parameter string format. +// See ECMA-48 § 5.4.1 +type DcsSequence struct { + // Params contains the raw parameters of the sequence. + // This is a slice of integers, where each integer is a 32-bit integer + // containing the parameter value in the lower 31 bits and a flag in the + // most significant bit indicating whether there are more sub-parameters. + Params []int + + // Data contains the string raw data of the sequence. + // This is the data between the final byte and the escape sequence terminator. + Data []byte + + // Cmd contains the raw command of the sequence. + // The command is a 32-bit integer containing the DCS command byte in the + // lower 8 bits, the private marker in the next 8 bits, and the intermediate + // byte in the next 8 bits. + // + // DCS > 0 ; 1 $ r ST + // + // Is represented as: + // + // 'r' | '>' << 8 | '$' << 16 + Cmd int +} + +var _ Sequence = DcsSequence{} + +// Marker returns the marker byte of the DCS sequence. +// This is always gonna be one of the following '<' '=' '>' '?' and in the +// range of 0x3C-0x3F. +// Zero is returned if the sequence does not have a marker. +func (s DcsSequence) Marker() int { + return parser.Marker(s.Cmd) +} + +// Intermediate returns the intermediate byte of the DCS sequence. +// An intermediate byte is in the range of 0x20-0x2F. This includes these +// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+', +// ',', '-', '.', '/'. +// Zero is returned if the sequence does not have an intermediate byte. +func (s DcsSequence) Intermediate() int { + return parser.Intermediate(s.Cmd) +} + +// Command returns the command byte of the CSI sequence. +func (s DcsSequence) Command() int { + return parser.Command(s.Cmd) +} + +// Param returns the parameter at the given index. +// It returns -1 if the parameter does not exist. +func (s DcsSequence) Param(i int) int { + return parser.Param(s.Params, i) +} + +// HasMore returns true if the parameter has more sub-parameters. +func (s DcsSequence) HasMore(i int) bool { + return parser.HasMore(s.Params, i) +} + +// Subparams returns the sub-parameters of the given parameter. +// It returns nil if the parameter does not exist. +func (s DcsSequence) Subparams(i int) []int { + return parser.Subparams(s.Params, i) +} + +// Len returns the number of parameters in the sequence. +// This will return the number of parameters in the sequence, excluding any +// sub-parameters. +func (s DcsSequence) Len() int { + return parser.Len(s.Params) +} + +// Range iterates over the parameters of the sequence and calls the given +// function for each parameter. +// The function should return false to stop the iteration. +func (s DcsSequence) Range(fn func(i int, param int, hasMore bool) bool) { + parser.Range(s.Params, fn) +} + +// Clone returns a copy of the DCS sequence. +func (s DcsSequence) Clone() Sequence { + return DcsSequence{ + Params: append([]int(nil), s.Params...), + Data: append([]byte(nil), s.Data...), + Cmd: s.Cmd, + } +} + +// String returns a string representation of the sequence. +// The string will always be in the 7-bit format i.e (ESC P p..p i..i f ESC \). +func (s DcsSequence) String() string { + return s.buffer().String() +} + +// buffer returns a buffer containing the sequence. +func (s DcsSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteString("\x1bP") + if m := s.Marker(); m != 0 { + b.WriteByte(byte(m)) + } + s.Range(func(i, param int, hasMore bool) bool { + if param >= -1 { + b.WriteString(strconv.Itoa(param)) + } + if i < len(s.Params)-1 { + if hasMore { + b.WriteByte(':') + } else { + b.WriteByte(';') + } + } + return true + }) + if i := s.Intermediate(); i != 0 { + b.WriteByte(byte(i)) + } + b.WriteByte(byte(s.Command())) + b.Write(s.Data) + b.WriteByte(ESC) + b.WriteByte('\\') + return &b +} + +// Bytes returns the byte representation of the sequence. +// The bytes will always be in the 7-bit format i.e (ESC P p..p i..i F ESC \). +func (s DcsSequence) Bytes() []byte { + return s.buffer().Bytes() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/doc.go b/vendor/github.com/charmbracelet/x/ansi/doc.go new file mode 100644 index 00000000..e955e9f1 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/doc.go @@ -0,0 +1,7 @@ +// Package ansi defines common ANSI escape sequences based on the ECMA-48 +// specs. +// +// All sequences use 7-bit C1 control codes, which are supported by most +// terminal emulators. OSC sequences are terminated by a BEL for wider +// compatibility with terminals. +package ansi diff --git a/vendor/github.com/charmbracelet/x/ansi/hyperlink.go b/vendor/github.com/charmbracelet/x/ansi/hyperlink.go new file mode 100644 index 00000000..323bfe93 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/hyperlink.go @@ -0,0 +1,28 @@ +package ansi + +import "strings" + +// SetHyperlink returns a sequence for starting a hyperlink. +// +// OSC 8 ; Params ; Uri ST +// OSC 8 ; Params ; Uri BEL +// +// To reset the hyperlink, omit the URI. +// +// See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda +func SetHyperlink(uri string, params ...string) string { + var p string + if len(params) > 0 { + p = strings.Join(params, ":") + } + return "\x1b]8;" + p + ";" + uri + "\x07" +} + +// ResetHyperlink returns a sequence for resetting the hyperlink. +// +// This is equivalent to SetHyperlink("", params...). +// +// See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda +func ResetHyperlink(params ...string) string { + return SetHyperlink("", params...) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty.go b/vendor/github.com/charmbracelet/x/ansi/kitty.go new file mode 100644 index 00000000..c56d8d1c --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/kitty.go @@ -0,0 +1,90 @@ +package ansi + +import "strconv" + +// Kitty keyboard protocol progressive enhancement flags. +// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +const ( + KittyDisambiguateEscapeCodes = 1 << iota + KittyReportEventTypes + KittyReportAlternateKeys + KittyReportAllKeysAsEscapeCodes + KittyReportAssociatedKeys + + KittyAllFlags = KittyDisambiguateEscapeCodes | KittyReportEventTypes | + KittyReportAlternateKeys | KittyReportAllKeysAsEscapeCodes | KittyReportAssociatedKeys +) + +// RequestKittyKeyboard is a sequence to request the terminal Kitty keyboard +// protocol enabled flags. +// +// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/ +const RequestKittyKeyboard = "\x1b[?u" + +// KittyKeyboard returns a sequence to request keyboard enhancements from the terminal. +// The flags argument is a bitmask of the Kitty keyboard protocol flags. While +// mode specifies how the flags should be interpreted. +// +// Possible values for flags mask: +// +// 1: Disambiguate escape codes +// 2: Report event types +// 4: Report alternate keys +// 8: Report all keys as escape codes +// 16: Report associated text +// +// Possible values for mode: +// +// 1: Set given flags and unset all others +// 2: Set given flags and keep existing flags unchanged +// 3: Unset given flags and keep existing flags unchanged +// +// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +func KittyKeyboard(flags, mode int) string { + return "\x1b[=" + strconv.Itoa(flags) + ";" + strconv.Itoa(mode) + "u" +} + +// PushKittyKeyboard returns a sequence to push the given flags to the terminal +// Kitty Keyboard stack. +// +// Possible values for flags mask: +// +// 0: Disable all features +// 1: Disambiguate escape codes +// 2: Report event types +// 4: Report alternate keys +// 8: Report all keys as escape codes +// 16: Report associated text +// +// CSI > flags u +// +// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +func PushKittyKeyboard(flags int) string { + var f string + if flags > 0 { + f = strconv.Itoa(flags) + } + + return "\x1b[>" + f + "u" +} + +// DisableKittyKeyboard is a sequence to push zero into the terminal Kitty +// Keyboard stack to disable the protocol. +// +// This is equivalent to PushKittyKeyboard(0). +const DisableKittyKeyboard = "\x1b[>0u" + +// PopKittyKeyboard returns a sequence to pop n number of flags from the +// terminal Kitty Keyboard stack. +// +// CSI < flags u +// +// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +func PopKittyKeyboard(n int) string { + var num string + if n > 0 { + num = strconv.Itoa(n) + } + + return "\x1b[<" + num + "u" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/mode.go b/vendor/github.com/charmbracelet/x/ansi/mode.go new file mode 100644 index 00000000..7d25ddc5 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/mode.go @@ -0,0 +1,153 @@ +package ansi + +// This file define uses multiple sequences to set (SM), reset (RM), and request +// (DECRQM) different ANSI and DEC modes. +// +// See: https://vt100.net/docs/vt510-rm/SM.html +// See: https://vt100.net/docs/vt510-rm/RM.html +// See: https://vt100.net/docs/vt510-rm/DECRQM.html +// +// The terminal then responds to the request with a Report Mode function +// (DECRPM) in the format: +// +// ANSI format: +// +// CSI Pa ; Ps ; $ y +// +// DEC format: +// +// CSI ? Pa ; Ps $ y +// +// Where Pa is the mode number, and Ps is the mode value. +// See: https://vt100.net/docs/vt510-rm/DECRPM.html + +// Application Cursor Keys (DECCKM) is a mode that determines whether the +// cursor keys send ANSI cursor sequences or application sequences. +// +// See: https://vt100.net/docs/vt510-rm/DECCKM.html +const ( + EnableCursorKeys = "\x1b[?1h" + DisableCursorKeys = "\x1b[?1l" + RequestCursorKeys = "\x1b[?1$p" +) + +// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor. +// +// See: https://vt100.net/docs/vt510-rm/DECTCEM.html +const ( + ShowCursor = "\x1b[?25h" + HideCursor = "\x1b[?25l" + RequestCursorVisibility = "\x1b[?25$p" +) + +// VT Mouse Tracking is a mode that determines whether the mouse reports on +// button press and release. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + EnableMouse = "\x1b[?1000h" + DisableMouse = "\x1b[?1000l" + RequestMouse = "\x1b[?1000$p" +) + +// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on +// button presses, releases, and highlighted cells. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + EnableMouseHilite = "\x1b[?1001h" + DisableMouseHilite = "\x1b[?1001l" + RequestMouseHilite = "\x1b[?1001$p" +) + +// Cell Motion Mouse Tracking is a mode that determines whether the mouse +// reports on button press, release, and motion events. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + EnableMouseCellMotion = "\x1b[?1002h" + DisableMouseCellMotion = "\x1b[?1002l" + RequestMouseCellMotion = "\x1b[?1002$p" +) + +// All Mouse Tracking is a mode that determines whether the mouse reports on +// button press, release, motion, and highlight events. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + EnableMouseAllMotion = "\x1b[?1003h" + DisableMouseAllMotion = "\x1b[?1003l" + RequestMouseAllMotion = "\x1b[?1003$p" +) + +// Report Focus is a mode that makes the terminal report focus-in and focus-out events. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-FocusIn_FocusOut +const ( + EnableReportFocus = "\x1b[?1004h" + DisableReportFocus = "\x1b[?1004l" + RequestReportFocus = "\x1b[?1004$p" +) + +// SGR Mouse Extension is a mode that determines whether the mouse reports events +// formatted with SGR parameters. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + EnableMouseSgrExt = "\x1b[?1006h" + DisableMouseSgrExt = "\x1b[?1006l" + RequestMouseSgrExt = "\x1b[?1006$p" +) + +// Alternate Screen Buffer is a mode that determines whether the alternate screen +// buffer is active. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer +const ( + EnableAltScreenBuffer = "\x1b[?1049h" + DisableAltScreenBuffer = "\x1b[?1049l" + RequestAltScreenBuffer = "\x1b[?1049$p" +) + +// Bracketed Paste Mode is a mode that determines whether pasted text is +// bracketed with escape sequences. +// +// See: https://cirw.in/blog/bracketed-paste +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode +const ( + EnableBracketedPaste = "\x1b[?2004h" + DisableBracketedPaste = "\x1b[?2004l" + RequestBracketedPaste = "\x1b[?2004$p" +) + +// Synchronized Output Mode is a mode that determines whether output is +// synchronized with the terminal. +// +// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 +const ( + EnableSyncdOutput = "\x1b[?2026h" + DisableSyncdOutput = "\x1b[?2026l" + RequestSyncdOutput = "\x1b[?2026$p" +) + +// Grapheme Clustering Mode is a mode that determines whether the terminal +// should look for grapheme clusters instead of single runes in the rendered +// text. This makes the terminal properly render combining characters such as +// emojis. +// +// See: https://github.com/contour-terminal/terminal-unicode-core +const ( + EnableGraphemeClustering = "\x1b[?2027h" + DisableGraphemeClustering = "\x1b[?2027l" + RequestGraphemeClustering = "\x1b[?2027$p" +) + +// Win32Input is a mode that determines whether input is processed by the +// Win32 console and Conpty. +// +// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md +const ( + EnableWin32Input = "\x1b[?9001h" + DisableWin32Input = "\x1b[?9001l" + RequestWin32Input = "\x1b[?9001$p" +) diff --git a/vendor/github.com/charmbracelet/x/ansi/osc.go b/vendor/github.com/charmbracelet/x/ansi/osc.go new file mode 100644 index 00000000..40b543c2 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/osc.go @@ -0,0 +1,69 @@ +package ansi + +import ( + "bytes" + "strings" +) + +// OscSequence represents an OSC sequence. +// +// The sequence starts with a OSC sequence, OSC (0x9D) in a 8-bit environment +// or ESC ] (0x1B 0x5D) in a 7-bit environment, followed by positive integer identifier, +// then by arbitrary data terminated by a ST (0x9C) in a 8-bit environment, +// ESC \ (0x1B 0x5C) in a 7-bit environment, or BEL (0x07) for backwards compatibility. +// +// OSC Ps ; Pt ST +// OSC Ps ; Pt BEL +// +// See ECMA-48 § 5.7. +type OscSequence struct { + // Data contains the raw data of the sequence including the identifier + // command. + Data []byte + + // Cmd contains the raw command of the sequence. + Cmd int +} + +var _ Sequence = OscSequence{} + +// Command returns the command of the OSC sequence. +func (s OscSequence) Command() int { + return s.Cmd +} + +// Params returns the parameters of the OSC sequence split by ';'. +// The first element is the identifier command. +func (s OscSequence) Params() []string { + return strings.Split(string(s.Data), ";") +} + +// Clone returns a copy of the OSC sequence. +func (s OscSequence) Clone() Sequence { + return OscSequence{ + Data: append([]byte(nil), s.Data...), + Cmd: s.Cmd, + } +} + +// String returns the string representation of the OSC sequence. +// To be more compatible with different terminal, this will always return a +// 7-bit formatted sequence, terminated by BEL. +func (s OscSequence) String() string { + return s.buffer().String() +} + +// Bytes returns the byte representation of the OSC sequence. +// To be more compatible with different terminal, this will always return a +// 7-bit formatted sequence, terminated by BEL. +func (s OscSequence) Bytes() []byte { + return s.buffer().Bytes() +} + +func (s OscSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteString("\x1b]") + b.Write(s.Data) + b.WriteByte(BEL) + return &b +} diff --git a/vendor/github.com/charmbracelet/x/ansi/params.go b/vendor/github.com/charmbracelet/x/ansi/params.go new file mode 100644 index 00000000..a1bb4249 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/params.go @@ -0,0 +1,45 @@ +package ansi + +import ( + "bytes" +) + +// Params parses and returns a list of control sequence parameters. +// +// Parameters are positive integers separated by semicolons. Empty parameters +// default to zero. Parameters can have sub-parameters separated by colons. +// +// Any non-parameter bytes are ignored. This includes bytes that are not in the +// range of 0x30-0x3B. +// +// See ECMA-48 § 5.4.1. +func Params(p []byte) [][]uint { + if len(p) == 0 { + return [][]uint{} + } + + // Filter out non-parameter bytes i.e. non 0x30-0x3B. + p = bytes.TrimFunc(p, func(r rune) bool { + return r < 0x30 || r > 0x3B + }) + + parts := bytes.Split(p, []byte{';'}) + params := make([][]uint, len(parts)) + for i, part := range parts { + sparts := bytes.Split(part, []byte{':'}) + params[i] = make([]uint, len(sparts)) + for j, spart := range sparts { + params[i][j] = bytesToUint16(spart) + } + } + + return params +} + +func bytesToUint16(b []byte) uint { + var n uint + for _, c := range b { + n = n*10 + uint(c-'0') + } + return n +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser.go b/vendor/github.com/charmbracelet/x/ansi/parser.go new file mode 100644 index 00000000..63654c04 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser.go @@ -0,0 +1,370 @@ +package ansi + +import ( + "unicode/utf8" + "unsafe" + + "github.com/charmbracelet/x/ansi/parser" +) + +// ParserDispatcher is a function that dispatches a sequence. +type ParserDispatcher func(Sequence) + +// Parser represents a DEC ANSI compatible sequence parser. +// +// It uses a state machine to parse ANSI escape sequences and control +// characters. The parser is designed to be used with a terminal emulator or +// similar application that needs to parse ANSI escape sequences and control +// characters. +// See package [parser] for more information. +// +//go:generate go run ./gen.go +type Parser struct { + // Params contains the raw parameters of the sequence. + // These parameters used when constructing CSI and DCS sequences. + Params []int + + // Data contains the raw data of the sequence. + // These data used when constructing OSC, DCS, SOS, PM, and APC sequences. + Data []byte + + // DataLen keeps track of the length of the data buffer. + // If DataLen is -1, the data buffer is unlimited and will grow as needed. + // Otherwise, DataLen is limited by the size of the Data buffer. + DataLen int + + // ParamsLen keeps track of the number of parameters. + // This is limited by the size of the Params buffer. + // + // This is also used when collecting UTF-8 runes to keep track of the + // number of rune bytes collected. + ParamsLen int + + // Cmd contains the raw command along with the private marker and + // intermediate bytes of the sequence. + // The first lower byte contains the command byte, the next byte contains + // the private marker, and the next byte contains the intermediate byte. + // + // This is also used when collecting UTF-8 runes treating it as a slice of + // 4 bytes. + Cmd int + + // State is the current state of the parser. + State byte +} + +// NewParser returns a new parser with the given sizes allocated. +// If dataSize is zero, the underlying data buffer will be unlimited and will +// grow as needed. +func NewParser(paramsSize, dataSize int) *Parser { + s := new(Parser) + if dataSize <= 0 { + dataSize = 0 + s.DataLen = -1 + } + s.Params = make([]int, paramsSize) + s.Data = make([]byte, dataSize) + return s +} + +// Reset resets the parser to its initial state. +func (p *Parser) Reset() { + p.clear() + p.State = parser.GroundState +} + +// clear clears the parser parameters and command. +func (p *Parser) clear() { + if len(p.Params) > 0 { + p.Params[0] = parser.MissingParam + } + p.ParamsLen = 0 + p.Cmd = 0 +} + +// clearCmd clears the parser command, params len and data len. +func (p *Parser) clearCmd() { + p.Cmd = 0 + p.ParamsLen = 0 + p.DataLen = 0 +} + +// StateName returns the name of the current state. +func (p *Parser) StateName() string { + return parser.StateNames[p.State] +} + +// Parse parses the given dispatcher and byte buffer. +func (p *Parser) Parse(dispatcher ParserDispatcher, b []byte) { + for i := 0; i < len(b); i++ { + p.Advance(dispatcher, b[i], i < len(b)-1) + } +} + +// Advance advances the parser with the given dispatcher and byte. +func (p *Parser) Advance(dispatcher ParserDispatcher, b byte, more bool) parser.Action { + switch p.State { + case parser.Utf8State: + // We handle UTF-8 here. + return p.advanceUtf8(dispatcher, b) + default: + return p.advance(dispatcher, b, more) + } +} + +func (p *Parser) collectRune(b byte) { + if p.ParamsLen >= utf8.UTFMax { + return + } + + shift := p.ParamsLen * 8 + p.Cmd &^= 0xff << shift + p.Cmd |= int(b) << shift + p.ParamsLen++ +} + +func (p *Parser) advanceUtf8(dispatcher ParserDispatcher, b byte) parser.Action { + // Collect UTF-8 rune bytes. + p.collectRune(b) + rw := utf8ByteLen(byte(p.Cmd & 0xff)) + if rw == -1 { + // We panic here because the first byte comes from the state machine, + // if this panics, it means there is a bug in the state machine! + panic("invalid rune") // unreachable + } + + if p.ParamsLen < rw { + return parser.CollectAction + } + + // We have enough bytes to decode the rune using unsafe + r, _ := utf8.DecodeRune((*[utf8.UTFMax]byte)(unsafe.Pointer(&p.Cmd))[:rw]) + if dispatcher != nil { + dispatcher(Rune(r)) + } + + p.State = parser.GroundState + p.ParamsLen = 0 + + return parser.PrintAction +} + +func (p *Parser) advance(d ParserDispatcher, b byte, more bool) parser.Action { + state, action := parser.Table.Transition(p.State, b) + + // We need to clear the parser state if the state changes from EscapeState. + // This is because when we enter the EscapeState, we don't get a chance to + // clear the parser state. For example, when a sequence terminates with a + // ST (\x1b\\ or \x9c), we dispatch the current sequence and transition to + // EscapeState. However, the parser state is not cleared in this case and + // we need to clear it here before dispatching the esc sequence. + if p.State != state { + if p.State == parser.EscapeState { + p.performAction(d, parser.ClearAction, state, b) + } + if action == parser.PutAction && + p.State == parser.DcsEntryState && state == parser.DcsStringState { + // XXX: This is a special case where we need to start collecting + // non-string parameterized data i.e. doesn't follow the ECMA-48 § + // 5.4.1 string parameters format. + p.performAction(d, parser.StartAction, state, 0) + } + } + + // Handle special cases + switch { + case b == ESC && p.State == parser.EscapeState: + // Two ESCs in a row + p.performAction(d, parser.ExecuteAction, state, b) + if !more { + // Two ESCs at the end of the buffer + p.performAction(d, parser.ExecuteAction, state, b) + } + case b == ESC && !more: + // Last byte is an ESC + p.performAction(d, parser.ExecuteAction, state, b) + case p.State == parser.EscapeState && b == 'P' && !more: + // ESC P (DCS) at the end of the buffer + p.performAction(d, parser.DispatchAction, state, b) + case p.State == parser.EscapeState && b == 'X' && !more: + // ESC X (SOS) at the end of the buffer + p.performAction(d, parser.DispatchAction, state, b) + case p.State == parser.EscapeState && b == '[' && !more: + // ESC [ (CSI) at the end of the buffer + p.performAction(d, parser.DispatchAction, state, b) + case p.State == parser.EscapeState && b == ']' && !more: + // ESC ] (OSC) at the end of the buffer + p.performAction(d, parser.DispatchAction, state, b) + case p.State == parser.EscapeState && b == '^' && !more: + // ESC ^ (PM) at the end of the buffer + p.performAction(d, parser.DispatchAction, state, b) + case p.State == parser.EscapeState && b == '_' && !more: + // ESC _ (APC) at the end of the buffer + p.performAction(d, parser.DispatchAction, state, b) + default: + p.performAction(d, action, state, b) + } + + p.State = state + + return action +} + +func (p *Parser) performAction(dispatcher ParserDispatcher, action parser.Action, state parser.State, b byte) { + switch action { + case parser.IgnoreAction: + break + + case parser.ClearAction: + p.clear() + + case parser.PrintAction: + if dispatcher != nil { + dispatcher(Rune(b)) + } + + case parser.ExecuteAction: + if dispatcher != nil { + dispatcher(ControlCode(b)) + } + + case parser.MarkerAction: + // Collect private marker + // we only store the last marker + p.Cmd &^= 0xff << parser.MarkerShift + p.Cmd |= int(b) << parser.MarkerShift + + case parser.CollectAction: + if state == parser.Utf8State { + // Reset the UTF-8 counter + p.ParamsLen = 0 + p.collectRune(b) + } else { + // Collect intermediate bytes + // we only store the last intermediate byte + p.Cmd &^= 0xff << parser.IntermedShift + p.Cmd |= int(b) << parser.IntermedShift + } + + case parser.ParamAction: + // Collect parameters + if p.ParamsLen >= len(p.Params) { + break + } + + if b >= '0' && b <= '9' { + if p.Params[p.ParamsLen] == parser.MissingParam { + p.Params[p.ParamsLen] = 0 + } + + p.Params[p.ParamsLen] *= 10 + p.Params[p.ParamsLen] += int(b - '0') + } + + if b == ':' { + p.Params[p.ParamsLen] |= parser.HasMoreFlag + } + + if b == ';' || b == ':' { + p.ParamsLen++ + if p.ParamsLen < len(p.Params) { + p.Params[p.ParamsLen] = parser.MissingParam + } + } + + case parser.StartAction: + if p.DataLen < 0 && p.Data != nil { + p.Data = p.Data[:0] + } else { + p.DataLen = 0 + } + if p.State >= parser.DcsEntryState && p.State <= parser.DcsStringState { + // Collect the command byte for DCS + p.Cmd |= int(b) + } else { + p.Cmd = parser.MissingCommand + } + + case parser.PutAction: + switch p.State { + case parser.OscStringState: + if b == ';' && p.Cmd == parser.MissingCommand { + // Try to parse the command + datalen := len(p.Data) + if p.DataLen >= 0 { + datalen = p.DataLen + } + for i := 0; i < datalen; i++ { + d := p.Data[i] + if d < '0' || d > '9' { + break + } + if p.Cmd == parser.MissingCommand { + p.Cmd = 0 + } + p.Cmd *= 10 + p.Cmd += int(d - '0') + } + } + } + + if p.DataLen < 0 { + p.Data = append(p.Data, b) + } else { + if p.DataLen < len(p.Data) { + p.Data[p.DataLen] = b + p.DataLen++ + } + } + + case parser.DispatchAction: + // Increment the last parameter + if p.ParamsLen > 0 && p.ParamsLen < len(p.Params)-1 || + p.ParamsLen == 0 && len(p.Params) > 0 && p.Params[0] != parser.MissingParam { + p.ParamsLen++ + } + + if dispatcher == nil { + break + } + + var seq Sequence + data := p.Data + if p.DataLen >= 0 { + data = data[:p.DataLen] + } + switch p.State { + case parser.CsiEntryState, parser.CsiParamState, parser.CsiIntermediateState: + p.Cmd |= int(b) + seq = CsiSequence{Cmd: p.Cmd, Params: p.Params[:p.ParamsLen]} + case parser.EscapeState, parser.EscapeIntermediateState: + p.Cmd |= int(b) + seq = EscSequence(p.Cmd) + case parser.DcsEntryState, parser.DcsParamState, parser.DcsIntermediateState, parser.DcsStringState: + seq = DcsSequence{Cmd: p.Cmd, Params: p.Params[:p.ParamsLen], Data: data} + case parser.OscStringState: + seq = OscSequence{Cmd: p.Cmd, Data: data} + case parser.SosStringState: + seq = SosSequence{Data: data} + case parser.PmStringState: + seq = PmSequence{Data: data} + case parser.ApcStringState: + seq = ApcSequence{Data: data} + } + + dispatcher(seq) + } +} + +func utf8ByteLen(b byte) int { + if b <= 0b0111_1111 { // 0x00-0x7F + return 1 + } else if b >= 0b1100_0000 && b <= 0b1101_1111 { // 0xC0-0xDF + return 2 + } else if b >= 0b1110_0000 && b <= 0b1110_1111 { // 0xE0-0xEF + return 3 + } else if b >= 0b1111_0000 && b <= 0b1111_0111 { // 0xF0-0xF7 + return 4 + } + return -1 +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/const.go b/vendor/github.com/charmbracelet/x/ansi/parser/const.go new file mode 100644 index 00000000..54b7383b --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser/const.go @@ -0,0 +1,78 @@ +package parser + +// Action is a DEC ANSI parser action. +type Action = byte + +// These are the actions that the parser can take. +const ( + NoneAction Action = iota + ClearAction + CollectAction + MarkerAction + DispatchAction + ExecuteAction + StartAction // Start of a data string + PutAction // Put into the data string + ParamAction + PrintAction + + IgnoreAction = NoneAction +) + +// nolint: unused +var ActionNames = []string{ + "NoneAction", + "ClearAction", + "CollectAction", + "MarkerAction", + "DispatchAction", + "ExecuteAction", + "StartAction", + "PutAction", + "ParamAction", + "PrintAction", +} + +// State is a DEC ANSI parser state. +type State = byte + +// These are the states that the parser can be in. +const ( + GroundState State = iota + CsiEntryState + CsiIntermediateState + CsiParamState + DcsEntryState + DcsIntermediateState + DcsParamState + DcsStringState + EscapeState + EscapeIntermediateState + OscStringState + SosStringState + PmStringState + ApcStringState + + // Utf8State is not part of the DEC ANSI standard. It is used to handle + // UTF-8 sequences. + Utf8State +) + +// nolint: unused +var StateNames = []string{ + "GroundState", + "CsiEntryState", + "CsiIntermediateState", + "CsiParamState", + "DcsEntryState", + "DcsIntermediateState", + "DcsParamState", + "DcsStringState", + "EscapeState", + "EscapeIntermediateState", + "OscStringState", + "SosStringState", + "PmStringState", + "ApcStringState", + "Utf8State", +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/seq.go b/vendor/github.com/charmbracelet/x/ansi/parser/seq.go new file mode 100644 index 00000000..c99f1632 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser/seq.go @@ -0,0 +1,136 @@ +package parser + +import "math" + +// Shift and masks for sequence parameters and intermediates. +const ( + MarkerShift = 8 + IntermedShift = 16 + CommandMask = 0xff + HasMoreFlag = math.MinInt32 + ParamMask = ^HasMoreFlag + MissingParam = ParamMask + MissingCommand = MissingParam + MaxParam = math.MaxUint16 // the maximum value a parameter can have +) + +const ( + // MaxParamsSize is the maximum number of parameters a sequence can have. + MaxParamsSize = 32 + + // DefaultParamValue is the default value used for missing parameters. + DefaultParamValue = 0 +) + +// Marker returns the marker byte of the sequence. +// This is always gonna be one of the following '<' '=' '>' '?' and in the +// range of 0x3C-0x3F. +// Zero is returned if the sequence does not have a marker. +func Marker(cmd int) int { + return (cmd >> MarkerShift) & CommandMask +} + +// Intermediate returns the intermediate byte of the sequence. +// An intermediate byte is in the range of 0x20-0x2F. This includes these +// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+', +// ',', '-', '.', '/'. +// Zero is returned if the sequence does not have an intermediate byte. +func Intermediate(cmd int) int { + return (cmd >> IntermedShift) & CommandMask +} + +// Command returns the command byte of the CSI sequence. +func Command(cmd int) int { + return cmd & CommandMask +} + +// Param returns the parameter at the given index. +// It returns -1 if the parameter does not exist. +func Param(params []int, i int) int { + if len(params) == 0 || i < 0 || i >= len(params) { + return -1 + } + + p := params[i] & ParamMask + if p == MissingParam { + return -1 + } + + return p +} + +// HasMore returns true if the parameter has more sub-parameters. +func HasMore(params []int, i int) bool { + if len(params) == 0 || i >= len(params) { + return false + } + + return params[i]&HasMoreFlag != 0 +} + +// Subparams returns the sub-parameters of the given parameter. +// It returns nil if the parameter does not exist. +func Subparams(params []int, i int) []int { + if len(params) == 0 || i < 0 || i >= len(params) { + return nil + } + + // Count the number of parameters before the given parameter index. + var count int + var j int + for j = 0; j < len(params); j++ { + if count == i { + break + } + if !HasMore(params, j) { + count++ + } + } + + if count > i || j >= len(params) { + return nil + } + + var subs []int + for ; j < len(params); j++ { + if !HasMore(params, j) { + break + } + p := Param(params, j) + if p == -1 { + p = DefaultParamValue + } + subs = append(subs, p) + } + + p := Param(params, j) + if p == -1 { + p = DefaultParamValue + } + + return append(subs, p) +} + +// Len returns the number of parameters in the sequence. +// This will return the number of parameters in the sequence, excluding any +// sub-parameters. +func Len(params []int) int { + var n int + for i := 0; i < len(params); i++ { + if !HasMore(params, i) { + n++ + } + } + return n +} + +// Range iterates over the parameters of the sequence and calls the given +// function for each parameter. +// The function should return false to stop the iteration. +func Range(params []int, fn func(i int, param int, hasMore bool) bool) { + for i := 0; i < len(params); i++ { + if !fn(i, Param(params, i), HasMore(params, i)) { + break + } + } +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go b/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go new file mode 100644 index 00000000..5d368ebf --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go @@ -0,0 +1,273 @@ +package parser + +// Table values are generated like this: +// +// index: currentState << IndexStateShift | charCode +// value: action << TransitionActionShift | nextState +const ( + TransitionActionShift = 4 + TransitionStateMask = 15 + IndexStateShift = 8 + + // DefaultTableSize is the default size of the transition table. + DefaultTableSize = 4096 +) + +// Table is a DEC ANSI transition table. +var Table = GenerateTransitionTable() + +// TransitionTable is a DEC ANSI transition table. +// https://vt100.net/emu/dec_ansi_parser +type TransitionTable []byte + +// NewTransitionTable returns a new DEC ANSI transition table. +func NewTransitionTable(size int) TransitionTable { + if size <= 0 { + size = DefaultTableSize + } + return TransitionTable(make([]byte, size)) +} + +// SetDefault sets default transition. +func (t TransitionTable) SetDefault(action Action, state State) { + for i := 0; i < len(t); i++ { + t[i] = action<> TransitionActionShift +} + +// byte range macro +func r(start, end byte) []byte { + var a []byte + for i := int(start); i <= int(end); i++ { + a = append(a, byte(i)) + } + return a +} + +// GenerateTransitionTable generates a DEC ANSI transition table compatible +// with the VT500-series of terminals. This implementation includes a few +// modifications that include: +// - A new Utf8State is introduced to handle UTF8 sequences. +// - Osc and Dcs data accept UTF8 sequences by extending the printable range +// to 0xFF and 0xFE respectively. +// - We don't ignore 0x3A (':') when building Csi and Dcs parameters and +// instead use it to denote sub-parameters. +// - Support dispatching SosPmApc sequences. +// - The DEL (0x7F) character is executed in the Ground state. +// - The DEL (0x7F) character is collected in the DcsPassthrough string state. +// - The ST C1 control character (0x9C) is executed and not ignored. +func GenerateTransitionTable() TransitionTable { + table := NewTransitionTable(DefaultTableSize) + table.SetDefault(NoneAction, GroundState) + + // Anywhere + for _, state := range r(GroundState, Utf8State) { + // Anywhere -> Ground + table.AddMany([]byte{0x18, 0x1a, 0x99, 0x9a}, state, ExecuteAction, GroundState) + table.AddRange(0x80, 0x8F, state, ExecuteAction, GroundState) + table.AddRange(0x90, 0x97, state, ExecuteAction, GroundState) + table.AddOne(0x9C, state, ExecuteAction, GroundState) + // Anywhere -> Escape + table.AddOne(0x1B, state, ClearAction, EscapeState) + // Anywhere -> SosStringState + table.AddOne(0x98, state, StartAction, SosStringState) + // Anywhere -> PmStringState + table.AddOne(0x9E, state, StartAction, PmStringState) + // Anywhere -> ApcStringState + table.AddOne(0x9F, state, StartAction, ApcStringState) + // Anywhere -> CsiEntry + table.AddOne(0x9B, state, ClearAction, CsiEntryState) + // Anywhere -> DcsEntry + table.AddOne(0x90, state, ClearAction, DcsEntryState) + // Anywhere -> OscString + table.AddOne(0x9D, state, StartAction, OscStringState) + // Anywhere -> Utf8 + table.AddRange(0xC2, 0xDF, state, CollectAction, Utf8State) // UTF8 2 byte sequence + table.AddRange(0xE0, 0xEF, state, CollectAction, Utf8State) // UTF8 3 byte sequence + table.AddRange(0xF0, 0xF4, state, CollectAction, Utf8State) // UTF8 4 byte sequence + } + + // Ground + table.AddRange(0x00, 0x17, GroundState, ExecuteAction, GroundState) + table.AddOne(0x19, GroundState, ExecuteAction, GroundState) + table.AddRange(0x1C, 0x1F, GroundState, ExecuteAction, GroundState) + table.AddRange(0x20, 0x7E, GroundState, PrintAction, GroundState) + table.AddOne(0x7F, GroundState, ExecuteAction, GroundState) + + // EscapeIntermediate + table.AddRange(0x00, 0x17, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState) + table.AddOne(0x19, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState) + table.AddRange(0x1C, 0x1F, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState) + table.AddRange(0x20, 0x2F, EscapeIntermediateState, CollectAction, EscapeIntermediateState) + table.AddOne(0x7F, EscapeIntermediateState, IgnoreAction, EscapeIntermediateState) + // EscapeIntermediate -> Ground + table.AddRange(0x30, 0x7E, EscapeIntermediateState, DispatchAction, GroundState) + + // Escape + table.AddRange(0x00, 0x17, EscapeState, ExecuteAction, EscapeState) + table.AddOne(0x19, EscapeState, ExecuteAction, EscapeState) + table.AddRange(0x1C, 0x1F, EscapeState, ExecuteAction, EscapeState) + table.AddOne(0x7F, EscapeState, IgnoreAction, EscapeState) + // Escape -> Ground + table.AddRange(0x30, 0x4F, EscapeState, DispatchAction, GroundState) + table.AddRange(0x51, 0x57, EscapeState, DispatchAction, GroundState) + table.AddOne(0x59, EscapeState, DispatchAction, GroundState) + table.AddOne(0x5A, EscapeState, DispatchAction, GroundState) + table.AddOne(0x5C, EscapeState, DispatchAction, GroundState) + table.AddRange(0x60, 0x7E, EscapeState, DispatchAction, GroundState) + // Escape -> Escape_intermediate + table.AddRange(0x20, 0x2F, EscapeState, CollectAction, EscapeIntermediateState) + // Escape -> Sos_pm_apc_string + table.AddOne('X', EscapeState, StartAction, SosStringState) // SOS + table.AddOne('^', EscapeState, StartAction, PmStringState) // PM + table.AddOne('_', EscapeState, StartAction, ApcStringState) // APC + // Escape -> Dcs_entry + table.AddOne('P', EscapeState, ClearAction, DcsEntryState) + // Escape -> Csi_entry + table.AddOne('[', EscapeState, ClearAction, CsiEntryState) + // Escape -> Osc_string + table.AddOne(']', EscapeState, StartAction, OscStringState) + + // Sos_pm_apc_string + for _, state := range r(SosStringState, ApcStringState) { + table.AddRange(0x00, 0x17, state, PutAction, state) + table.AddOne(0x19, state, PutAction, state) + table.AddRange(0x1C, 0x1F, state, PutAction, state) + table.AddRange(0x20, 0x7F, state, PutAction, state) + // ESC, ST, CAN, and SUB terminate the sequence + table.AddOne(0x1B, state, DispatchAction, EscapeState) + table.AddOne(0x9C, state, DispatchAction, GroundState) + table.AddMany([]byte{0x18, 0x1A}, state, IgnoreAction, GroundState) + } + + // Dcs_entry + table.AddRange(0x00, 0x07, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddRange(0x0E, 0x17, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddOne(0x19, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddRange(0x1C, 0x1F, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddOne(0x7F, DcsEntryState, IgnoreAction, DcsEntryState) + // Dcs_entry -> Dcs_intermediate + table.AddRange(0x20, 0x2F, DcsEntryState, CollectAction, DcsIntermediateState) + // Dcs_entry -> Dcs_param + table.AddRange(0x30, 0x3B, DcsEntryState, ParamAction, DcsParamState) + table.AddRange(0x3C, 0x3F, DcsEntryState, MarkerAction, DcsParamState) + // Dcs_entry -> Dcs_passthrough + table.AddRange(0x08, 0x0D, DcsEntryState, PutAction, DcsStringState) // Follows ECMA-48 § 8.3.27 + // XXX: allows passing ESC (not a ECMA-48 standard) this to allow for + // passthrough of ANSI sequences like in Screen or Tmux passthrough mode. + table.AddOne(0x1B, DcsEntryState, PutAction, DcsStringState) + table.AddRange(0x40, 0x7E, DcsEntryState, StartAction, DcsStringState) + + // Dcs_intermediate + table.AddRange(0x00, 0x17, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + table.AddOne(0x19, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + table.AddRange(0x1C, 0x1F, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + table.AddRange(0x20, 0x2F, DcsIntermediateState, CollectAction, DcsIntermediateState) + table.AddOne(0x7F, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + // Dcs_intermediate -> Dcs_passthrough + table.AddRange(0x30, 0x3F, DcsIntermediateState, StartAction, DcsStringState) + table.AddRange(0x40, 0x7E, DcsIntermediateState, StartAction, DcsStringState) + + // Dcs_param + table.AddRange(0x00, 0x17, DcsParamState, IgnoreAction, DcsParamState) + table.AddOne(0x19, DcsParamState, IgnoreAction, DcsParamState) + table.AddRange(0x1C, 0x1F, DcsParamState, IgnoreAction, DcsParamState) + table.AddRange(0x30, 0x3B, DcsParamState, ParamAction, DcsParamState) + table.AddOne(0x7F, DcsParamState, IgnoreAction, DcsParamState) + table.AddRange(0x3C, 0x3F, DcsParamState, IgnoreAction, DcsParamState) + // Dcs_param -> Dcs_intermediate + table.AddRange(0x20, 0x2F, DcsParamState, CollectAction, DcsIntermediateState) + // Dcs_param -> Dcs_passthrough + table.AddRange(0x40, 0x7E, DcsParamState, StartAction, DcsStringState) + + // Dcs_passthrough + table.AddRange(0x00, 0x17, DcsStringState, PutAction, DcsStringState) + table.AddOne(0x19, DcsStringState, PutAction, DcsStringState) + table.AddRange(0x1C, 0x1F, DcsStringState, PutAction, DcsStringState) + table.AddRange(0x20, 0x7E, DcsStringState, PutAction, DcsStringState) + table.AddOne(0x7F, DcsStringState, PutAction, DcsStringState) + table.AddRange(0x80, 0xFF, DcsStringState, PutAction, DcsStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF + // ST, CAN, SUB, and ESC terminate the sequence + table.AddOne(0x1B, DcsStringState, DispatchAction, EscapeState) + table.AddOne(0x9C, DcsStringState, DispatchAction, GroundState) + table.AddMany([]byte{0x18, 0x1A}, DcsStringState, IgnoreAction, GroundState) + + // Csi_param + table.AddRange(0x00, 0x17, CsiParamState, ExecuteAction, CsiParamState) + table.AddOne(0x19, CsiParamState, ExecuteAction, CsiParamState) + table.AddRange(0x1C, 0x1F, CsiParamState, ExecuteAction, CsiParamState) + table.AddRange(0x30, 0x3B, CsiParamState, ParamAction, CsiParamState) + table.AddOne(0x7F, CsiParamState, IgnoreAction, CsiParamState) + table.AddRange(0x3C, 0x3F, CsiParamState, IgnoreAction, CsiParamState) + // Csi_param -> Ground + table.AddRange(0x40, 0x7E, CsiParamState, DispatchAction, GroundState) + // Csi_param -> Csi_intermediate + table.AddRange(0x20, 0x2F, CsiParamState, CollectAction, CsiIntermediateState) + + // Csi_intermediate + table.AddRange(0x00, 0x17, CsiIntermediateState, ExecuteAction, CsiIntermediateState) + table.AddOne(0x19, CsiIntermediateState, ExecuteAction, CsiIntermediateState) + table.AddRange(0x1C, 0x1F, CsiIntermediateState, ExecuteAction, CsiIntermediateState) + table.AddRange(0x20, 0x2F, CsiIntermediateState, CollectAction, CsiIntermediateState) + table.AddOne(0x7F, CsiIntermediateState, IgnoreAction, CsiIntermediateState) + // Csi_intermediate -> Ground + table.AddRange(0x40, 0x7E, CsiIntermediateState, DispatchAction, GroundState) + // Csi_intermediate -> Csi_ignore + table.AddRange(0x30, 0x3F, CsiIntermediateState, IgnoreAction, GroundState) + + // Csi_entry + table.AddRange(0x00, 0x17, CsiEntryState, ExecuteAction, CsiEntryState) + table.AddOne(0x19, CsiEntryState, ExecuteAction, CsiEntryState) + table.AddRange(0x1C, 0x1F, CsiEntryState, ExecuteAction, CsiEntryState) + table.AddOne(0x7F, CsiEntryState, IgnoreAction, CsiEntryState) + // Csi_entry -> Ground + table.AddRange(0x40, 0x7E, CsiEntryState, DispatchAction, GroundState) + // Csi_entry -> Csi_intermediate + table.AddRange(0x20, 0x2F, CsiEntryState, CollectAction, CsiIntermediateState) + // Csi_entry -> Csi_param + table.AddRange(0x30, 0x3B, CsiEntryState, ParamAction, CsiParamState) + table.AddRange(0x3C, 0x3F, CsiEntryState, MarkerAction, CsiParamState) + + // Osc_string + table.AddRange(0x00, 0x06, OscStringState, IgnoreAction, OscStringState) + table.AddRange(0x08, 0x17, OscStringState, IgnoreAction, OscStringState) + table.AddOne(0x19, OscStringState, IgnoreAction, OscStringState) + table.AddRange(0x1C, 0x1F, OscStringState, IgnoreAction, OscStringState) + table.AddRange(0x20, 0xFF, OscStringState, PutAction, OscStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF + + // ST, CAN, SUB, ESC, and BEL terminate the sequence + table.AddOne(0x1B, OscStringState, DispatchAction, EscapeState) + table.AddOne(0x07, OscStringState, DispatchAction, GroundState) + table.AddOne(0x9C, OscStringState, DispatchAction, GroundState) + table.AddMany([]byte{0x18, 0x1A}, OscStringState, IgnoreAction, GroundState) + + return table +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_decode.go b/vendor/github.com/charmbracelet/x/ansi/parser_decode.go new file mode 100644 index 00000000..76688d0b --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser_decode.go @@ -0,0 +1,423 @@ +package ansi + +import ( + "bytes" + "strings" + "unicode/utf8" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/rivo/uniseg" +) + +// State represents the state of the ANSI escape sequence parser used by +// [DecodeSequence]. +type State = byte + +// ANSI escape sequence states used by [DecodeSequence]. +const ( + NormalState State = iota + MarkerState + ParamsState + IntermedState + EscapeState + StringState +) + +// DecodeSequence decodes the first ANSI escape sequence or a printable +// grapheme from the given data. It returns the sequence slice, the number of +// bytes read, the cell width for each sequence, and the new state. +// +// The cell width will always be 0 for control and escape sequences, 1 for +// ASCII printable characters, and the number of cells other Unicode characters +// occupy. It uses the uniseg package to calculate the width of Unicode +// graphemes and characters. This means it will always do grapheme clustering +// (mode 2027). +// +// Passing a non-nil [*Parser] as the last argument will allow the decoder to +// collect sequence parameters, data, and commands. The parser cmd will have +// the packed command value that contains intermediate and marker characters. +// In the case of a OSC sequence, the cmd will be the OSC command number. Use +// [Cmd] and [Param] types to unpack command intermediates and markers as well +// as parameters. +// +// Zero [p.Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the +// validity of other data sequences, OSC, DCS, etc, will require checking for +// the returned sequence terminator bytes such as ST (ESC \\) and BEL). +// +// We store the command byte in [p.Cmd] in the most significant byte, the +// marker byte in the next byte, and the intermediate byte in the least +// significant byte. This is done to avoid using a struct to store the command +// and its intermediates and markers. The command byte is always the least +// significant byte i.e. [p.Cmd & 0xff]. Use the [Cmd] type to unpack the +// command, intermediate, and marker bytes. Note that we only collect the last +// marker character and intermediate byte. +// +// The [p.Params] slice will contain the parameters of the sequence. Any +// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type +// to unpack the parameters. +// +// Example: +// +// var state byte // the initial state is always zero [NormalState] +// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional) +// input := []byte("\x1b[31mHello, World!\x1b[0m") +// for len(input) > 0 { +// seq, width, n, newState := DecodeSequence(input, state, p) +// log.Printf("seq: %q, width: %d", seq, width) +// state = newState +// input = input[n:] +// } +func DecodeSequence[T string | []byte](b T, state byte, p *Parser) (seq T, width int, n int, newState byte) { + for i := 0; i < len(b); i++ { + c := b[i] + + switch state { + case NormalState: + switch c { + case ESC: + if p != nil { + if len(p.Params) > 0 { + p.Params[0] = parser.MissingParam + } + p.Cmd = 0 + p.ParamsLen = 0 + p.DataLen = 0 + } + state = EscapeState + continue + case CSI, DCS: + if p != nil { + if len(p.Params) > 0 { + p.Params[0] = parser.MissingParam + } + p.Cmd = 0 + p.ParamsLen = 0 + p.DataLen = 0 + } + state = MarkerState + continue + case OSC, APC, SOS, PM: + if p != nil { + p.Cmd = parser.MissingCommand + p.DataLen = 0 + } + state = StringState + continue + } + + if p != nil { + p.DataLen = 0 + p.ParamsLen = 0 + p.Cmd = 0 + } + if c > US && c < DEL { + // ASCII printable characters + return b[i : i+1], 1, 1, NormalState + } + + if c <= US || c == DEL || c < 0xC0 { + // C0 & C1 control characters & DEL + return b[i : i+1], 0, 1, NormalState + } + + if utf8.RuneStart(c) { + seq, _, width, _ = FirstGraphemeCluster(b, -1) + i += len(seq) + return b[:i], width, i, NormalState + } + + // Invalid UTF-8 sequence + return b[:i], 0, i, NormalState + case MarkerState: + if c >= '<' && c <= '?' { + if p != nil { + // We only collect the last marker character. + p.Cmd &^= 0xff << parser.MarkerShift + p.Cmd |= int(c) << parser.MarkerShift + } + break + } + + state = ParamsState + fallthrough + case ParamsState: + if c >= '0' && c <= '9' { + if p != nil { + if p.Params[p.ParamsLen] == parser.MissingParam { + p.Params[p.ParamsLen] = 0 + } + + p.Params[p.ParamsLen] *= 10 + p.Params[p.ParamsLen] += int(c - '0') + } + break + } + + if c == ':' { + if p != nil { + p.Params[p.ParamsLen] |= parser.HasMoreFlag + } + } + + if c == ';' || c == ':' { + if p != nil { + p.ParamsLen++ + if p.ParamsLen < len(p.Params) { + p.Params[p.ParamsLen] = parser.MissingParam + } + } + break + } + + state = IntermedState + fallthrough + case IntermedState: + if c >= ' ' && c <= '/' { + if p != nil { + p.Cmd &^= 0xff << parser.IntermedShift + p.Cmd |= int(c) << parser.IntermedShift + } + break + } + + state = NormalState + if c >= '@' && c <= '~' { + if p != nil { + // Increment the last parameter + if p.ParamsLen > 0 && p.ParamsLen < len(p.Params)-1 || + p.ParamsLen == 0 && len(p.Params) > 0 && p.Params[0] != parser.MissingParam { + p.ParamsLen++ + } + + p.Cmd &^= 0xff + p.Cmd |= int(c) + } + + if HasDcsPrefix(b) { + // Continue to collect DCS data + if p != nil { + p.DataLen = 0 + } + state = StringState + continue + } + + return b[:i+1], 0, i + 1, state + } + + // Invalid CSI/DCS sequence + return b[:i], 0, i, NormalState + case EscapeState: + switch c { + case '[', 'P': + if p != nil { + if len(p.Params) > 0 { + p.Params[0] = parser.MissingParam + } + p.ParamsLen = 0 + p.Cmd = 0 + } + state = MarkerState + continue + case ']', 'X', '^', '_': + if p != nil { + p.Cmd = parser.MissingCommand + p.DataLen = 0 + } + state = StringState + continue + } + + if c >= ' ' && c <= '/' { + if p != nil { + p.Cmd &^= 0xff << parser.IntermedShift + p.Cmd |= int(c) << parser.IntermedShift + } + continue + } else if c >= '0' && c <= '~' { + if p != nil { + p.Cmd &^= 0xff + p.Cmd |= int(c) + } + return b[:i+1], 0, i + 1, NormalState + } + + // Invalid escape sequence + return b[:i], 0, i, NormalState + case StringState: + switch c { + case BEL: + if HasOscPrefix(b) { + return b[:i+1], 0, i + 1, NormalState + } + case CAN, SUB: + // Cancel the sequence + return b[:i], 0, i, NormalState + case ST: + return b[:i+1], 0, i + 1, NormalState + case ESC: + if HasStPrefix(b[i:]) { + // End of string 7-bit (ST) + return b[:i+2], 0, i + 2, NormalState + } + + // Otherwise, cancel the sequence + return b[:i], 0, i, NormalState + } + + if p != nil && p.DataLen < len(p.Data) { + p.Data[p.DataLen] = c + p.DataLen++ + + // Parse the OSC command number + if c == ';' && p.Cmd == parser.MissingCommand && HasOscPrefix(b) { + for j := 0; j < p.DataLen; j++ { + d := p.Data[j] + if d < '0' || d > '9' { + break + } + if p.Cmd == parser.MissingCommand { + p.Cmd = 0 + } + p.Cmd *= 10 + p.Cmd += int(d - '0') + } + } + } + } + } + + return b, 0, len(b), state +} + +// Index returns the index of the first occurrence of the given byte slice in +// the data. It returns -1 if the byte slice is not found. +func Index[T string | []byte](data, b T) int { + switch data := any(data).(type) { + case string: + return strings.Index(data, string(b)) + case []byte: + return bytes.Index(data, []byte(b)) + } + panic("unreachable") +} + +// Equal returns true if the given byte slices are equal. +func Equal[T string | []byte](a, b T) bool { + return string(a) == string(b) +} + +// HasPrefix returns true if the given byte slice has prefix. +func HasPrefix[T string | []byte](b, prefix T) bool { + return len(b) >= len(prefix) && Equal(b[0:len(prefix)], prefix) +} + +// HasSuffix returns true if the given byte slice has suffix. +func HasSuffix[T string | []byte](b, suffix T) bool { + return len(b) >= len(suffix) && Equal(b[len(b)-len(suffix):], suffix) +} + +// HasCsiPrefix returns true if the given byte slice has a CSI prefix. +func HasCsiPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == CSI) || + (len(b) > 1 && b[0] == ESC && b[1] == '[') +} + +// HasOscPrefix returns true if the given byte slice has an OSC prefix. +func HasOscPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == OSC) || + (len(b) > 1 && b[0] == ESC && b[1] == ']') +} + +// HasApcPrefix returns true if the given byte slice has an APC prefix. +func HasApcPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == APC) || + (len(b) > 1 && b[0] == ESC && b[1] == '_') +} + +// HasDcsPrefix returns true if the given byte slice has a DCS prefix. +func HasDcsPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == DCS) || + (len(b) > 1 && b[0] == ESC && b[1] == 'P') +} + +// HasSosPrefix returns true if the given byte slice has a SOS prefix. +func HasSosPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == SOS) || + (len(b) > 1 && b[0] == ESC && b[1] == 'X') +} + +// HasPmPrefix returns true if the given byte slice has a PM prefix. +func HasPmPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == PM) || + (len(b) > 1 && b[0] == ESC && b[1] == '^') +} + +// HasStPrefix returns true if the given byte slice has a ST prefix. +func HasStPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == ST) || + (len(b) > 1 && b[0] == ESC && b[1] == '\\') +} + +// HasEscPrefix returns true if the given byte slice has an ESC prefix. +func HasEscPrefix[T string | []byte](b T) bool { + return len(b) > 0 && b[0] == ESC +} + +// FirstGraphemeCluster returns the first grapheme cluster in the given string or byte slice. +// This is a syntactic sugar function that wraps +// uniseg.FirstGraphemeClusterInString and uniseg.FirstGraphemeCluster. +func FirstGraphemeCluster[T string | []byte](b T, state int) (T, T, int, int) { + switch b := any(b).(type) { + case string: + cluster, rest, width, newState := uniseg.FirstGraphemeClusterInString(b, state) + return T(cluster), T(rest), width, newState + case []byte: + cluster, rest, width, newState := uniseg.FirstGraphemeCluster(b, state) + return T(cluster), T(rest), width, newState + } + panic("unreachable") +} + +// Cmd represents a sequence command. This is used to pack/unpack a sequence +// command with its intermediate and marker characters. Those are commonly +// found in CSI and DCS sequences. +type Cmd int + +// Marker returns the marker byte of the CSI sequence. +// This is always gonna be one of the following '<' '=' '>' '?' and in the +// range of 0x3C-0x3F. +// Zero is returned if the sequence does not have a marker. +func (c Cmd) Marker() int { + return parser.Marker(int(c)) +} + +// Intermediate returns the intermediate byte of the CSI sequence. +// An intermediate byte is in the range of 0x20-0x2F. This includes these +// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+', +// ',', '-', '.', '/'. +// Zero is returned if the sequence does not have an intermediate byte. +func (c Cmd) Intermediate() int { + return parser.Intermediate(int(c)) +} + +// Command returns the command byte of the CSI sequence. +func (c Cmd) Command() int { + return parser.Command(int(c)) +} + +// Param represents a sequence parameter. Sequence parameters with +// sub-parameters are packed with the HasMoreFlag set. This is used to unpack +// the parameters from a CSI and DCS sequences. +type Param int + +// Param returns the parameter at the given index. +// It returns -1 if the parameter does not exist. +func (s Param) Param() int { + return int(s) & parser.ParamMask +} + +// HasMore returns true if the parameter has more sub-parameters. +func (s Param) HasMore() bool { + return int(s)&parser.HasMoreFlag != 0 +} diff --git a/vendor/github.com/charmbracelet/x/ansi/passthrough.go b/vendor/github.com/charmbracelet/x/ansi/passthrough.go new file mode 100644 index 00000000..14a74522 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/passthrough.go @@ -0,0 +1,63 @@ +package ansi + +import ( + "bytes" +) + +// ScreenPassthrough wraps the given ANSI sequence in a DCS passthrough +// sequence to be sent to the outer terminal. This is used to send raw escape +// sequences to the outer terminal when running inside GNU Screen. +// +// DCS ST +// +// Note: Screen limits the length of string sequences to 768 bytes (since 2014). +// Use zero to indicate no limit, otherwise, this will chunk the returned +// string into limit sized chunks. +// +// See: https://www.gnu.org/software/screen/manual/screen.html#String-Escapes +// See: https://git.savannah.gnu.org/cgit/screen.git/tree/src/screen.h?id=c184c6ec27683ff1a860c45be5cf520d896fd2ef#n44 +func ScreenPassthrough(seq string, limit int) string { + var b bytes.Buffer + b.WriteString("\x1bP") + if limit > 0 { + for i := 0; i < len(seq); i += limit { + end := i + limit + if end > len(seq) { + end = len(seq) + } + b.WriteString(seq[i:end]) + if end < len(seq) { + b.WriteString("\x1b\\\x1bP") + } + } + } else { + b.WriteString(seq) + } + b.WriteString("\x1b\\") + return b.String() +} + +// TmuxPassthrough wraps the given ANSI sequence in a special DCS passthrough +// sequence to be sent to the outer terminal. This is used to send raw escape +// sequences to the outer terminal when running inside Tmux. +// +// DCS tmux ; ST +// +// Where is the given sequence in which all occurrences of ESC +// (0x1b) are doubled i.e. replaced with ESC ESC (0x1b 0x1b). +// +// Note: this needs the `allow-passthrough` option to be set to `on`. +// +// See: https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it +func TmuxPassthrough(seq string) string { + var b bytes.Buffer + b.WriteString("\x1bPtmux;") + for i := 0; i < len(seq); i++ { + if seq[i] == ESC { + b.WriteByte(ESC) + } + b.WriteByte(seq[i]) + } + b.WriteString("\x1b\\") + return b.String() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/screen.go b/vendor/github.com/charmbracelet/x/ansi/screen.go new file mode 100644 index 00000000..4909cf07 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/screen.go @@ -0,0 +1,126 @@ +package ansi + +import "strconv" + +// EraseDisplay (ED) clears the screen or parts of the screen. Possible values: +// +// 0: Clear from cursor to end of screen. +// 1: Clear from cursor to beginning of the screen. +// 2: Clear entire screen (and moves cursor to upper left on DOS). +// 3: Clear entire screen and delete all lines saved in the scrollback buffer. +// +// CSI J +// +// See: https://vt100.net/docs/vt510-rm/ED.html +func EraseDisplay(n int) string { + if n < 0 { + n = 0 + } + return "\x1b[" + strconv.Itoa(n) + "J" +} + +// EraseDisplay constants. +// These are the possible values for the EraseDisplay function. +const ( + EraseDisplayRight = "\x1b[0J" + EraseDisplayLeft = "\x1b[1J" + EraseEntireDisplay = "\x1b[2J" +) + +// EraseLine (EL) clears the current line or parts of the line. Possible values: +// +// 0: Clear from cursor to end of line. +// 1: Clear from cursor to beginning of the line. +// 2: Clear entire line. +// +// The cursor position is not affected. +// +// CSI K +// +// See: https://vt100.net/docs/vt510-rm/EL.html +func EraseLine(n int) string { + if n < 0 { + n = 0 + } + return "\x1b[" + strconv.Itoa(n) + "K" +} + +// EraseLine constants. +// These are the possible values for the EraseLine function. +const ( + EraseLineRight = "\x1b[0K" + EraseLineLeft = "\x1b[1K" + EraseEntireLine = "\x1b[2K" +) + +// ScrollUp (SU) scrolls the screen up n lines. New lines are added at the +// bottom of the screen. +// +// CSI S +// +// See: https://vt100.net/docs/vt510-rm/SU.html +func ScrollUp(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "S" +} + +// ScrollDown (SD) scrolls the screen down n lines. New lines are added at the +// top of the screen. +// +// CSI T +// +// See: https://vt100.net/docs/vt510-rm/SD.html +func ScrollDown(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "T" +} + +// InsertLine (IL) inserts n blank lines at the current cursor position. +// Existing lines are moved down. +// +// CSI L +// +// See: https://vt100.net/docs/vt510-rm/IL.html +func InsertLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "L" +} + +// DeleteLine (DL) deletes n lines at the current cursor position. Existing +// lines are moved up. +// +// CSI M +// +// See: https://vt100.net/docs/vt510-rm/DL.html +func DeleteLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "M" +} + +// SetScrollingRegion (DECSTBM) sets the top and bottom margins for the scrolling +// region. The default is the entire screen. +// +// CSI ; r +// +// See: https://vt100.net/docs/vt510-rm/DECSTBM.html +func SetScrollingRegion(t, b int) string { + if t < 0 { + t = 0 + } + if b < 0 { + b = 0 + } + return "\x1b[" + strconv.Itoa(t) + ";" + strconv.Itoa(b) + "r" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/sequence.go b/vendor/github.com/charmbracelet/x/ansi/sequence.go new file mode 100644 index 00000000..f294a229 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/sequence.go @@ -0,0 +1,199 @@ +package ansi + +import ( + "bytes" + + "github.com/charmbracelet/x/ansi/parser" +) + +// Sequence represents an ANSI sequence. This can be a control sequence, escape +// sequence, a printable character, etc. +type Sequence interface { + // String returns the string representation of the sequence. + String() string + // Bytes returns the byte representation of the sequence. + Bytes() []byte + // Clone returns a copy of the sequence. + Clone() Sequence +} + +// Rune represents a printable character. +type Rune rune + +var _ Sequence = Rune(0) + +// Bytes implements Sequence. +func (r Rune) Bytes() []byte { + return []byte(string(r)) +} + +// String implements Sequence. +func (r Rune) String() string { + return string(r) +} + +// Clone implements Sequence. +func (r Rune) Clone() Sequence { + return r +} + +// ControlCode represents a control code character. This is a character that +// is not printable and is used to control the terminal. This would be a +// character in the C0 or C1 set in the range of 0x00-0x1F and 0x80-0x9F. +type ControlCode byte + +var _ Sequence = ControlCode(0) + +// Bytes implements Sequence. +func (c ControlCode) Bytes() []byte { + return []byte{byte(c)} +} + +// String implements Sequence. +func (c ControlCode) String() string { + return string(c) +} + +// Clone implements Sequence. +func (c ControlCode) Clone() Sequence { + return c +} + +// EscSequence represents an escape sequence. +type EscSequence int + +var _ Sequence = EscSequence(0) + +// buffer returns the buffer of the escape sequence. +func (e EscSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteByte('\x1b') + if i := parser.Intermediate(int(e)); i != 0 { + b.WriteByte(byte(i)) + } + b.WriteByte(byte(e.Command())) + return &b +} + +// Bytes implements Sequence. +func (e EscSequence) Bytes() []byte { + return e.buffer().Bytes() +} + +// String implements Sequence. +func (e EscSequence) String() string { + return e.buffer().String() +} + +// Clone implements Sequence. +func (e EscSequence) Clone() Sequence { + return e +} + +// Command returns the command byte of the escape sequence. +func (e EscSequence) Command() int { + return parser.Command(int(e)) +} + +// Intermediate returns the intermediate byte of the escape sequence. +func (e EscSequence) Intermediate() int { + return parser.Intermediate(int(e)) +} + +// SosSequence represents a SOS sequence. +type SosSequence struct { + // Data contains the raw data of the sequence. + Data []byte +} + +var _ Sequence = &SosSequence{} + +// Clone implements Sequence. +func (s SosSequence) Clone() Sequence { + return SosSequence{Data: append([]byte(nil), s.Data...)} +} + +// Bytes implements Sequence. +func (s SosSequence) Bytes() []byte { + return s.buffer().Bytes() +} + +// String implements Sequence. +func (s SosSequence) String() string { + return s.buffer().String() +} + +func (s SosSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteByte('\x1b') + b.WriteByte('X') + b.Write(s.Data) + b.WriteString("\x1b\\") + return &b +} + +// PmSequence represents a PM sequence. +type PmSequence struct { + // Data contains the raw data of the sequence. + Data []byte +} + +var _ Sequence = &PmSequence{} + +// Clone implements Sequence. +func (s PmSequence) Clone() Sequence { + return PmSequence{Data: append([]byte(nil), s.Data...)} +} + +// Bytes implements Sequence. +func (s PmSequence) Bytes() []byte { + return s.buffer().Bytes() +} + +// String implements Sequence. +func (s PmSequence) String() string { + return s.buffer().String() +} + +// buffer returns the buffer of the PM sequence. +func (s PmSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteByte('\x1b') + b.WriteByte('^') + b.Write(s.Data) + b.WriteString("\x1b\\") + return &b +} + +// ApcSequence represents an APC sequence. +type ApcSequence struct { + // Data contains the raw data of the sequence. + Data []byte +} + +var _ Sequence = &ApcSequence{} + +// Clone implements Sequence. +func (s ApcSequence) Clone() Sequence { + return ApcSequence{Data: append([]byte(nil), s.Data...)} +} + +// Bytes implements Sequence. +func (s ApcSequence) Bytes() []byte { + return s.buffer().Bytes() +} + +// String implements Sequence. +func (s ApcSequence) String() string { + return s.buffer().String() +} + +// buffer returns the buffer of the APC sequence. +func (s ApcSequence) buffer() *bytes.Buffer { + var b bytes.Buffer + b.WriteByte('\x1b') + b.WriteByte('_') + b.Write(s.Data) + b.WriteString("\x1b\\") + return &b +} diff --git a/vendor/github.com/charmbracelet/x/ansi/style.go b/vendor/github.com/charmbracelet/x/ansi/style.go new file mode 100644 index 00000000..96e3c532 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/style.go @@ -0,0 +1,296 @@ +package ansi + +import ( + "image/color" + "strconv" + "strings" +) + +// ResetStyle is a SGR (Select Graphic Rendition) style sequence that resets +// all attributes. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +const ResetStyle = "\x1b[m" + +// Attr is a SGR (Select Graphic Rendition) style attribute. +type Attr = string + +// Style represents an ANSI SGR (Select Graphic Rendition) style. +type Style []Attr + +// String returns the ANSI SGR (Select Graphic Rendition) style sequence for +// the given style. +func (s Style) String() string { + if len(s) == 0 { + return ResetStyle + } + return "\x1b[" + strings.Join(s, ";") + "m" +} + +// Styled returns a styled string with the given style applied. +func (s Style) Styled(str string) string { + if len(s) == 0 { + return str + } + return s.String() + str + ResetStyle +} + +// Reset appends the reset style attribute to the style. +func (s Style) Reset() Style { + return append(s, ResetAttr) +} + +// Bold appends the bold style attribute to the style. +func (s Style) Bold() Style { + return append(s, BoldAttr) +} + +// Faint appends the faint style attribute to the style. +func (s Style) Faint() Style { + return append(s, FaintAttr) +} + +// Italic appends the italic style attribute to the style. +func (s Style) Italic() Style { + return append(s, ItalicAttr) +} + +// Underline appends the underline style attribute to the style. +func (s Style) Underline() Style { + return append(s, UnderlineAttr) +} + +// DoubleUnderline appends the double underline style attribute to the style. +func (s Style) DoubleUnderline() Style { + return append(s, DoubleUnderlineAttr) +} + +// CurlyUnderline appends the curly underline style attribute to the style. +func (s Style) CurlyUnderline() Style { + return append(s, CurlyUnderlineAttr) +} + +// DottedUnderline appends the dotted underline style attribute to the style. +func (s Style) DottedUnderline() Style { + return append(s, DottedUnderlineAttr) +} + +// DashedUnderline appends the dashed underline style attribute to the style. +func (s Style) DashedUnderline() Style { + return append(s, DashedUnderlineAttr) +} + +// SlowBlink appends the slow blink style attribute to the style. +func (s Style) SlowBlink() Style { + return append(s, SlowBlinkAttr) +} + +// RapidBlink appends the rapid blink style attribute to the style. +func (s Style) RapidBlink() Style { + return append(s, RapidBlinkAttr) +} + +// Reverse appends the reverse style attribute to the style. +func (s Style) Reverse() Style { + return append(s, ReverseAttr) +} + +// Conceal appends the conceal style attribute to the style. +func (s Style) Conceal() Style { + return append(s, ConcealAttr) +} + +// Strikethrough appends the strikethrough style attribute to the style. +func (s Style) Strikethrough() Style { + return append(s, StrikethroughAttr) +} + +// NoBold appends the no bold style attribute to the style. +func (s Style) NoBold() Style { + return append(s, NoBoldAttr) +} + +// NormalIntensity appends the normal intensity style attribute to the style. +func (s Style) NormalIntensity() Style { + return append(s, NormalIntensityAttr) +} + +// NoItalic appends the no italic style attribute to the style. +func (s Style) NoItalic() Style { + return append(s, NoItalicAttr) +} + +// NoUnderline appends the no underline style attribute to the style. +func (s Style) NoUnderline() Style { + return append(s, NoUnderlineAttr) +} + +// NoBlink appends the no blink style attribute to the style. +func (s Style) NoBlink() Style { + return append(s, NoBlinkAttr) +} + +// NoReverse appends the no reverse style attribute to the style. +func (s Style) NoReverse() Style { + return append(s, NoReverseAttr) +} + +// NoConceal appends the no conceal style attribute to the style. +func (s Style) NoConceal() Style { + return append(s, NoConcealAttr) +} + +// NoStrikethrough appends the no strikethrough style attribute to the style. +func (s Style) NoStrikethrough() Style { + return append(s, NoStrikethroughAttr) +} + +// DefaultForegroundColor appends the default foreground color style attribute to the style. +func (s Style) DefaultForegroundColor() Style { + return append(s, DefaultForegroundColorAttr) +} + +// DefaultBackgroundColor appends the default background color style attribute to the style. +func (s Style) DefaultBackgroundColor() Style { + return append(s, DefaultBackgroundColorAttr) +} + +// DefaultUnderlineColor appends the default underline color style attribute to the style. +func (s Style) DefaultUnderlineColor() Style { + return append(s, DefaultUnderlineColorAttr) +} + +// ForegroundColor appends the foreground color style attribute to the style. +func (s Style) ForegroundColor(c Color) Style { + return append(s, ForegroundColorAttr(c)) +} + +// BackgroundColor appends the background color style attribute to the style. +func (s Style) BackgroundColor(c Color) Style { + return append(s, BackgroundColorAttr(c)) +} + +// UnderlineColor appends the underline color style attribute to the style. +func (s Style) UnderlineColor(c Color) Style { + return append(s, UnderlineColorAttr(c)) +} + +// SGR (Select Graphic Rendition) style attributes. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +const ( + ResetAttr Attr = "0" + BoldAttr Attr = "1" + FaintAttr Attr = "2" + ItalicAttr Attr = "3" + UnderlineAttr Attr = "4" + DoubleUnderlineAttr Attr = "4:2" + CurlyUnderlineAttr Attr = "4:3" + DottedUnderlineAttr Attr = "4:4" + DashedUnderlineAttr Attr = "4:5" + SlowBlinkAttr Attr = "5" + RapidBlinkAttr Attr = "6" + ReverseAttr Attr = "7" + ConcealAttr Attr = "8" + StrikethroughAttr Attr = "9" + NoBoldAttr Attr = "21" // Some terminals treat this as double underline. + NormalIntensityAttr Attr = "22" + NoItalicAttr Attr = "23" + NoUnderlineAttr Attr = "24" + NoBlinkAttr Attr = "25" + NoReverseAttr Attr = "27" + NoConcealAttr Attr = "28" + NoStrikethroughAttr Attr = "29" + DefaultForegroundColorAttr Attr = "39" + DefaultBackgroundColorAttr Attr = "49" + DefaultUnderlineColorAttr Attr = "59" +) + +// ForegroundColorAttr returns the style SGR attribute for the given foreground +// color. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +func ForegroundColorAttr(c Color) Attr { + switch c := c.(type) { + case BasicColor: + // 3-bit or 4-bit ANSI foreground + // "3" or "9" where n is the color number from 0 to 7 + if c < 8 { + return "3" + string('0'+c) + } else if c < 16 { + return "9" + string('0'+c-8) + } + case ExtendedColor: + // 256-color ANSI foreground + // "38;5;" + return "38;5;" + strconv.FormatUint(uint64(c), 10) + case TrueColor, color.Color: + // 24-bit "true color" foreground + // "38;2;;;" + r, g, b, _ := c.RGBA() + return "38;2;" + + strconv.FormatUint(uint64(shift(r)), 10) + ";" + + strconv.FormatUint(uint64(shift(g)), 10) + ";" + + strconv.FormatUint(uint64(shift(b)), 10) + } + return DefaultForegroundColorAttr +} + +// BackgroundColorAttr returns the style SGR attribute for the given background +// color. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +func BackgroundColorAttr(c Color) Attr { + switch c := c.(type) { + case BasicColor: + // 3-bit or 4-bit ANSI foreground + // "4" or "10" where n is the color number from 0 to 7 + if c < 8 { + return "4" + string('0'+c) + } else { + return "10" + string('0'+c-8) + } + case ExtendedColor: + // 256-color ANSI foreground + // "48;5;" + return "48;5;" + strconv.FormatUint(uint64(c), 10) + case TrueColor, color.Color: + // 24-bit "true color" foreground + // "38;2;;;" + r, g, b, _ := c.RGBA() + return "48;2;" + + strconv.FormatUint(uint64(shift(r)), 10) + ";" + + strconv.FormatUint(uint64(shift(g)), 10) + ";" + + strconv.FormatUint(uint64(shift(b)), 10) + } + return DefaultBackgroundColorAttr +} + +// UnderlineColorAttr returns the style SGR attribute for the given underline +// color. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +func UnderlineColorAttr(c Color) Attr { + switch c := c.(type) { + // NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline + // color, use 256-color instead. + // + // 256-color ANSI underline color + // "58;5;" + case BasicColor: + return "58;5;" + strconv.FormatUint(uint64(c), 10) + case ExtendedColor: + return "58;5;" + strconv.FormatUint(uint64(c), 10) + case TrueColor, color.Color: + // 24-bit "true color" foreground + // "38;2;;;" + r, g, b, _ := c.RGBA() + return "58;2;" + + strconv.FormatUint(uint64(shift(r)), 10) + ";" + + strconv.FormatUint(uint64(shift(g)), 10) + ";" + + strconv.FormatUint(uint64(shift(b)), 10) + } + return DefaultUnderlineColorAttr +} + +func shift(v uint32) uint32 { + if v > 0xff { + return v >> 8 + } + return v +} diff --git a/vendor/github.com/charmbracelet/x/ansi/termcap.go b/vendor/github.com/charmbracelet/x/ansi/termcap.go new file mode 100644 index 00000000..1dfc52a6 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/termcap.go @@ -0,0 +1,31 @@ +package ansi + +import ( + "encoding/hex" + "strings" +) + +// RequestTermcap (XTGETTCAP) requests Termcap/Terminfo strings. +// +// DCS + q ST +// +// Where is a list of Termcap/Terminfo capabilities, encoded in 2-digit +// hexadecimals, separated by semicolons. +// +// See: https://man7.org/linux/man-pages/man5/terminfo.5.html +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func RequestTermcap(caps ...string) string { + if len(caps) == 0 { + return "" + } + + s := "\x1bP+q" + for i, c := range caps { + if i > 0 { + s += ";" + } + s += strings.ToUpper(hex.EncodeToString([]byte(c))) + } + + return s + "\x1b\\" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/title.go b/vendor/github.com/charmbracelet/x/ansi/title.go new file mode 100644 index 00000000..8fd8bf98 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/title.go @@ -0,0 +1,32 @@ +package ansi + +// SetIconNameWindowTitle returns a sequence for setting the icon name and +// window title. +// +// OSC 0 ; title ST +// OSC 0 ; title BEL +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetIconNameWindowTitle(s string) string { + return "\x1b]0;" + s + "\x07" +} + +// SetIconName returns a sequence for setting the icon name. +// +// OSC 1 ; title ST +// OSC 1 ; title BEL +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetIconName(s string) string { + return "\x1b]1;" + s + "\x07" +} + +// SetWindowTitle returns a sequence for setting the window title. +// +// OSC 2 ; title ST +// OSC 2 ; title BEL +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetWindowTitle(s string) string { + return "\x1b]2;" + s + "\x07" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/truncate.go b/vendor/github.com/charmbracelet/x/ansi/truncate.go new file mode 100644 index 00000000..db0782c8 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/truncate.go @@ -0,0 +1,107 @@ +package ansi + +import ( + "bytes" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/rivo/uniseg" +) + +// Truncate truncates a string to a given length, adding a tail to the +// end if the string is longer than the given length. +// This function is aware of ANSI escape codes and will not break them, and +// accounts for wide-characters (such as East Asians and emojis). +func Truncate(s string, length int, tail string) string { + if sw := StringWidth(s); sw <= length { + return s + } + + tw := StringWidth(tail) + length -= tw + if length < 0 { + return "" + } + + var cluster []byte + var buf bytes.Buffer + curWidth := 0 + ignoring := false + pstate := parser.GroundState // initial state + b := []byte(s) + i := 0 + + // Here we iterate over the bytes of the string and collect printable + // characters and runes. We also keep track of the width of the string + // in cells. + // Once we reach the given length, we start ignoring characters and only + // collect ANSI escape codes until we reach the end of string. + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { + // This action happens when we transition to the Utf8State. + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + + // increment the index by the length of the cluster + i += len(cluster) + + // Are we ignoring? Skip to the next byte + if ignoring { + continue + } + + // Is this gonna be too wide? + // If so write the tail and stop collecting. + if curWidth+width > length && !ignoring { + ignoring = true + buf.WriteString(tail) + } + + if curWidth+width > length { + continue + } + + curWidth += width + buf.Write(cluster) + + // Done collecting, now we're back in the ground state. + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction: + // Is this gonna be too wide? + // If so write the tail and stop collecting. + if curWidth >= length && !ignoring { + ignoring = true + buf.WriteString(tail) + } + + // Skip to the next byte if we're ignoring + if ignoring { + i++ + continue + } + + // collects printable ASCII + curWidth++ + fallthrough + default: + buf.WriteByte(b[i]) + i++ + } + + // Transition to the next state. + pstate = state + + // Once we reach the given length, we start ignoring runes and write + // the tail to the buffer. + if curWidth > length && !ignoring { + ignoring = true + buf.WriteString(tail) + } + } + + return buf.String() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/util.go b/vendor/github.com/charmbracelet/x/ansi/util.go new file mode 100644 index 00000000..767093f9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/util.go @@ -0,0 +1,29 @@ +package ansi + +import ( + "fmt" + "image/color" +) + +// colorToHexString returns a hex string representation of a color. +func colorToHexString(c color.Color) string { + if c == nil { + return "" + } + shift := func(v uint32) uint32 { + if v > 0xff { + return v >> 8 + } + return v + } + r, g, b, _ := c.RGBA() + r, g, b = shift(r), shift(g), shift(b) + return fmt.Sprintf("#%02x%02x%02x", r, g, b) +} + +// rgbToHex converts red, green, and blue values to a hexadecimal value. +// +// hex := rgbToHex(0, 0, 255) // 0x0000FF +func rgbToHex(r, g, b uint32) uint32 { + return r<<16 + g<<8 + b +} diff --git a/vendor/github.com/charmbracelet/x/ansi/width.go b/vendor/github.com/charmbracelet/x/ansi/width.go new file mode 100644 index 00000000..80890e42 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/width.go @@ -0,0 +1,95 @@ +package ansi + +import ( + "bytes" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/rivo/uniseg" +) + +// Strip removes ANSI escape codes from a string. +func Strip(s string) string { + var ( + buf bytes.Buffer // buffer for collecting printable characters + ri int // rune index + rw int // rune width + pstate = parser.GroundState // initial state + ) + + // This implements a subset of the Parser to only collect runes and + // printable characters. + for i := 0; i < len(s); i++ { + if pstate == parser.Utf8State { + // During this state, collect rw bytes to form a valid rune in the + // buffer. After getting all the rune bytes into the buffer, + // transition to GroundState and reset the counters. + buf.WriteByte(s[i]) + ri++ + if ri < rw { + continue + } + pstate = parser.GroundState + ri = 0 + rw = 0 + continue + } + + state, action := parser.Table.Transition(pstate, s[i]) + switch action { + case parser.CollectAction: + if state == parser.Utf8State { + // This action happens when we transition to the Utf8State. + rw = utf8ByteLen(s[i]) + buf.WriteByte(s[i]) + ri++ + } + case parser.PrintAction, parser.ExecuteAction: + // collects printable ASCII and non-printable characters + buf.WriteByte(s[i]) + } + + // Transition to the next state. + // The Utf8State is managed separately above. + if pstate != parser.Utf8State { + pstate = state + } + } + + return buf.String() +} + +// StringWidth returns the width of a string in cells. This is the number of +// cells that the string will occupy when printed in a terminal. ANSI escape +// codes are ignored and wide characters (such as East Asians and emojis) are +// accounted for. +func StringWidth(s string) int { + if s == "" { + return 0 + } + + var ( + pstate = parser.GroundState // initial state + cluster string + width int + ) + + for i := 0; i < len(s); i++ { + state, action := parser.Table.Transition(pstate, s[i]) + if state == parser.Utf8State { + var w int + cluster, _, w, _ = uniseg.FirstGraphemeClusterInString(s[i:], -1) + width += w + i += len(cluster) - 1 + pstate = parser.GroundState + continue + } + + if action == parser.PrintAction { + width++ + } + + pstate = state + } + + return width +} diff --git a/vendor/github.com/charmbracelet/x/ansi/wrap.go b/vendor/github.com/charmbracelet/x/ansi/wrap.go new file mode 100644 index 00000000..2cab5cec --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/wrap.go @@ -0,0 +1,395 @@ +package ansi + +import ( + "bytes" + "unicode" + "unicode/utf8" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/rivo/uniseg" +) + +// nbsp is a non-breaking space +const nbsp = 0xA0 + +// Hardwrap wraps a string or a block of text to a given line length, breaking +// word boundaries. This will preserve ANSI escape codes and will account for +// wide-characters in the string. +// When preserveSpace is true, spaces at the beginning of a line will be +// preserved. +func Hardwrap(s string, limit int, preserveSpace bool) string { + if limit < 1 { + return s + } + + var ( + cluster []byte + buf bytes.Buffer + curWidth int + forceNewline bool + pstate = parser.GroundState // initial state + b = []byte(s) + ) + + addNewline := func() { + buf.WriteByte('\n') + curWidth = 0 + } + + i := 0 + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + i += len(cluster) + + if curWidth+width > limit { + addNewline() + } + if !preserveSpace && curWidth == 0 && len(cluster) <= 4 { + // Skip spaces at the beginning of a line + if r, _ := utf8.DecodeRune(cluster); r != utf8.RuneError && unicode.IsSpace(r) { + pstate = parser.GroundState + continue + } + } + + buf.Write(cluster) + curWidth += width + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction, parser.ExecuteAction: + if b[i] == '\n' { + addNewline() + forceNewline = false + break + } + + if curWidth+1 > limit { + addNewline() + forceNewline = true + } + + // Skip spaces at the beginning of a line + if curWidth == 0 { + if !preserveSpace && forceNewline && unicode.IsSpace(rune(b[i])) { + break + } + forceNewline = false + } + + buf.WriteByte(b[i]) + curWidth++ + default: + buf.WriteByte(b[i]) + } + + // We manage the UTF8 state separately manually above. + if pstate != parser.Utf8State { + pstate = state + } + i++ + } + + return buf.String() +} + +// Wordwrap wraps a string or a block of text to a given line length, not +// breaking word boundaries. This will preserve ANSI escape codes and will +// account for wide-characters in the string. +// The breakpoints string is a list of characters that are considered +// breakpoints for word wrapping. A hyphen (-) is always considered a +// breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +func Wordwrap(s string, limit int, breakpoints string) string { + if limit < 1 { + return s + } + + var ( + cluster []byte + buf bytes.Buffer + word bytes.Buffer + space bytes.Buffer + curWidth int + wordLen int + pstate = parser.GroundState // initial state + b = []byte(s) + ) + + addSpace := func() { + curWidth += space.Len() + buf.Write(space.Bytes()) + space.Reset() + } + + addWord := func() { + if word.Len() == 0 { + return + } + + addSpace() + curWidth += wordLen + buf.Write(word.Bytes()) + word.Reset() + wordLen = 0 + } + + addNewline := func() { + buf.WriteByte('\n') + curWidth = 0 + space.Reset() + } + + i := 0 + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + i += len(cluster) + + r, _ := utf8.DecodeRune(cluster) + if r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp { + addWord() + space.WriteRune(r) + } else if bytes.ContainsAny(cluster, breakpoints) { + addSpace() + addWord() + buf.Write(cluster) + curWidth++ + } else { + word.Write(cluster) + wordLen += width + if curWidth+space.Len()+wordLen > limit && + wordLen < limit { + addNewline() + } + } + + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction, parser.ExecuteAction: + r := rune(b[i]) + switch { + case r == '\n': + if wordLen == 0 { + if curWidth+space.Len() > limit { + curWidth = 0 + } else { + buf.Write(space.Bytes()) + } + space.Reset() + } + + addWord() + addNewline() + case unicode.IsSpace(r): + addWord() + space.WriteByte(b[i]) + case r == '-': + fallthrough + case runeContainsAny(r, breakpoints): + addSpace() + addWord() + buf.WriteByte(b[i]) + curWidth++ + default: + word.WriteByte(b[i]) + wordLen++ + if curWidth+space.Len()+wordLen > limit && + wordLen < limit { + addNewline() + } + } + + default: + word.WriteByte(b[i]) + } + + // We manage the UTF8 state separately manually above. + if pstate != parser.Utf8State { + pstate = state + } + i++ + } + + addWord() + + return buf.String() +} + +// Wrap wraps a string or a block of text to a given line length, breaking word +// boundaries if necessary. This will preserve ANSI escape codes and will +// account for wide-characters in the string. The breakpoints string is a list +// of characters that are considered breakpoints for word wrapping. A hyphen +// (-) is always considered a breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +func Wrap(s string, limit int, breakpoints string) string { + if limit < 1 { + return s + } + + var ( + cluster []byte + buf bytes.Buffer + word bytes.Buffer + space bytes.Buffer + curWidth int // written width of the line + wordLen int // word buffer len without ANSI escape codes + pstate = parser.GroundState // initial state + b = []byte(s) + ) + + addSpace := func() { + curWidth += space.Len() + buf.Write(space.Bytes()) + space.Reset() + } + + addWord := func() { + if word.Len() == 0 { + return + } + + addSpace() + curWidth += wordLen + buf.Write(word.Bytes()) + word.Reset() + wordLen = 0 + } + + addNewline := func() { + buf.WriteByte('\n') + curWidth = 0 + space.Reset() + } + + i := 0 + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + i += len(cluster) + + r, _ := utf8.DecodeRune(cluster) + switch { + case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space + addWord() + space.WriteRune(r) + case bytes.ContainsAny(cluster, breakpoints): + addSpace() + if curWidth+wordLen+width > limit { + word.Write(cluster) + wordLen += width + } else { + addWord() + buf.Write(cluster) + curWidth += width + } + default: + if wordLen+width > limit { + // Hardwrap the word if it's too long + addWord() + } + + word.Write(cluster) + wordLen += width + + if curWidth+wordLen+space.Len() > limit { + addNewline() + } + } + + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction, parser.ExecuteAction: + switch r := rune(b[i]); { + case r == '\n': + if wordLen == 0 { + if curWidth+space.Len() > limit { + curWidth = 0 + } else { + // preserve whitespaces + buf.Write(space.Bytes()) + } + space.Reset() + } + + addWord() + addNewline() + case unicode.IsSpace(r): + addWord() + space.WriteRune(r) + case r == '-': + fallthrough + case runeContainsAny(r, breakpoints): + addSpace() + if curWidth+wordLen >= limit { + // We can't fit the breakpoint in the current line, treat + // it as part of the word. + word.WriteRune(r) + wordLen++ + } else { + addWord() + buf.WriteRune(r) + curWidth++ + } + default: + word.WriteRune(r) + wordLen++ + + if wordLen == limit { + // Hardwrap the word if it's too long + addWord() + } + + if curWidth+wordLen+space.Len() > limit { + addNewline() + } + } + + default: + word.WriteByte(b[i]) + } + + // We manage the UTF8 state separately manually above. + if pstate != parser.Utf8State { + pstate = state + } + i++ + } + + if word.Len() != 0 { + // Preserve ANSI wrapped spaces at the end of string + if curWidth+space.Len() > limit { + buf.WriteByte('\n') + } + addSpace() + } + buf.Write(word.Bytes()) + + return buf.String() +} + +func runeContainsAny(r rune, s string) bool { + for _, c := range s { + if c == r { + return true + } + } + return false +} diff --git a/vendor/github.com/charmbracelet/x/ansi/xterm.go b/vendor/github.com/charmbracelet/x/ansi/xterm.go new file mode 100644 index 00000000..f87712a6 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/xterm.go @@ -0,0 +1,50 @@ +package ansi + +import "strconv" + +// ModifyOtherKeys returns a sequence that sets XTerm modifyOtherKeys mode. +// The mode argument specifies the mode to set. +// +// 0: Disable modifyOtherKeys mode. +// 1: Enable modifyOtherKeys mode 1. +// 2: Enable modifyOtherKeys mode 2. +// +// CSI > 4 ; mode m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +func ModifyOtherKeys(mode int) string { + return "\x1b[>4;" + strconv.Itoa(mode) + "m" +} + +// DisableModifyOtherKeys disables the modifyOtherKeys mode. +// +// CSI > 4 ; 0 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +const DisableModifyOtherKeys = "\x1b[>4;0m" + +// EnableModifyOtherKeys1 enables the modifyOtherKeys mode 1. +// +// CSI > 4 ; 1 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +const EnableModifyOtherKeys1 = "\x1b[>4;1m" + +// EnableModifyOtherKeys2 enables the modifyOtherKeys mode 2. +// +// CSI > 4 ; 2 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +const EnableModifyOtherKeys2 = "\x1b[>4;2m" + +// RequestModifyOtherKeys requests the modifyOtherKeys mode. +// +// CSI ? 4 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +const RequestModifyOtherKeys = "\x1b[?4m" diff --git a/vendor/github.com/charmbracelet/x/term/LICENSE b/vendor/github.com/charmbracelet/x/term/LICENSE new file mode 100644 index 00000000..65a5654e --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Charmbracelet, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/x/term/term.go b/vendor/github.com/charmbracelet/x/term/term.go new file mode 100644 index 00000000..58d6522c --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term.go @@ -0,0 +1,49 @@ +package term + +// State contains platform-specific state of a terminal. +type State struct { + state +} + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + return isTerminal(fd) +} + +// MakeRaw puts the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd uintptr) (*State, error) { + return makeRaw(fd) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd uintptr) (*State, error) { + return getState(fd) +} + +// SetState sets the given state of the terminal. +func SetState(fd uintptr, state *State) error { + return setState(fd, state) +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd uintptr, oldState *State) error { + return restore(fd, oldState) +} + +// GetSize returns the visible dimensions of the given terminal. +// +// These dimensions don't include any scrollback buffer height. +func GetSize(fd uintptr) (width, height int, err error) { + return getSize(fd) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd uintptr) ([]byte, error) { + return readPassword(fd) +} diff --git a/vendor/github.com/charmbracelet/x/term/term_other.go b/vendor/github.com/charmbracelet/x/term/term_other.go new file mode 100644 index 00000000..092c7e9d --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_other.go @@ -0,0 +1,39 @@ +//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !zos && !windows && !solaris && !plan9 +// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!zos,!windows,!solaris,!plan9 + +package term + +import ( + "fmt" + "runtime" +) + +type state struct{} + +func isTerminal(fd uintptr) bool { + return false +} + +func makeRaw(fd uintptr) (*State, error) { + return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func getState(fd uintptr) (*State, error) { + return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func restore(fd uintptr, state *State) error { + return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func getSize(fd uintptr) (width, height int, err error) { + return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func setState(fd uintptr, state *State) error { + return fmt.Errorf("terminal: SetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func readPassword(fd uintptr) ([]byte, error) { + return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} diff --git a/vendor/github.com/charmbracelet/x/term/term_unix.go b/vendor/github.com/charmbracelet/x/term/term_unix.go new file mode 100644 index 00000000..1459cb1b --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_unix.go @@ -0,0 +1,96 @@ +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos + +package term + +import ( + "golang.org/x/sys/unix" +) + +type state struct { + unix.Termios +} + +func isTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + return err == nil +} + +func makeRaw(fd uintptr) (*State, error) { + termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + if err != nil { + return nil, err + } + + oldState := State{state{Termios: *termios}} + + // This attempts to replicate the behaviour documented for cfmakeraw in + // the termios(3) manpage. + termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON + termios.Oflag &^= unix.OPOST + termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN + termios.Cflag &^= unix.CSIZE | unix.PARENB + termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 + if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios); err != nil { + return nil, err + } + + return &oldState, nil +} + +func setState(fd uintptr, state *State) error { + var termios *unix.Termios + if state != nil { + termios = &state.Termios + } + return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios) +} + +func getState(fd uintptr) (*State, error) { + termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + if err != nil { + return nil, err + } + + return &State{state{Termios: *termios}}, nil +} + +func restore(fd uintptr, state *State) error { + return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &state.Termios) +} + +func getSize(fd uintptr) (width, height int, err error) { + ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) + if err != nil { + return 0, 0, err + } + return int(ws.Col), int(ws.Row), nil +} + +// passwordReader is an io.Reader that reads from a specific file descriptor. +type passwordReader int + +func (r passwordReader) Read(buf []byte) (int, error) { + return unix.Read(int(r), buf) +} + +func readPassword(fd uintptr) ([]byte, error) { + termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + if err != nil { + return nil, err + } + + newState := *termios + newState.Lflag &^= unix.ECHO + newState.Lflag |= unix.ICANON | unix.ISIG + newState.Iflag |= unix.ICRNL + if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &newState); err != nil { + return nil, err + } + + defer unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios) + + return readPasswordLine(passwordReader(fd)) +} diff --git a/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go b/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go new file mode 100644 index 00000000..b435031a --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go @@ -0,0 +1,11 @@ +//go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd + +package term + +import "golang.org/x/sys/unix" + +const ( + ioctlReadTermios = unix.TIOCGETA + ioctlWriteTermios = unix.TIOCSETA +) diff --git a/vendor/github.com/charmbracelet/x/term/term_unix_other.go b/vendor/github.com/charmbracelet/x/term/term_unix_other.go new file mode 100644 index 00000000..ee2a29eb --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_unix_other.go @@ -0,0 +1,11 @@ +//go:build aix || linux || solaris || zos +// +build aix linux solaris zos + +package term + +import "golang.org/x/sys/unix" + +const ( + ioctlReadTermios = unix.TCGETS + ioctlWriteTermios = unix.TCSETS +) diff --git a/vendor/github.com/charmbracelet/x/term/term_windows.go b/vendor/github.com/charmbracelet/x/term/term_windows.go new file mode 100644 index 00000000..9e1c4740 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_windows.go @@ -0,0 +1,86 @@ +//go:build windows +// +build windows + +package term + +import ( + "os" + + "golang.org/x/sys/windows" +) + +type state struct { + Mode uint32 +} + +func isTerminal(fd uintptr) bool { + var st uint32 + err := windows.GetConsoleMode(windows.Handle(fd), &st) + return err == nil +} + +func makeRaw(fd uintptr) (*State, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { + return nil, err + } + return &State{state{st}}, nil +} + +func setState(fd uintptr, state *State) error { + var mode uint32 + if state != nil { + mode = state.Mode + } + return windows.SetConsoleMode(windows.Handle(fd), mode) +} + +func getState(fd uintptr) (*State, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + return &State{state{st}}, nil +} + +func restore(fd uintptr, state *State) error { + return windows.SetConsoleMode(windows.Handle(fd), state.Mode) +} + +func getSize(fd uintptr) (width, height int, err error) { + var info windows.ConsoleScreenBufferInfo + if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { + return 0, 0, err + } + return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil +} + +func readPassword(fd uintptr) ([]byte, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + old := st + + st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT) + st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { + return nil, err + } + + defer windows.SetConsoleMode(windows.Handle(fd), old) + + var h windows.Handle + p, _ := windows.GetCurrentProcess() + if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { + return nil, err + } + + f := os.NewFile(uintptr(h), "stdin") + defer f.Close() + return readPasswordLine(f) +} diff --git a/vendor/github.com/charmbracelet/x/term/terminal.go b/vendor/github.com/charmbracelet/x/term/terminal.go new file mode 100644 index 00000000..8963163f --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/terminal.go @@ -0,0 +1,12 @@ +package term + +import ( + "io" +) + +// File represents a file that has a file descriptor and can be read from, +// written to, and closed. +type File interface { + io.ReadWriteCloser + Fd() uintptr +} diff --git a/vendor/github.com/charmbracelet/x/term/util.go b/vendor/github.com/charmbracelet/x/term/util.go new file mode 100644 index 00000000..b7313418 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/util.go @@ -0,0 +1,47 @@ +package term + +import ( + "io" + "runtime" +) + +// readPasswordLine reads from reader until it finds \n or io.EOF. +// The slice returned does not include the \n. +// readPasswordLine also ignores any \r it finds. +// Windows uses \r as end of line. So, on Windows, readPasswordLine +// reads until it finds \r and ignores any \n it finds during processing. +func readPasswordLine(reader io.Reader) ([]byte, error) { + var buf [1]byte + var ret []byte + + for { + n, err := reader.Read(buf[:]) + if n > 0 { + switch buf[0] { + case '\b': + if len(ret) > 0 { + ret = ret[:len(ret)-1] + } + case '\n': + if runtime.GOOS != "windows" { + return ret, nil + } + // otherwise ignore \n + case '\r': + if runtime.GOOS == "windows" { + return ret, nil + } + // otherwise ignore \r + default: + ret = append(ret, buf[0]) + } + continue + } + if err != nil { + if err == io.EOF && len(ret) > 0 { + return ret, nil + } + return ret, err + } + } +} diff --git a/vendor/github.com/containerd/console/.golangci.yml b/vendor/github.com/containerd/console/.golangci.yml deleted file mode 100644 index abe3d84b..00000000 --- a/vendor/github.com/containerd/console/.golangci.yml +++ /dev/null @@ -1,20 +0,0 @@ -linters: - enable: - - gofmt - - goimports - - ineffassign - - misspell - - revive - - staticcheck - - structcheck - - unconvert - - unused - - varcheck - - vet - disable: - - errcheck - -run: - timeout: 3m - skip-dirs: - - vendor diff --git a/vendor/github.com/containerd/console/LICENSE b/vendor/github.com/containerd/console/LICENSE deleted file mode 100644 index 584149b6..00000000 --- a/vendor/github.com/containerd/console/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright The containerd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/containerd/console/README.md b/vendor/github.com/containerd/console/README.md deleted file mode 100644 index 580b461a..00000000 --- a/vendor/github.com/containerd/console/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# console - -[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/console)](https://pkg.go.dev/github.com/containerd/console) -[![Build Status](https://github.com/containerd/console/workflows/CI/badge.svg)](https://github.com/containerd/console/actions?query=workflow%3ACI) -[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/console)](https://goreportcard.com/report/github.com/containerd/console) - -Golang package for dealing with consoles. Light on deps and a simple API. - -## Modifying the current process - -```go -current := console.Current() -defer current.Reset() - -if err := current.SetRaw(); err != nil { -} -ws, err := current.Size() -current.Resize(ws) -``` - -## Project details - -console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). -As a containerd sub-project, you will find the: - * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), - * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), - * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) - -information in our [`containerd/project`](https://github.com/containerd/project) repository. diff --git a/vendor/github.com/containerd/console/console.go b/vendor/github.com/containerd/console/console.go deleted file mode 100644 index 810a71f4..00000000 --- a/vendor/github.com/containerd/console/console.go +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "errors" - "io" - "os" -) - -var ErrNotAConsole = errors.New("provided file is not a console") - -type File interface { - io.ReadWriteCloser - - // Fd returns its file descriptor - Fd() uintptr - // Name returns its file name - Name() string -} - -type Console interface { - File - - // Resize resizes the console to the provided window size - Resize(WinSize) error - // ResizeFrom resizes the calling console to the size of the - // provided console - ResizeFrom(Console) error - // SetRaw sets the console in raw mode - SetRaw() error - // DisableEcho disables echo on the console - DisableEcho() error - // Reset restores the console to its orignal state - Reset() error - // Size returns the window size of the console - Size() (WinSize, error) -} - -// WinSize specifies the window size of the console -type WinSize struct { - // Height of the console - Height uint16 - // Width of the console - Width uint16 - x uint16 - y uint16 -} - -// Current returns the current process' console -func Current() (c Console) { - var err error - // Usually all three streams (stdin, stdout, and stderr) - // are open to the same console, but some might be redirected, - // so try all three. - for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} { - if c, err = ConsoleFromFile(s); err == nil { - return c - } - } - // One of the std streams should always be a console - // for the design of this function. - panic(err) -} - -// ConsoleFromFile returns a console using the provided file -// nolint:revive -func ConsoleFromFile(f File) (Console, error) { - if err := checkConsole(f); err != nil { - return nil, err - } - return newMaster(f) -} diff --git a/vendor/github.com/containerd/console/console_linux.go b/vendor/github.com/containerd/console/console_linux.go deleted file mode 100644 index 28b77b7a..00000000 --- a/vendor/github.com/containerd/console/console_linux.go +++ /dev/null @@ -1,281 +0,0 @@ -//go:build linux -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "io" - "os" - "sync" - - "golang.org/x/sys/unix" -) - -const ( - maxEvents = 128 -) - -// Epoller manages multiple epoll consoles using edge-triggered epoll api so we -// dont have to deal with repeated wake-up of EPOLLER or EPOLLHUP. -// For more details, see: -// - https://github.com/systemd/systemd/pull/4262 -// - https://github.com/moby/moby/issues/27202 -// -// Example usage of Epoller and EpollConsole can be as follow: -// -// epoller, _ := NewEpoller() -// epollConsole, _ := epoller.Add(console) -// go epoller.Wait() -// var ( -// b bytes.Buffer -// wg sync.WaitGroup -// ) -// wg.Add(1) -// go func() { -// io.Copy(&b, epollConsole) -// wg.Done() -// }() -// // perform I/O on the console -// epollConsole.Shutdown(epoller.CloseConsole) -// wg.Wait() -// epollConsole.Close() -type Epoller struct { - efd int - mu sync.Mutex - fdMapping map[int]*EpollConsole - closeOnce sync.Once -} - -// NewEpoller returns an instance of epoller with a valid epoll fd. -func NewEpoller() (*Epoller, error) { - efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC) - if err != nil { - return nil, err - } - return &Epoller{ - efd: efd, - fdMapping: make(map[int]*EpollConsole), - }, nil -} - -// Add creates an epoll console based on the provided console. The console will -// be registered with EPOLLET (i.e. using edge-triggered notification) and its -// file descriptor will be set to non-blocking mode. After this, user should use -// the return console to perform I/O. -func (e *Epoller) Add(console Console) (*EpollConsole, error) { - sysfd := int(console.Fd()) - // Set sysfd to non-blocking mode - if err := unix.SetNonblock(sysfd, true); err != nil { - return nil, err - } - - ev := unix.EpollEvent{ - Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET, - Fd: int32(sysfd), - } - if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, sysfd, &ev); err != nil { - return nil, err - } - ef := &EpollConsole{ - Console: console, - sysfd: sysfd, - readc: sync.NewCond(&sync.Mutex{}), - writec: sync.NewCond(&sync.Mutex{}), - } - e.mu.Lock() - e.fdMapping[sysfd] = ef - e.mu.Unlock() - return ef, nil -} - -// Wait starts the loop to wait for its consoles' notifications and signal -// appropriate console that it can perform I/O. -func (e *Epoller) Wait() error { - events := make([]unix.EpollEvent, maxEvents) - for { - n, err := unix.EpollWait(e.efd, events, -1) - if err != nil { - // EINTR: The call was interrupted by a signal handler before either - // any of the requested events occurred or the timeout expired - if err == unix.EINTR { - continue - } - return err - } - for i := 0; i < n; i++ { - ev := &events[i] - // the console is ready to be read from - if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 { - if epfile := e.getConsole(int(ev.Fd)); epfile != nil { - epfile.signalRead() - } - } - // the console is ready to be written to - if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 { - if epfile := e.getConsole(int(ev.Fd)); epfile != nil { - epfile.signalWrite() - } - } - } - } -} - -// CloseConsole unregisters the console's file descriptor from epoll interface -func (e *Epoller) CloseConsole(fd int) error { - e.mu.Lock() - defer e.mu.Unlock() - delete(e.fdMapping, fd) - return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{}) -} - -func (e *Epoller) getConsole(sysfd int) *EpollConsole { - e.mu.Lock() - f := e.fdMapping[sysfd] - e.mu.Unlock() - return f -} - -// Close closes the epoll fd -func (e *Epoller) Close() error { - closeErr := os.ErrClosed // default to "file already closed" - e.closeOnce.Do(func() { - closeErr = unix.Close(e.efd) - }) - return closeErr -} - -// EpollConsole acts like a console but registers its file descriptor with an -// epoll fd and uses epoll API to perform I/O. -type EpollConsole struct { - Console - readc *sync.Cond - writec *sync.Cond - sysfd int - closed bool -} - -// Read reads up to len(p) bytes into p. It returns the number of bytes read -// (0 <= n <= len(p)) and any error encountered. -// -// If the console's read returns EAGAIN or EIO, we assume that it's a -// temporary error because the other side went away and wait for the signal -// generated by epoll event to continue. -func (ec *EpollConsole) Read(p []byte) (n int, err error) { - var read int - ec.readc.L.Lock() - defer ec.readc.L.Unlock() - for { - read, err = ec.Console.Read(p[n:]) - n += read - if err != nil { - var hangup bool - if perr, ok := err.(*os.PathError); ok { - hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO) - } else { - hangup = (err == unix.EAGAIN || err == unix.EIO) - } - // if the other end disappear, assume this is temporary and wait for the - // signal to continue again. Unless we didnt read anything and the - // console is already marked as closed then we should exit - if hangup && !(n == 0 && len(p) > 0 && ec.closed) { - ec.readc.Wait() - continue - } - } - break - } - // if we didnt read anything then return io.EOF to end gracefully - if n == 0 && len(p) > 0 && err == nil { - err = io.EOF - } - // signal for others that we finished the read - ec.readc.Signal() - return n, err -} - -// Writes len(p) bytes from p to the console. It returns the number of bytes -// written from p (0 <= n <= len(p)) and any error encountered that caused -// the write to stop early. -// -// If writes to the console returns EAGAIN or EIO, we assume that it's a -// temporary error because the other side went away and wait for the signal -// generated by epoll event to continue. -func (ec *EpollConsole) Write(p []byte) (n int, err error) { - var written int - ec.writec.L.Lock() - defer ec.writec.L.Unlock() - for { - written, err = ec.Console.Write(p[n:]) - n += written - if err != nil { - var hangup bool - if perr, ok := err.(*os.PathError); ok { - hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO) - } else { - hangup = (err == unix.EAGAIN || err == unix.EIO) - } - // if the other end disappears, assume this is temporary and wait for the - // signal to continue again. - if hangup { - ec.writec.Wait() - continue - } - } - // unrecoverable error, break the loop and return the error - break - } - if n < len(p) && err == nil { - err = io.ErrShortWrite - } - // signal for others that we finished the write - ec.writec.Signal() - return n, err -} - -// Shutdown closes the file descriptor and signals call waiters for this fd. -// It accepts a callback which will be called with the console's fd. The -// callback typically will be used to do further cleanup such as unregister the -// console's fd from the epoll interface. -// User should call Shutdown and wait for all I/O operation to be finished -// before closing the console. -func (ec *EpollConsole) Shutdown(close func(int) error) error { - ec.readc.L.Lock() - defer ec.readc.L.Unlock() - ec.writec.L.Lock() - defer ec.writec.L.Unlock() - - ec.readc.Broadcast() - ec.writec.Broadcast() - ec.closed = true - return close(ec.sysfd) -} - -// signalRead signals that the console is readable. -func (ec *EpollConsole) signalRead() { - ec.readc.L.Lock() - ec.readc.Signal() - ec.readc.L.Unlock() -} - -// signalWrite signals that the console is writable. -func (ec *EpollConsole) signalWrite() { - ec.writec.L.Lock() - ec.writec.Signal() - ec.writec.L.Unlock() -} diff --git a/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/containerd/console/console_unix.go deleted file mode 100644 index 161f5d12..00000000 --- a/vendor/github.com/containerd/console/console_unix.go +++ /dev/null @@ -1,157 +0,0 @@ -//go:build darwin || freebsd || linux || netbsd || openbsd || zos -// +build darwin freebsd linux netbsd openbsd zos - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "golang.org/x/sys/unix" -) - -// NewPty creates a new pty pair -// The master is returned as the first console and a string -// with the path to the pty slave is returned as the second -func NewPty() (Console, string, error) { - f, err := openpt() - if err != nil { - return nil, "", err - } - slave, err := ptsname(f) - if err != nil { - return nil, "", err - } - if err := unlockpt(f); err != nil { - return nil, "", err - } - m, err := newMaster(f) - if err != nil { - return nil, "", err - } - return m, slave, nil -} - -type master struct { - f File - original *unix.Termios -} - -func (m *master) Read(b []byte) (int, error) { - return m.f.Read(b) -} - -func (m *master) Write(b []byte) (int, error) { - return m.f.Write(b) -} - -func (m *master) Close() error { - return m.f.Close() -} - -func (m *master) Resize(ws WinSize) error { - return tcswinsz(m.f.Fd(), ws) -} - -func (m *master) ResizeFrom(c Console) error { - ws, err := c.Size() - if err != nil { - return err - } - return m.Resize(ws) -} - -func (m *master) Reset() error { - if m.original == nil { - return nil - } - return tcset(m.f.Fd(), m.original) -} - -func (m *master) getCurrent() (unix.Termios, error) { - var termios unix.Termios - if err := tcget(m.f.Fd(), &termios); err != nil { - return unix.Termios{}, err - } - return termios, nil -} - -func (m *master) SetRaw() error { - rawState, err := m.getCurrent() - if err != nil { - return err - } - rawState = cfmakeraw(rawState) - rawState.Oflag = rawState.Oflag | unix.OPOST - return tcset(m.f.Fd(), &rawState) -} - -func (m *master) DisableEcho() error { - rawState, err := m.getCurrent() - if err != nil { - return err - } - rawState.Lflag = rawState.Lflag &^ unix.ECHO - return tcset(m.f.Fd(), &rawState) -} - -func (m *master) Size() (WinSize, error) { - return tcgwinsz(m.f.Fd()) -} - -func (m *master) Fd() uintptr { - return m.f.Fd() -} - -func (m *master) Name() string { - return m.f.Name() -} - -// checkConsole checks if the provided file is a console -func checkConsole(f File) error { - var termios unix.Termios - if tcget(f.Fd(), &termios) != nil { - return ErrNotAConsole - } - return nil -} - -func newMaster(f File) (Console, error) { - m := &master{ - f: f, - } - t, err := m.getCurrent() - if err != nil { - return nil, err - } - m.original = &t - return m, nil -} - -// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair -// created by us acts normally. In particular, a not-very-well-known default of -// Linux unix98 ptys is that they have +onlcr by default. While this isn't a -// problem for terminal emulators, because we relay data from the terminal we -// also relay that funky line discipline. -func ClearONLCR(fd uintptr) error { - return setONLCR(fd, false) -} - -// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair -// created by us acts as intended for a terminal emulator. -func SetONLCR(fd uintptr) error { - return setONLCR(fd, true) -} diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go deleted file mode 100644 index f48e4861..00000000 --- a/vendor/github.com/containerd/console/console_windows.go +++ /dev/null @@ -1,222 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "errors" - "fmt" - "os" - - "golang.org/x/sys/windows" -) - -var ( - vtInputSupported bool - ErrNotImplemented = errors.New("not implemented") -) - -func (m *master) initStdios() { - // Note: We discard console mode warnings, because in/out can be redirected. - // - // TODO: Investigate opening CONOUT$/CONIN$ to handle this correctly - - m.in = windows.Handle(os.Stdin.Fd()) - if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil { - // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it. - if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil { - vtInputSupported = true - } - // Unconditionally set the console mode back even on failure because SetConsoleMode - // remembers invalid bits on input handles. - windows.SetConsoleMode(m.in, m.inMode) - } - - m.out = windows.Handle(os.Stdout.Fd()) - if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil { - if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil { - m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - } else { - windows.SetConsoleMode(m.out, m.outMode) - } - } - - m.err = windows.Handle(os.Stderr.Fd()) - if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil { - if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil { - m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - } else { - windows.SetConsoleMode(m.err, m.errMode) - } - } -} - -type master struct { - in windows.Handle - inMode uint32 - - out windows.Handle - outMode uint32 - - err windows.Handle - errMode uint32 -} - -func (m *master) SetRaw() error { - if err := makeInputRaw(m.in, m.inMode); err != nil { - return err - } - - // Set StdOut and StdErr to raw mode, we ignore failures since - // windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of - // Windows. - - windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN) - - windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN) - - return nil -} - -func (m *master) Reset() error { - var errs []error - - for _, s := range []struct { - fd windows.Handle - mode uint32 - }{ - {m.in, m.inMode}, - {m.out, m.outMode}, - {m.err, m.errMode}, - } { - if err := windows.SetConsoleMode(s.fd, s.mode); err != nil { - // we can't just abort on the first error, otherwise we might leave - // the console in an unexpected state. - errs = append(errs, fmt.Errorf("unable to restore console mode: %w", err)) - } - } - - if len(errs) > 0 { - return errs[0] - } - - return nil -} - -func (m *master) Size() (WinSize, error) { - var info windows.ConsoleScreenBufferInfo - err := windows.GetConsoleScreenBufferInfo(m.out, &info) - if err != nil { - return WinSize{}, fmt.Errorf("unable to get console info: %w", err) - } - - winsize := WinSize{ - Width: uint16(info.Window.Right - info.Window.Left + 1), - Height: uint16(info.Window.Bottom - info.Window.Top + 1), - } - - return winsize, nil -} - -func (m *master) Resize(ws WinSize) error { - return ErrNotImplemented -} - -func (m *master) ResizeFrom(c Console) error { - return ErrNotImplemented -} - -func (m *master) DisableEcho() error { - mode := m.inMode &^ windows.ENABLE_ECHO_INPUT - mode |= windows.ENABLE_PROCESSED_INPUT - mode |= windows.ENABLE_LINE_INPUT - - if err := windows.SetConsoleMode(m.in, mode); err != nil { - return fmt.Errorf("unable to set console to disable echo: %w", err) - } - - return nil -} - -func (m *master) Close() error { - return nil -} - -func (m *master) Read(b []byte) (int, error) { - return os.Stdin.Read(b) -} - -func (m *master) Write(b []byte) (int, error) { - return os.Stdout.Write(b) -} - -func (m *master) Fd() uintptr { - return uintptr(m.in) -} - -// on windows, console can only be made from os.Std{in,out,err}, hence there -// isnt a single name here we can use. Return a dummy "console" value in this -// case should be sufficient. -func (m *master) Name() string { - return "console" -} - -// makeInputRaw puts the terminal (Windows Console) connected to the given -// file descriptor into raw mode -func makeInputRaw(fd windows.Handle, mode uint32) error { - // See - // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx - // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx - - // Disable these modes - mode &^= windows.ENABLE_ECHO_INPUT - mode &^= windows.ENABLE_LINE_INPUT - mode &^= windows.ENABLE_MOUSE_INPUT - mode &^= windows.ENABLE_WINDOW_INPUT - mode &^= windows.ENABLE_PROCESSED_INPUT - - // Enable these modes - mode |= windows.ENABLE_EXTENDED_FLAGS - mode |= windows.ENABLE_INSERT_MODE - mode |= windows.ENABLE_QUICK_EDIT_MODE - - if vtInputSupported { - mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT - } - - if err := windows.SetConsoleMode(fd, mode); err != nil { - return fmt.Errorf("unable to set console to raw mode: %w", err) - } - - return nil -} - -func checkConsole(f File) error { - var mode uint32 - if err := windows.GetConsoleMode(windows.Handle(f.Fd()), &mode); err != nil { - return err - } - return nil -} - -func newMaster(f File) (Console, error) { - if f != os.Stdin && f != os.Stdout && f != os.Stderr { - return nil, errors.New("creating a console from a file is not supported on windows") - } - m := &master{} - m.initStdios() - return m, nil -} diff --git a/vendor/github.com/containerd/console/pty_freebsd_cgo.go b/vendor/github.com/containerd/console/pty_freebsd_cgo.go deleted file mode 100644 index 22368623..00000000 --- a/vendor/github.com/containerd/console/pty_freebsd_cgo.go +++ /dev/null @@ -1,46 +0,0 @@ -//go:build freebsd && cgo -// +build freebsd,cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" -) - -/* -#include -#include -#include -*/ -import "C" - -// openpt allocates a new pseudo-terminal and establishes a connection with its -// control device. -func openpt() (*os.File, error) { - fd, err := C.posix_openpt(C.O_RDWR) - if err != nil { - return nil, fmt.Errorf("posix_openpt: %w", err) - } - if _, err := C.grantpt(fd); err != nil { - C.close(fd) - return nil, fmt.Errorf("grantpt: %w", err) - } - return os.NewFile(uintptr(fd), ""), nil -} diff --git a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go deleted file mode 100644 index ceb90a47..00000000 --- a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go +++ /dev/null @@ -1,37 +0,0 @@ -//go:build freebsd && !cgo -// +build freebsd,!cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "os" -) - -// -// Implementing the functions below requires cgo support. Non-cgo stubs -// versions are defined below to enable cross-compilation of source code -// that depends on these functions, but the resultant cross-compiled -// binaries cannot actually be used. If the stub function(s) below are -// actually invoked they will display an error message and cause the -// calling process to exit. -// - -func openpt() (*os.File, error) { - panic("openpt() support requires cgo.") -} diff --git a/vendor/github.com/containerd/console/pty_unix.go b/vendor/github.com/containerd/console/pty_unix.go deleted file mode 100644 index f5a5b805..00000000 --- a/vendor/github.com/containerd/console/pty_unix.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build darwin || linux || netbsd || openbsd -// +build darwin linux netbsd openbsd - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "os" - - "golang.org/x/sys/unix" -) - -// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device -func openpt() (*os.File, error) { - return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0) -} diff --git a/vendor/github.com/containerd/console/pty_zos.go b/vendor/github.com/containerd/console/pty_zos.go deleted file mode 100644 index 58f59aba..00000000 --- a/vendor/github.com/containerd/console/pty_zos.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build zos -// +build zos - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" -) - -// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device -func openpt() (*os.File, error) { - var f *os.File - var err error - for i := 0; ; i++ { - ptyp := fmt.Sprintf("/dev/ptyp%04d", i) - f, err = os.OpenFile(ptyp, os.O_RDWR, 0600) - if err == nil { - break - } - if os.IsNotExist(err) { - return nil, err - } - // else probably Resource Busy - } - return f, nil -} diff --git a/vendor/github.com/containerd/console/tc_darwin.go b/vendor/github.com/containerd/console/tc_darwin.go deleted file mode 100644 index 78715458..00000000 --- a/vendor/github.com/containerd/console/tc_darwin.go +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0) -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME) - if err != nil { - return "", err - } - return fmt.Sprintf("/dev/pts/%d", n), nil -} diff --git a/vendor/github.com/containerd/console/tc_freebsd_cgo.go b/vendor/github.com/containerd/console/tc_freebsd_cgo.go deleted file mode 100644 index 33282579..00000000 --- a/vendor/github.com/containerd/console/tc_freebsd_cgo.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build freebsd && cgo -// +build freebsd,cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -/* -#include -#include -*/ -import "C" - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - fd := C.int(f.Fd()) - if _, err := C.unlockpt(fd); err != nil { - C.close(fd) - return fmt.Errorf("unlockpt: %w", err) - } - return nil -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN) - if err != nil { - return "", err - } - return fmt.Sprintf("/dev/pts/%d", n), nil -} diff --git a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go deleted file mode 100644 index 18a9b9cb..00000000 --- a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go +++ /dev/null @@ -1,56 +0,0 @@ -//go:build freebsd && !cgo -// +build freebsd,!cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -// -// Implementing the functions below requires cgo support. Non-cgo stubs -// versions are defined below to enable cross-compilation of source code -// that depends on these functions, but the resultant cross-compiled -// binaries cannot actually be used. If the stub function(s) below are -// actually invoked they will display an error message and cause the -// calling process to exit. -// - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - panic("unlockpt() support requires cgo.") -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN) - if err != nil { - return "", err - } - return fmt.Sprintf("/dev/pts/%d", n), nil -} diff --git a/vendor/github.com/containerd/console/tc_linux.go b/vendor/github.com/containerd/console/tc_linux.go deleted file mode 100644 index 7d552ea4..00000000 --- a/vendor/github.com/containerd/console/tc_linux.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" - "unsafe" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TCGETS - cmdTcSet = unix.TCSETS -) - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - var u int32 - // XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81. - if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 { - return err - } - return nil -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - var u uint32 - // XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81. - if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 { - return "", err - } - return fmt.Sprintf("/dev/pts/%d", u), nil -} diff --git a/vendor/github.com/containerd/console/tc_netbsd.go b/vendor/github.com/containerd/console/tc_netbsd.go deleted file mode 100644 index 71227aef..00000000 --- a/vendor/github.com/containerd/console/tc_netbsd.go +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "bytes" - "os" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -// This does not exist on NetBSD, it does not allocate controlling terminals on open -func unlockpt(f *os.File) error { - return nil -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME) - if err != nil { - return "", err - } - return string(ptm.Sn[:bytes.IndexByte(ptm.Sn[:], 0)]), nil -} diff --git a/vendor/github.com/containerd/console/tc_openbsd_cgo.go b/vendor/github.com/containerd/console/tc_openbsd_cgo.go deleted file mode 100644 index 0e76f6cc..00000000 --- a/vendor/github.com/containerd/console/tc_openbsd_cgo.go +++ /dev/null @@ -1,52 +0,0 @@ -//go:build openbsd && cgo -// +build openbsd,cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "os" - - "golang.org/x/sys/unix" -) - -//#include -import "C" - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - ptspath, err := C.ptsname(C.int(f.Fd())) - if err != nil { - return "", err - } - return C.GoString(ptspath), nil -} - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - if _, err := C.grantpt(C.int(f.Fd())); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go deleted file mode 100644 index dca92418..00000000 --- a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build openbsd && !cgo -// +build openbsd,!cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// -// Implementing the functions below requires cgo support. Non-cgo stubs -// versions are defined below to enable cross-compilation of source code -// that depends on these functions, but the resultant cross-compiled -// binaries cannot actually be used. If the stub function(s) below are -// actually invoked they will display an error message and cause the -// calling process to exit. -// - -package console - -import ( - "os" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -func ptsname(f *os.File) (string, error) { - panic("ptsname() support requires cgo.") -} - -func unlockpt(f *os.File) error { - panic("unlockpt() support requires cgo.") -} diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go deleted file mode 100644 index f5053b2f..00000000 --- a/vendor/github.com/containerd/console/tc_unix.go +++ /dev/null @@ -1,92 +0,0 @@ -//go:build darwin || freebsd || linux || netbsd || openbsd || zos -// +build darwin freebsd linux netbsd openbsd zos - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "golang.org/x/sys/unix" -) - -func tcget(fd uintptr, p *unix.Termios) error { - termios, err := unix.IoctlGetTermios(int(fd), cmdTcGet) - if err != nil { - return err - } - *p = *termios - return nil -} - -func tcset(fd uintptr, p *unix.Termios) error { - return unix.IoctlSetTermios(int(fd), cmdTcSet, p) -} - -func tcgwinsz(fd uintptr) (WinSize, error) { - var ws WinSize - - uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) - if err != nil { - return ws, err - } - - // Translate from unix.Winsize to console.WinSize - ws.Height = uws.Row - ws.Width = uws.Col - ws.x = uws.Xpixel - ws.y = uws.Ypixel - return ws, nil -} - -func tcswinsz(fd uintptr, ws WinSize) error { - // Translate from console.WinSize to unix.Winsize - - var uws unix.Winsize - uws.Row = ws.Height - uws.Col = ws.Width - uws.Xpixel = ws.x - uws.Ypixel = ws.y - - return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &uws) -} - -func setONLCR(fd uintptr, enable bool) error { - var termios unix.Termios - if err := tcget(fd, &termios); err != nil { - return err - } - if enable { - // Set +onlcr so we can act like a real terminal - termios.Oflag |= unix.ONLCR - } else { - // Set -onlcr so we don't have to deal with \r. - termios.Oflag &^= unix.ONLCR - } - return tcset(fd, &termios) -} - -func cfmakeraw(t unix.Termios) unix.Termios { - t.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON) - t.Oflag &^= unix.OPOST - t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN) - t.Cflag &^= (unix.CSIZE | unix.PARENB) - t.Cflag &^= unix.CS8 - t.Cc[unix.VMIN] = 1 - t.Cc[unix.VTIME] = 0 - - return t -} diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go deleted file mode 100644 index fc90ba5f..00000000 --- a/vendor/github.com/containerd/console/tc_zos.go +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "os" - "strings" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TCGETS - cmdTcSet = unix.TCSETS -) - -// unlockpt is a no-op on zos. -func unlockpt(_ *os.File) error { - return nil -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil -} diff --git a/vendor/github.com/erikgeiser/coninput/.gitignore b/vendor/github.com/erikgeiser/coninput/.gitignore new file mode 100644 index 00000000..66fd13c9 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/vendor/github.com/erikgeiser/coninput/.golangci.yml b/vendor/github.com/erikgeiser/coninput/.golangci.yml new file mode 100644 index 00000000..d3ed7103 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/.golangci.yml @@ -0,0 +1,24 @@ +linters: + enable-all: true + disable: + - golint + - interfacer + - scopelint + - maligned + - rowserrcheck + - funlen + - depguard + - goerr113 + - exhaustivestruct + - testpackage + - gochecknoglobals + - wrapcheck + - forbidigo + - ifshort + - cyclop + - gomoddirectives +linters-settings: + exhaustive: + default-signifies-exhaustive: true +issues: + exclude-use-default: false diff --git a/vendor/github.com/erikgeiser/coninput/LICENSE b/vendor/github.com/erikgeiser/coninput/LICENSE new file mode 100644 index 00000000..83c24408 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Erik G. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/erikgeiser/coninput/README.md b/vendor/github.com/erikgeiser/coninput/README.md new file mode 100644 index 00000000..22619d13 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/README.md @@ -0,0 +1,2 @@ +# coninput +Go library for input handling using Windows Console API diff --git a/vendor/github.com/erikgeiser/coninput/keycodes.go b/vendor/github.com/erikgeiser/coninput/keycodes.go new file mode 100644 index 00000000..902ee1b7 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/keycodes.go @@ -0,0 +1,205 @@ +package coninput + +// VirtualKeyCode holds a virtual key code (see +// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). +type VirtualKeyCode uint16 + +const ( + VK_LBUTTON VirtualKeyCode = 0x01 + VK_RBUTTON VirtualKeyCode = 0x02 + VK_CANCEL VirtualKeyCode = 0x03 + VK_MBUTTON VirtualKeyCode = 0x04 + VK_XBUTTON1 VirtualKeyCode = 0x05 + VK_XBUTTON2 VirtualKeyCode = 0x06 + VK_BACK VirtualKeyCode = 0x08 + VK_TAB VirtualKeyCode = 0x09 + VK_CLEAR VirtualKeyCode = 0x0C + VK_RETURN VirtualKeyCode = 0x0D + VK_SHIFT VirtualKeyCode = 0x10 + VK_CONTROL VirtualKeyCode = 0x11 + VK_MENU VirtualKeyCode = 0x12 + VK_PAUSE VirtualKeyCode = 0x13 + VK_CAPITAL VirtualKeyCode = 0x14 + VK_KANA VirtualKeyCode = 0x15 + VK_HANGEUL VirtualKeyCode = 0x15 + VK_HANGUL VirtualKeyCode = 0x15 + VK_IME_ON VirtualKeyCode = 0x16 + VK_JUNJA VirtualKeyCode = 0x17 + VK_FINAL VirtualKeyCode = 0x18 + VK_HANJA VirtualKeyCode = 0x19 + VK_KANJI VirtualKeyCode = 0x19 + VK_IME_OFF VirtualKeyCode = 0x1A + VK_ESCAPE VirtualKeyCode = 0x1B + VK_CONVERT VirtualKeyCode = 0x1C + VK_NONCONVERT VirtualKeyCode = 0x1D + VK_ACCEPT VirtualKeyCode = 0x1E + VK_MODECHANGE VirtualKeyCode = 0x1F + VK_SPACE VirtualKeyCode = 0x20 + VK_PRIOR VirtualKeyCode = 0x21 + VK_NEXT VirtualKeyCode = 0x22 + VK_END VirtualKeyCode = 0x23 + VK_HOME VirtualKeyCode = 0x24 + VK_LEFT VirtualKeyCode = 0x25 + VK_UP VirtualKeyCode = 0x26 + VK_RIGHT VirtualKeyCode = 0x27 + VK_DOWN VirtualKeyCode = 0x28 + VK_SELECT VirtualKeyCode = 0x29 + VK_PRINT VirtualKeyCode = 0x2A + VK_EXECUTE VirtualKeyCode = 0x2B + VK_SNAPSHOT VirtualKeyCode = 0x2C + VK_INSERT VirtualKeyCode = 0x2D + VK_DELETE VirtualKeyCode = 0x2E + VK_HELP VirtualKeyCode = 0x2F + VK_0 VirtualKeyCode = 0x30 + VK_1 VirtualKeyCode = 0x31 + VK_2 VirtualKeyCode = 0x32 + VK_3 VirtualKeyCode = 0x33 + VK_4 VirtualKeyCode = 0x34 + VK_5 VirtualKeyCode = 0x35 + VK_6 VirtualKeyCode = 0x36 + VK_7 VirtualKeyCode = 0x37 + VK_8 VirtualKeyCode = 0x38 + VK_9 VirtualKeyCode = 0x39 + VK_A VirtualKeyCode = 0x41 + VK_B VirtualKeyCode = 0x42 + VK_C VirtualKeyCode = 0x43 + VK_D VirtualKeyCode = 0x44 + VK_E VirtualKeyCode = 0x45 + VK_F VirtualKeyCode = 0x46 + VK_G VirtualKeyCode = 0x47 + VK_H VirtualKeyCode = 0x48 + VK_I VirtualKeyCode = 0x49 + VK_J VirtualKeyCode = 0x4A + VK_K VirtualKeyCode = 0x4B + VK_L VirtualKeyCode = 0x4C + VK_M VirtualKeyCode = 0x4D + VK_N VirtualKeyCode = 0x4E + VK_O VirtualKeyCode = 0x4F + VK_P VirtualKeyCode = 0x50 + VK_Q VirtualKeyCode = 0x51 + VK_R VirtualKeyCode = 0x52 + VK_S VirtualKeyCode = 0x53 + VK_T VirtualKeyCode = 0x54 + VK_U VirtualKeyCode = 0x55 + VK_V VirtualKeyCode = 0x56 + VK_W VirtualKeyCode = 0x57 + VK_X VirtualKeyCode = 0x58 + VK_Y VirtualKeyCode = 0x59 + VK_Z VirtualKeyCode = 0x5A + VK_LWIN VirtualKeyCode = 0x5B + VK_RWIN VirtualKeyCode = 0x5C + VK_APPS VirtualKeyCode = 0x5D + VK_SLEEP VirtualKeyCode = 0x5F + VK_NUMPAD0 VirtualKeyCode = 0x60 + VK_NUMPAD1 VirtualKeyCode = 0x61 + VK_NUMPAD2 VirtualKeyCode = 0x62 + VK_NUMPAD3 VirtualKeyCode = 0x63 + VK_NUMPAD4 VirtualKeyCode = 0x64 + VK_NUMPAD5 VirtualKeyCode = 0x65 + VK_NUMPAD6 VirtualKeyCode = 0x66 + VK_NUMPAD7 VirtualKeyCode = 0x67 + VK_NUMPAD8 VirtualKeyCode = 0x68 + VK_NUMPAD9 VirtualKeyCode = 0x69 + VK_MULTIPLY VirtualKeyCode = 0x6A + VK_ADD VirtualKeyCode = 0x6B + VK_SEPARATOR VirtualKeyCode = 0x6C + VK_SUBTRACT VirtualKeyCode = 0x6D + VK_DECIMAL VirtualKeyCode = 0x6E + VK_DIVIDE VirtualKeyCode = 0x6F + VK_F1 VirtualKeyCode = 0x70 + VK_F2 VirtualKeyCode = 0x71 + VK_F3 VirtualKeyCode = 0x72 + VK_F4 VirtualKeyCode = 0x73 + VK_F5 VirtualKeyCode = 0x74 + VK_F6 VirtualKeyCode = 0x75 + VK_F7 VirtualKeyCode = 0x76 + VK_F8 VirtualKeyCode = 0x77 + VK_F9 VirtualKeyCode = 0x78 + VK_F10 VirtualKeyCode = 0x79 + VK_F11 VirtualKeyCode = 0x7A + VK_F12 VirtualKeyCode = 0x7B + VK_F13 VirtualKeyCode = 0x7C + VK_F14 VirtualKeyCode = 0x7D + VK_F15 VirtualKeyCode = 0x7E + VK_F16 VirtualKeyCode = 0x7F + VK_F17 VirtualKeyCode = 0x80 + VK_F18 VirtualKeyCode = 0x81 + VK_F19 VirtualKeyCode = 0x82 + VK_F20 VirtualKeyCode = 0x83 + VK_F21 VirtualKeyCode = 0x84 + VK_F22 VirtualKeyCode = 0x85 + VK_F23 VirtualKeyCode = 0x86 + VK_F24 VirtualKeyCode = 0x87 + VK_NUMLOCK VirtualKeyCode = 0x90 + VK_SCROLL VirtualKeyCode = 0x91 + VK_OEM_NEC_EQUAL VirtualKeyCode = 0x92 + VK_OEM_FJ_JISHO VirtualKeyCode = 0x92 + VK_OEM_FJ_MASSHOU VirtualKeyCode = 0x93 + VK_OEM_FJ_TOUROKU VirtualKeyCode = 0x94 + VK_OEM_FJ_LOYA VirtualKeyCode = 0x95 + VK_OEM_FJ_ROYA VirtualKeyCode = 0x96 + VK_LSHIFT VirtualKeyCode = 0xA0 + VK_RSHIFT VirtualKeyCode = 0xA1 + VK_LCONTROL VirtualKeyCode = 0xA2 + VK_RCONTROL VirtualKeyCode = 0xA3 + VK_LMENU VirtualKeyCode = 0xA4 + VK_RMENU VirtualKeyCode = 0xA5 + VK_BROWSER_BACK VirtualKeyCode = 0xA6 + VK_BROWSER_FORWARD VirtualKeyCode = 0xA7 + VK_BROWSER_REFRESH VirtualKeyCode = 0xA8 + VK_BROWSER_STOP VirtualKeyCode = 0xA9 + VK_BROWSER_SEARCH VirtualKeyCode = 0xAA + VK_BROWSER_FAVORITES VirtualKeyCode = 0xAB + VK_BROWSER_HOME VirtualKeyCode = 0xAC + VK_VOLUME_MUTE VirtualKeyCode = 0xAD + VK_VOLUME_DOWN VirtualKeyCode = 0xAE + VK_VOLUME_UP VirtualKeyCode = 0xAF + VK_MEDIA_NEXT_TRACK VirtualKeyCode = 0xB0 + VK_MEDIA_PREV_TRACK VirtualKeyCode = 0xB1 + VK_MEDIA_STOP VirtualKeyCode = 0xB2 + VK_MEDIA_PLAY_PAUSE VirtualKeyCode = 0xB3 + VK_LAUNCH_MAIL VirtualKeyCode = 0xB4 + VK_LAUNCH_MEDIA_SELECT VirtualKeyCode = 0xB5 + VK_LAUNCH_APP1 VirtualKeyCode = 0xB6 + VK_LAUNCH_APP2 VirtualKeyCode = 0xB7 + VK_OEM_1 VirtualKeyCode = 0xBA + VK_OEM_PLUS VirtualKeyCode = 0xBB + VK_OEM_COMMA VirtualKeyCode = 0xBC + VK_OEM_MINUS VirtualKeyCode = 0xBD + VK_OEM_PERIOD VirtualKeyCode = 0xBE + VK_OEM_2 VirtualKeyCode = 0xBF + VK_OEM_3 VirtualKeyCode = 0xC0 + VK_OEM_4 VirtualKeyCode = 0xDB + VK_OEM_5 VirtualKeyCode = 0xDC + VK_OEM_6 VirtualKeyCode = 0xDD + VK_OEM_7 VirtualKeyCode = 0xDE + VK_OEM_8 VirtualKeyCode = 0xDF + VK_OEM_AX VirtualKeyCode = 0xE1 + VK_OEM_102 VirtualKeyCode = 0xE2 + VK_ICO_HELP VirtualKeyCode = 0xE3 + VK_ICO_00 VirtualKeyCode = 0xE4 + VK_PROCESSKEY VirtualKeyCode = 0xE5 + VK_ICO_CLEAR VirtualKeyCode = 0xE6 + VK_OEM_RESET VirtualKeyCode = 0xE9 + VK_OEM_JUMP VirtualKeyCode = 0xEA + VK_OEM_PA1 VirtualKeyCode = 0xEB + VK_OEM_PA2 VirtualKeyCode = 0xEC + VK_OEM_PA3 VirtualKeyCode = 0xED + VK_OEM_WSCTRL VirtualKeyCode = 0xEE + VK_OEM_CUSEL VirtualKeyCode = 0xEF + VK_OEM_ATTN VirtualKeyCode = 0xF0 + VK_OEM_FINISH VirtualKeyCode = 0xF1 + VK_OEM_COPY VirtualKeyCode = 0xF2 + VK_OEM_AUTO VirtualKeyCode = 0xF3 + VK_OEM_ENLW VirtualKeyCode = 0xF4 + VK_OEM_BACKTAB VirtualKeyCode = 0xF5 + VK_ATTN VirtualKeyCode = 0xF6 + VK_CRSEL VirtualKeyCode = 0xF7 + VK_EXSEL VirtualKeyCode = 0xF8 + VK_EREOF VirtualKeyCode = 0xF9 + VK_PLAY VirtualKeyCode = 0xFA + VK_ZOOM VirtualKeyCode = 0xFB + VK_NONAME VirtualKeyCode = 0xFC + VK_PA1 VirtualKeyCode = 0xFD + VK_OEM_CLEAR VirtualKeyCode = 0xFE +) diff --git a/vendor/github.com/erikgeiser/coninput/mode.go b/vendor/github.com/erikgeiser/coninput/mode.go new file mode 100644 index 00000000..e6d8bf44 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/mode.go @@ -0,0 +1,82 @@ +//go:build windows +// +build windows + +package coninput + +import ( + "strings" + + "golang.org/x/sys/windows" +) + +// AddInputModes returns the given mode with one or more additional modes enabled. +func AddInputModes(mode uint32, enableModes ...uint32) uint32 { + for _, enableMode := range enableModes { + mode |= enableMode + } + + return mode +} + +// RemoveInputModes returns the given mode with one or more additional modes disabled. +func RemoveInputModes(mode uint32, disableModes ...uint32) uint32 { + for _, disableMode := range disableModes { + mode &^= disableMode + } + + return mode +} + +// ToggleInputModes returns the given mode with one or more additional modes toggeled. +func ToggleInputModes(mode uint32, toggleModes ...uint32) uint32 { + for _, toggeMode := range toggleModes { + mode ^= toggeMode + } + + return mode +} + +var inputModes = []struct { + mode uint32 + name string +}{ + {mode: windows.ENABLE_ECHO_INPUT, name: "ENABLE_ECHO_INPUT"}, + {mode: windows.ENABLE_INSERT_MODE, name: "ENABLE_INSERT_MODE"}, + {mode: windows.ENABLE_LINE_INPUT, name: "ENABLE_LINE_INPUT"}, + {mode: windows.ENABLE_MOUSE_INPUT, name: "ENABLE_MOUSE_INPUT"}, + {mode: windows.ENABLE_PROCESSED_INPUT, name: "ENABLE_PROCESSED_INPUT"}, + {mode: windows.ENABLE_QUICK_EDIT_MODE, name: "ENABLE_QUICK_EDIT_MODE"}, + {mode: windows.ENABLE_WINDOW_INPUT, name: "ENABLE_WINDOW_INPUT"}, + {mode: windows.ENABLE_VIRTUAL_TERMINAL_INPUT, name: "ENABLE_VIRTUAL_TERMINAL_INPUT"}, +} + +// ListInputMode returnes the isolated enabled input modes as a list. +func ListInputModes(mode uint32) []uint32 { + modes := []uint32{} + + for _, inputMode := range inputModes { + if mode&inputMode.mode > 0 { + modes = append(modes, inputMode.mode) + } + } + + return modes +} + +// ListInputMode returnes the isolated enabled input mode names as a list. +func ListInputModeNames(mode uint32) []string { + modes := []string{} + + for _, inputMode := range inputModes { + if mode&inputMode.mode > 0 { + modes = append(modes, inputMode.name) + } + } + + return modes +} + +// DescribeInputMode returns a string containing the names of each enabled input mode. +func DescribeInputMode(mode uint32) string { + return strings.Join(ListInputModeNames(mode), "|") +} diff --git a/vendor/github.com/erikgeiser/coninput/read.go b/vendor/github.com/erikgeiser/coninput/read.go new file mode 100644 index 00000000..b2dd82f1 --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/read.go @@ -0,0 +1,154 @@ +//go:build windows +// +build windows + +package coninput + +import ( + "fmt" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + procReadConsoleInputW = modkernel32.NewProc("ReadConsoleInputW") + procPeekConsoleInputW = modkernel32.NewProc("PeekConsoleInputW") + procGetNumberOfConsoleInputEvents = modkernel32.NewProc("GetNumberOfConsoleInputEvents") + procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer") +) + +// NewStdinHandle is a shortcut for windows.GetStdHandle(windows.STD_INPUT_HANDLE). +func NewStdinHandle() (windows.Handle, error) { + return windows.GetStdHandle(windows.STD_INPUT_HANDLE) +} + +// WinReadConsoleInput is a thin wrapper around the Windows console API function +// ReadConsoleInput (see +// https://docs.microsoft.com/en-us/windows/console/readconsoleinput). In most +// cases it is more practical to either use ReadConsoleInput or +// ReadNConsoleInputs. +func WinReadConsoleInput(consoleInput windows.Handle, buffer *InputRecord, + length uint32, numberOfEventsRead *uint32) error { + r, _, e := syscall.Syscall6(procReadConsoleInputW.Addr(), 4, + uintptr(consoleInput), uintptr(unsafe.Pointer(buffer)), uintptr(length), + uintptr(unsafe.Pointer(numberOfEventsRead)), 0, 0) + if r == 0 { + return error(e) + } + + return nil +} + +// ReadNConsoleInputs is a wrapper around ReadConsoleInput (see +// https://docs.microsoft.com/en-us/windows/console/readconsoleinput) that +// automates the event buffer allocation in oder to provide io.Reader-like +// sematics. maxEvents must be greater than zero. +func ReadNConsoleInputs(console windows.Handle, maxEvents uint32) ([]InputRecord, error) { + if maxEvents == 0 { + return nil, fmt.Errorf("maxEvents cannot be zero") + } + + var inputRecords = make([]InputRecord, maxEvents) + n, err := ReadConsoleInput(console, inputRecords) + + return inputRecords[:n], err +} + +// ReadConsoleInput provides an ideomatic interface to the Windows console API +// function ReadConsoleInput (see +// https://docs.microsoft.com/en-us/windows/console/readconsoleinput). The size +// of inputRecords must be greater than zero. +func ReadConsoleInput(console windows.Handle, inputRecords []InputRecord) (uint32, error) { + if len(inputRecords) == 0 { + return 0, fmt.Errorf("size of input record buffer cannot be zero") + } + + var read uint32 + err := WinReadConsoleInput(console, &inputRecords[0], uint32(len(inputRecords)), &read) + + return read, err +} + +// WinPeekConsoleInput is a thin wrapper around the Windows console API function +// PeekConsoleInput (see +// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput). In most +// cases it is more practical to either use PeekConsoleInput or +// PeekNConsoleInputs. +func WinPeekConsoleInput(consoleInput windows.Handle, buffer *InputRecord, + length uint32, numberOfEventsRead *uint32) error { + r, _, e := syscall.Syscall6(procPeekConsoleInputW.Addr(), 4, + uintptr(consoleInput), uintptr(unsafe.Pointer(buffer)), uintptr(length), + uintptr(unsafe.Pointer(numberOfEventsRead)), 0, 0) + if r == 0 { + return error(e) + } + + return nil + +} + +// PeekNConsoleInputs is a wrapper around PeekConsoleInput (see +// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput) that +// automates the event buffer allocation in oder to provide io.Reader-like +// sematics. maxEvents must be greater than zero. +func PeekNConsoleInputs(console windows.Handle, maxEvents uint32) ([]InputRecord, error) { + if maxEvents == 0 { + return nil, fmt.Errorf("maxEvents cannot be zero") + } + + var inputRecords = make([]InputRecord, maxEvents) + n, err := PeekConsoleInput(console, inputRecords) + + return inputRecords[:n], err +} + +// PeekConsoleInput provides an ideomatic interface to the Windows console API +// function PeekConsoleInput (see +// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput). The size +// of inputRecords must be greater than zero. +func PeekConsoleInput(console windows.Handle, inputRecords []InputRecord) (uint32, error) { + if len(inputRecords) == 0 { + return 0, fmt.Errorf("size of input record buffer cannot be zero") + } + + var read uint32 + + err := WinPeekConsoleInput(console, &inputRecords[0], uint32(len(inputRecords)), &read) + + return read, err +} + +// WinGetNumberOfConsoleInputEvents provides an ideomatic interface to the +// Windows console API function GetNumberOfConsoleInputEvents (see +// https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents). +func WinGetNumberOfConsoleInputEvents(consoleInput windows.Handle, numberOfEvents *uint32) error { + r, _, e := syscall.Syscall6(procGetNumberOfConsoleInputEvents.Addr(), 2, + uintptr(consoleInput), uintptr(unsafe.Pointer(numberOfEvents)), 0, + 0, 0, 0) + if r == 0 { + return error(e) + } + + return nil +} + +// GetNumberOfConsoleInputEvents provides an ideomatic interface to the Windows +// console API function GetNumberOfConsoleInputEvents (see +// https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents). +func GetNumberOfConsoleInputEvents(console windows.Handle) (uint32, error) { + var nEvents uint32 + err := WinGetNumberOfConsoleInputEvents(console, &nEvents) + + return nEvents, err +} + +func FlushConsoleInputBuffer(consoleInput windows.Handle) error { + r, _, e := syscall.Syscall(procFlushConsoleInputBuffer.Addr(), 1, uintptr(consoleInput), 0, 0) + if r == 0 { + return error(e) + } + + return nil +} diff --git a/vendor/github.com/erikgeiser/coninput/records.go b/vendor/github.com/erikgeiser/coninput/records.go new file mode 100644 index 00000000..cccf7fbf --- /dev/null +++ b/vendor/github.com/erikgeiser/coninput/records.go @@ -0,0 +1,486 @@ +package coninput + +import ( + "encoding/binary" + "fmt" + "strconv" + "strings" +) + +const ( + maxEventSize = 16 + wordPaddingBytes = 2 +) + +// EventType denots the type of an event +type EventType uint16 + +// EventUnion is the union data type that contains the data for any event. +type EventUnion [maxEventSize]byte + +// InputRecord corresponds to the INPUT_RECORD structure from the Windows +// console API (see +// https://docs.microsoft.com/en-us/windows/console/input-record-str). +type InputRecord struct { + // EventType specifies the type of event that helt in Event. + EventType EventType + + // Padding of the 16-bit EventType to a whole 32-bit dword. + _ [wordPaddingBytes]byte + + // Event holds the actual event data. Use Unrap to access it as its + // respective event type. + Event EventUnion +} + +// String implements fmt.Stringer for InputRecord. +func (ir InputRecord) String() string { + return ir.Unwrap().String() +} + +// Unwrap parses the event data into an EventRecord of the respective event +// type. The data in the returned EventRecord does not contain any references to +// the passed InputRecord. +func (ir InputRecord) Unwrap() EventRecord { + switch ir.EventType { + case FocusEventType: + return FocusEventRecord{SetFocus: ir.Event[0] > 0} + case KeyEventType: + return KeyEventRecord{ + KeyDown: binary.LittleEndian.Uint32(ir.Event[0:4]) > 0, + RepeatCount: binary.LittleEndian.Uint16(ir.Event[4:6]), + VirtualKeyCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[6:8])), + VirtualScanCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[8:10])), + Char: rune(binary.LittleEndian.Uint16(ir.Event[10:12])), + ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[12:16])), + } + case MouseEventType: + m := MouseEventRecord{ + MousePositon: Coord{ + X: binary.LittleEndian.Uint16(ir.Event[0:2]), + Y: binary.LittleEndian.Uint16(ir.Event[2:4]), + }, + ButtonState: ButtonState(binary.LittleEndian.Uint32(ir.Event[4:8])), + ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[8:12])), + EventFlags: EventFlags(binary.LittleEndian.Uint32(ir.Event[12:16])), + } + + if (m.EventFlags&MOUSE_WHEELED > 0) || (m.EventFlags&MOUSE_HWHEELED > 0) { + if int16(highWord(uint32(m.ButtonState))) > 0 { + m.WheelDirection = 1 + } else { + m.WheelDirection = -1 + } + } + + return m + case WindowBufferSizeEventType: + return WindowBufferSizeEventRecord{ + Size: Coord{ + X: binary.LittleEndian.Uint16(ir.Event[0:2]), + Y: binary.LittleEndian.Uint16(ir.Event[2:4]), + }, + } + case MenuEventType: + return MenuEventRecord{ + CommandID: binary.LittleEndian.Uint32(ir.Event[0:4]), + } + default: + return &UnknownEvent{InputRecord: ir} + } +} + +// EventRecord represents one of the following event types: +// TypeFocusEventRecord, TypeKeyEventRecord, TypeMouseEventRecord, +// TypeWindowBufferSizeEvent, TypeMenuEventRecord and UnknownEvent. +type EventRecord interface { + Type() string + fmt.Stringer +} + +// FocusEventType is the event type for a FocusEventRecord (see +// https://docs.microsoft.com/en-us/windows/console/input-record-str). +const FocusEventType EventType = 0x0010 + +// FocusEventRecord represent the FOCUS_EVENT_RECORD structure from the Windows +// console API (see +// https://docs.microsoft.com/en-us/windows/console/focus-event-record-str). +// These events are used internally by the Windows console API and should be +// ignored. +type FocusEventRecord struct { + // SetFocus is reserved and should not be used. + SetFocus bool +} + +// Ensure that FocusEventRecord satisfies EventRecord interface. +var _ EventRecord = FocusEventRecord{} + +// Type ensures that FocusEventRecord satisfies EventRecord interface. +func (e FocusEventRecord) Type() string { return "FocusEvent" } + +// String ensures that FocusEventRecord satisfies EventRecord and fmt.Stringer +// interfaces. +func (e FocusEventRecord) String() string { return fmt.Sprintf("%s[%v]", e.Type(), e.SetFocus) } + +// KeyEventType is the event type for a KeyEventRecord (see +// https://docs.microsoft.com/en-us/windows/console/input-record-str). +const KeyEventType EventType = 0x0001 + +// KeyEventRecord represent the KEY_EVENT_RECORD structure from the Windows +// console API (see +// https://docs.microsoft.com/en-us/windows/console/key-event-record-str). +type KeyEventRecord struct { + // KeyDown specified whether the key is pressed or released. + KeyDown bool + + // RepeatCount indicates that a key is being held down. For example, when a + // key is held down, five events with RepeatCount equal to 1 may be + // generated, one event with RepeatCount equal to 5, or multiple events + // with RepeatCount greater than or equal to 1. + RepeatCount uint16 + + // VirtualKeyCode identifies the given key in a device-independent manner + // (see + // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). + VirtualKeyCode VirtualKeyCode + + // VirtualScanCode represents the device-dependent value generated by the + // keyboard hardware. + VirtualScanCode VirtualKeyCode + + // Char is the character that corresponds to the pressed key. Char can be + // zero for some keys. + Char rune + + //ControlKeyState holds the state of the control keys. + ControlKeyState ControlKeyState +} + +// Ensure that KeyEventRecord satisfies EventRecord interface. +var _ EventRecord = KeyEventRecord{} + +// Type ensures that KeyEventRecord satisfies EventRecord interface. +func (e KeyEventRecord) Type() string { return "KeyEvent" } + +// String ensures that KeyEventRecord satisfies EventRecord and fmt.Stringer +// interfaces. +func (e KeyEventRecord) String() string { + infos := []string{} + + repeat := "" + if e.RepeatCount > 1 { + repeat = "x" + strconv.Itoa(int(e.RepeatCount)) + } + + infos = append(infos, fmt.Sprintf("%q%s", e.Char, repeat)) + + direction := "up" + if e.KeyDown { + direction = "down" + } + + infos = append(infos, direction) + + if e.ControlKeyState != NO_CONTROL_KEY { + infos = append(infos, e.ControlKeyState.String()) + } + + infos = append(infos, fmt.Sprintf("KeyCode: %d", e.VirtualKeyCode)) + infos = append(infos, fmt.Sprintf("ScanCode: %d", e.VirtualScanCode)) + + return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", ")) +} + +// MenuEventType is the event type for a MenuEventRecord (see +// https://docs.microsoft.com/en-us/windows/console/input-record-str). +const MenuEventType EventType = 0x0008 + +// MenuEventRecord represent the MENU_EVENT_RECORD structure from the Windows +// console API (see +// https://docs.microsoft.com/en-us/windows/console/menu-event-record-str). +// These events are deprecated by the Windows console API and should be ignored. +type MenuEventRecord struct { + CommandID uint32 +} + +// Ensure that MenuEventRecord satisfies EventRecord interface. +var _ EventRecord = MenuEventRecord{} + +// Type ensures that MenuEventRecord satisfies EventRecord interface. +func (e MenuEventRecord) Type() string { return "MenuEvent" } + +// String ensures that MenuEventRecord satisfies EventRecord and fmt.Stringer +// interfaces. +func (e MenuEventRecord) String() string { return fmt.Sprintf("MenuEvent[%d]", e.CommandID) } + +// MouseEventType is the event type for a MouseEventRecord (see +// https://docs.microsoft.com/en-us/windows/console/input-record-str). +const MouseEventType EventType = 0x0002 + +// MouseEventRecord represent the MOUSE_EVENT_RECORD structure from the Windows +// console API (see +// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). +type MouseEventRecord struct { + // MousePosition contains the location of the cursor, in terms of the + // console screen buffer's character-cell coordinates. + MousePositon Coord + + // ButtonState holds the status of the mouse buttons. + ButtonState ButtonState + + // ControlKeyState holds the state of the control keys. + ControlKeyState ControlKeyState + + // EventFlags specify tge type of mouse event. + EventFlags EventFlags + + // WheelDirection specified the direction in which the mouse wheel is + // spinning when EventFlags contains MOUSE_HWHEELED or MOUSE_WHEELED. When + // the event flags specify MOUSE_WHEELED it is 1 if the wheel rotated + // forward (away from the user) or -1 when it rotates backwards. When + // MOUSE_HWHEELED is specified it is 1 when the wheel rotates right and -1 + // when it rotates left. When the EventFlags do not indicate a mouse wheel + // event it is 0. + WheelDirection int +} + +// Ensure that MouseEventRecord satisfies EventRecord interface. +var _ EventRecord = MouseEventRecord{} + +func (e MouseEventRecord) WheelDirectionName() string { + if e.EventFlags&MOUSE_WHEELED > 0 { + if e.WheelDirection > 0 { + return "Forward" + } + + return "Backward" + } else if e.EventFlags&MOUSE_HWHEELED > 0 { + if e.WheelDirection > 0 { + return "Right" + } + + return "Left" + } + + return "" +} + +// Type ensures that MouseEventRecord satisfies EventRecord interface. +func (e MouseEventRecord) Type() string { return "MouseEvent" } + +// String ensures that MouseEventRecord satisfies EventRecord and fmt.Stringer +// interfaces. +func (e MouseEventRecord) String() string { + infos := []string{e.MousePositon.String()} + + if e.ButtonState&0xFF != 0 { + infos = append(infos, e.ButtonState.String()) + } + + eventDescription := e.EventFlags.String() + + wheelDirection := e.WheelDirectionName() + if wheelDirection != "" { + eventDescription += "(" + wheelDirection + ")" + } + + infos = append(infos, eventDescription) + + if e.ControlKeyState != NO_CONTROL_KEY { + infos = append(infos, e.ControlKeyState.String()) + } + + return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", ")) +} + +// WindowBufferSizeEventType is the event type for a WindowBufferSizeEventRecord +// (see https://docs.microsoft.com/en-us/windows/console/input-record-str). +const WindowBufferSizeEventType EventType = 0x0004 + +// WindowBufferSizeEventRecord represent the WINDOW_BUFFER_SIZE_RECORD structure +// from the Windows console API (see +// https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str). +type WindowBufferSizeEventRecord struct { + // Size contains the size of the console screen buffer, in character cell columns and rows. + Size Coord +} + +// Ensure that WindowBufferSizeEventRecord satisfies EventRecord interface. +var _ EventRecord = WindowBufferSizeEventRecord{} + +// Type ensures that WindowBufferSizeEventRecord satisfies EventRecord interface. +func (e WindowBufferSizeEventRecord) Type() string { return "WindowBufferSizeEvent" } + +// String ensures that WindowBufferSizeEventRecord satisfies EventRecord and fmt.Stringer +// interfaces. +func (e WindowBufferSizeEventRecord) String() string { + return fmt.Sprintf("WindowBufferSizeEvent[%s]", e.Size) +} + +// UnknownEvent is generated when the event type does not match one of the +// following types: TypeFocusEventRecord, TypeKeyEventRecord, +// TypeMouseEventRecord, TypeWindowBufferSizeEvent, TypeMenuEventRecord and +// UnknownEvent. +type UnknownEvent struct { + InputRecord +} + +// Ensure that UnknownEvent satisfies EventRecord interface. +var _ EventRecord = UnknownEvent{} + +// Type ensures that UnknownEvent satisfies EventRecord interface. +func (e UnknownEvent) Type() string { return "UnknownEvent" } + +// String ensures that UnknownEvent satisfies EventRecord and fmt.Stringer +// interfaces. +func (e UnknownEvent) String() string { + return fmt.Sprintf("%s[Type: %d, Data: %v]", e.Type(), e.InputRecord.EventType, e.InputRecord.Event[:]) +} + +// Coord represent the COORD structure from the Windows +// console API (see https://docs.microsoft.com/en-us/windows/console/coord-str). +type Coord struct { + // X is the horizontal coordinate or column value. The units depend on the function call. + X uint16 + // Y is the vertical coordinate or row value. The units depend on the function call. + Y uint16 +} + +// String ensures that Coord satisfies the fmt.Stringer interface. +func (c Coord) String() string { + return fmt.Sprintf("(%d, %d)", c.X, c.Y) +} + +// ButtonState holds the state of the mouse buttons (see +// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). +type ButtonState uint32 + +func (bs ButtonState) Contains(state ButtonState) bool { + return bs&state > 0 +} + +// String ensures that ButtonState satisfies the fmt.Stringer interface. +func (bs ButtonState) String() string { + switch { + case bs&FROM_LEFT_1ST_BUTTON_PRESSED > 0: + return "Left" + case bs&FROM_LEFT_2ND_BUTTON_PRESSED > 0: + return "2" + case bs&FROM_LEFT_3RD_BUTTON_PRESSED > 0: + return "3" + case bs&FROM_LEFT_4TH_BUTTON_PRESSED > 0: + return "4" + case bs&RIGHTMOST_BUTTON_PRESSED > 0: + return "Right" + case bs&0xFF == 0: + return "No Button" + default: + return fmt.Sprintf("Unknown(%d)", bs) + } +} + +func (bs ButtonState) IsReleased() bool { + return bs&0xff > 0 +} + +// Valid values for ButtonState. +const ( + FROM_LEFT_1ST_BUTTON_PRESSED ButtonState = 0x0001 + RIGHTMOST_BUTTON_PRESSED ButtonState = 0x0002 + FROM_LEFT_2ND_BUTTON_PRESSED ButtonState = 0x0004 + FROM_LEFT_3RD_BUTTON_PRESSED ButtonState = 0x0008 + FROM_LEFT_4TH_BUTTON_PRESSED ButtonState = 0x0010 +) + +// ControlKeyState holds the state of the control keys for key and mouse events +// (see https://docs.microsoft.com/en-us/windows/console/key-event-record-str +// and https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). +type ControlKeyState uint32 + +func (cks ControlKeyState) Contains(state ControlKeyState) bool { + return cks&state > 0 +} + +// Valid values for ControlKeyState. +const ( + CAPSLOCK_ON ControlKeyState = 0x0080 + ENHANCED_KEY ControlKeyState = 0x0100 + LEFT_ALT_PRESSED ControlKeyState = 0x0002 + LEFT_CTRL_PRESSED ControlKeyState = 0x0008 + NUMLOCK_ON ControlKeyState = 0x0020 + RIGHT_ALT_PRESSED ControlKeyState = 0x0001 + RIGHT_CTRL_PRESSED ControlKeyState = 0x0004 + SCROLLLOCK_ON ControlKeyState = 0x0040 + SHIFT_PRESSED ControlKeyState = 0x0010 + NO_CONTROL_KEY ControlKeyState = 0x0000 +) + +// String ensures that ControlKeyState satisfies the fmt.Stringer interface. +func (cks ControlKeyState) String() string { + controlKeys := []string{} + + switch { + case cks&CAPSLOCK_ON > 0: + controlKeys = append(controlKeys, "CapsLock") + case cks&ENHANCED_KEY > 0: + controlKeys = append(controlKeys, "Enhanced") + case cks&LEFT_ALT_PRESSED > 0: + controlKeys = append(controlKeys, "Alt") + case cks&LEFT_CTRL_PRESSED > 0: + controlKeys = append(controlKeys, "CTRL") + case cks&NUMLOCK_ON > 0: + controlKeys = append(controlKeys, "NumLock") + case cks&RIGHT_ALT_PRESSED > 0: + controlKeys = append(controlKeys, "RightAlt") + case cks&RIGHT_CTRL_PRESSED > 0: + controlKeys = append(controlKeys, "RightCTRL") + case cks&SCROLLLOCK_ON > 0: + controlKeys = append(controlKeys, "ScrollLock") + case cks&SHIFT_PRESSED > 0: + controlKeys = append(controlKeys, "Shift") + case cks == NO_CONTROL_KEY: + default: + return fmt.Sprintf("Unknown(%d)", cks) + } + + return strings.Join(controlKeys, ",") +} + +// EventFlags specifies the type of a mouse event (see +// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). +type EventFlags uint32 + +// String ensures that EventFlags satisfies the fmt.Stringer interface. +func (ef EventFlags) String() string { + switch { + case ef&DOUBLE_CLICK > 0: + return "DoubleClick" + case ef&MOUSE_WHEELED > 0: + return "Wheeled" + case ef&MOUSE_MOVED > 0: + return "Moved" + case ef&MOUSE_HWHEELED > 0: + return "HWheeld" + case ef == CLICK: + return "Click" + default: + return fmt.Sprintf("Unknown(%d)", ef) + } +} + +func (ef EventFlags) Contains(flag EventFlags) bool { + return ef&flag > 0 +} + +// Valid values for EventFlags. +const ( + CLICK EventFlags = 0x0000 + MOUSE_MOVED EventFlags = 0x0001 + DOUBLE_CLICK EventFlags = 0x0002 + MOUSE_WHEELED EventFlags = 0x0004 + MOUSE_HWHEELED EventFlags = 0x0008 +) + +func highWord(data uint32) uint16 { + return uint16((data & 0xFFFF0000) >> 16) +} diff --git a/vendor/github.com/muesli/ansi/README.md b/vendor/github.com/muesli/ansi/README.md index cb28c656..f9d0fe9a 100644 --- a/vendor/github.com/muesli/ansi/README.md +++ b/vendor/github.com/muesli/ansi/README.md @@ -1,2 +1,31 @@ # ansi + +[![Latest Release](https://img.shields.io/github/release/muesli/ansi.svg)](https://github.com/muesli/ansi/releases) +[![Build Status](https://github.com/muesli/ansi/workflows/build/badge.svg)](https://github.com/muesli/ansi/actions) +[![Coverage Status](https://coveralls.io/repos/github/muesli/ansi/badge.svg?branch=master)](https://coveralls.io/github/muesli/ansi?branch=master) +[![Go ReportCard](https://goreportcard.com/badge/muesli/ansi)](https://goreportcard.com/report/muesli/ansi) +[![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](https://pkg.go.dev/github.com/muesli/ansi) + Raw ANSI sequence helpers + +## ANSI Writer + +```go +import "github.com/muesli/ansi" + +w := ansi.Writer{Forward: os.Stdout} +w.Write([]byte("\x1b[31mHello, world!\x1b[0m")) +w.Close() +``` + +## Compressor + +The ANSI compressor eliminates unnecessary/redundant ANSI sequences. + +```go +import "github.com/muesli/ansi/compressor" + +w := compressor.Writer{Forward: os.Stdout} +w.Write([]byte("\x1b[31mHello, world!\x1b[0m")) +w.Close() +``` diff --git a/vendor/github.com/muesli/reflow/wrap/wrap.go b/vendor/github.com/muesli/reflow/wrap/wrap.go deleted file mode 100644 index f624c5f4..00000000 --- a/vendor/github.com/muesli/reflow/wrap/wrap.go +++ /dev/null @@ -1,134 +0,0 @@ -package wrap - -import ( - "bytes" - "strings" - "unicode" - - "github.com/mattn/go-runewidth" - "github.com/muesli/reflow/ansi" -) - -var ( - defaultNewline = []rune{'\n'} - defaultTabWidth = 4 -) - -type Wrap struct { - Limit int - Newline []rune - KeepNewlines bool - PreserveSpace bool - TabWidth int - - buf *bytes.Buffer - lineLen int - ansi bool - forcefulNewline bool -} - -// NewWriter returns a new instance of a wrapping writer, initialized with -// default settings. -func NewWriter(limit int) *Wrap { - return &Wrap{ - Limit: limit, - Newline: defaultNewline, - KeepNewlines: true, - // Keep whitespaces following a forceful line break. If disabled, - // leading whitespaces in a line are only kept if the line break - // was not forceful, meaning a line break that was already present - // in the input - PreserveSpace: false, - TabWidth: defaultTabWidth, - - buf: &bytes.Buffer{}, - } -} - -// Bytes is shorthand for declaring a new default Wrap instance, -// used to immediately wrap a byte slice. -func Bytes(b []byte, limit int) []byte { - f := NewWriter(limit) - _, _ = f.Write(b) - - return f.buf.Bytes() -} - -func (w *Wrap) addNewLine() { - _, _ = w.buf.WriteRune('\n') - w.lineLen = 0 -} - -// String is shorthand for declaring a new default Wrap instance, -// used to immediately wrap a string. -func String(s string, limit int) string { - return string(Bytes([]byte(s), limit)) -} - -func (w *Wrap) Write(b []byte) (int, error) { - s := strings.Replace(string(b), "\t", strings.Repeat(" ", w.TabWidth), -1) - if !w.KeepNewlines { - s = strings.Replace(s, "\n", "", -1) - } - - width := ansi.PrintableRuneWidth(s) - - if w.Limit <= 0 || w.lineLen+width <= w.Limit { - w.lineLen += width - return w.buf.Write(b) - } - - for _, c := range s { - if c == ansi.Marker { - w.ansi = true - } else if w.ansi { - if ansi.IsTerminator(c) { - w.ansi = false - } - } else if inGroup(w.Newline, c) { - w.addNewLine() - w.forcefulNewline = false - continue - } else { - width := runewidth.RuneWidth(c) - - if w.lineLen+width > w.Limit { - w.addNewLine() - w.forcefulNewline = true - } - - if w.lineLen == 0 { - if w.forcefulNewline && !w.PreserveSpace && unicode.IsSpace(c) { - continue - } - } else { - w.forcefulNewline = false - } - - w.lineLen += width - } - - _, _ = w.buf.WriteRune(c) - } - - return len(b), nil -} - -// Bytes returns the wrapped result as a byte slice. -func (w *Wrap) Bytes() []byte { - return w.buf.Bytes() -} - -// String returns the wrapped result as a string. -func (w *Wrap) String() string { - return w.buf.String() -} - -func inGroup(a []rune, c rune) bool { - for _, v := range a { - if v == c { - return true - } - } - return false -} diff --git a/vendor/golang.org/x/sync/LICENSE b/vendor/golang.org/x/sync/LICENSE index 6a66aea5..2a7cf70d 100644 --- a/vendor/golang.org/x/sync/LICENSE +++ b/vendor/golang.org/x/sync/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer. copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google Inc. nor the names of its + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/vendor/golang.org/x/sys/LICENSE b/vendor/golang.org/x/sys/LICENSE index 6a66aea5..2a7cf70d 100644 --- a/vendor/golang.org/x/sys/LICENSE +++ b/vendor/golang.org/x/sys/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer. copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google Inc. nor the names of its + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 4ed2e488..d07dd09e 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -58,6 +58,7 @@ includes_Darwin=' #define _DARWIN_USE_64_BIT_INODE #define __APPLE_USE_RFC_3542 #include +#include #include #include #include diff --git a/vendor/golang.org/x/sys/unix/mremap.go b/vendor/golang.org/x/sys/unix/mremap.go index fd45fe52..3a5e776f 100644 --- a/vendor/golang.org/x/sys/unix/mremap.go +++ b/vendor/golang.org/x/sys/unix/mremap.go @@ -50,3 +50,8 @@ func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data [ func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { return mapper.Mremap(oldData, newLength, flags) } + +func MremapPtr(oldAddr unsafe.Pointer, oldSize uintptr, newAddr unsafe.Pointer, newSize uintptr, flags int) (ret unsafe.Pointer, err error) { + xaddr, err := mapper.mremap(uintptr(oldAddr), oldSize, newSize, flags, uintptr(newAddr)) + return unsafe.Pointer(xaddr), err +} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 59542a89..2d15200a 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -402,6 +402,18 @@ func IoctlSetIfreqMTU(fd int, ifreq *IfreqMTU) error { return ioctlPtr(fd, SIOCSIFMTU, unsafe.Pointer(ifreq)) } +//sys renamexNp(from string, to string, flag uint32) (err error) + +func RenamexNp(from string, to string, flag uint32) (err error) { + return renamexNp(from, to, flag) +} + +//sys renameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) + +func RenameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) { + return renameatxNp(fromfd, from, tofd, to, flag) +} + //sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS_SYSCTL func Uname(uname *Utsname) error { @@ -542,6 +554,18 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) { } } +//sys pthread_chdir_np(path string) (err error) + +func PthreadChdir(path string) (err error) { + return pthread_chdir_np(path) +} + +//sys pthread_fchdir_np(fd int) (err error) + +func PthreadFchdir(fd int) (err error) { + return pthread_fchdir_np(fd) +} + //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 5682e262..3f1d3d4c 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -2592,3 +2592,4 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) { } //sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error) +//sys Mseal(b []byte, flags uint) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/vendor/golang.org/x/sys/unix/syscall_openbsd.go index b25343c7..b86ded54 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -293,6 +293,7 @@ func Uname(uname *Utsname) error { //sys Mkfifoat(dirfd int, path string, mode uint32) (err error) //sys Mknod(path string, mode uint32, dev int) (err error) //sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) +//sys Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Open(path string, mode int, perm uint32) (fd int, err error) //sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go index 77081de8..4e92e5aa 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix.go @@ -154,6 +154,15 @@ func Munmap(b []byte) (err error) { return mapper.Munmap(b) } +func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) { + xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset) + return unsafe.Pointer(xaddr), err +} + +func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) { + return mapper.munmap(uintptr(addr), length) +} + func Read(fd int, p []byte) (n int, err error) { n, err = read(fd, p) if raceenabled { diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go index e40fa852..4308ac17 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go @@ -1169,6 +1169,11 @@ const ( PT_WRITE_D = 0x5 PT_WRITE_I = 0x4 PT_WRITE_U = 0x6 + RENAME_EXCL = 0x4 + RENAME_NOFOLLOW_ANY = 0x10 + RENAME_RESERVED1 = 0x8 + RENAME_SECLUDE = 0x1 + RENAME_SWAP = 0x2 RLIMIT_AS = 0x5 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go index bb02aa6c..c8068a7a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go @@ -1169,6 +1169,11 @@ const ( PT_WRITE_D = 0x5 PT_WRITE_I = 0x4 PT_WRITE_U = 0x6 + RENAME_EXCL = 0x4 + RENAME_NOFOLLOW_ANY = 0x10 + RENAME_RESERVED1 = 0x8 + RENAME_SECLUDE = 0x1 + RENAME_SWAP = 0x2 RLIMIT_AS = 0x5 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 877a62b4..01a70b24 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -457,6 +457,7 @@ const ( B600 = 0x8 B75 = 0x2 B9600 = 0xd + BCACHEFS_SUPER_MAGIC = 0xca451a4e BDEVFS_MAGIC = 0x62646576 BINDERFS_SUPER_MAGIC = 0x6c6f6f70 BINFMTFS_MAGIC = 0x42494e4d @@ -928,6 +929,7 @@ const ( EPOLL_CTL_ADD = 0x1 EPOLL_CTL_DEL = 0x2 EPOLL_CTL_MOD = 0x3 + EPOLL_IOC_TYPE = 0x8a EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2 ESP_V4_FLOW = 0xa ESP_V6_FLOW = 0xc @@ -941,9 +943,6 @@ const ( ETHTOOL_FEC_OFF = 0x4 ETHTOOL_FEC_RS = 0x8 ETHTOOL_FLAG_ALL = 0x7 - ETHTOOL_FLAG_COMPACT_BITSETS = 0x1 - ETHTOOL_FLAG_OMIT_REPLY = 0x2 - ETHTOOL_FLAG_STATS = 0x4 ETHTOOL_FLASHDEV = 0x33 ETHTOOL_FLASH_MAX_FILENAME = 0x80 ETHTOOL_FWVERS_LEN = 0x20 @@ -1705,6 +1704,7 @@ const ( KEXEC_ARCH_S390 = 0x160000 KEXEC_ARCH_SH = 0x2a0000 KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_CRASH_HOTPLUG_SUPPORT = 0x8 KEXEC_FILE_DEBUG = 0x8 KEXEC_FILE_NO_INITRAMFS = 0x4 KEXEC_FILE_ON_CRASH = 0x2 @@ -1780,6 +1780,7 @@ const ( KEY_SPEC_USER_KEYRING = -0x4 KEY_SPEC_USER_SESSION_KEYRING = -0x5 LANDLOCK_ACCESS_FS_EXECUTE = 0x1 + LANDLOCK_ACCESS_FS_IOCTL_DEV = 0x8000 LANDLOCK_ACCESS_FS_MAKE_BLOCK = 0x800 LANDLOCK_ACCESS_FS_MAKE_CHAR = 0x40 LANDLOCK_ACCESS_FS_MAKE_DIR = 0x80 @@ -1861,6 +1862,19 @@ const ( MAP_FILE = 0x0 MAP_FIXED = 0x10 MAP_FIXED_NOREPLACE = 0x100000 + MAP_HUGE_16GB = 0x88000000 + MAP_HUGE_16KB = 0x38000000 + MAP_HUGE_16MB = 0x60000000 + MAP_HUGE_1GB = 0x78000000 + MAP_HUGE_1MB = 0x50000000 + MAP_HUGE_256MB = 0x70000000 + MAP_HUGE_2GB = 0x7c000000 + MAP_HUGE_2MB = 0x54000000 + MAP_HUGE_32MB = 0x64000000 + MAP_HUGE_512KB = 0x4c000000 + MAP_HUGE_512MB = 0x74000000 + MAP_HUGE_64KB = 0x40000000 + MAP_HUGE_8MB = 0x5c000000 MAP_HUGE_MASK = 0x3f MAP_HUGE_SHIFT = 0x1a MAP_PRIVATE = 0x2 @@ -2498,6 +2512,23 @@ const ( PR_PAC_GET_ENABLED_KEYS = 0x3d PR_PAC_RESET_KEYS = 0x36 PR_PAC_SET_ENABLED_KEYS = 0x3c + PR_PPC_DEXCR_CTRL_CLEAR = 0x4 + PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC = 0x10 + PR_PPC_DEXCR_CTRL_EDITABLE = 0x1 + PR_PPC_DEXCR_CTRL_MASK = 0x1f + PR_PPC_DEXCR_CTRL_SET = 0x2 + PR_PPC_DEXCR_CTRL_SET_ONEXEC = 0x8 + PR_PPC_DEXCR_IBRTPD = 0x1 + PR_PPC_DEXCR_NPHIE = 0x3 + PR_PPC_DEXCR_SBHE = 0x0 + PR_PPC_DEXCR_SRAPD = 0x2 + PR_PPC_GET_DEXCR = 0x48 + PR_PPC_SET_DEXCR = 0x49 + PR_RISCV_CTX_SW_FENCEI_OFF = 0x1 + PR_RISCV_CTX_SW_FENCEI_ON = 0x0 + PR_RISCV_SCOPE_PER_PROCESS = 0x0 + PR_RISCV_SCOPE_PER_THREAD = 0x1 + PR_RISCV_SET_ICACHE_FLUSH_CTX = 0x47 PR_RISCV_V_GET_CONTROL = 0x46 PR_RISCV_V_SET_CONTROL = 0x45 PR_RISCV_V_VSTATE_CTRL_CUR_MASK = 0x3 @@ -3192,6 +3223,7 @@ const ( STATX_MTIME = 0x40 STATX_NLINK = 0x4 STATX_SIZE = 0x200 + STATX_SUBVOL = 0x8000 STATX_TYPE = 0x1 STATX_UID = 0x8 STATX__RESERVED = 0x80000000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index e4bc0bd5..684a5168 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 689317af..61d74b59 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index 5cca668a..a28c9e3e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 14270508..ab5d1fe8 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 ESR_MAGIC = 0x45535201 EXTPROC = 0x10000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index 28e39afd..c523090e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index cd66e92c..01e6ea78 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index c1595eba..7aa610b1 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index ee9456b0..92af771b 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 8cfca81e..b27ef5e6 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 60b0deb3..237a2cef 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x20 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000000 FF1 = 0x4000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index f90aa728..4a5c555a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x20 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000000 FF1 = 0x4000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index ba9e0150..a02fb49a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x20 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000000 FF1 = 0x4000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 07cdfd6e..e26a7c61 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 2f1dd214..c48f7c21 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -78,6 +78,8 @@ const ( ECHOPRT = 0x400 EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 + EPIOCGPARAMS = 0x80088a02 + EPIOCSPARAMS = 0x40088a01 EPOLL_CLOEXEC = 0x80000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index f40519d9..ad4b9aac 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -82,6 +82,8 @@ const ( EFD_CLOEXEC = 0x400000 EFD_NONBLOCK = 0x4000 EMT_TAGOVF = 0x1 + EPIOCGPARAMS = 0x40088a02 + EPIOCSPARAMS = 0x80088a01 EPOLL_CLOEXEC = 0x400000 EXTPROC = 0x10000 FF1 = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index ccb02f24..b622533e 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -740,6 +740,54 @@ func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func renamexNp(from string, to string, flag uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := syscall_syscall(libc_renamex_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_renamex_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_renamex_np renamex_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func renameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_renameatx_np_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), uintptr(flag), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_renameatx_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_renameatx_np renameatx_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { var _p0 unsafe.Pointer if len(mib) > 0 { @@ -760,6 +808,39 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func pthread_chdir_np(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(libc_pthread_chdir_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pthread_chdir_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pthread_chdir_np pthread_chdir_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pthread_fchdir_np(fd int) (err error) { + _, _, e1 := syscall_syscall(libc_pthread_fchdir_np_trampoline_addr, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pthread_fchdir_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pthread_fchdir_np pthread_fchdir_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index 8b8bb284..cfe6646b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -223,11 +223,31 @@ TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_ioctl_trampoline_addr(SB)/8, $libc_ioctl_trampoline<>(SB) +TEXT libc_renamex_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_renamex_np(SB) +GLOBL ·libc_renamex_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_renamex_np_trampoline_addr(SB)/8, $libc_renamex_np_trampoline<>(SB) + +TEXT libc_renameatx_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_renameatx_np(SB) +GLOBL ·libc_renameatx_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_renameatx_np_trampoline_addr(SB)/8, $libc_renameatx_np_trampoline<>(SB) + TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_pthread_chdir_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pthread_chdir_np(SB) +GLOBL ·libc_pthread_chdir_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pthread_chdir_np_trampoline_addr(SB)/8, $libc_pthread_chdir_np_trampoline<>(SB) + +TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pthread_fchdir_np(SB) +GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) + TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 1b40b997..13f624f6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -740,6 +740,54 @@ func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func renamexNp(from string, to string, flag uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := syscall_syscall(libc_renamex_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_renamex_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_renamex_np renamex_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func renameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_renameatx_np_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), uintptr(flag), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_renameatx_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_renameatx_np renameatx_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { var _p0 unsafe.Pointer if len(mib) > 0 { @@ -760,6 +808,39 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func pthread_chdir_np(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(libc_pthread_chdir_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pthread_chdir_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pthread_chdir_np pthread_chdir_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pthread_fchdir_np(fd int) (err error) { + _, _, e1 := syscall_syscall(libc_pthread_fchdir_np_trampoline_addr, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pthread_fchdir_np_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pthread_fchdir_np pthread_fchdir_np "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index 08362c1a..fe222b75 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -223,11 +223,31 @@ TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_ioctl_trampoline_addr(SB)/8, $libc_ioctl_trampoline<>(SB) +TEXT libc_renamex_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_renamex_np(SB) +GLOBL ·libc_renamex_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_renamex_np_trampoline_addr(SB)/8, $libc_renamex_np_trampoline<>(SB) + +TEXT libc_renameatx_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_renameatx_np(SB) +GLOBL ·libc_renameatx_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_renameatx_np_trampoline_addr(SB)/8, $libc_renameatx_np_trampoline<>(SB) + TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_pthread_chdir_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pthread_chdir_np(SB) +GLOBL ·libc_pthread_chdir_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pthread_chdir_np_trampoline_addr(SB)/8, $libc_pthread_chdir_np_trampoline<>(SB) + +TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pthread_fchdir_np(SB) +GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) + TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 87d8612a..1bc1a5ad 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -2229,3 +2229,19 @@ func Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mseal(b []byte, flags uint) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSEAL, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go index 9dc42410..1851df14 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s index 41b56173..0b43c693 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s @@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $4 DATA ·libc_mknodat_trampoline_addr(SB)/4, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mount(SB) +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mount_trampoline_addr(SB)/4, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $4 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go index 0d3a0751..e1ec0dbe 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s index 4019a656..880c6d6e 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s @@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8 DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mount(SB) +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index c39f7776..7c8452a6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s index ac4af24f..b8ef95b0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s @@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $4 DATA ·libc_mknodat_trampoline_addr(SB)/4, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mount(SB) +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $4 +DATA ·libc_mount_trampoline_addr(SB)/4, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $4 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go index 57571d07..2ffdf861 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s index f77d5321..2af3b5c7 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s @@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8 DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mount(SB) +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go index e62963e6..1da08d52 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s index fae140b6..b7a25135 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s @@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8 DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mount(SB) +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go index 00831354..6e85b0aa 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s index 9d1e0ff0..f15dadf0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s @@ -555,6 +555,12 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8 DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + CALL libc_mount(SB) + RET +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 CALL libc_nanosleep(SB) RET diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go index 79029ed5..28b487df 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go @@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(fsType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(dir) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_mount_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_mount mount "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s index da115f9a..1e7f321e 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s @@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8 DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB) +TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_mount(SB) +GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8 +DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB) + TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index 53aef5dc..524b0820 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -457,4 +457,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index 71d52476..d3e38f68 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -379,4 +379,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index c7477061..70b35bf3 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -421,4 +421,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index f96e214f..6c778c23 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -324,4 +324,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index 28425346..37281cf5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -318,4 +318,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index d0953018..7e567f1e 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -441,4 +441,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 4459 SYS_LSM_SET_SELF_ATTR = 4460 SYS_LSM_LIST_MODULES = 4461 + SYS_MSEAL = 4462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 295c7f4b..38ae55e5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -371,4 +371,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 5459 SYS_LSM_SET_SELF_ATTR = 5460 SYS_LSM_LIST_MODULES = 5461 + SYS_MSEAL = 5462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index d1a9eaca..55e92e60 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -371,4 +371,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 5459 SYS_LSM_SET_SELF_ATTR = 5460 SYS_LSM_LIST_MODULES = 5461 + SYS_MSEAL = 5462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index bec157c3..60658d6a 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -441,4 +441,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 4459 SYS_LSM_SET_SELF_ATTR = 4460 SYS_LSM_LIST_MODULES = 4461 + SYS_MSEAL = 4462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index 7ee7bdc4..e203e8a7 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -448,4 +448,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index fad1f25b..5944b97d 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -420,4 +420,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index 7d3e1635..c66d416d 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -420,4 +420,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 0ed53ad9..9889f6a5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -325,4 +325,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 2fba04ad..01d86825 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -386,4 +386,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 621d00d7..7b703e77 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -399,4 +399,5 @@ const ( SYS_LSM_GET_SELF_ATTR = 459 SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 + SYS_MSEAL = 462 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index 4740b834..7f1961b9 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -110,7 +110,8 @@ type Statx_t struct { Mnt_id uint64 Dio_mem_align uint32 Dio_offset_align uint32 - _ [12]uint64 + Subvol uint64 + _ [11]uint64 } type Fsid struct { @@ -3473,7 +3474,7 @@ const ( DEVLINK_PORT_FN_ATTR_STATE = 0x2 DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3 DEVLINK_PORT_FN_ATTR_CAPS = 0x4 - DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x5 + DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x6 ) type FsverityDigest struct { @@ -3806,6 +3807,9 @@ const ( ETHTOOL_MSG_PSE_GET_REPLY = 0x25 ETHTOOL_MSG_RSS_GET_REPLY = 0x26 ETHTOOL_MSG_KERNEL_MAX = 0x2b + ETHTOOL_FLAG_COMPACT_BITSETS = 0x1 + ETHTOOL_FLAG_OMIT_REPLY = 0x2 + ETHTOOL_FLAG_STATS = 0x4 ETHTOOL_A_HEADER_UNSPEC = 0x0 ETHTOOL_A_HEADER_DEV_INDEX = 0x1 ETHTOOL_A_HEADER_DEV_NAME = 0x2 @@ -3975,7 +3979,7 @@ const ( ETHTOOL_A_TSINFO_TX_TYPES = 0x3 ETHTOOL_A_TSINFO_RX_FILTERS = 0x4 ETHTOOL_A_TSINFO_PHC_INDEX = 0x5 - ETHTOOL_A_TSINFO_MAX = 0x5 + ETHTOOL_A_TSINFO_MAX = 0x6 ETHTOOL_A_CABLE_TEST_UNSPEC = 0x0 ETHTOOL_A_CABLE_TEST_HEADER = 0x1 ETHTOOL_A_CABLE_TEST_MAX = 0x1 diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go index 6f7d2ac7..b6e1ab76 100644 --- a/vendor/golang.org/x/sys/windows/security_windows.go +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -894,7 +894,7 @@ type ACL struct { aclRevision byte sbz1 byte aclSize uint16 - aceCount uint16 + AceCount uint16 sbz2 uint16 } @@ -1087,6 +1087,27 @@ type EXPLICIT_ACCESS struct { Trustee TRUSTEE } +// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header +type ACE_HEADER struct { + AceType uint8 + AceFlags uint8 + AceSize uint16 +} + +// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace +type ACCESS_ALLOWED_ACE struct { + Header ACE_HEADER + Mask ACCESS_MASK + SidStart uint32 +} + +const ( + // Constants for AceType + // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header + ACCESS_ALLOWED_ACE_TYPE = 0 + ACCESS_DENIED_ACE_TYPE = 1 +) + // This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions. type TrusteeValue uintptr @@ -1158,6 +1179,7 @@ type OBJECTS_AND_NAME struct { //sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD //sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW +//sys GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) = advapi32.GetAce // Control returns the security descriptor control bits. func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) { diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 6525c62f..1fa34fd1 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -17,8 +17,10 @@ import ( "unsafe" ) -type Handle uintptr -type HWND uintptr +type ( + Handle uintptr + HWND uintptr +) const ( InvalidHandle = ^Handle(0) @@ -211,6 +213,10 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (handle Handle, err error) //sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) [failretval<=32] = shell32.ShellExecuteW //sys GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) = user32.GetWindowThreadProcessId +//sys LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) [failretval==0] = user32.LoadKeyboardLayoutW +//sys UnloadKeyboardLayout(hkl Handle) (err error) = user32.UnloadKeyboardLayout +//sys GetKeyboardLayout(tid uint32) (hkl Handle) = user32.GetKeyboardLayout +//sys ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) = user32.ToUnicodeEx //sys GetShellWindow() (shellWindow HWND) = user32.GetShellWindow //sys MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW //sys ExitWindowsEx(flags uint32, reason uint32) (err error) = user32.ExitWindowsEx @@ -1368,9 +1374,11 @@ func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) { return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4) } + func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) } + func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { return syscall.EWINDOWS } diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index d8cb71db..3f03b3d5 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -2003,7 +2003,21 @@ const ( MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 ) -const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 +// Flags for GetAdaptersAddresses, see +// https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses. +const ( + GAA_FLAG_SKIP_UNICAST = 0x1 + GAA_FLAG_SKIP_ANYCAST = 0x2 + GAA_FLAG_SKIP_MULTICAST = 0x4 + GAA_FLAG_SKIP_DNS_SERVER = 0x8 + GAA_FLAG_INCLUDE_PREFIX = 0x10 + GAA_FLAG_SKIP_FRIENDLY_NAME = 0x20 + GAA_FLAG_INCLUDE_WINS_INFO = 0x40 + GAA_FLAG_INCLUDE_GATEWAYS = 0x80 + GAA_FLAG_INCLUDE_ALL_INTERFACES = 0x100 + GAA_FLAG_INCLUDE_ALL_COMPARTMENTS = 0x200 + GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER = 0x400 +) const ( IF_TYPE_OTHER = 1 @@ -2017,6 +2031,50 @@ const ( IF_TYPE_IEEE1394 = 144 ) +// Enum NL_PREFIX_ORIGIN for [IpAdapterUnicastAddress], see +// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_prefix_origin +const ( + IpPrefixOriginOther = 0 + IpPrefixOriginManual = 1 + IpPrefixOriginWellKnown = 2 + IpPrefixOriginDhcp = 3 + IpPrefixOriginRouterAdvertisement = 4 + IpPrefixOriginUnchanged = 1 << 4 +) + +// Enum NL_SUFFIX_ORIGIN for [IpAdapterUnicastAddress], see +// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_suffix_origin +const ( + NlsoOther = 0 + NlsoManual = 1 + NlsoWellKnown = 2 + NlsoDhcp = 3 + NlsoLinkLayerAddress = 4 + NlsoRandom = 5 + IpSuffixOriginOther = 0 + IpSuffixOriginManual = 1 + IpSuffixOriginWellKnown = 2 + IpSuffixOriginDhcp = 3 + IpSuffixOriginLinkLayerAddress = 4 + IpSuffixOriginRandom = 5 + IpSuffixOriginUnchanged = 1 << 4 +) + +// Enum NL_DAD_STATE for [IpAdapterUnicastAddress], see +// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_dad_state +const ( + NldsInvalid = 0 + NldsTentative = 1 + NldsDuplicate = 2 + NldsDeprecated = 3 + NldsPreferred = 4 + IpDadStateInvalid = 0 + IpDadStateTentative = 1 + IpDadStateDuplicate = 2 + IpDadStateDeprecated = 3 + IpDadStatePreferred = 4 +) + type SocketAddress struct { Sockaddr *syscall.RawSockaddrAny SockaddrLength int32 @@ -3404,3 +3462,14 @@ type DCB struct { EvtChar byte wReserved1 uint16 } + +// Keyboard Layout Flags. +// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadkeyboardlayoutw +const ( + KLF_ACTIVATE = 0x00000001 + KLF_SUBSTITUTE_OK = 0x00000002 + KLF_REORDER = 0x00000008 + KLF_REPLACELANG = 0x00000010 + KLF_NOTELLSHELL = 0x00000080 + KLF_SETFORPROCESS = 0x00000100 +) diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 9f73df75..9bb979a3 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -91,6 +91,7 @@ var ( procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW") procEqualSid = modadvapi32.NewProc("EqualSid") procFreeSid = modadvapi32.NewProc("FreeSid") + procGetAce = modadvapi32.NewProc("GetAce") procGetLengthSid = modadvapi32.NewProc("GetLengthSid") procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW") procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl") @@ -477,12 +478,16 @@ var ( procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow") procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow") procGetGUIThreadInfo = moduser32.NewProc("GetGUIThreadInfo") + procGetKeyboardLayout = moduser32.NewProc("GetKeyboardLayout") procGetShellWindow = moduser32.NewProc("GetShellWindow") procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId") procIsWindow = moduser32.NewProc("IsWindow") procIsWindowUnicode = moduser32.NewProc("IsWindowUnicode") procIsWindowVisible = moduser32.NewProc("IsWindowVisible") + procLoadKeyboardLayoutW = moduser32.NewProc("LoadKeyboardLayoutW") procMessageBoxW = moduser32.NewProc("MessageBoxW") + procToUnicodeEx = moduser32.NewProc("ToUnicodeEx") + procUnloadKeyboardLayout = moduser32.NewProc("UnloadKeyboardLayout") procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") @@ -788,6 +793,14 @@ func FreeSid(sid *SID) (err error) { return } +func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) { + r1, _, e1 := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func GetLengthSid(sid *SID) (len uint32) { r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) len = uint32(r0) @@ -4073,6 +4086,12 @@ func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) { return } +func GetKeyboardLayout(tid uint32) (hkl Handle) { + r0, _, _ := syscall.Syscall(procGetKeyboardLayout.Addr(), 1, uintptr(tid), 0, 0) + hkl = Handle(r0) + return +} + func GetShellWindow() (shellWindow HWND) { r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0) shellWindow = HWND(r0) @@ -4106,6 +4125,15 @@ func IsWindowVisible(hwnd HWND) (isVisible bool) { return } +func LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) { + r0, _, e1 := syscall.Syscall(procLoadKeyboardLayoutW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(flags), 0) + hkl = Handle(r0) + if hkl == 0 { + err = errnoErr(e1) + } + return +} + func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) { r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0) ret = int32(r0) @@ -4115,6 +4143,20 @@ func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret i return } +func ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) { + r0, _, _ := syscall.Syscall9(procToUnicodeEx.Addr(), 7, uintptr(vkey), uintptr(scancode), uintptr(unsafe.Pointer(keystate)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(flags), uintptr(hkl), 0, 0) + ret = int32(r0) + return +} + +func UnloadKeyboardLayout(hkl Handle) (err error) { + r1, _, e1 := syscall.Syscall(procUnloadKeyboardLayout.Addr(), 1, uintptr(hkl), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) { var _p0 uint32 if inheritExisting { diff --git a/vendor/modules.txt b/vendor/modules.txt index e635074d..e5b257fe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -62,19 +62,23 @@ github.com/charmbracelet/bubbles/runeutil github.com/charmbracelet/bubbles/spinner github.com/charmbracelet/bubbles/textinput github.com/charmbracelet/bubbles/viewport -# github.com/charmbracelet/bubbletea v0.25.0 -## explicit; go 1.17 +# github.com/charmbracelet/bubbletea v1.1.0 +## explicit; go 1.18 github.com/charmbracelet/bubbletea # github.com/charmbracelet/glamour v0.6.0 ## explicit; go 1.13 github.com/charmbracelet/glamour github.com/charmbracelet/glamour/ansi -# github.com/charmbracelet/lipgloss v0.10.0 +# github.com/charmbracelet/lipgloss v0.13.0 ## explicit; go 1.18 github.com/charmbracelet/lipgloss -# github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 -## explicit; go 1.13 -github.com/containerd/console +# github.com/charmbracelet/x/ansi v0.2.3 +## explicit; go 1.18 +github.com/charmbracelet/x/ansi +github.com/charmbracelet/x/ansi/parser +# github.com/charmbracelet/x/term v0.2.0 +## explicit; go 1.18 +github.com/charmbracelet/x/term # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew @@ -82,6 +86,9 @@ github.com/davecgh/go-spew/spew ## explicit github.com/dlclark/regexp2 github.com/dlclark/regexp2/syntax +# github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f +## explicit; go 1.16 +github.com/erikgeiser/coninput # github.com/felixge/httpsnoop v1.0.3 ## explicit; go 1.13 github.com/felixge/httpsnoop @@ -231,7 +238,7 @@ github.com/mitchellh/mapstructure # github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 ## explicit github.com/mohae/deepcopy -# github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b +# github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 ## explicit; go 1.17 github.com/muesli/ansi github.com/muesli/ansi/compressor @@ -245,7 +252,6 @@ github.com/muesli/reflow/indent github.com/muesli/reflow/padding github.com/muesli/reflow/truncate github.com/muesli/reflow/wordwrap -github.com/muesli/reflow/wrap # github.com/muesli/termenv v0.15.2 ## explicit; go 1.17 github.com/muesli/termenv @@ -389,11 +395,11 @@ golang.org/x/net/html/atom ## explicit; go 1.18 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sync v0.7.0 +# golang.org/x/sync v0.8.0 ## explicit; go 1.18 golang.org/x/sync/errgroup golang.org/x/sync/singleflight -# golang.org/x/sys v0.21.0 +# golang.org/x/sys v0.24.0 ## explicit; go 1.18 golang.org/x/sys/plan9 golang.org/x/sys/unix