pax_global_header 0000666 0000000 0000000 00000000064 14023461024 0014506 g ustar 00root root 0000000 0000000 52 comment=5670729abbe5a43d05159447503dc60ae7ff78ff term-grid-0.2.4/ 0000775 0000000 0000000 00000000000 14023461024 0013403 5 ustar 00root root 0000000 0000000 term-grid-0.2.4/.github/ 0000775 0000000 0000000 00000000000 14023461024 0014743 5 ustar 00root root 0000000 0000000 term-grid-0.2.4/.github/FUNDING.yml 0000664 0000000 0000000 00000000031 14023461024 0016552 0 ustar 00root root 0000000 0000000 github: [achannarasappa] term-grid-0.2.4/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14023461024 0017126 5 ustar 00root root 0000000 0000000 term-grid-0.2.4/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000001403 14023461024 0021616 0 ustar 00root root 0000000 0000000 --- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Start with options '...' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Environment (please complete the following information):** - OS: [e.g. Mac, Windows, Linux] - Terminal: [e.g. iTerm, ConEmu, Guake] - Terminal Version: [e.g. 22] - Font: (Optional) [e.g. Powerline] - term-grid Version: [e.g. v2.2.0] **Additional context** Add any other context about the problem here. term-grid-0.2.4/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000001257 14023461024 0022660 0 ustar 00root root 0000000 0000000 --- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- **Problem Statement** Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Proposed Solution** A clear and concise description of what you want to happen. **Alternatives** A clear and concise description of any alternative solutions or features you've considered. **Use Cases** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. term-grid-0.2.4/.github/workflows/ 0000775 0000000 0000000 00000000000 14023461024 0017000 5 ustar 00root root 0000000 0000000 term-grid-0.2.4/.github/workflows/close-stale-issue.yaml 0000664 0000000 0000000 00000001632 14023461024 0023227 0 ustar 00root root 0000000 0000000 name: 'github-close-stale' on: schedule: - cron: '30 1 * * *' jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v3 with: repo-token: ${{ secrets.GH_PAT }} stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.' stale-pr-message: 'This pr is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.' close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' close-pr-message: 'This pr was closed because it has been stalled for 7 days with no activity.' days-before-stale: 30 days-before-close: 7 exempt-issue-milestones: 'future-release' exempt-pr-milestones: 'future-release' term-grid-0.2.4/.github/workflows/lint-commit.yml 0000664 0000000 0000000 00000000331 14023461024 0021754 0 ustar 00root root 0000000 0000000 name: lint-commit-message on: [push] jobs: commitlint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - uses: wagoid/commitlint-github-action@v2 term-grid-0.2.4/.github/workflows/lint.yml 0000664 0000000 0000000 00000000362 14023461024 0020472 0 ustar 00root root 0000000 0000000 name: lint on: [push, pull_request] jobs: lint: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: lint uses: golangci/golangci-lint-action@v2 with: version: v1.29 term-grid-0.2.4/.github/workflows/test.yml 0000664 0000000 0000000 00000002225 14023461024 0020503 0 ustar 00root root 0000000 0000000 name: test on: [push, pull_request] jobs: test: strategy: matrix: go-version: [1.15.x] platform: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Install Ginkgo run: go get -u github.com/onsi/ginkgo/ginkgo - name: Checkout code uses: actions/checkout@v2 - name: Test run: ginkgo -cover ./... coverage: runs-on: ubuntu-latest steps: - name: Install Go if: success() uses: actions/setup-go@v2 with: go-version: 1.15.x - name: Install Ginkgo run: go get -u github.com/onsi/ginkgo/ginkgo - name: Checkout code uses: actions/checkout@v2 - name: Calc coverage run: | ginkgo -cover -outputdir=./ -coverprofile=coverage.out ./... - name: Convert coverage.out to coverage.lcov uses: jandelgado/gcov2lcov-action@v1.0.6 - name: Coveralls uses: coverallsapp/github-action@v1.1.2 with: github-token: ${{ secrets.github_token }} path-to-lcov: coverage.lcov term-grid-0.2.4/.gitignore 0000664 0000000 0000000 00000000007 14023461024 0015370 0 ustar 00root root 0000000 0000000 .vscode term-grid-0.2.4/LICENSE 0000664 0000000 0000000 00000002061 14023461024 0014407 0 ustar 00root root 0000000 0000000 MIT License Copyright (c) 2021 Ani Channarasappa 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. term-grid-0.2.4/README.md 0000664 0000000 0000000 00000004326 14023461024 0014667 0 ustar 00root root 0000000 0000000 # term-grid
Position text and visuals in a grid layout for terminal UIs (TUIs) with familiar web semantics ## Features * **Flex Layout** - dynamically resize cells to use available space * **Responsive** - show or hide cells dynamically based on grid size * **Alignment** - align text to the right of left of a cell * **Overflow/Wrap** - set whether text should be hidden, wrap on word, or wrap unconditionally when width exceeds the cell width * **Margins** - set width vertically and horizontally between cells ## Install ```sh go get github.com/achannarasappa/term-grid ``` ## Quick Start ```go // main.go package main import ( "fmt" . "github.com/achannarasappa/term-grid" ) func main() { out := Render( Grid{ GutterVertical: 2, GutterHorizontal: 5, Rows: []Row{ { Width: 100, Cells: []Cell{ {Width: 10, Text: "term-grid is awesome!", Overflow: WrapWord}, {Width: 10, Text: "everything to the right", Overflow: Wrap, Align: Right}, {Width: 20, Text: "To Do:\n- take out trash\n- book my flight\n- workout", Overflow: WrapWord}, {Text: "I'm baby pitchfork iPhone tilde umami man braid"}, }, }, }, }) fmt.Print(out) } ``` ```sh $ go run main.go term-grid everything To Do: I'm baby pitchfork iPhone tilde umami man bra is to the rig - take out trash awesome! ht - book my flight - workout ``` term-grid-0.2.4/cell.go 0000664 0000000 0000000 00000003717 14023461024 0014661 0 ustar 00root root 0000000 0000000 package grid import ( "strings" "github.com/muesli/reflow/ansi" "github.com/muesli/reflow/wordwrap" "github.com/muesli/reflow/wrap" ) const ( fillChar string = " " gutterChar string = " " ) // Cell contains settings for a single cell within the parent Row type Cell struct { Text string Width int Align TextAlign Overflow Overflow VisibleMinWidth int } func getText(cell Cell) string { if cell.Overflow == Wrap { return wrap.String(cell.Text, cell.Width) } if cell.Overflow == WrapWord { return wordwrap.String(cell.Text, cell.Width) } return cell.Text } func getLineText(lineIndex int, lineTexts []string, cellHeightMax int, cellWidth int, cellAlign TextAlign) string { if lineIndex < cellHeightMax { textWidth := ansi.PrintableRuneWidth(lineTexts[lineIndex]) if textWidth > cellWidth { return lineTexts[lineIndex][:cellWidth] } if textWidth < cellWidth && cellAlign == Right { return strings.Repeat(fillChar, cellWidth-textWidth) + lineTexts[lineIndex] } if textWidth < cellWidth && cellAlign == Left { return lineTexts[lineIndex] + strings.Repeat(fillChar, cellWidth-textWidth) } return lineTexts[lineIndex] } return strings.Repeat(fillChar, cellWidth) } func getLines(cell Cell, lines []string, heightMax int, widthLinePreviousCells int, config gridConfig) ([]string, int) { text := getText(cell) textLines := strings.Split(text, "\n") cellHeightMax := len(textLines) if cellHeightMax > heightMax { countLinesToAdd := cellHeightMax - heightMax for i := 0; i < countLinesToAdd; i++ { lines = append(lines, strings.Repeat(fillChar, widthLinePreviousCells)) } heightMax = cellHeightMax } for lineIndex := 0; lineIndex < heightMax; lineIndex++ { temptextline := getLineText(lineIndex, textLines, cellHeightMax, cell.Width, cell.Align) lines[lineIndex] = lines[lineIndex] + temptextline + strings.Repeat(gutterChar, config.widthGutter) } return lines, heightMax } term-grid-0.2.4/enum.go 0000664 0000000 0000000 00000002153 14023461024 0014677 0 ustar 00root root 0000000 0000000 package grid // TextAlign is an enum used to set the text alignment within a cell type TextAlign int const ( // Left align text within a cell Left TextAlign = iota // Right align text within a cell Right ) func (ta TextAlign) String() string { return [...]string{"Left", "Right"}[ta] } // Overflow is an enum used to set the text overflow behavior within a cell type Overflow int const ( // Hide text that extends beyond the width of a cell Hidden Overflow = iota // Wrap text onto the next line when the text width exceeds the width of the cell Wrap // Wrap text onto the next line when the text width exceeds the width of the cell // but only break on words WrapWord ) func (to Overflow) String() string { return [...]string{"Hidden", "Wrap", "WrapWord"}[to] } // Breakpoint is an enum used to set the visibility of cells are various terminal sizes type Breakpoint int const ( Small Breakpoint = iota Medium Large XLarge ) func (bp Breakpoint) String() string { return [...]string{"Small", "Medium", "Large", "XLarge"}[bp] } func (bp Breakpoint) Size() int { return [...]int{50, 100, 200, 400}[bp] } term-grid-0.2.4/go.mod 0000664 0000000 0000000 00000000300 14023461024 0014502 0 ustar 00root root 0000000 0000000 module github.com/achannarasappa/term-grid go 1.15 require ( github.com/muesli/reflow v0.2.1-0.20201126184510-3bcb929042f2 github.com/onsi/ginkgo v1.15.0 github.com/onsi/gomega v1.10.5 ) term-grid-0.2.4/go.sum 0000664 0000000 0000000 00000017347 14023461024 0014552 0 ustar 00root root 0000000 0000000 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/muesli/reflow v0.2.1-0.20201126184510-3bcb929042f2 h1:+cpkcmASpeBn4qXz2tU+x+njyKe91NoHXqrJdhoDnZo= github.com/muesli/reflow v0.2.1-0.20201126184510-3bcb929042f2/go.mod h1:qT22vjVmM9MIUeLgsVYe/Ye7eZlbv9dZjL3dVhUqLX8= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= term-grid-0.2.4/grid.go 0000664 0000000 0000000 00000001372 14023461024 0014662 0 ustar 00root root 0000000 0000000 // Package grid provides the functionality to render a configurable text grid // for use in terminal UI application package grid import "strings" // Grid contains settings that apply to the entire grid type Grid struct { Rows []Row GutterVertical int GutterHorizontal int } type gridConfig struct { widthGutter int } // Renders a grid based on the settings defined by the argument Grid, Row(s), and Cell(s) // Outputs a string with the settings applied func Render(grid Grid) string { var rows = make([]string, 0) config := gridConfig{ widthGutter: grid.GutterHorizontal, } for _, row := range grid.Rows { rows = append(rows, renderRow(row, config)) } return strings.Join(rows, strings.Repeat("\n", 1+grid.GutterVertical)) } term-grid-0.2.4/grid_suite_test.go 0000664 0000000 0000000 00000000370 14023461024 0017127 0 ustar 00root root 0000000 0000000 package grid_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/format" ) func TestGrid(t *testing.T) { format.TruncatedDiff = false RegisterFailHandler(Fail) RunSpecs(t, "Grid Suite") } term-grid-0.2.4/grid_test.go 0000664 0000000 0000000 00000007524 14023461024 0015726 0 ustar 00root root 0000000 0000000 package grid_test import ( . "github.com/achannarasappa/term-grid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Grid", func() { It("should render a grid", func() { output := Render( Grid{ GutterVertical: 1, GutterHorizontal: 2, Rows: []Row{ { Width: 70, Cells: []Cell{ { Width: 10, Text: "test2 this is a long sentence that will need to be wrapped by word", Overflow: WrapWord, }, { Width: 10, Text: "test1a test1b test1c test1d", Overflow: Wrap, }, { Width: 10, Text: "test4a\ntest4b\ntest4c\ntest4d", }, { Text: "test3 this is another long sentence that will need to be wrapped but will overflow", }, }, }, { Width: 70, Cells: []Cell{ { Width: 50, Text: "right aligned fixed width cell with word wrap. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do", Align: Right, Overflow: WrapWord, }, { Text: "flex width cell here", }, }, }, { Width: 70, Cells: []Cell{ { Width: 35, Text: "fixed width cell that does not take up entire width of row", Overflow: WrapWord, }, { Width: 20, Text: "cell that is only visible on larger terminals", VisibleMinWidth: Large.Size(), }, { Width: -1, Text: "cell with invalid width", }, }, }, { Width: 70, Cells: []Cell{ { Width: 11, Text: "fixed width", }, { Text: "flex width 1", }, { Text: "flex width 2", }, { Text: "flex width 3", }, }, }, { Width: 70, Cells: []Cell{ { Width: 50, Text: "oversize 1", }, { Width: 50, Text: "oversize 2", }, { Width: 50, Text: "oversize 3", }, { Text: "flex width 4", }, }, }, }, }) expected := ` test2 this test1a tes test4a test3 this is another long sentenc is a long t1b test1c test4b sentence test1d test4c that will test4d need to be wrapped by word right aligned fixed width cell with word wrap. flex width cell he Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do fixed width cell that does not take up entire width of row fixed width flex width 1 flex width 2 flex width 3 oversize 1 oversize 2 ` Expect("\n\n" + output).To(BeIdenticalTo(expected)) }) Describe("TextAlign", func() { When("left align is selected", func() { It("returns the text for left align text", func() { input := Left.String() output := "Left" Expect(input).To(Equal(output)) }) }) }) Describe("Overflow", func() { When("hidden is selected", func() { It("returns the text for hidden overflow text", func() { input := Hidden.String() output := "Hidden" Expect(input).To(Equal(output)) }) }) }) Describe("Breakpoint", func() { When("hidden is selected", func() { It("returns the breakpoint text", func() { input := Small.String() output := "Small" Expect(input).To(Equal(output)) }) }) }) }) term-grid-0.2.4/row.go 0000664 0000000 0000000 00000003741 14023461024 0014546 0 ustar 00root root 0000000 0000000 package grid import ( "math" "strings" "github.com/muesli/reflow/ansi" ) // Row contains settings for a single row within the parent Grid type Row struct { Width int Cells []Cell } func getWidthFlexCells(widthTotal int, count int) (int, int) { if count <= 0 { return widthTotal, 0 } remainder := widthTotal % count width := int(math.Floor(float64(widthTotal) / float64(count))) return width, remainder } func updateCells(widthTotal int, widthGutter int, cells []Cell) []Cell { widthFlex := widthTotal countFlexWidthCells := 0 var cellsFiltered = make([]Cell, 0) for _, cell := range cells { if cell.Width < 0 { continue } if cell.VisibleMinWidth > 0 && cell.VisibleMinWidth > widthTotal { continue } if cell.Width <= 0 { countFlexWidthCells++ } widthFlex -= cell.Width cellsFiltered = append(cellsFiltered, cell) } widthFlex = widthFlex - (widthGutter * (len(cellsFiltered) - 1)) if widthFlex <= 0 { return cellsFiltered } widthFlexCellsWithoutRemainder, widthRemainder := getWidthFlexCells(widthFlex, countFlexWidthCells) for i, cell := range cellsFiltered { if cell.Width <= 0 && widthRemainder > 0 { widthRemainder-- cellsFiltered[i].Width = widthFlexCellsWithoutRemainder + 1 continue } if cell.Width <= 0 { cellsFiltered[i].Width = widthFlexCellsWithoutRemainder continue } } return cellsFiltered } func renderRow(row Row, config gridConfig) string { lines := []string{} heightMax := 0 widthLinePreviousCells := 0 cells := updateCells(row.Width, config.widthGutter, row.Cells) cellLastIndex := (len(cells) - 1) for i, cell := range cells { if i == cellLastIndex { config.widthGutter = 0 } lines, heightMax = getLines(cell, lines, heightMax, widthLinePreviousCells, config) widthLinePreviousCells += cell.Width + config.widthGutter } for i := range lines { if ansi.PrintableRuneWidth(lines[i]) > row.Width { lines[i] = lines[i][:row.Width] } } return strings.Join(lines, "\n") }