mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-19 05:21:03 +01:00
Compare commits
21 Commits
feature/mu
...
v1.3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65732a58d0 | ||
|
|
ace7f76210 | ||
| fda365bd8b | |||
| c1cfc08c23 | |||
| 150fdddd2a | |||
| 6b659773f1 | |||
| 74d82fa356 | |||
| 3949411c57 | |||
| a455f6b79a | |||
| 2c08687c29 | |||
| 200f1f32f8 | |||
| 768a19b4d6 | |||
|
|
dc718392b6 | ||
|
|
e8f4fef41c | ||
| 6566dd66f0 | |||
| 1593799c03 | |||
| ea3dd75fec | |||
| a306f2c601 | |||
| 82f54c120d | |||
|
|
2d5799e2f2 | ||
| 8e33cadcaa |
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@@ -5,9 +5,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
version: ['1.22']
|
version: ['1.22']
|
||||||
# windows-latest removed, see:
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
# https://github.com/rogpeppe/go-internal/issues/284
|
|
||||||
os: [ubuntu-latest, macos-latest]
|
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
63
.github/workflows/release.yaml
vendored
63
.github/workflows/release.yaml
vendored
@@ -1,8 +1,8 @@
|
|||||||
name: build-and-test
|
name: build-release
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- "v*.*.*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -10,10 +10,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.22.11
|
go-version: 1.22.11
|
||||||
|
|
||||||
@@ -30,3 +30,58 @@ jobs:
|
|||||||
tag: ${{ github.ref_name }}
|
tag: ${{ github.ref_name }}
|
||||||
file: ./releases/*
|
file: ./releases/*
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|
||||||
|
- name: Build Changelog
|
||||||
|
id: github_release
|
||||||
|
uses: mikepenz/release-changelog-builder-action@v5
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
mode: "PR"
|
||||||
|
configurationJson: |
|
||||||
|
{
|
||||||
|
"template": "#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}",
|
||||||
|
"pr_template": "- #{{TITLE}} (##{{NUMBER}}) by #{{AUTHOR}}\n#{{BODY}}",
|
||||||
|
"empty_template": "- no changes",
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"title": "## New Features",
|
||||||
|
"labels": ["add", "feature"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## Bug Fixes",
|
||||||
|
"labels": ["fix", "bug", "revert"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## Documentation Enhancements",
|
||||||
|
"labels": ["doc"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## Refactoring Efforts",
|
||||||
|
"labels": ["refactor"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## Miscellaneus Changes",
|
||||||
|
"labels": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ignore_labels": [
|
||||||
|
"duplicate", "good first issue", "help wanted", "invalid", "question", "wontfix"
|
||||||
|
],
|
||||||
|
"label_extractor": [
|
||||||
|
{
|
||||||
|
"pattern": "(.) (.+)",
|
||||||
|
"target": "$1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": "(.) (.+)",
|
||||||
|
"target": "$1",
|
||||||
|
"on_property": "title"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
body: ${{steps.github_release.outputs.changelog}}
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -64,12 +64,12 @@ install: buildlocal
|
|||||||
clean:
|
clean:
|
||||||
rm -rf $(tool) releases coverage.out
|
rm -rf $(tool) releases coverage.out
|
||||||
|
|
||||||
test:
|
test: clean
|
||||||
go test ./... $(OPTS)
|
go test ./... $(OPTS)
|
||||||
|
|
||||||
singletest:
|
singletest:
|
||||||
@echo "Call like this: 'make singletest TEST=TestPrepareColumns MOD=lib'"
|
@echo "Call like this: 'make singletest TEST=TestPrepareColumns MOD=lib'"
|
||||||
go test -run $(TEST) github.com/tlinden/tablizer/$(MOD)
|
go test -run $(TEST) github.com/tlinden/tablizer/$(MOD) $(OPTS)
|
||||||
|
|
||||||
cover-report:
|
cover-report:
|
||||||
go test ./... -cover -coverprofile=coverage.out
|
go test ./... -cover -coverprofile=coverage.out
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Operational Flags:
|
|||||||
-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 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
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ Output Flags (mutually exclusive):
|
|||||||
-C, --csv Enable CSV output
|
-C, --csv Enable CSV output
|
||||||
-A, --ascii Default output mode, ascii tabular
|
-A, --ascii Default output mode, ascii tabular
|
||||||
-L, --hightlight-lines Use alternating background colors for tables
|
-L, --hightlight-lines Use alternating background colors for tables
|
||||||
|
-y, --yank-columns Yank specified columns (separated by ,) to clipboard,
|
||||||
|
space separated
|
||||||
|
|
||||||
Sort Mode Flags (mutually exclusive):
|
Sort Mode Flags (mutually exclusive):
|
||||||
-a, --sort-age sort according to age (duration) string
|
-a, --sort-age sort according to age (duration) string
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2022-2024 Thomas von Dein
|
Copyright © 2022-2025 Thomas von Dein
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const DefaultSeparator string = `(\s\s+|\t)`
|
const DefaultSeparator string = `(\s\s+|\t)`
|
||||||
const Version string = "v1.3.1"
|
const Version string = "v1.3.3"
|
||||||
const MAXPARTS = 2
|
const MAXPARTS = 2
|
||||||
|
|
||||||
var DefaultConfigfile = os.Getenv("HOME") + "/.config/tablizer/config"
|
var DefaultConfigfile = os.Getenv("HOME") + "/.config/tablizer/config"
|
||||||
@@ -58,6 +58,11 @@ type Pattern struct {
|
|||||||
Negate bool
|
Negate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
Regex *regexp.Regexp
|
||||||
|
Negate bool
|
||||||
|
}
|
||||||
|
|
||||||
// internal config
|
// internal config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
@@ -65,6 +70,8 @@ type Config struct {
|
|||||||
NoHeaders bool
|
NoHeaders bool
|
||||||
Columns string
|
Columns string
|
||||||
UseColumns []int
|
UseColumns []int
|
||||||
|
YankColumns string
|
||||||
|
UseYankColumns []int
|
||||||
Separator string
|
Separator string
|
||||||
OutputMode int
|
OutputMode int
|
||||||
InvertMatch bool
|
InvertMatch bool
|
||||||
@@ -100,7 +107,7 @@ type Config struct {
|
|||||||
|
|
||||||
// used for field filtering
|
// used for field filtering
|
||||||
Rawfilters []string
|
Rawfilters []string
|
||||||
Filters map[string]*regexp.Regexp
|
Filters map[string]Filter //map[string]*regexp.Regexp
|
||||||
|
|
||||||
// -r <file>
|
// -r <file>
|
||||||
InputFile string
|
InputFile string
|
||||||
@@ -270,12 +277,20 @@ func (conf *Config) PrepareModeFlags(flag Modeflag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conf *Config) PrepareFilters() error {
|
func (conf *Config) PrepareFilters() error {
|
||||||
conf.Filters = make(map[string]*regexp.Regexp, len(conf.Rawfilters))
|
conf.Filters = make(map[string]Filter, len(conf.Rawfilters))
|
||||||
|
|
||||||
for _, filter := range conf.Rawfilters {
|
for _, rawfilter := range conf.Rawfilters {
|
||||||
parts := strings.Split(filter, "=")
|
filter := Filter{}
|
||||||
|
|
||||||
|
parts := strings.Split(rawfilter, "!=")
|
||||||
if len(parts) != MAXPARTS {
|
if len(parts) != MAXPARTS {
|
||||||
return errors.New("filter field and value must be separated by =")
|
parts = strings.Split(rawfilter, "=")
|
||||||
|
|
||||||
|
if len(parts) != MAXPARTS {
|
||||||
|
return errors.New("filter field and value must be separated by '=' or '!='")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filter.Negate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
reg, err := regexp.Compile(parts[1])
|
reg, err := regexp.Compile(parts[1])
|
||||||
@@ -284,7 +299,8 @@ func (conf *Config) PrepareFilters() error {
|
|||||||
parts[0], err)
|
parts[0], err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.Filters[strings.ToLower(strings.ToLower(parts[0]))] = reg
|
filter.Regex = reg
|
||||||
|
conf.Filters[strings.ToLower(parts[0])] = filter
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2022-2024 Thomas von Dein
|
Copyright © 2022-2025 Thomas von Dein
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -147,6 +147,8 @@ func Execute() {
|
|||||||
"Custom field separator")
|
"Custom field separator")
|
||||||
rootCmd.PersistentFlags().StringVarP(&conf.Columns, "columns", "c", "",
|
rootCmd.PersistentFlags().StringVarP(&conf.Columns, "columns", "c", "",
|
||||||
"Only show the speficied columns (separated by ,)")
|
"Only show the speficied columns (separated by ,)")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&conf.YankColumns, "yank-columns", "y", "",
|
||||||
|
"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 ,)")
|
||||||
|
|
||||||
@@ -190,7 +192,7 @@ func Execute() {
|
|||||||
|
|
||||||
// filters
|
// filters
|
||||||
rootCmd.PersistentFlags().StringArrayVarP(&conf.Rawfilters,
|
rootCmd.PersistentFlags().StringArrayVarP(&conf.Rawfilters,
|
||||||
"filter", "F", nil, "Filter by field (field=regexp)")
|
"filter", "F", nil, "Filter by field (field=regexp || field!=regexp)")
|
||||||
rootCmd.PersistentFlags().StringArrayVarP(&conf.Transposers,
|
rootCmd.PersistentFlags().StringArrayVarP(&conf.Transposers,
|
||||||
"regex-transposer", "R", nil, "apply /search/replace/ regexp to fields given in -T")
|
"regex-transposer", "R", nil, "apply /search/replace/ regexp to fields given in -T")
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ SYNOPSIS
|
|||||||
-s, --separator string Custom field separator
|
-s, --separator string Custom field separator
|
||||||
-k, --sort-by int|name 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
|
||||||
|
|
||||||
@@ -30,6 +30,8 @@ SYNOPSIS
|
|||||||
-C, --csv Enable CSV output
|
-C, --csv Enable CSV output
|
||||||
-A, --ascii Default output mode, ascii tabular
|
-A, --ascii Default output mode, ascii tabular
|
||||||
-L, --hightlight-lines Use alternating background colors for tables
|
-L, --hightlight-lines Use alternating background colors for tables
|
||||||
|
-y, --yank-columns Yank specified columns (separated by ,) to clipboard,
|
||||||
|
space separated
|
||||||
|
|
||||||
Sort Mode Flags (mutually exclusive):
|
Sort Mode Flags (mutually exclusive):
|
||||||
-a, --sort-age sort according to age (duration) string
|
-a, --sort-age sort according to age (duration) string
|
||||||
@@ -181,6 +183,10 @@ DESCRIPTION
|
|||||||
If you specify more than one filter, both filters have to match (AND
|
If you specify more than one filter, both filters have to match (AND
|
||||||
operation).
|
operation).
|
||||||
|
|
||||||
|
These field filters can also be negated:
|
||||||
|
|
||||||
|
fieldname!=regexp
|
||||||
|
|
||||||
If the option -v is specified, the filtering is inverted.
|
If the option -v is specified, the filtering is inverted.
|
||||||
|
|
||||||
COLUMNS
|
COLUMNS
|
||||||
@@ -280,6 +286,18 @@ DESCRIPTION
|
|||||||
markdown which prints a Markdown table, yaml, which prints yaml encoding
|
markdown which prints a Markdown table, yaml, which prints yaml encoding
|
||||||
and CSV mode, which prints a comma separated value file.
|
and CSV mode, which prints a comma separated value file.
|
||||||
|
|
||||||
|
PUT FIELDS TO CLIPBOARD
|
||||||
|
You can let tablizer put fields to the clipboard using the option "-y".
|
||||||
|
This best fits the use-case when the result of your filtering yields
|
||||||
|
just one row. For example:
|
||||||
|
|
||||||
|
cloudctl cluster ls | tablizer -yid matchbox
|
||||||
|
|
||||||
|
If "matchbox" matches one cluster, you can immediately use the id of
|
||||||
|
that cluster somewhere else and paste it. Of course, if there are
|
||||||
|
multiple matches, then all id's will be put into the clipboard separated
|
||||||
|
by one space.
|
||||||
|
|
||||||
ENVIRONMENT VARIABLES
|
ENVIRONMENT VARIABLES
|
||||||
tablizer supports certain environment variables which use can use to
|
tablizer supports certain environment variables which use can use to
|
||||||
influence program behavior. Commandline flags have always precedence
|
influence program behavior. Commandline flags have always precedence
|
||||||
@@ -416,7 +434,7 @@ Operational Flags:
|
|||||||
-s, --separator string Custom field separator
|
-s, --separator string Custom field separator
|
||||||
-k, --sort-by int|name 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
|
||||||
|
|
||||||
@@ -429,6 +447,8 @@ Output Flags (mutually exclusive):
|
|||||||
-C, --csv Enable CSV output
|
-C, --csv Enable CSV output
|
||||||
-A, --ascii Default output mode, ascii tabular
|
-A, --ascii Default output mode, ascii tabular
|
||||||
-L, --hightlight-lines Use alternating background colors for tables
|
-L, --hightlight-lines Use alternating background colors for tables
|
||||||
|
-y, --yank-columns Yank specified columns (separated by ,) to clipboard,
|
||||||
|
space separated
|
||||||
|
|
||||||
Sort Mode Flags (mutually exclusive):
|
Sort Mode Flags (mutually exclusive):
|
||||||
-a, --sort-age sort according to age (duration) string
|
-a, --sort-age sort according to age (duration) string
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -22,8 +22,10 @@ require (
|
|||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.2 // 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.13.3 // indirect
|
github.com/zclconf/go-cty v1.13.3 // indirect
|
||||||
golang.org/x/mod v0.18.0 // indirect
|
golang.org/x/mod v0.18.0 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -32,6 +32,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzC
|
|||||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
@@ -49,6 +51,12 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.1 h1:nddQ5DsEnKW0KdzTILhbLpSq3e9y2dkJXEOtsMs6H7A=
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.1/go.mod h1:kXtjJBIMimZaGbxmcKZ8+JqK+acSNf5tAJiChlZBOr8=
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.2-0.20250126153310-fcc1f95408cf h1:csb/+rmJBAtOP6OP+9soTnwJVuhlUpedjb5dPlNZasY=
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.2-0.20250126153310-fcc1f95408cf/go.mod h1:kXtjJBIMimZaGbxmcKZ8+JqK+acSNf5tAJiChlZBOr8=
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.2 h1:Ph2icR0vZRIj3v5ExvsGweBwsbbDUTlS6HoF40MkQD8=
|
||||||
|
github.com/tiagomelo/go-clipboard v0.1.2/go.mod h1:kXtjJBIMimZaGbxmcKZ8+JqK+acSNf5tAJiChlZBOr8=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2022-2024 Thomas von Dein
|
Copyright © 2022-2025 Thomas von Dein
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -86,15 +86,19 @@ func FilterByFields(conf cfg.Config, data *Tabdata) (*Tabdata, bool, error) {
|
|||||||
keep := true
|
keep := true
|
||||||
|
|
||||||
for idx, header := range data.headers {
|
for idx, header := range data.headers {
|
||||||
if !Exists(conf.Filters, strings.ToLower(header)) {
|
lcheader := strings.ToLower(header)
|
||||||
|
if !Exists(conf.Filters, lcheader) {
|
||||||
// do not filter by unspecified field
|
// do not filter by unspecified field
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !conf.Filters[strings.ToLower(header)].MatchString(row[idx]) {
|
match := conf.Filters[lcheader].Regex.MatchString(row[idx])
|
||||||
// there IS a filter, but it doesn't match
|
if conf.Filters[lcheader].Negate {
|
||||||
keep = false
|
match = !match
|
||||||
|
}
|
||||||
|
|
||||||
|
if !match {
|
||||||
|
keep = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2024 Thomas von Dein
|
Copyright © 2024-2025 Thomas von Dein
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -98,6 +98,20 @@ func TestFilterByFields(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "one-field-negative",
|
||||||
|
filter: []string{"one!=asd"},
|
||||||
|
expect: Tabdata{
|
||||||
|
headers: []string{
|
||||||
|
"ONE", "TWO", "THREE",
|
||||||
|
},
|
||||||
|
entries: [][]string{
|
||||||
|
{"19191", "EDD 1", "x"},
|
||||||
|
{"8d8", "AN 1", "y"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "one-field-inverted",
|
name: "one-field-inverted",
|
||||||
filter: []string{"one=19"},
|
filter: []string{"one=19"},
|
||||||
|
|||||||
@@ -77,6 +77,14 @@ func PrepareColumns(conf *cfg.Config, data *Tabdata) error {
|
|||||||
|
|
||||||
conf.UseColumns = usecolumns
|
conf.UseColumns = usecolumns
|
||||||
|
|
||||||
|
// -y columns
|
||||||
|
useyankcolumns, err := PrepareColumnVars(conf.YankColumns, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.UseYankColumns = useyankcolumns
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2022 Thomas von Dein
|
Copyright © 2022-2025 Thomas von Dein
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -38,6 +38,9 @@ func printData(writer io.Writer, conf cfg.Config, data *Tabdata) {
|
|||||||
// by, independently if it's being used for display or not.
|
// by, independently if it's being used for display or not.
|
||||||
sortTable(conf, data)
|
sortTable(conf, data)
|
||||||
|
|
||||||
|
// put one or more columns into clipboard
|
||||||
|
yankColumns(conf, data)
|
||||||
|
|
||||||
// add numbers to headers and remove those we're not interested in
|
// add numbers to headers and remove those we're not interested in
|
||||||
numberizeAndReduceHeaders(conf, data)
|
numberizeAndReduceHeaders(conf, data)
|
||||||
|
|
||||||
|
|||||||
51
lib/yank.go
Normal file
51
lib/yank.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright © 2022-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 (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tiagomelo/go-clipboard/clipboard"
|
||||||
|
"github.com/tlinden/tablizer/cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func yankColumns(conf cfg.Config, data *Tabdata) {
|
||||||
|
var yank []string
|
||||||
|
|
||||||
|
if len(data.entries) == 0 || len(conf.UseYankColumns) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, row := range data.entries {
|
||||||
|
for i, field := range row {
|
||||||
|
for _, idx := range conf.UseYankColumns {
|
||||||
|
if i == idx-1 {
|
||||||
|
yank = append(yank, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(yank) > 0 {
|
||||||
|
cb := clipboard.New(clipboard.ClipboardOptions{Primary: true})
|
||||||
|
if err := cb.CopyText(strings.Join(yank, " ")); err != nil {
|
||||||
|
log.Fatalln("error writing string to clipboard:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
lib/yank_test.go
Normal file
72
lib/yank_test.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tiagomelo/go-clipboard/clipboard"
|
||||||
|
"github.com/tlinden/tablizer/cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var yanktests = []struct {
|
||||||
|
name string
|
||||||
|
yank []int // -y$colum,$column... after processing
|
||||||
|
filter string
|
||||||
|
expect string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "one",
|
||||||
|
yank: []int{1},
|
||||||
|
filter: "beta",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func DISABLED_TestYankColumns(t *testing.T) {
|
||||||
|
cb := clipboard.New()
|
||||||
|
|
||||||
|
for _, testdata := range yanktests {
|
||||||
|
testname := fmt.Sprintf("yank-%s-filter-%s",
|
||||||
|
testdata.name, testdata.filter)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
conf := cfg.Config{
|
||||||
|
OutputMode: cfg.ASCII,
|
||||||
|
UseYankColumns: testdata.yank,
|
||||||
|
NoColor: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.ApplyDefaults()
|
||||||
|
data := newData() // defined in printer_test.go, reused here
|
||||||
|
|
||||||
|
var writer bytes.Buffer
|
||||||
|
printData(&writer, conf, &data)
|
||||||
|
|
||||||
|
got, err := cb.PasteText()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to fetch yanked text from clipboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
if got != testdata.expect {
|
||||||
|
t.Errorf("not yanked correctly:\n+++ got:\n%s\n+++ want:\n%s",
|
||||||
|
got, testdata.expect)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
9
mkrel.sh
9
mkrel.sh
@@ -42,8 +42,15 @@ for D in $DIST; do
|
|||||||
binfile="releases/${tool}-${os}-${arch}-${version}"
|
binfile="releases/${tool}-${os}-${arch}-${version}"
|
||||||
tardir="${tool}-${os}-${arch}-${version}"
|
tardir="${tool}-${os}-${arch}-${version}"
|
||||||
tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz"
|
tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz"
|
||||||
|
pie=""
|
||||||
|
|
||||||
|
if test "$D" = "linux/amd64"; then
|
||||||
|
pie="-buildmode=pie"
|
||||||
|
fi
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
GOOS=${os} GOARCH=${arch} go build -o ${binfile} -ldflags "-X 'github.com/tlinden/tablizer/cfg.VERSION=${version}'"
|
GOOS=${os} GOARCH=${arch} go build -tags osusergo,netgo -ldflags "-extldflags=-static -w -X 'github.com/tlinden/tablizer/cfg.VERSION=${version}'" --trimpath $pie -o ${binfile}
|
||||||
|
strip --strip-all ${binfile}
|
||||||
mkdir -p ${tardir}
|
mkdir -p ${tardir}
|
||||||
cp ${binfile} README.md LICENSE ${tardir}/
|
cp ${binfile} README.md LICENSE ${tardir}/
|
||||||
echo 'tool = tablizer
|
echo 'tool = tablizer
|
||||||
|
|||||||
27
tablizer.1
27
tablizer.1
@@ -133,7 +133,8 @@
|
|||||||
.\" ========================================================================
|
.\" ========================================================================
|
||||||
.\"
|
.\"
|
||||||
.IX Title "TABLIZER 1"
|
.IX Title "TABLIZER 1"
|
||||||
.TH TABLIZER 1 "2025-01-22" "1" "User Commands"
|
.TH TABLIZER 1 "2025-02-23" "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
|
||||||
@@ -155,7 +156,7 @@ tablizer \- Manipulate tabular output of other programs
|
|||||||
\& \-s, \-\-separator string Custom field separator
|
\& \-s, \-\-separator string Custom field separator
|
||||||
\& \-k, \-\-sort\-by int|name 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
|
||||||
\&
|
\&
|
||||||
@@ -168,6 +169,8 @@ tablizer \- Manipulate tabular output of other programs
|
|||||||
\& \-C, \-\-csv Enable CSV output
|
\& \-C, \-\-csv Enable CSV output
|
||||||
\& \-A, \-\-ascii Default output mode, ascii tabular
|
\& \-A, \-\-ascii Default output mode, ascii tabular
|
||||||
\& \-L, \-\-hightlight\-lines Use alternating background colors for tables
|
\& \-L, \-\-hightlight\-lines Use alternating background colors for tables
|
||||||
|
\& \-y, \-\-yank\-columns Yank specified columns (separated by ,) to clipboard,
|
||||||
|
\& space separated
|
||||||
\&
|
\&
|
||||||
\& Sort Mode Flags (mutually exclusive):
|
\& Sort Mode Flags (mutually exclusive):
|
||||||
\& \-a, \-\-sort\-age sort according to age (duration) string
|
\& \-a, \-\-sort\-age sort according to age (duration) string
|
||||||
@@ -340,6 +343,12 @@ Fieldnames (== columns headers) are case insensitive.
|
|||||||
If you specify more than one filter, both filters have to match (\s-1AND\s0
|
If you specify more than one filter, both filters have to match (\s-1AND\s0
|
||||||
operation).
|
operation).
|
||||||
.PP
|
.PP
|
||||||
|
These field filters can also be negated:
|
||||||
|
.PP
|
||||||
|
.Vb 1
|
||||||
|
\& fieldname!=regexp
|
||||||
|
.Ve
|
||||||
|
.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-1COLUMNS\s0"
|
.SS "\s-1COLUMNS\s0"
|
||||||
.IX Subsection "COLUMNS"
|
.IX Subsection "COLUMNS"
|
||||||
@@ -456,6 +465,20 @@ more output modes available: \fBorgtbl\fR which prints an Emacs org-mode
|
|||||||
table and \fBmarkdown\fR which prints a Markdown table, \fByaml\fR, which
|
table and \fBmarkdown\fR which prints a Markdown table, \fByaml\fR, which
|
||||||
prints yaml encoding and \s-1CSV\s0 mode, which prints a comma separated
|
prints yaml encoding and \s-1CSV\s0 mode, which prints a comma separated
|
||||||
value file.
|
value file.
|
||||||
|
.SS "\s-1PUT FIELDS TO CLIPBOARD\s0"
|
||||||
|
.IX Subsection "PUT FIELDS TO CLIPBOARD"
|
||||||
|
You can let tablizer put fields to the clipboard using the option
|
||||||
|
\&\f(CW\*(C`\-y\*(C'\fR. This best fits the use-case when the result of your filtering
|
||||||
|
yields just one row. For example:
|
||||||
|
.PP
|
||||||
|
.Vb 1
|
||||||
|
\& cloudctl cluster ls | tablizer \-yid matchbox
|
||||||
|
.Ve
|
||||||
|
.PP
|
||||||
|
If \*(L"matchbox\*(R" matches one cluster, you can immediately use the id of
|
||||||
|
that cluster somewhere else and paste it. Of course, if there are
|
||||||
|
multiple matches, then all id's will be put into the clipboard
|
||||||
|
separated by one space.
|
||||||
.SS "\s-1ENVIRONMENT VARIABLES\s0"
|
.SS "\s-1ENVIRONMENT VARIABLES\s0"
|
||||||
.IX Subsection "ENVIRONMENT VARIABLES"
|
.IX Subsection "ENVIRONMENT VARIABLES"
|
||||||
\&\fBtablizer\fR supports certain environment variables which use can use
|
\&\fBtablizer\fR supports certain environment variables which use can use
|
||||||
|
|||||||
21
tablizer.pod
21
tablizer.pod
@@ -16,7 +16,7 @@ tablizer - Manipulate tabular output of other programs
|
|||||||
-s, --separator string Custom field separator
|
-s, --separator string Custom field separator
|
||||||
-k, --sort-by int|name 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
|
||||||
|
|
||||||
@@ -29,6 +29,8 @@ tablizer - Manipulate tabular output of other programs
|
|||||||
-C, --csv Enable CSV output
|
-C, --csv Enable CSV output
|
||||||
-A, --ascii Default output mode, ascii tabular
|
-A, --ascii Default output mode, ascii tabular
|
||||||
-L, --hightlight-lines Use alternating background colors for tables
|
-L, --hightlight-lines Use alternating background colors for tables
|
||||||
|
-y, --yank-columns Yank specified columns (separated by ,) to clipboard,
|
||||||
|
space separated
|
||||||
|
|
||||||
Sort Mode Flags (mutually exclusive):
|
Sort Mode Flags (mutually exclusive):
|
||||||
-a, --sort-age sort according to age (duration) string
|
-a, --sort-age sort according to age (duration) string
|
||||||
@@ -194,6 +196,10 @@ Fieldnames (== columns headers) are case insensitive.
|
|||||||
If you specify more than one filter, both filters have to match (AND
|
If you specify more than one filter, both filters have to match (AND
|
||||||
operation).
|
operation).
|
||||||
|
|
||||||
|
These field filters can also be negated:
|
||||||
|
|
||||||
|
fieldname!=regexp
|
||||||
|
|
||||||
If the option B<-v> is specified, the filtering is inverted.
|
If the option B<-v> is specified, the filtering is inverted.
|
||||||
|
|
||||||
|
|
||||||
@@ -302,6 +308,19 @@ table and B<markdown> which prints a Markdown table, B<yaml>, which
|
|||||||
prints yaml encoding and CSV mode, which prints a comma separated
|
prints yaml encoding and CSV mode, which prints a comma separated
|
||||||
value file.
|
value file.
|
||||||
|
|
||||||
|
=head2 PUT FIELDS TO CLIPBOARD
|
||||||
|
|
||||||
|
You can let tablizer put fields to the clipboard using the option
|
||||||
|
C<-y>. This best fits the use-case when the result of your filtering
|
||||||
|
yields just one row. For example:
|
||||||
|
|
||||||
|
cloudctl cluster ls | tablizer -yid matchbox
|
||||||
|
|
||||||
|
If "matchbox" matches one cluster, you can immediately use the id of
|
||||||
|
that cluster somewhere else and paste it. Of course, if there are
|
||||||
|
multiple matches, then all id's will be put into the clipboard
|
||||||
|
separated by one space.
|
||||||
|
|
||||||
=head2 ENVIRONMENT VARIABLES
|
=head2 ENVIRONMENT VARIABLES
|
||||||
|
|
||||||
B<tablizer> supports certain environment variables which use can use
|
B<tablizer> supports certain environment variables which use can use
|
||||||
|
|||||||
Reference in New Issue
Block a user