From 14c50b4e63cfd350b1588847454538be44843852 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Tue, 14 Jan 2025 12:28:54 +0100 Subject: [PATCH] get rid of lisp interpreter, -R and -F are enough, fixes #30 --- README.md | 46 ++++++- TODO.md | 10 -- cfg/config.go | 14 --- cmd/root.go | 7 -- cmd/tablizer.go | 56 --------- lib/filter.go | 13 -- lib/lisp.go | 319 ------------------------------------------------ lib/lisplib.go | 110 ----------------- lib/parser.go | 23 ---- tablizer.1 | 58 --------- tablizer.pod | 61 --------- 11 files changed, 43 insertions(+), 674 deletions(-) delete mode 100644 lib/lisp.go delete mode 100644 lib/lisplib.go diff --git a/README.md b/README.md index 14d738f..9d19502 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,49 @@ Tablizer can be used to re-format tabular output of other programs. While you could do this using standard unix tools, in some cases it's a hard job. +Usage: +```default +Usage: + tablizer [regex] [file, ...] [flags] + +Operational Flags: + -c, --columns string Only show the speficied columns (separated by ,) + -v, --invert-match select non-matching rows + -n, --no-numbering Disable header numbering + -N, --no-color Disable pattern highlighting + -H, --no-headers Disable headers display + -s, --separator string Custom field separator + -k, --sort-by int Sort by column (default: 1) + -z, --fuzzy Use fuzzy search [experimental] + -F, --filter field=reg Filter given field with regex, can be used multiple times + -T, --transpose-columns string Transpose the speficied columns (separated by ,) + -R, --regex-transposer /from/to/ Apply /search/replace/ regexp to fields given in -T + +Output Flags (mutually exclusive): + -X, --extended Enable extended output + -M, --markdown Enable markdown table output + -O, --orgtbl Enable org-mode table output + -S, --shell Enable shell evaluable output + -Y, --yaml Enable yaml output + -C, --csv Enable CSV output + -A, --ascii Default output mode, ascii tabular + -L, --hightlight-lines Use alternating background colors for tables + +Sort Mode Flags (mutually exclusive): + -a, --sort-age sort according to age (duration) string + -D, --sort-desc Sort in descending order (default: ascending) + -i, --sort-numeric sort according to string numerical value + -t, --sort-time sort according to time string + +Other Flags: + --completion Generate the autocompletion script for + -f, --config Configuration file (default: ~/.config/tablizer/config) + -d, --debug Enable debugging + -h, --help help for tablizer + -m, --man Display manual page + -V, --version Print program version +``` + Let's take this output: ``` % kubectl get pods -o wide @@ -99,9 +142,6 @@ a dash. If you need to work with `/` characters, you can also use any other separator, for instance: `-R '| |-|'`. -Last but not least tablizer has support for plugins written in -lisp. This feature is expermental yet. Take a look into the manpage -for details. ## Demo diff --git a/TODO.md b/TODO.md index cec4393..b9fdacc 100644 --- a/TODO.md +++ b/TODO.md @@ -6,13 +6,3 @@ - add --no-headers option -### Lisp Plugin Infrastructure using zygo - -Hooks: - -| Filter | Purpose | Args | Return | -|-----------|-------------------------------------------------------------|---------------------|--------| -| filter | include or exclude lines | row as hash | bool | -| process | do calculations with data, store results in global lisp env | whole dataset | nil | -| transpose | modify a cell | headername and cell | cell | -| append | add one or more rows to the dataset (use this to add stats) | nil | rows | diff --git a/cfg/config.go b/cfg/config.go index ffca5ef..424f6ad 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -23,7 +23,6 @@ import ( "regexp" "strings" - "github.com/glycerine/zygomys/zygo" "github.com/gookit/color" "github.com/hashicorp/hcl/v2/hclsimple" ) @@ -32,7 +31,6 @@ const DefaultSeparator string = `(\s\s+|\t)` const Version string = "v1.3.0" const MAXPARTS = 2 -var DefaultLoadPath = os.Getenv("HOME") + "/.config/tablizer/lisp" var DefaultConfigfile = os.Getenv("HOME") + "/.config/tablizer/config" var VERSION string // maintained by -x @@ -89,13 +87,6 @@ type Config struct { NoColor bool - // special case: we use the config struct to transport the lisp - // env trough the program - Lisp *zygo.Zlisp - - // a path containing lisp scripts to be loaded on startup - LispLoadPath string - // config file, optional Configfile string @@ -138,9 +129,6 @@ type Sortmode struct { Age bool } -// valid lisp hooks -var ValidHooks []string - // default color schemes func (conf *Config) Colors() map[color.Level]map[string]color.Color { colors := map[color.Level]map[string]color.Color{ @@ -342,8 +330,6 @@ func (conf *Config) ApplyDefaults() { if conf.OutputMode == Yaml || conf.OutputMode == CSV { conf.NoNumbering = true } - - ValidHooks = []string{"filter", "process", "transpose", "append"} } func (conf *Config) PreparePattern(pattern string) error { diff --git a/cmd/root.go b/cmd/root.go index 19a89ab..057794b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -117,9 +117,6 @@ func Execute() { conf.DetermineColormode() conf.ApplyDefaults() - // setup lisp env, load plugins etc - wrapE(lib.SetupLisp(&conf)) - // actual execution starts here wrapE(lib.ProcessFiles(&conf, args)) }, @@ -187,10 +184,6 @@ func Execute() { rootCmd.MarkFlagsMutuallyExclusive("extended", "markdown", "orgtbl", "shell", "yaml", "csv") - // lisp options - rootCmd.PersistentFlags().StringVarP(&conf.LispLoadPath, "load-path", "l", cfg.DefaultLoadPath, - "Load path for lisp plugins (expects *.zy files)") - // config file rootCmd.PersistentFlags().StringVarP(&conf.Configfile, "config", "f", cfg.DefaultConfigfile, "config file (default: ~/.config/tablizer/config)") diff --git a/cmd/tablizer.go b/cmd/tablizer.go index 04bfd9c..4139129 100644 --- a/cmd/tablizer.go +++ b/cmd/tablizer.go @@ -40,7 +40,6 @@ SYNOPSIS Other Flags: --completion Generate the autocompletion script for -f, --config Configuration file (default: ~/.config/tablizer/config) - -l, --load-path Load path for lisp plugins (expects *.zy files) -d, --debug Enable debugging -h, --help help for tablizer -m, --man Display manual page @@ -344,60 +343,6 @@ CONFIGURATION AND COLORS Colorization can be turned off completely either by setting the parameter "-N" or the environment variable NO_COLOR to a true value. -LISP PLUGINS [experimental] - Tablizer supports plugins written in zygomys lisp. You can supply a - directory to the "-l" parameter containing *.zy files or a single .zy - file containing lisp code. - - You can put as much code as you want into the file, but you need to add - one lips function to a hook at the end. - - The following hooks are available: - - filter - The filter hook works one a whole line of the input. Your hook - function is expected to return true or false. If you return true, - the line will be included in the output, otherwise not. - - Multiple filter hook functions are supported. - - Example: - - /* - Simple filter hook function. Splits the argument by whitespace, - fetches the 2nd element, converts it to an int and returns true - if it s larger than 5, false otherwise. - */ - (defn uselarge [line] - (cond (> (atoi (second (resplit line ` +`))) 5) true false)) - - /* Register the filter hook */ - (addhook %filter %uselarge) - - process - The process hook function gets a table containing the parsed input - data (see "lib/common.go:type Tabdata struct". It is expected to - return a pair containing a bool to denote if the table has been - modified, and the [modified] table. The resulting table may have - less rows than the original and cells may have changed content but - the number of columns must persist. - - transpose - not yet implemented. - - append - not yet implemented. - - Beside the existing language features, the following additional lisp - functions are provided by tablizer: - - (resplit [string, regex]) => list - (atoi [string]) => int - (matchre [string, regex]) => bool - - The standard language is described here: - . - BUGS In order to report a bug, unexpected behavior, feature requests or to submit a patch, please open an issue on github: @@ -472,7 +417,6 @@ Sort Mode Flags (mutually exclusive): Other Flags: --completion Generate the autocompletion script for -f, --config Configuration file (default: ~/.config/tablizer/config) - -l, --load-path Load path for lisp plugins (expects *.zy files) -d, --debug Enable debugging -h, --help help for tablizer -m, --man Display manual page diff --git a/lib/filter.go b/lib/filter.go index 103508f..dadbb06 100644 --- a/lib/filter.go +++ b/lib/filter.go @@ -19,7 +19,6 @@ package lib import ( "bufio" - "fmt" "io" "strings" @@ -144,18 +143,6 @@ func FilterByPattern(conf cfg.Config, input io.Reader) (io.Reader, error) { // so we ignore all lines, which DO match. continue } - - // apply user defined lisp filters, if any - accept, err := RunFilterHooks(conf, line) - if err != nil { - return input, fmt.Errorf("failed to apply filter hook: %w", err) - } - - if !accept { - // IF there are filter hook[s] and IF one of them - // returns false on the current line, reject it - continue - } } lines = append(lines, line) diff --git a/lib/lisp.go b/lib/lisp.go deleted file mode 100644 index 10585ac..0000000 --- a/lib/lisp.go +++ /dev/null @@ -1,319 +0,0 @@ -/* -Copyright © 2023 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 . -*/ - -package lib - -import ( - "errors" - "fmt" - "log" - "os" - "strings" - - "github.com/glycerine/zygomys/zygo" - "github.com/tlinden/tablizer/cfg" -) - -/* -needs to be global because we can't feed an cfg object to AddHook() -which is being called from user lisp code -*/ -var Hooks map[string][]*zygo.SexpSymbol - -/* -AddHook() (called addhook from lisp code) can be used by the user to -add a function to one of the available hooks provided by tablizer. -*/ -func AddHook(env *zygo.Zlisp, name string, args []zygo.Sexp) (zygo.Sexp, error) { - var hookname string - - if len(args) < 2 { - return zygo.SexpNull, errors.New("argument of %add-hook should be: %hook-name %your-function") - } - - switch sexptype := args[0].(type) { - case *zygo.SexpSymbol: - if !HookExists(sexptype.Name()) { - return zygo.SexpNull, errors.New("Unknown hook " + sexptype.Name()) - } - - hookname = sexptype.Name() - - default: - return zygo.SexpNull, errors.New("hook name must be a symbol ") - } - - switch sexptype := args[1].(type) { - case *zygo.SexpSymbol: - _, exists := Hooks[hookname] - if !exists { - Hooks[hookname] = []*zygo.SexpSymbol{sexptype} - } else { - Hooks[hookname] = append(Hooks[hookname], sexptype) - } - - default: - return zygo.SexpNull, errors.New("hook function must be a symbol ") - } - - return zygo.SexpNull, nil -} - -/* -Check if a hook exists -*/ -func HookExists(key string) bool { - for _, hook := range cfg.ValidHooks { - if hook == key { - return true - } - } - - return false -} - -/* - * Basic sanity checks and load lisp file - */ -func LoadAndEvalFile(env *zygo.Zlisp, path string) error { - if strings.HasSuffix(path, `.zy`) { - code, err := os.ReadFile(path) - if err != nil { - return fmt.Errorf("failed to read lisp file %s: %w", path, err) - } - - // FIXME: check what res (_ here) could be and mean - _, err = env.EvalString(string(code)) - if err != nil { - log.Fatal(env.GetStackTrace(err)) - } - } - - return nil -} - -/* - * Setup lisp interpreter environment - */ -func SetupLisp(conf *cfg.Config) error { - // iterate over load-path and evaluate all *.zy files there, if any - // we ignore if load-path does not exist, which is the default anyway - path, err := os.Stat(conf.LispLoadPath) - - if err != nil { - if os.IsNotExist(err) { - // ignore non-existent files - return nil - } - - return fmt.Errorf("failed to stat path: %w", err) - } - - // init global hooks - Hooks = make(map[string][]*zygo.SexpSymbol) - - // init sandbox - env := zygo.NewZlispSandbox() - env.AddFunction("addhook", AddHook) - - if !path.IsDir() { - // load single lisp file - err = LoadAndEvalFile(env, conf.LispLoadPath) - if err != nil { - return err - } - } else { - // load all lisp file in load dir - dir, err := os.ReadDir(conf.LispLoadPath) - if err != nil { - return fmt.Errorf("failed to read lisp dir %s: %w", - conf.LispLoadPath, err) - } - - for _, entry := range dir { - if !entry.IsDir() { - err := LoadAndEvalFile(env, conf.LispLoadPath+"/"+entry.Name()) - if err != nil { - return err - } - } - } - } - - RegisterLib(env) - - conf.Lisp = env - - return nil -} - -/* -Execute every user lisp function registered as filter hook. - -Each function is given the current line as argument and is expected to -return a boolean. True indicates to keep the line, false to skip -it. - -If there are multiple such functions registered, then the first one -returning false wins, that is if each function returns true the line -will be kept, if at least one of them returns false, it will be -skipped. -*/ -func RunFilterHooks(conf cfg.Config, line string) (bool, error) { - for _, hook := range Hooks["filter"] { - var result bool - - conf.Lisp.Clear() - - res, err := conf.Lisp.EvalString(fmt.Sprintf("(%s `%s`)", hook.Name(), line)) - if err != nil { - return false, fmt.Errorf("failed to evaluate hook loader: %w", err) - } - - switch sexptype := res.(type) { - case *zygo.SexpBool: - result = sexptype.Val - default: - return false, fmt.Errorf("filter hook shall return bool") - } - - if !result { - // the first hook which returns false leads to complete false - return result, nil - } - } - - // if no hook returned false, we succeed and accept the given line - return true, nil -} - -/* -These hooks get the data (Tabdata) readily processed by tablizer as -argument. They are expected to return a SexpPair containing a boolean -denoting if the data has been modified and the actual modified -data. Columns must be the same, rows may differ. Cells may also have -been modified. - -Replaces the internal data structure Tabdata with the user supplied -version. - -Only one process hook function is supported. - -The somewhat complicated code is being caused by the fact, that we -need to convert our internal structure to a lisp variable and vice -versa afterwards. -*/ -func RunProcessHooks(conf cfg.Config, data *Tabdata) (*Tabdata, bool, error) { - var userdata Tabdata - - lisplist := []zygo.Sexp{} - - if len(Hooks["process"]) == 0 { - return data, false, nil - } - - if len(Hooks["process"]) > 1 { - fmt.Println("Warning: only one process hook is allowed!") - } - - // there are hook[s] installed, convert the go data structure 'data to lisp - for _, row := range data.entries { - var entry zygo.SexpHash - - for idx, cell := range row { - err := entry.HashSet(&zygo.SexpStr{S: data.headers[idx]}, &zygo.SexpStr{S: cell}) - if err != nil { - return data, false, fmt.Errorf("failed to convert to lisp data: %w", err) - } - } - - lisplist = append(lisplist, &entry) - } - - // we need to add it to the env so that the function can use the struct directly - conf.Lisp.AddGlobal("data", &zygo.SexpArray{Val: lisplist, Env: conf.Lisp}) - - // execute the actual hook - hook := Hooks["process"][0] - - conf.Lisp.Clear() - - var result bool - - res, err := conf.Lisp.EvalString(fmt.Sprintf("(%s data)", hook.Name())) - if err != nil { - return data, false, fmt.Errorf("failed to eval lisp loader: %w", err) - } - - // we expect (bool, array(hash)) as return from the function - switch sexptype := res.(type) { - case *zygo.SexpPair: - switch th := sexptype.Head.(type) { - case *zygo.SexpBool: - result = th.Val - default: - return data, false, errors.New("expect (bool, array(hash)) as return value") - } - - switch sexptailtype := sexptype.Tail.(type) { - case *zygo.SexpArray: - lisplist = sexptailtype.Val - default: - return data, false, errors.New("expect (bool, array(hash)) as return value ") - } - default: - return data, false, errors.New("process hook shall return array of hashes ") - } - - if !result { - // no further processing required - return data, result, nil - } - - // finally convert lispdata back to Tabdata - for _, item := range lisplist { - row := []string{} - - switch hash := item.(type) { - case *zygo.SexpHash: - for _, header := range data.headers { - entry, err := hash.HashGetDefault( - conf.Lisp, - &zygo.SexpStr{S: header}, - &zygo.SexpStr{S: ""}) - if err != nil { - return data, false, fmt.Errorf("failed to get lisp hash entry: %w", err) - } - - switch sexptype := entry.(type) { - case *zygo.SexpStr: - row = append(row, sexptype.S) - default: - return data, false, errors.New("hash values should be string ") - } - } - default: - return data, false, errors.New("returned array should contain hashes ") - } - - userdata.entries = append(userdata.entries, row) - } - - userdata.headers = data.headers - - return &userdata, result, nil -} diff --git a/lib/lisplib.go b/lib/lisplib.go deleted file mode 100644 index d65466a..0000000 --- a/lib/lisplib.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright © 2023 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 . -*/ - -package lib - -import ( - "errors" - "fmt" - "regexp" - "strconv" - - "github.com/glycerine/zygomys/zygo" -) - -func Splice2SexpList(list []string) zygo.Sexp { - slist := []zygo.Sexp{} - - for _, item := range list { - slist = append(slist, &zygo.SexpStr{S: item}) - } - - return zygo.MakeList(slist) -} - -func StringReSplit(env *zygo.Zlisp, name string, args []zygo.Sexp) (zygo.Sexp, error) { - if len(args) < 2 { - return zygo.SexpNull, errors.New("expecting 2 arguments: , ") - } - - var separator, input string - - switch t := args[0].(type) { - case *zygo.SexpStr: - input = t.S - default: - return zygo.SexpNull, errors.New("first argument must be a string") - } - - switch t := args[1].(type) { - case *zygo.SexpStr: - separator = t.S - default: - return zygo.SexpNull, errors.New("second argument must be a string") - } - - sep := regexp.MustCompile(separator) - - return Splice2SexpList(sep.Split(input, -1)), nil -} - -func String2Int(env *zygo.Zlisp, name string, args []zygo.Sexp) (zygo.Sexp, error) { - var number int - - switch t := args[0].(type) { - case *zygo.SexpStr: - num, err := strconv.Atoi(t.S) - - if err != nil { - return zygo.SexpNull, fmt.Errorf("failed to convert string to number: %w", err) - } - - number = num - - default: - return zygo.SexpNull, errors.New("argument must be a string") - } - - return &zygo.SexpInt{Val: int64(number)}, nil -} - -func RegMatch(env *zygo.Zlisp, name string, args []zygo.Sexp) (zygo.Sexp, error) { - if len(args) != 2 { - return zygo.SexpNull, fmt.Errorf("argument must be , ") - } - - arguments := []string{} - - for _, arg := range args { - switch t := arg.(type) { - case *zygo.SexpStr: - arguments = append(arguments, t.S) - default: - return zygo.SexpNull, errors.New("argument must be a string") - } - } - - reg := regexp.MustCompile(arguments[0]) - - return &zygo.SexpBool{Val: reg.MatchString(arguments[1])}, nil -} - -func RegisterLib(env *zygo.Zlisp) { - env.AddFunction("resplit", StringReSplit) - env.AddFunction("atoi", String2Int) - env.AddFunction("matchre", RegMatch) -} diff --git a/lib/parser.go b/lib/parser.go index 9d44afb..40fe69b 100644 --- a/lib/parser.go +++ b/lib/parser.go @@ -145,18 +145,6 @@ func parseTabular(conf cfg.Config, input io.Reader) (Tabdata, error) { continue } - // apply user defined lisp filters, if any - accept, err := RunFilterHooks(conf, line) - if err != nil { - return data, fmt.Errorf("failed to apply filter hook: %w", err) - } - - if !accept { - // IF there are filter hook[s] and IF one of them - // returns false on the current line, reject it - continue - } - idx := 0 // we cannot use the header index, because we could exclude columns values := []string{} for _, part := range parts { @@ -214,17 +202,6 @@ func PostProcess(conf cfg.Config, data *Tabdata) (*Tabdata, bool, error) { modified = true } - // apply user defined lisp process hooks, if any - userdata, changed, err := RunProcessHooks(conf, data) - if err != nil { - return data, false, fmt.Errorf("failed to apply filter hook: %w", err) - } - - if changed { - data = userdata - modified = true - } - if conf.Debug { repr.Print(data) } diff --git a/tablizer.1 b/tablizer.1 index 86f9f42..49b640e 100644 --- a/tablizer.1 +++ b/tablizer.1 @@ -178,7 +178,6 @@ tablizer \- Manipulate tabular output of other programs \& Other Flags: \& \-\-completion Generate the autocompletion script for \& \-f, \-\-config Configuration file (default: ~/.config/tablizer/config) -\& \-l, \-\-load\-path Load path for lisp plugins (expects *.zy files) \& \-d, \-\-debug Enable debugging \& \-h, \-\-help help for tablizer \& \-m, \-\-man Display manual page @@ -541,63 +540,6 @@ the \f(CW\*(C`\-L\*(C'\fR parameter). .PP Colorization can be turned off completely either by setting the parameter \f(CW\*(C`\-N\*(C'\fR or the environment variable \fB\s-1NO_COLOR\s0\fR to a true value. -.SH "LISP PLUGINS [experimental]" -.IX Header "LISP PLUGINS [experimental]" -Tablizer supports plugins written in zygomys lisp. You can supply a -directory to the \f(CW\*(C`\-l\*(C'\fR parameter containing \fB*.zy\fR files or a single -\&.zy file containing lisp code. -.PP -You can put as much code as you want into the file, but you need to -add one lips function to a hook at the end. -.PP -The following hooks are available: -.IP "\fBfilter\fR" 4 -.IX Item "filter" -The filter hook works one a whole line of the input. Your hook -function is expected to return true or false. If you return true, the -line will be included in the output, otherwise not. -.Sp -Multiple filter hook functions are supported. -.Sp -Example: -.Sp -.Vb 7 -\& /* -\& Simple filter hook function. Splits the argument by whitespace, -\& fetches the 2nd element, converts it to an int and returns true -\& if it s larger than 5, false otherwise. -\& */ -\& (defn uselarge [line] -\& (cond (> (atoi (second (resplit line \` +\`))) 5) true false)) -\& -\& /* Register the filter hook */ -\& (addhook %filter %uselarge) -.Ve -.IP "\fBprocess\fR" 4 -.IX Item "process" -The process hook function gets a table containing the parsed input -data (see \f(CW\*(C`lib/common.go:type Tabdata struct\*(C'\fR. It is expected to -return a pair containing a bool to denote if the table has been -modified, and the [modified] table. The resulting table may have less -rows than the original and cells may have changed content but the -number of columns must persist. -.IP "\fBtranspose\fR" 4 -.IX Item "transpose" -not yet implemented. -.IP "\fBappend\fR" 4 -.IX Item "append" -not yet implemented. -.PP -Beside the existing language features, the following additional lisp -functions are provided by tablizer: -.PP -.Vb 3 -\& (resplit [string, regex]) => list -\& (atoi [string]) => int -\& (matchre [string, regex]) => bool -.Ve -.PP -The standard language is described here: . .SH "BUGS" .IX Header "BUGS" In order to report a bug, unexpected behavior, feature requests diff --git a/tablizer.pod b/tablizer.pod index d8b36ce..90fd331 100644 --- a/tablizer.pod +++ b/tablizer.pod @@ -39,7 +39,6 @@ tablizer - Manipulate tabular output of other programs Other Flags: --completion Generate the autocompletion script for -f, --config Configuration file (default: ~/.config/tablizer/config) - -l, --load-path Load path for lisp plugins (expects *.zy files) -d, --debug Enable debugging -h, --help help for tablizer -m, --man Display manual page @@ -384,67 +383,7 @@ the C<-L> parameter). Colorization can be turned off completely either by setting the parameter C<-N> or the environment variable B to a true value. -=head1 LISP PLUGINS [experimental] -Tablizer supports plugins written in zygomys lisp. You can supply a -directory to the C<-l> parameter containing B<*.zy> files or a single -.zy file containing lisp code. - -You can put as much code as you want into the file, but you need to -add one lips function to a hook at the end. - -The following hooks are available: - -=over - -=item B - -The filter hook works one a whole line of the input. Your hook -function is expected to return true or false. If you return true, the -line will be included in the output, otherwise not. - -Multiple filter hook functions are supported. - -Example: - - /* - Simple filter hook function. Splits the argument by whitespace, - fetches the 2nd element, converts it to an int and returns true - if it s larger than 5, false otherwise. - */ - (defn uselarge [line] - (cond (> (atoi (second (resplit line ` +`))) 5) true false)) - - /* Register the filter hook */ - (addhook %filter %uselarge) - -=item B - -The process hook function gets a table containing the parsed input -data (see C. It is expected to -return a pair containing a bool to denote if the table has been -modified, and the [modified] table. The resulting table may have less -rows than the original and cells may have changed content but the -number of columns must persist. - -=item B - -not yet implemented. - -=item B - -not yet implemented. - -=back - -Beside the existing language features, the following additional lisp -functions are provided by tablizer: - - (resplit [string, regex]) => list - (atoi [string]) => int - (matchre [string, regex]) => bool - -The standard language is described here: L. =head1 BUGS