mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-19 21:41:02 +01:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec864f42d6 | ||
|
|
4eaa676510 | ||
|
|
c600fb1136 | ||
|
|
abf9fac5c7 | ||
|
|
80dd6849ae | ||
| e2b82515f5 | |||
|
|
1976b4046e |
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: make
|
run: make
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23
|
go-version: 1.23
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -6,25 +6,29 @@
|
|||||||
|
|
||||||
Tablizer can be used to re-format tabular output of other
|
Tablizer can be used to re-format tabular output of other
|
||||||
programs. While you could do this using standard unix tools, in some
|
programs. While you could do this using standard unix tools, in some
|
||||||
cases it's a hard job.
|
cases it's a hard job. With tablizer you can filter by column[s],
|
||||||
|
ignore certain column[s] by regex, name or number. It can output the
|
||||||
|
tabular data in a range of formats (see below). There's even an
|
||||||
|
interactive filter/selection tool available.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
```default
|
```default
|
||||||
Usage:
|
Usage:
|
||||||
tablizer [regex] [file, ...] [flags]
|
tablizer [regex,...] [file, ...] [flags]
|
||||||
|
|
||||||
Operational Flags:
|
Operational Flags:
|
||||||
-c, --columns string Only show the speficied columns (separated by ,)
|
-c, --columns string Only show the speficied columns (separated by ,)
|
||||||
-v, --invert-match select non-matching rows
|
-v, --invert-match select non-matching rows
|
||||||
-n, --no-numbering Disable header numbering
|
-n, --numbering Enable header numbering
|
||||||
-N, --no-color Disable pattern highlighting
|
-N, --no-color Disable pattern highlighting
|
||||||
-H, --no-headers Disable headers display
|
-H, --no-headers Disable headers display
|
||||||
-s, --separator string Custom field separator
|
-s, --separator string Custom field separator
|
||||||
-k, --sort-by int Sort by column (default: 1)
|
-k, --sort-by int|name Sort by column (default: 1)
|
||||||
-z, --fuzzy Use fuzzy search [experimental]
|
-z, --fuzzy Use fuzzy search [experimental]
|
||||||
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
||||||
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
||||||
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
||||||
|
-I, --interactive Interactively filter and select rows
|
||||||
|
|
||||||
Output Flags (mutually exclusive):
|
Output Flags (mutually exclusive):
|
||||||
-X, --extended Enable extended output
|
-X, --extended Enable extended output
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const DefaultSeparator string = `(\s\s+|\t)`
|
const DefaultSeparator string = `(\s\s+|\t)`
|
||||||
const Version string = "v1.4.4"
|
const Version string = "v1.5.1"
|
||||||
const MAXPARTS = 2
|
const MAXPARTS = 2
|
||||||
|
|
||||||
var DefaultConfigfile = os.Getenv("HOME") + "/.config/tablizer/config"
|
var DefaultConfigfile = os.Getenv("HOME") + "/.config/tablizer/config"
|
||||||
@@ -78,6 +78,7 @@ type Config struct {
|
|||||||
Patterns []*Pattern
|
Patterns []*Pattern
|
||||||
UseFuzzySearch bool
|
UseFuzzySearch bool
|
||||||
UseHighlight bool
|
UseHighlight bool
|
||||||
|
Interactive bool
|
||||||
|
|
||||||
SortMode string
|
SortMode string
|
||||||
SortDescending bool
|
SortDescending bool
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func Execute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ShowManual {
|
if ShowManual {
|
||||||
Pager("tablizer manual page", manpage)
|
lib.Pager("tablizer manual page", manpage)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -130,6 +130,8 @@ func Execute() {
|
|||||||
"Yank the speficied columns (separated by ,) to the clipboard")
|
"Yank the speficied columns (separated by ,) to the clipboard")
|
||||||
rootCmd.PersistentFlags().StringVarP(&conf.TransposeColumns, "transpose-columns", "T", "",
|
rootCmd.PersistentFlags().StringVarP(&conf.TransposeColumns, "transpose-columns", "T", "",
|
||||||
"Transpose the speficied columns (separated by ,)")
|
"Transpose the speficied columns (separated by ,)")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&conf.Interactive, "interactive", "I", false,
|
||||||
|
"interactive mode (experimental)")
|
||||||
|
|
||||||
// sort options
|
// sort options
|
||||||
rootCmd.PersistentFlags().StringVarP(&conf.SortByColumn, "sort-by", "k", "",
|
rootCmd.PersistentFlags().StringVarP(&conf.SortByColumn, "sort-by", "k", "",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ SYNOPSIS
|
|||||||
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
||||||
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
||||||
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
||||||
|
-I, --interactive Interactively filter and select rows
|
||||||
|
|
||||||
Output Flags (mutually exclusive):
|
Output Flags (mutually exclusive):
|
||||||
-X, --extended Enable extended output
|
-X, --extended Enable extended output
|
||||||
@@ -189,6 +190,20 @@ DESCRIPTION
|
|||||||
|
|
||||||
If the option -v is specified, the filtering is inverted.
|
If the option -v is specified, the filtering is inverted.
|
||||||
|
|
||||||
|
INTERACTIVE FILTERING
|
||||||
|
You can also use the interactive mode, enabled with "-I" to filter and
|
||||||
|
select rows. This mode is complementary, that is, other filter options
|
||||||
|
are still being respected.
|
||||||
|
|
||||||
|
To enter e filter, hit "/", enter a filter string and finish with
|
||||||
|
"ENTER". Use "SPACE" to select/deselect rows, use "a" to select all
|
||||||
|
(visible) rows.
|
||||||
|
|
||||||
|
Commit your selection with "q". The selected rows are being fed to the
|
||||||
|
requested output mode as usual. Abort with "CTRL-c", in which case the
|
||||||
|
results of the interactive mode are being ignored and all rows are being
|
||||||
|
fed to output.
|
||||||
|
|
||||||
COLUMNS
|
COLUMNS
|
||||||
The parameter -c can be used to specify, which columns to display. By
|
The parameter -c can be used to specify, which columns to display. By
|
||||||
default tablizer numerizes the header names and these numbers can be
|
default tablizer numerizes the header names and these numbers can be
|
||||||
@@ -416,6 +431,9 @@ LICENSE
|
|||||||
Released under the MIT License, Copyright (c) 2006-2011 Kirill
|
Released under the MIT License, Copyright (c) 2006-2011 Kirill
|
||||||
Simonov
|
Simonov
|
||||||
|
|
||||||
|
bubble-table (https://github.com/Evertras/bubble-table)
|
||||||
|
Released under the MIT License, Copyright (c) 2022 Brandon Fulljames
|
||||||
|
|
||||||
AUTHORS
|
AUTHORS
|
||||||
Thomas von Dein tom AT vondein DOT org
|
Thomas von Dein tom AT vondein DOT org
|
||||||
|
|
||||||
@@ -437,6 +455,7 @@ Operational Flags:
|
|||||||
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
||||||
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
||||||
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
||||||
|
-I, --interactive Interactively filter and select rows
|
||||||
|
|
||||||
Output Flags (mutually exclusive):
|
Output Flags (mutually exclusive):
|
||||||
-X, --extended Enable extended output
|
-X, --extended Enable extended output
|
||||||
|
|||||||
16
go.mod
16
go.mod
@@ -8,9 +8,10 @@ require (
|
|||||||
github.com/alecthomas/repr v0.5.1
|
github.com/alecthomas/repr v0.5.1
|
||||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
||||||
github.com/charmbracelet/bubbles v0.21.0
|
github.com/charmbracelet/bubbles v0.21.0
|
||||||
github.com/charmbracelet/bubbletea v1.3.4
|
github.com/charmbracelet/bubbletea v1.3.6
|
||||||
github.com/charmbracelet/lipgloss v1.1.0
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
github.com/gookit/color v1.5.4
|
github.com/evertras/bubble-table v0.19.0
|
||||||
|
github.com/gookit/color v1.6.0
|
||||||
github.com/hashicorp/hcl/v2 v2.24.0
|
github.com/hashicorp/hcl/v2 v2.24.0
|
||||||
github.com/lithammer/fuzzysearch v1.1.8
|
github.com/lithammer/fuzzysearch v1.1.8
|
||||||
github.com/olekukonko/tablewriter v1.0.9
|
github.com/olekukonko/tablewriter v1.0.9
|
||||||
@@ -23,10 +24,11 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/agext/levenshtein v1.2.3 // indirect
|
github.com/agext/levenshtein v1.2.3 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||||
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
github.com/charmbracelet/colorprofile v0.3.1 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
@@ -40,6 +42,7 @@ require (
|
|||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/olekukonko/errors v1.1.0 // indirect
|
github.com/olekukonko/errors v1.1.0 // indirect
|
||||||
github.com/olekukonko/ll v0.0.9 // indirect
|
github.com/olekukonko/ll v0.0.9 // indirect
|
||||||
@@ -48,8 +51,9 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
github.com/zclconf/go-cty v1.16.3 // indirect
|
github.com/zclconf/go-cty v1.16.3 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||||
golang.org/x/mod v0.21.0 // indirect
|
golang.org/x/mod v0.21.0 // indirect
|
||||||
golang.org/x/sync v0.14.0 // indirect
|
golang.org/x/sync v0.15.0 // indirect
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/text v0.25.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
|
|||||||
37
go.sum
37
go.sum
@@ -6,20 +6,22 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
|
|||||||
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
|
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
|
||||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
||||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||||
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
|
github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU=
|
||||||
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
|
github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc=
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40=
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0=
|
||||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
|
||||||
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
@@ -28,14 +30,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
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/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
|
github.com/evertras/bubble-table v0.19.0 h1:+JlXRUjNuBN1JI7XU1PapmW1wglbcqZUKkiPnVKPgrc=
|
||||||
|
github.com/evertras/bubble-table v0.19.0/go.mod h1:ifHujS1YxwnYSOgcR2+m3GnJ84f7CVU/4kUOxUCjEbQ=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=
|
||||||
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
|
github.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E=
|
||||||
|
github.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA=
|
||||||
|
github.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
|
||||||
github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=
|
github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=
|
||||||
github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=
|
github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
@@ -51,6 +57,7 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||||
@@ -59,6 +66,8 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D
|
|||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
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 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||||
|
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||||
@@ -98,8 +107,8 @@ github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6
|
|||||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
|
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||||
@@ -111,8 +120,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|||||||
@@ -58,6 +58,15 @@ func ProcessFiles(conf *cfg.Config, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.Interactive {
|
||||||
|
newdata, err := tableEditor(conf, &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data = *newdata
|
||||||
|
}
|
||||||
|
|
||||||
printData(os.Stdout, *conf, &data)
|
printData(os.Stdout, *conf, &data)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package lib
|
||||||
|
|
||||||
// pager setup using bubbletea
|
// pager setup using bubbletea
|
||||||
// file shamlelessly copied from:
|
// file shamlelessly copied from:
|
||||||
@@ -28,18 +28,18 @@ var (
|
|||||||
}()
|
}()
|
||||||
)
|
)
|
||||||
|
|
||||||
type model struct {
|
type Doc struct {
|
||||||
content string
|
content string
|
||||||
title string
|
title string
|
||||||
ready bool
|
ready bool
|
||||||
viewport viewport.Model
|
viewport viewport.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
func (m Doc) Init() tea.Cmd {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m Doc) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
var (
|
var (
|
||||||
cmd tea.Cmd
|
cmd tea.Cmd
|
||||||
cmds []tea.Cmd
|
cmds []tea.Cmd
|
||||||
@@ -79,21 +79,21 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return m, tea.Batch(cmds...)
|
return m, tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) View() string {
|
func (m Doc) View() string {
|
||||||
if !m.ready {
|
if !m.ready {
|
||||||
return "\n Initializing..."
|
return "\n Initializing..."
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s\n%s\n%s", m.headerView(), m.viewport.View(), m.footerView())
|
return fmt.Sprintf("%s\n%s\n%s", m.headerView(), m.viewport.View(), m.footerView())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) headerView() string {
|
func (m Doc) headerView() string {
|
||||||
// title := titleStyle.Render("RPN Help Overview")
|
// title := titleStyle.Render("RPN Help Overview")
|
||||||
title := titleStyle.Render(m.title)
|
title := titleStyle.Render(m.title)
|
||||||
line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(title)))
|
line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(title)))
|
||||||
return lipgloss.JoinHorizontal(lipgloss.Center, title, line)
|
return lipgloss.JoinHorizontal(lipgloss.Center, title, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) footerView() string {
|
func (m Doc) footerView() string {
|
||||||
info := infoStyle.Render(fmt.Sprintf("%3.f%%", m.viewport.ScrollPercent()*100))
|
info := infoStyle.Render(fmt.Sprintf("%3.f%%", m.viewport.ScrollPercent()*100))
|
||||||
line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(info)))
|
line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(info)))
|
||||||
return lipgloss.JoinHorizontal(lipgloss.Center, line, info)
|
return lipgloss.JoinHorizontal(lipgloss.Center, line, info)
|
||||||
@@ -108,7 +108,7 @@ func max(a, b int) int {
|
|||||||
|
|
||||||
func Pager(title, message string) {
|
func Pager(title, message string) {
|
||||||
p := tea.NewProgram(
|
p := tea.NewProgram(
|
||||||
model{content: message, title: title},
|
Doc{content: message, title: title},
|
||||||
tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer"
|
tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer"
|
||||||
tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel
|
tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel
|
||||||
)
|
)
|
||||||
516
lib/tableeditor.go
Normal file
516
lib/tableeditor.go
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
/*
|
||||||
|
Copyright © 2025 Thomas von Dein
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/evertras/bubble-table/table"
|
||||||
|
"github.com/tlinden/tablizer/cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The context exists outside of the bubble loop, and is being used as
|
||||||
|
// pointer reciever. That way we can use it as our primary storage
|
||||||
|
// container.
|
||||||
|
type Context struct {
|
||||||
|
selectedColumn int
|
||||||
|
showHelp bool
|
||||||
|
descending bool
|
||||||
|
data *Tabdata
|
||||||
|
|
||||||
|
// Window dimensions
|
||||||
|
totalWidth int
|
||||||
|
totalHeight int
|
||||||
|
|
||||||
|
// Table dimensions
|
||||||
|
horizontalMargin int
|
||||||
|
verticalMargin int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute tablizer sort function, feed it with fresh config, we do
|
||||||
|
// NOT use the existing runtime config, because sorting is
|
||||||
|
// configurable in the UI separately.
|
||||||
|
func (ctx *Context) Sort(mode string) {
|
||||||
|
conf := cfg.Config{
|
||||||
|
SortMode: mode,
|
||||||
|
SortDescending: ctx.descending,
|
||||||
|
UseSortByColumn: []int{ctx.selectedColumn + 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.descending = !ctx.descending
|
||||||
|
|
||||||
|
sortTable(conf, ctx.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The actual table model, holds the context pointer, a copy of the
|
||||||
|
// pre-processed data and some flags
|
||||||
|
type FilterTable struct {
|
||||||
|
Table table.Model
|
||||||
|
|
||||||
|
Rows int
|
||||||
|
|
||||||
|
quitting bool
|
||||||
|
unchanged bool
|
||||||
|
|
||||||
|
maxColumns int
|
||||||
|
headerIdx map[string]int
|
||||||
|
|
||||||
|
ctx *Context
|
||||||
|
|
||||||
|
columns []table.Column
|
||||||
|
}
|
||||||
|
|
||||||
|
type HelpLine []string
|
||||||
|
type HelpColumn []HelpLine
|
||||||
|
|
||||||
|
const (
|
||||||
|
// header+footer
|
||||||
|
ExtraRows = 5
|
||||||
|
|
||||||
|
HelpFooter = "?:help | "
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// we use our own custom border style
|
||||||
|
customBorder = table.Border{
|
||||||
|
Top: "─",
|
||||||
|
Left: "│",
|
||||||
|
Right: "│",
|
||||||
|
Bottom: "─",
|
||||||
|
|
||||||
|
TopRight: "╮",
|
||||||
|
TopLeft: "╭",
|
||||||
|
BottomRight: "╯",
|
||||||
|
BottomLeft: "╰",
|
||||||
|
|
||||||
|
TopJunction: "┬",
|
||||||
|
LeftJunction: "├",
|
||||||
|
RightJunction: "┤",
|
||||||
|
BottomJunction: "┴",
|
||||||
|
InnerJunction: "┼",
|
||||||
|
|
||||||
|
InnerDivider: "│",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cells in selected columns will be highlighted
|
||||||
|
StyleSelected = lipgloss.NewStyle().
|
||||||
|
Background(lipgloss.Color("#696969")).
|
||||||
|
Foreground(lipgloss.Color("#ffffff")).
|
||||||
|
Align(lipgloss.Left)
|
||||||
|
|
||||||
|
StyleHeader = lipgloss.NewStyle().
|
||||||
|
Background(lipgloss.Color("#ffffff")).
|
||||||
|
Foreground(lipgloss.Color("#696969")).
|
||||||
|
Align(lipgloss.Left)
|
||||||
|
|
||||||
|
// help buffer styles
|
||||||
|
StyleKey = lipgloss.NewStyle().Bold(true)
|
||||||
|
StyleHelp = lipgloss.NewStyle().Foreground(lipgloss.Color("#ff4500"))
|
||||||
|
|
||||||
|
// the default style
|
||||||
|
NoStyle = lipgloss.NewStyle().Align(lipgloss.Left)
|
||||||
|
|
||||||
|
HelpData = []HelpColumn{
|
||||||
|
{
|
||||||
|
HelpLine{"up", "navigate up"},
|
||||||
|
HelpLine{"down", "navigate down"},
|
||||||
|
HelpLine{"tab", "navigate columns"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HelpLine{"s", "sort alpha-numerically"},
|
||||||
|
HelpLine{"n", "sort numerically"},
|
||||||
|
HelpLine{"t", "sort by time"},
|
||||||
|
HelpLine{"d", "sort by duration"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HelpLine{"spc", "[de]select a row"},
|
||||||
|
HelpLine{"a", "[de]select all visible rows"},
|
||||||
|
HelpLine{"f", "enter fuzzy filter"},
|
||||||
|
HelpLine{"esc", "finish filter input"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HelpLine{"?", "show help buffer"},
|
||||||
|
HelpLine{"q", "commit and quit"},
|
||||||
|
HelpLine{"c-c", "discard and quit"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// rendered from Help above
|
||||||
|
Help = ""
|
||||||
|
|
||||||
|
// number of lines taken by help below, adjust accordingly!
|
||||||
|
HelpRows = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// generate a lipgloss styled help buffer consisting of various
|
||||||
|
// columns
|
||||||
|
func generateHelp() {
|
||||||
|
help := strings.Builder{}
|
||||||
|
helpcols := []string{}
|
||||||
|
maxrows := 0
|
||||||
|
|
||||||
|
for _, col := range HelpData {
|
||||||
|
help.Reset()
|
||||||
|
|
||||||
|
// determine max key width to avoid excess spaces between keys and help
|
||||||
|
keylen := 0
|
||||||
|
for _, line := range col {
|
||||||
|
if len(line[0]) > keylen {
|
||||||
|
keylen = len(line[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keylenstr := fmt.Sprintf("%d", keylen)
|
||||||
|
|
||||||
|
for _, line := range col {
|
||||||
|
// 0: key, 1: help text
|
||||||
|
help.WriteString(StyleKey.Render(fmt.Sprintf("%-"+keylenstr+"s", line[0])))
|
||||||
|
help.WriteString(" " + StyleHelp.Render(line[1]) + " \n")
|
||||||
|
}
|
||||||
|
|
||||||
|
helpcols = append(helpcols, help.String())
|
||||||
|
|
||||||
|
if len(col) > maxrows {
|
||||||
|
maxrows = len(col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HelpRows = maxrows + 1
|
||||||
|
Help = "\n" + lipgloss.JoinHorizontal(lipgloss.Top, helpcols...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializes the table model
|
||||||
|
func NewModel(data *Tabdata, ctx *Context) FilterTable {
|
||||||
|
columns := make([]table.Column, len(data.headers))
|
||||||
|
lengths := make([]int, len(data.headers))
|
||||||
|
hidx := make(map[string]int, len(data.headers))
|
||||||
|
|
||||||
|
// give columns at least the header width
|
||||||
|
for idx, header := range data.headers {
|
||||||
|
lengths[idx] = len(header)
|
||||||
|
hidx[strings.ToLower(header)] = idx
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine max width per column
|
||||||
|
for _, entry := range data.entries {
|
||||||
|
for i, cell := range entry {
|
||||||
|
if len(cell) > lengths[i] {
|
||||||
|
lengths[i] = len(cell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine flexFactor with base 10, used by flexColumns
|
||||||
|
for i, len := range lengths {
|
||||||
|
if len <= 10 {
|
||||||
|
lengths[i] = 1
|
||||||
|
} else {
|
||||||
|
lengths[i] = len / 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup column data with flexColumns
|
||||||
|
for idx, header := range data.headers {
|
||||||
|
// FIXME: doesn't work
|
||||||
|
//columns[idx] = table.NewFlexColumn(strings.ToLower(header), StyleHeader.Render(header),
|
||||||
|
columns[idx] = table.NewFlexColumn(strings.ToLower(header), header,
|
||||||
|
lengths[idx]).WithFiltered(true).WithStyle(NoStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// separate variable so we can share the row filling code
|
||||||
|
filtertbl := FilterTable{
|
||||||
|
maxColumns: len(data.headers),
|
||||||
|
Rows: len(data.entries),
|
||||||
|
headerIdx: hidx,
|
||||||
|
ctx: ctx,
|
||||||
|
columns: columns,
|
||||||
|
}
|
||||||
|
|
||||||
|
filtertbl.Table = table.New(columns)
|
||||||
|
filtertbl.fillRows()
|
||||||
|
|
||||||
|
// finally construct help buffer
|
||||||
|
generateHelp()
|
||||||
|
|
||||||
|
return filtertbl
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applied to every cell on every change (TAB,up,down key, resize
|
||||||
|
// event etc)
|
||||||
|
func CellController(input table.StyledCellFuncInput, m FilterTable) lipgloss.Style {
|
||||||
|
if m.headerIdx[input.Column.Key()] == m.ctx.selectedColumn {
|
||||||
|
return StyleSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selects or deselects ALL rows
|
||||||
|
func (m *FilterTable) ToggleAllSelected() {
|
||||||
|
rows := m.Table.GetVisibleRows()
|
||||||
|
selected := m.Table.SelectedRows()
|
||||||
|
|
||||||
|
if len(selected) > 0 {
|
||||||
|
for i, row := range selected {
|
||||||
|
rows[i] = row.Selected(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, row := range rows {
|
||||||
|
rows[i] = row.Selected(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Table.WithRows(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ? pressed, display help message
|
||||||
|
func (m FilterTable) ToggleHelp() {
|
||||||
|
m.ctx.showHelp = !m.ctx.showHelp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m FilterTable) Init() tea.Cmd {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward call to context sort
|
||||||
|
func (m *FilterTable) Sort(mode string) {
|
||||||
|
m.ctx.Sort(mode)
|
||||||
|
m.fillRows()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fills the table rows with our data. Called once on startup and
|
||||||
|
// repeatedly if the user changes the sort order in some way
|
||||||
|
func (m *FilterTable) fillRows() {
|
||||||
|
// required to be able to feed the model to the controller
|
||||||
|
controllerWrapper := func(input table.StyledCellFuncInput) lipgloss.Style {
|
||||||
|
return CellController(input, *m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill the rows with style
|
||||||
|
rows := make([]table.Row, len(m.ctx.data.entries))
|
||||||
|
for idx, entry := range m.ctx.data.entries {
|
||||||
|
rowdata := make(table.RowData, len(entry))
|
||||||
|
|
||||||
|
for i, cell := range entry {
|
||||||
|
rowdata[strings.ToLower(m.ctx.data.headers[i])] =
|
||||||
|
table.NewStyledCellWithStyleFunc(cell+" ", controllerWrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows[idx] = table.NewRow(rowdata)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Table = m.Table.
|
||||||
|
WithRows(rows).
|
||||||
|
Filtered(true).
|
||||||
|
WithFuzzyFilter().
|
||||||
|
Focused(true).
|
||||||
|
SelectableRows(true).
|
||||||
|
WithSelectedText(" ", "✓").
|
||||||
|
WithFooterVisibility(true).
|
||||||
|
WithHeaderVisibility(true).
|
||||||
|
Border(customBorder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part of the bubbletea event loop, called every tick
|
||||||
|
func (m FilterTable) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
var (
|
||||||
|
cmd tea.Cmd
|
||||||
|
cmds []tea.Cmd
|
||||||
|
)
|
||||||
|
|
||||||
|
m.Table, cmd = m.Table.Update(msg)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
|
||||||
|
// If the user is about to enter filter text, do NOT respond to
|
||||||
|
// key bindings, as they might be part of the filter!
|
||||||
|
if !m.Table.GetIsFilterInputFocused() {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch msg.String() {
|
||||||
|
case "q":
|
||||||
|
m.quitting = true
|
||||||
|
m.unchanged = false
|
||||||
|
cmds = append(cmds, tea.Quit)
|
||||||
|
|
||||||
|
case "ctrl+c":
|
||||||
|
m.quitting = true
|
||||||
|
m.unchanged = true
|
||||||
|
cmds = append(cmds, tea.Quit)
|
||||||
|
|
||||||
|
case "a":
|
||||||
|
m.ToggleAllSelected()
|
||||||
|
|
||||||
|
case "tab":
|
||||||
|
m.SelectNextColumn()
|
||||||
|
|
||||||
|
case "?":
|
||||||
|
m.ToggleHelp()
|
||||||
|
m.recalculateTable()
|
||||||
|
|
||||||
|
case "s":
|
||||||
|
m.Sort("alphanumeric")
|
||||||
|
|
||||||
|
case "n":
|
||||||
|
m.Sort("numeric")
|
||||||
|
|
||||||
|
case "d":
|
||||||
|
m.Sort("duration")
|
||||||
|
|
||||||
|
case "t":
|
||||||
|
m.Sort("time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Happens when the terminal window has been resized
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.WindowSizeMsg:
|
||||||
|
m.ctx.totalWidth = msg.Width
|
||||||
|
m.ctx.totalHeight = msg.Height
|
||||||
|
|
||||||
|
m.recalculateTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
m.updateFooter()
|
||||||
|
|
||||||
|
return m, tea.Batch(cmds...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add some info to the footer
|
||||||
|
func (m *FilterTable) updateFooter() {
|
||||||
|
selected := m.Table.SelectedRows()
|
||||||
|
footer := fmt.Sprintf("selected: %d ", len(selected))
|
||||||
|
|
||||||
|
if m.Table.GetIsFilterInputFocused() {
|
||||||
|
footer = fmt.Sprintf("/%s %s", m.Table.GetCurrentFilter(), footer)
|
||||||
|
} else if m.Table.GetIsFilterActive() {
|
||||||
|
footer = fmt.Sprintf("Filter: %s %s", m.Table.GetCurrentFilter(), footer)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Table = m.Table.WithStaticFooter(HelpFooter + footer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called on resize event (or if help has been toggled)
|
||||||
|
func (m *FilterTable) recalculateTable() {
|
||||||
|
m.Table = m.Table.
|
||||||
|
WithTargetWidth(m.calculateWidth()).
|
||||||
|
WithMinimumHeight(m.calculateHeight()).
|
||||||
|
WithPageSize(m.calculateHeight() - ExtraRows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FilterTable) calculateWidth() int {
|
||||||
|
return m.ctx.totalWidth - m.ctx.horizontalMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take help height into account, if enabled
|
||||||
|
func (m *FilterTable) calculateHeight() int {
|
||||||
|
height := m.Rows + ExtraRows
|
||||||
|
|
||||||
|
if height >= m.ctx.totalHeight {
|
||||||
|
height = m.ctx.totalHeight - m.ctx.verticalMargin
|
||||||
|
} else {
|
||||||
|
height = m.ctx.totalHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.ctx.showHelp {
|
||||||
|
height = height - HelpRows
|
||||||
|
}
|
||||||
|
|
||||||
|
return height
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part of the bubbletable event view, called every tick
|
||||||
|
func (m FilterTable) View() string {
|
||||||
|
body := strings.Builder{}
|
||||||
|
|
||||||
|
if !m.quitting {
|
||||||
|
body.WriteString(m.Table.View())
|
||||||
|
|
||||||
|
if m.ctx.showHelp {
|
||||||
|
body.WriteString(Help)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return body.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// User hit the TAB key
|
||||||
|
func (m *FilterTable) SelectNextColumn() {
|
||||||
|
if m.ctx.selectedColumn == m.maxColumns-1 {
|
||||||
|
m.ctx.selectedColumn = 0
|
||||||
|
} else {
|
||||||
|
m.ctx.selectedColumn++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry point from outside tablizer into table editor
|
||||||
|
func tableEditor(conf *cfg.Config, data *Tabdata) (*Tabdata, error) {
|
||||||
|
// we render to STDERR to avoid dead lock when the user redirects STDOUT
|
||||||
|
// see https://github.com/charmbracelet/bubbletea/issues/860
|
||||||
|
//
|
||||||
|
// TODO: doesn't work with libgloss v2 anymore!
|
||||||
|
lipgloss.SetDefaultRenderer(lipgloss.NewRenderer(os.Stderr))
|
||||||
|
|
||||||
|
ctx := &Context{data: data}
|
||||||
|
|
||||||
|
// Output to STDERR because there's a known bubbletea/lipgloss
|
||||||
|
// issue: if a program with a tui is expected to write something
|
||||||
|
// to STDOUT when the tui is finished, then the styles do not
|
||||||
|
// work. So we write to STDERR (which works) and tablizer can
|
||||||
|
// still be used inside pipes.
|
||||||
|
program := tea.NewProgram(
|
||||||
|
NewModel(data, ctx),
|
||||||
|
tea.WithOutput(os.Stderr),
|
||||||
|
tea.WithAltScreen())
|
||||||
|
|
||||||
|
m, err := program.Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.(FilterTable).unchanged {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data has been modified. Extract it, put it back into our own
|
||||||
|
// structure and give control back to cmdline tablizer.
|
||||||
|
filteredtable := m.(FilterTable)
|
||||||
|
|
||||||
|
data.entries = make([][]string, len(filteredtable.Table.SelectedRows()))
|
||||||
|
for pos, row := range m.(FilterTable).Table.SelectedRows() {
|
||||||
|
entry := make([]string, len(data.headers))
|
||||||
|
for idx, field := range data.headers {
|
||||||
|
cell := row.Data[strings.ToLower(field)]
|
||||||
|
switch value := cell.(type) {
|
||||||
|
case string:
|
||||||
|
entry[idx] = value
|
||||||
|
case table.StyledCell:
|
||||||
|
entry[idx] = value.Data.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.entries[pos] = entry
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
20
tablizer.1
20
tablizer.1
@@ -133,7 +133,7 @@
|
|||||||
.\" ========================================================================
|
.\" ========================================================================
|
||||||
.\"
|
.\"
|
||||||
.IX Title "TABLIZER 1"
|
.IX Title "TABLIZER 1"
|
||||||
.TH TABLIZER 1 "2025-03-06" "1" "User Commands"
|
.TH TABLIZER 1 "2025-08-28" "1" "User Commands"
|
||||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||||
.\" way too many mistakes in technical documents.
|
.\" way too many mistakes in technical documents.
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
@@ -158,6 +158,7 @@ tablizer \- Manipulate tabular output of other programs
|
|||||||
\& \-F, \-\-filter field[!]=reg Filter given field with regex, can be used multiple times
|
\& \-F, \-\-filter field[!]=reg Filter given field with regex, can be used multiple times
|
||||||
\& \-T, \-\-transpose\-columns string Transpose the speficied columns (separated by ,)
|
\& \-T, \-\-transpose\-columns string Transpose the speficied columns (separated by ,)
|
||||||
\& \-R, \-\-regex\-transposer /from/to/ Apply /search/replace/ regexp to fields given in \-T
|
\& \-R, \-\-regex\-transposer /from/to/ Apply /search/replace/ regexp to fields given in \-T
|
||||||
|
\& \-I, \-\-interactive Interactively filter and select rows
|
||||||
\&
|
\&
|
||||||
\& Output Flags (mutually exclusive):
|
\& Output Flags (mutually exclusive):
|
||||||
\& \-X, \-\-extended Enable extended output
|
\& \-X, \-\-extended Enable extended output
|
||||||
@@ -349,6 +350,20 @@ These field filters can also be negated:
|
|||||||
.Ve
|
.Ve
|
||||||
.PP
|
.PP
|
||||||
If the option \fB\-v\fR is specified, the filtering is inverted.
|
If the option \fB\-v\fR is specified, the filtering is inverted.
|
||||||
|
.SS "\s-1INTERACTIVE FILTERING\s0"
|
||||||
|
.IX Subsection "INTERACTIVE FILTERING"
|
||||||
|
You can also use the interactive mode, enabled with \f(CW\*(C`\-I\*(C'\fR to filter
|
||||||
|
and select rows. This mode is complementary, that is, other filter
|
||||||
|
options are still being respected.
|
||||||
|
.PP
|
||||||
|
To enter e filter, hit \f(CW\*(C`/\*(C'\fR, enter a filter string and finish with
|
||||||
|
\&\f(CW\*(C`ENTER\*(C'\fR. Use \f(CW\*(C`SPACE\*(C'\fR to select/deselect rows, use \f(CW\*(C`a\*(C'\fR to select all
|
||||||
|
(visible) rows.
|
||||||
|
.PP
|
||||||
|
Commit your selection with \f(CW\*(C`q\*(C'\fR. The selected rows are being fed to
|
||||||
|
the requested output mode as usual. Abort with \f(CW\*(C`CTRL\-c\*(C'\fR, in which
|
||||||
|
case the results of the interactive mode are being ignored and all
|
||||||
|
rows are being fed to output.
|
||||||
.SS "\s-1COLUMNS\s0"
|
.SS "\s-1COLUMNS\s0"
|
||||||
.IX Subsection "COLUMNS"
|
.IX Subsection "COLUMNS"
|
||||||
The parameter \fB\-c\fR can be used to specify, which columns to
|
The parameter \fB\-c\fR can be used to specify, which columns to
|
||||||
@@ -615,6 +630,9 @@ Released under the \s-1MIT\s0 License, Copyright (c) 201 by Oleku Konko
|
|||||||
.IP "yaml (gopkg.in/yaml.v3)" 4
|
.IP "yaml (gopkg.in/yaml.v3)" 4
|
||||||
.IX Item "yaml (gopkg.in/yaml.v3)"
|
.IX Item "yaml (gopkg.in/yaml.v3)"
|
||||||
Released under the \s-1MIT\s0 License, Copyright (c) 2006\-2011 Kirill Simonov
|
Released under the \s-1MIT\s0 License, Copyright (c) 2006\-2011 Kirill Simonov
|
||||||
|
.IP "bubble-table (https://github.com/Evertras/bubble\-table)" 4
|
||||||
|
.IX Item "bubble-table (https://github.com/Evertras/bubble-table)"
|
||||||
|
Released under the \s-1MIT\s0 License, Copyright (c) 2022 Brandon Fulljames
|
||||||
.SH "AUTHORS"
|
.SH "AUTHORS"
|
||||||
.IX Header "AUTHORS"
|
.IX Header "AUTHORS"
|
||||||
Thomas von Dein \fBtom \s-1AT\s0 vondein \s-1DOT\s0 org\fR
|
Thomas von Dein \fBtom \s-1AT\s0 vondein \s-1DOT\s0 org\fR
|
||||||
|
|||||||
19
tablizer.pod
19
tablizer.pod
@@ -19,6 +19,7 @@ tablizer - Manipulate tabular output of other programs
|
|||||||
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
-F, --filter field[!]=reg Filter given field with regex, can be used multiple times
|
||||||
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
|
||||||
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
-R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T
|
||||||
|
-I, --interactive Interactively filter and select rows
|
||||||
|
|
||||||
Output Flags (mutually exclusive):
|
Output Flags (mutually exclusive):
|
||||||
-X, --extended Enable extended output
|
-X, --extended Enable extended output
|
||||||
@@ -202,6 +203,20 @@ These field filters can also be negated:
|
|||||||
|
|
||||||
If the option B<-v> is specified, the filtering is inverted.
|
If the option B<-v> is specified, the filtering is inverted.
|
||||||
|
|
||||||
|
=head2 INTERACTIVE FILTERING
|
||||||
|
|
||||||
|
You can also use the interactive mode, enabled with C<-I> to filter
|
||||||
|
and select rows. This mode is complementary, that is, other filter
|
||||||
|
options are still being respected.
|
||||||
|
|
||||||
|
To enter e filter, hit C</>, enter a filter string and finish with
|
||||||
|
C<ENTER>. Use C<SPACE> to select/deselect rows, use C<a> to select all
|
||||||
|
(visible) rows.
|
||||||
|
|
||||||
|
Commit your selection with C<q>. The selected rows are being fed to
|
||||||
|
the requested output mode as usual. Abort with C<CTRL-c>, in which
|
||||||
|
case the results of the interactive mode are being ignored and all
|
||||||
|
rows are being fed to output.
|
||||||
|
|
||||||
=head2 COLUMNS
|
=head2 COLUMNS
|
||||||
|
|
||||||
@@ -465,6 +480,10 @@ Released under the MIT License, Copyright (c) 201 by Oleku Konko
|
|||||||
|
|
||||||
Released under the MIT License, Copyright (c) 2006-2011 Kirill Simonov
|
Released under the MIT License, Copyright (c) 2006-2011 Kirill Simonov
|
||||||
|
|
||||||
|
=item bubble-table (https://github.com/Evertras/bubble-table)
|
||||||
|
|
||||||
|
Released under the MIT License, Copyright (c) 2022 Brandon Fulljames
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHORS
|
=head1 AUTHORS
|
||||||
|
|||||||
Reference in New Issue
Block a user