psv

package module
v0.4.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2026 License: MIT Imports: 13 Imported by: 0

README

PSV - Pipe Separated Values

Further Information

Plain Text Tables

PSV (Pipe Separated Values) is a go module and command line program for reading and writing plain text tables of data.

The PSV format used by this project is similar in concept to Comma-Separated Values (CSV), Tab-Separated Values (TSV) or Delimiter-Separated Values (DSV), but with the distinction that additional spaces are used so that that

  • all rows have the same number of columns
  • and all columns align vertically

PSV tables are deliberately human readable, while also still being machine readable.

For Example:

Some data, as CSV:

name,score,favourite natural constant
Alexander,3,299_792_458 m/s
Tim,5,3.14159
Johannes,17,6.022e23 per mol

... and the same data as formatted by psv (with some additional formatting hints):

|   name    | score | favourite natural constant |
| --------- | ----: | -----------.-------------^ |
| Tim       |     5 |           3.14159          |
| Alexander |     3 | 299_792_458 m/s            |
| Johannes  |    17 |           6.022e23 per mol |

PSV tables are also used by Markdown, with some minor differences.

Intended Use Cases

TODO: 2026-01-22 add links to examples of each intended use case

  • cleaning up existing tables of data
  • editing markdown tables
  • editing tables of test cases for data-driven testing (in golang code)
  • producing tables of data from command line programs
  • editing data tables in cucumber's BDD scenarios

TODO: 2025-03-17 consolidate with list above

Index

Goals

See also: project requirements

  • parse tables without rulers
  • generate tabled with aligned columns (without rulers)
  • parse and generate tables with a prefix (e.g. // or # for tables in code comments)
  • parse and generate simple horizontal rulers
    • rulers without padding
    • rulers with padding
    • rulers with horizontal characters - or =
    • rulers with vertical characters | or +
  • rulers are not included in a table's data rows
  • column alignment
    • parse and generate rulers with alignment hints
      • :- left
      • -: right
      • :: or -:- center
      • . numeric
      • .. semver version
    • align columns
      • left
      • right
      • center
      • numerically (right aligned, but numbers centered around their decimal point)
      • versions (left aligned, aligned to the right side of the major version number)
  • sorting of table rows
    • parse and generate rulers with sorting hints
      • ^ sort ascending
      • v sort descending
      • with order priority 0 ... 7
    • rows are not sorted between sections separated by rulers
      • column header row always stays on top
    • string comparisons
    • locale-specific comparisons
    • numeric comparisons
    • version comparisons
  • all data is stored as utf-8 text
    • no special numerical formats - numbers are just text
      • but floats are used internally for sorting
    • no special 'date' or 'time' formats
  • allow escaping of special characters
    • \ can be used to include |, \ or space in data
    • quotes are explicitly not supported as they are hard for humans to get right
    • | " " | can be used, however ...
      • psv does not care if the quotes are paired
      • if the code that receives the data expects the quotes, it can remove them and keep whatever is between them
      • e.g.:
        • | " | " | is be a row with two value, i.e. {","}
        • | " \| " | is a row with one value, i.e. {" | "} (including the quotes)
        • | " \| | is a row with one value, i.e. {" |}
        • | " | | is a row with two value, i.e. {", (empty string)}
  • full "round trip" support
    • all generated PSV tables should be parsable without loss of information
      • TODO: 2025-03-17 formatting hints are lost if the first ruler is not directly after the first row
    • non-PSV data should be left unchanged
  • it should be possible to generate documents with multiple tables
  • it should be possible to parse incorrectly formatted tables
    • incosistent row lengths are harmonized to the length of the longest row in the table
    • adjacent column separators
    • missing column headers
    • multiple horizontal ruler lines
    • empty rows
  • it should be possible to remove empty columns from a table
  • it should be possible to clear all the data from specific columns (e.g. a wip or todo column)
  • it should be possible to add columns to a table

Progress

doc/progress.svg

doc/progress.gv

User Journey Event Maps

doc/use_case_events.svg

doc/use_case_events.gv

PSV Document Structure

  • parsing text always returns a Document
  • all tables in a document may be aligned with each other by enabling the align_all option TODO: 2025-03-17 add link to documentation
  • a ruler after the first row of data in a table is special. It can …
    • specify left,right,center,numeric data alignment per column
    • specify that a column should be sorted before encoding
    • all other rulers are for decoration purposes only, and any additional markers within them will be ignored

PSV Table Formatting Rules

  • PSV is encoded in UTF-8
  • rulers
    • must begin with a | (ASCII code 124, Unicode U+007c) or + (ASCII code 43, Unicode U+002b)
    • must contain at least one - (ASCII code 45, Unicode U+002d) or = (ASCII code 61, Unicode U+003d)
    • may contain any number of spaces
      • if a space appears before the first - or =, then the ruler will be padded, otherwise, it will be unpadded
    • may contain special formatting hints
    • Examples:
      • | -
      • +-------+--------+
      • | ==== | | | =
  • data rows
    • must begin with a | (ASCII code 124, Unicode U+007c)
    • new columns are introduced by further | characters (one | per column)
      • a trailing | at the end of a data row is optonal
      • empty columns at the end of a line are always truncated
    • empty columns inside a table may be removed by enabling the squash-empty option TODO: 2025-03-17 add link to documentation
    • UTF-8 whitespace surrounding |s is ignored
    • any other UTF-8 characters are considered data
      • whitespace within data is retained verbatim
      • whitespace and | can be included as data by preceding them with a \ (ASCII code 92, Unicode U+005c)
    • \n (ASCII code 10, Unicode U+000a) separates data rows
      • \r (ASCII code 13, Unicode U+000a) is treated as whitespace, and is thus ignored
      • a trailing \n at the end of a file is not required
    • a line consisting of just a single | is treated as an empty row
      • the row is included in the tables data rows
      • the value of all fields in the row is the empty string
  • any text lines which do not begin with a | are retained verbatim, but are not part of a PSV table
    • non-table rows separate tables
    • each table is formatted independently

Introductory examples

Creating PSV Tables Manually

To write a PSV table, simply start a line with with a | and some text.

Don't worry about spacing or indentation, the psv tool will fix that in a minute.

For example, the following, deliberately sloppily entered table:

    |A| B     |     A   anb B
| -
  | false | false | false
|false| true        | false ||||||
  |true       |       false | false
    |true   | true  | true    | yay

will be turned into this:

    | A     | B     | A   anb B |     |
    | ----- | ----- | --------- | --- |
    | false | false | false     |     |
    | false | true  | false     |     |
    | true  | false | false     |     |
    | true  | true  | true      | yay |

with a single call to psv (in this case, the vim [^1] command: vip!psv [^2]).

Some things of note:

  • all table rows are indented to align with the first row
  • all rows have been trimmed to the same number of columns
  • all columns are vertically aligned
  • a trailing | is always included on every data row
  • the horizontal ruler has been resized to match the width of each column
  • the contents of the table has not changed
    • e.g. the extra spacing between A and B was retained

(see ruler formatting)

[^1]: You don't have to use vim! psv can be used from any editor or shell script that lets you pipe text through shell commands.

[^2]: which translates to: - v start a visual selection ... - i select everything in ... - p the current paragraph - !psv and replace the current selection with whatever psv makes of it

Using psv Tables Programmatically

REMOVE: 2025-03-17 cosolidate with other examples

psv Tables can also help improve the readibility of test data.

Here is an example of one of psv's actual test suites, (numbers_test.go):

func TestNumbers(t *testing.T) {
	is := is.New(t)

	testCases := table.New(table.FromString(`
        |     input      | numbers | versions |                               notes                                |
        | -------------- | ------- | -------- | ------------------------------------------------------------------ |
        |                |         |          |                                                                    |
        | abc            |         |          |                                                                    |
        | 1              | 1       | 1        |                                                                    |
        | +1             | 1       | 1        |                                                                    |
        | -1             | -1      | 1        |                                                                    |
        | 1 1            | 1 1     | 1        | only the first '[0-9][.]' or the last number are used for versions |
        | 1 2            | 1 2     | 2        |                                                                    |
        | 1.1            | 1.1     | 1 1      | IEEE floating point problem?                                       |
        | 1.2            | 1.2     | 1 2      |                                                                    |
        | 1.2e3          | 1200    | 1 2 3    |                                                                    |
        | -1.2e-2        | -0.012  | 1 2 2    |                                                                    |
        | 1_000_000      | 1000000 | 0        | '_' may be used to group digits                                    |
        | 1,000,000      | 1 0 0   | 0        | ',' is ambiguous                                                   |
        | v0.1           | 0.1     | 0 1      | version                                                            |
        | v0.1.2-alpha   | 0 1 2   | 0 1 2    | version                                                            |
        | v0.1.2.3-alpha | 0 1 2 3 | 0 1 2 3  | version                                                            |
        | -------------- | ------- | -------- | ------------------------------------------------------------------ |
        | a1b2c3d        | 1 2 3   | 3        | embedded numbers                                                   |
        | a 1.2 b 3.4 c  | 1.2 3.4 | 1 2 3 4  |                                                                    |
        | a1.2b3.4c      | 1.2 3.4 | 1 2 3 4  |                                                                    |
        | -------------- | ------- | -------- | ------------------------------------------------------------------ |
        | 0x1            | 1       | 1        |                                                                    |
        | 0x10           | 16      | 10       |                                                                    |
        | 0x.8           | 0.5     | 8        |                                                                    |
        | 0x2p4          | 32      | 4        | 2 << 4 == 1<<5                                                     |
        | -0x2p4         | -32     | 4        | 2 << 4 == 1<<5                                                     |
        | 0xe3           | 227     | 3        | 'e' is a valid hex digit, no exponent                              |
        | -------------- | ------- | -------- | ------------------------------------------------------------------ |
        | -.             |         |          | no digits                                                          |
        | -e3            | 3       | 3        | no digits in mantissa, '-e' skipped                                |
        | -e-1           | -1      | 1        |                                                                    |
        | 0x0x0x         | 0       | 0        | hugs and kisses? splits to: (0x0)(x)(0x)                           |
        `))

	for _, tc := range testCases.DataRows() {
		input := tc.Field("input")
		notes := tc.Field("notes")
		t.Run(input, func(t *testing.T) {

			if skip := tc.Field("skip"); skip != "" {
				t.Skip(skip, notes)
			}

			// fmt.Printf("testing: %q - %s\n", input, notes)

			var wantNumbers []float64
			for _, field := range strings.Fields(tc.Field("numbers")) {
				n, _ := strconv.ParseFloat(field, 64)
				wantNumbers = append(wantNumbers, n)
			}

			var wantInts []float64
			for _, field := range strings.Fields(tc.Field("versions")) {
				n, _ := strconv.ParseFloat(field, 64)
				wantInts = append(wantInts, n)
			}

			gotNumbers := sort.Numbers(input)
			gotInts := sort.VersionNumbers(input)

			if notes != "" {
				notes += " - " + notes
			}
			is.Equal(gotNumbers, wantNumbers, "%q floating point numbers %v%s", input, wantNumbers, notes)
			is.Equal(gotInts, wantInts, "%q integer numbers %v%s", input, wantInts, notes)
		})
	}
}

Detailed Description

REFACTOR: 2025-03-17 this seems to be repetition

  • explain "what" psv does - not why

psv reads, formats and writes simple tables of data in text files.

In doing so, psv focuses on human readibility and ease of use, rather than trying to provide a loss-less, ubiquitous, machine-readable data transfer format.

The same could be said of markdown, and indeed, psv can be used to generate github-style markdown tables that look nice in their markdown source code, and not just after they have been converted to HTML by the markdown renderer.

Another intended use case is data tables in Gherkin files, which are a central component of Behaviour Driven Development (BDD).

Main Features

  • normalisation of rows and columns, so that every row has the same number of cells
  • automatic table indentation and column alignment
  • the ability to automatically draw horizontal separation lines, called rulers
  • the ability to re-format existing tables, while leaving lines which "do not look like table rows" unchanged
  • a simple way to read data from tables into go programs via the psv go package
  • the (limited) ability to sort table data
    • without interfering with the rest of the table's formatting
  • any table produced by psv can be re-formatted by psv without any loss of information
  • and more ...
Column Alignment

The main reason for creating psv was to vertically align columns of text in plain-text tables, such as markdown tables (see: Tables - markdown guide).

In contrast tools like the ones mentioned in the markdown guide, I find it much more practical to edit tables in-place.

psv will vertically align any consecutive group of lines beginning with a | (pipe) character, so that all of the pipe characters align nicely. Additionally, missing pipes will be added and extraneous pipes removed as neeeded.

psv works like many unix utilities, in short:

  • without options, input is taken from STDIN and output is sent to STDOUT
  • with one or more file names, the files are read and their output is sent to STDOUT
  • with the -i option, the files are modified in-place and no output is produced at all
Example

Create a file called input.txt with the content:

A simple table:

    | Syntax | Description | Use |
    | ------------- | ---
| Header | Title | catching attention
    |Paragraph
    | | Body | || |     ||||

The table should have all its '|' characters aligned.

And run the command:

psv < input.txt > output.txt

output.txt should now look like this:

A simple table:

    |  Syntax   | Description |
    | --------- | ----------- |
    | Header    | Title       |
    | Paragraph |             |
    |           | Body        |

The table should have all its '|' characters aligned.

You should see that...

  • each line of the table now has the same number of columns
  • all pipe characters are vertically aligned
  • the horizonal lines have been extended / shrunk / added / removed to fit the data in the table
  • the pipe character in the last line was not included in the table
Horizontal Rulers

One of the main features of psv is the way that it supports horizontal rulers.

These serve 2 purposes:

  • visual separation between sections of a table
  • as a holder of column formatting and sorting hints

How do I create a ruler?

The easiest possible ruler is simply a line containing only |- or | - (with a space).

These rulers simply create a line of dashes as wide as the table. The |- pattern leaves the lines unpadded, whereas | - adds a space around each column separator.

Formatting Hints

psv also supports additional formatting hints, such as left/right alignment or sorting information, to help make the resulting tables more aesthetically pleasing.

The available hints are:

Hint Description psv markdown parsing rules
:- left aligned (default) yes yes : must be the first non-whitespace character
-: right aligned yes yes : must be the last non-whitespace character
:``: centered yes yes a column with 2 or more :s will be centered
-:- centered yes no - use :: : must have at least one - or = on either side
. numerically aligned yes no . can be placed anywhere
.. version aligned yes no a column with 2 or more .s will be sorted by version
^ + optional 0..9 sort, ascending yes no ^ can be placed anywhere
v + optional 0..9 sort, descending yes no v can be placed anywhere

Note psv tables with sorting or numerical hints cannot be used in markdown documents, as markdown does not support the ., ^ or v hints.

Formatting hints may be placed in any one of a table's horizontal rulers. - only the first ruler with hints is used to format a table - formatting hints are re-produced when re-formatting a psv table

Formatting Example

In this table, without formatting hints, ...

- the first row contains the column names
- all columns are left-aligned
| default   | left  | right      | center    | numeric     | version        | sort key |
| abc       | def   | hij        | klm       | 123         | v1.2.3         | d        |
| random    | stuff | neat       | boring    | .123        | v100.200.300   | b        |
| fish      | cat   | dog        | turtle    | 12.34       | v10.20.30      | a        |
| spaghetti | rice  | vegetables | take away | 1234.4567e5 | 0.0.1-prealpha | c        |

A ruler can added, separating the 1st row from the data rows:

| default | left  | right | center | numeric | version      | sort key |
| -|:- |-:|-:-|.|..|^
| abc     | def   | hij   | klm    | 123     | v1.2.3       | d        |

and run psv, we get:

|  default  | left  |   right    |  center   |   numeric   |      version      | sort key |
| --------- | :---- | ---------: | ----:---- | ----.------ | ----..----------- | -------^ |
| fish      | cat   |        dog |  turtle   |   12.34     |  v10.20.30        | a        |
| random    | stuff |       neat |  boring   |     .123    | v100.200.300      | b        |
| spaghetti | rice  | vegetables | take away | 1234.4567e5 |    0.0.1-prealpha | c        |
| abc       | def   |        hij |    klm    |  123        |   v1.2.3          | d        |
Sorting

The addition of ^ or v to one or more columns will cause psv to sort the table's rows according to the data in the marked columns.

When combined with a . (numeric alignment), psv converts the data in the column to a floating point numbers for comparison.

Sorting hexadecimal numbers (beginning with 0x, in upper or lower case) and numbers written with an exponent (e.g. 1.2e5 == 120_000) are also supported.

Note the use of commas in numerical data is not supported, to avoid confusion with environments that use a , instead of a . to represent a decimal point.

The ^ and v hints may also be followed by a number between 0 (default) and 7 to indicate a column's priority when comparing two rows.

Sorting hints do not need to be unique. All columns with the same priority will be compared, from left to right, before using columns with lower priority if no difference was found between higher priority columns.

e.g.:

- compare all columns with priory 1
- compare all columns with priory 2
- ...
- compare all columns with priory 7
- compare all columns with priory 0 or no priority
Sorting Example

Note psv tables with sorting hints cannot be used in markdown documents, as markdown does not support the ^ or v hints.

Let's assume we have some some scientific results, which we haphazardly records in the order they were reported:

| row | sample | size | temperature |   rating   |
| --- | ------ | ---- | ----------- | ---------- |
| 1   | a      | 4    | 2e2         | b - ok     |
| 2   | b      | 1    | 25          | a - great  |
| 3   | a      | 3    | 30          | a - great  |
| 4   | b      | 2    | 2e1         | b - ok     |
| 5   | a      | 2    | 20          | c - failed |
| 6   | a      | 1    | 2e3         | a - great  |
| 7   | b      | 4    | 20          | b - ok     |
| 8   | b      | 4    | 2e-1        | a - great  |

In order to sort the table by rating, temperature and then size (while ignoring the row and sample columns), we can - add ^1 to the rating column to sort by rating first - add ^2 to the temperature column to sort by temperature second - and ^ (no number means) to the size column to sort by size last

| row | sample | size | temperature |   rating   |                        comparisons                         |
| --- | ------ | --.v | --------.^2 | ----:---^1 | ---------------------------------------------------------- |
| 8   | b      |    4 |        2e-1 | a - great  | rating: `a` = `a`, temp:  `0.2` <   `25.0`                 |
| 2   | b      |    1 |          25 | a - great  | rating: `a` = `a`, temp: `25.0` <   `30.0`                 |
| 3   | a      |    3 |          30 | a - great  | rating: `a` = `a`, temp: `30.0` < `2000.0`                 |
| 6   | a      |    1 |         2e3 | a - great  | rating: `a` < `b`                                          |
| 7   | b      |    4 |          20 |   b - ok   | rating: `b` = `b`, temp: `20.0` < `200.0`                  |
| 4   | b      |    2 |         2e1 |   b - ok   | rating: `b` = `b`, temp: `20.0` =  `20.0`, size: `3` > `2` |
| 1   | a      |    4 |         2e2 |   b - ok   | rating: `b` < `c`                                          |
| 5   | a      |    2 |          20 | c - failed |                                                            |

Detailes Use Cases

Reading data from PSV tables into code

TODO: 2025-03-17 relocate

input := `

Winners:
	| name  | score | change |
	| ----- | ----v | -----. |
	| Alice | 42    |     +0 |
	| Bob   | 23    |     -2 |

Most Improved:
	| name  | score | change |
	| ----- | ----- | ----.v |
	| Jim   | 24    |    +10 |
	| Cindy | 26    |     +6 |
`

// read the input
doc := &psv.Document{}
doc.UnmarshalText([]byte(input))

// the input may contain any number of tables
// loop through each table looking for 'interesting' data
for _, item := range doc.Items() {

    fmt.Println(grep(item.Text.Lines,":"))

	// FieldByNameFunc provides a convenient name => column mapping
	value := table.FieldByNameFunc()

	// DataRows() returns all rows except the first row (assumed to be a header)
	// AllRows() returns all rows including the first row.
	for r, row := range table.DataRows() {
		fmt.Printf("  %v points were awarded to %q\n",
			value(row, "score"),
			value(row, "name"),
		)
	}
}

Output

Winners:
  42 points were awarded to "Alice"
  23 points were awarded to "Bob"
Most Improved:
  24 points were awarded to "Jim"
  26 points were awarded to "Cindy"
Generating PSV tables from code

TODO: 2025-03-17 relocate

doc := &psv.Document{}
doc.AppendRow([]string{"name","score"})
doc.AppendRow([]string{"Alice","3"})
doc.AppendRow([]string{"Bob","2"})
ouput, _ := doc.MarshalText()
fmt.Println(ouput)
| name  | score |
| Alice | 3     |
| Bob   | 2     |
Round-Trip re-formatting of existing PSV tables via the psv command

TODO: 2025-03-17 relocate

% cat input.txt
| name | score
| ---
    | Alice |       3
|Bob|2
% psv < input.txt > output.txt
% cat output.txt
| name  | score |
| ----- | ----- |
| Alice | 3     |
| Bob   | 2     |

Specification

A semi-formal specification is available as a separate, RFC-like document.

What about RFC 4180 - CSV MIME Type?

psv deliberately does not fulfill RFC 4180, as the two specification have very different goals.

  • psv is intended for presenting tabular data in a human-friendly form
  • RFC 4180 is intended for encoding and transmitting data between programs
Comparison of PSV with RFC 4180
Feature psv RFC 4180 Description
new lines native CRLF psv does not prefer any particular line separator
final new line yes optional psv will accept a final row without a new line, but will always terminate the final row with a new line
header row optional optional psv and RFC 4180 both allow an optional header row that provides column names
horizontal rulers yes no psv allows the use of decorative horizontal rulers to separate logical groups within a table
separator pipe comma vertical lines are more visualy distinctive
trailing separator yes no psv prioritises visual clarity over document size
padded values yes no psv aligns columns visually for human consumption, which requires the addition/removal of leading/trailing spaces
embedded spaces yes yes psv preserves space within a value
all rows have same width yes yes psv and RFC 4180 both recommend rows have the same number of columns
quoted values no yes psv tables reduce cognitive load by only using backslashes for escaping
multi-line values no yes psv is not intended to be a lossless format for any data, but a visual representation for humans
Not Supported

psv is not intended to replace spreadsheets etc 😄

Among a myriad of other non-features, the following are definitely not supported by psv:

  • the inclusion of | characters in a cell's data
  • multi-line cell data
  • any kind of cell merging or splitting
  • sorting of complex data formats, including:
    • date and/or timestamps (unless they are in ISO-8601 format, which sorts nicely)
    • signed numbers (+ and - signs confuse go's collators 😦)
    • floating point numbers
    • scientific notation
    • hexadecimal notation
  • ...
Design Principles
  • self contained
    • psv is a single go binary with no external dependencies
    • the psv go package is a single package, also with no external dependecies other than go's standard packages
      • exception: I do include another package of mine to provide simplified testing with meaningful success and error messages.
    • all psv actions occur locally (no network access required)
  • non-destructive
    • if psv doesn't know how to interperet a line of text, the text remains unchanged
      • only data rows (lines beginning with a |) and rulers are re-formatted, all other lines remain unchanged
  • idempotent
    • any table generated by psv can also be read be psv
    • running a formatted table through psv again must not change the table in any way
  • easy of use
    • normal use should not require any configuration or additional parameters

Markdown Support

Markdown's table format is a subset of the formatting options provided by psv.

Specifically, in contrast to psv, markdown imposes the following restrictions:

  • Markdown tables MUST begin with a header row of column names
  • Markdown tables MUST have exactly one ruler as their second line
  • Markdown rulers MUST have the same number of columns as the header row above them
  • Markdown rulers TYPICALLY only allow |, - and space in rulers
    • Markdown does not generally accept the use of + as a vertical character
    • Markdown does not generally accept the use of = as a horizontal character
  • Markdown rulers MAY contain the alignment hints :- (left-aligned), -: (right-aligned) or :-: (centered)
    • Markdown has no hints for numeric, or version alignment
    • Markdown has no hints for sorting
  • Markdown tables MUST NOT have embedded rulers anywhere else
  • Markdown does not allow \| to escape pipe characters
    • instead you have to use the HTML entity &#124;
User Documentation
Developer Documentation

Installation

psv consists of two components: the psv command and the psv go package.

To use the psv command, you only need the psv binary in your PATH, e.g. ~/bin/psv (see binary installation below).

If you don't want to install "a binary, downloaded from the 'net", you can download the source, (inspect it 😄), and build your own version.

Installation From Source
Prerequisites
  • go 1.18 or later
  • make (optional, but recommended)
Installing via go install
go install codeberg.org/japh/psv/...@latest
Manual Build Steps

Clone the psv git repository and use make to build, test and install psv in your $GOBIN directory (typically $GOPATH/bin or ~/Go/bin)

% git clone -o codeberg https://codeberg.org/japh/psv
% cd psv
% make install
% psv -v
Binary Installation

Note currently only available for darwin amd64 (64-bit Intel Macs)

  • download the latest psv.gz from https://codeberg.org/japh/psv/releases
  • verify psv.gz with gpg --verify psv.gz.asc
  • compare psv.gz's checksums against those provided with shasum -c psv.gz.sha256
  • unpack psv.gz with gunzip psv.gz
  • copy psv to any directory in your $PATH, or use it directly via ./psv
  • don't forget to check that it is executable, e.g. chmod +x psv

Now you can use the psv command...

Using The psv Package In Go Projects
Prerequisites
  • go 1.18 or later

To use psv in your go project, simply import codeberg.org/japh/psv and go mod tidy will download it, build it and make it available for your project.

See the psv package documentation for the API and code examples.

Alternatives

  • csv, tsv and delimeter-separated-values tables | wikipedia

    • generally, psv tables are just a single type of delimeter separated values format
  • ASCII Table Writer

    • go package for creating tables of almost any form
    • more traditional table.SetHeader, table.SetFooter() interface
    • more features (incl. colors)
    • does not read tables
      • no good for defining test cases etc in code
  • psv-spec (unrelated project!)

    • an attempt to standardize a CSV replacement using pipes as the delimiter
    • focuses on electronic data transfers
    • does not provide a tabular layout
    • escaping just |, \, \n and \r is nice
      • but does not allow for whitespace quoting
      • future: | " " | could be used by psv to represent a space

References

Copyright 2022-2025 Stephen Riehm japh-codeberg@opensauce.de

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultProfile = "psv"
View Source
var (
	ErrUnknownProfile = errors.New("unknown profile")
)
View Source
var Profiles = profile.List{

	{
		Name: "none",
	},

	{
		Name:          "psv",
		FlagsMask:     column.AllFlagsMask,
		CollapseEmpty: true,
		Left:          profile.Marker{Mark: ":", Placement: profile.PlaceLeft},
		Right:         profile.Marker{Mark: ":", Placement: profile.PlaceRight, NeedLine: true},
		Center:        profile.Marker{Mark: ":", Placement: profile.PlaceCenter, NeedLine: true},
		Number:        profile.Marker{Mark: ".", Placement: profile.PlaceFloatRight},
		Version:       profile.Marker{Mark: "..", Placement: profile.PlaceFloatLeft},
	},

	{
		Name:           "markdown",
		MinFill:        3,
		RulerPositions: []int{1},
		FlagsMask:      column.AlignFlagsMask,
		Left:           profile.Marker{Mark: ":", Placement: profile.PlaceLeft, NeedLine: true},
		Right:          profile.Marker{Mark: ":", Placement: profile.PlaceRight, NeedLine: true},
		Center:         profile.Marker{Mark: ":", Placement: profile.PlaceOuter, NeedLine: true},
		Replace: map[column.Flags]column.Flags{
			column.AlignNumberFlag:  column.AlignRightFlag,
			column.AlignVersionFlag: column.AlignLeftFlag,
		},
	},

	{
		Name:           "gherkin",
		CollapseEmpty:  true,
		RulerPositions: []int{},
	},
}

Functions

func Replace added in v0.4.16

func Replace(s, old, new string) string

Replace returns a copy of the string s with all non-overlapping instances of old replaced by new.

Replace just calls strings.ReplaceAll

func Unquote added in v0.4.16

func Unquote(s, quotes string) string

Unquote returns a copy of a string with a single pair of identical characters removed from the start and end of the original string.

Purpose:

  • allow data with leading or trailing whitespace to be stored in psv tables, e.g. " "
  • Unquote() is intended to be used on individual data strings
  • quoted strings cannot be used to prevent pipe characters from being used as column separators! i.e. "|" will not work! Use \| instead

Example:

t := psv.TableFromString(`
          | string | unicode |
          | ------ | ------- |
          | " "    | 0x20    |
          `)
for _, row := range t.DataRows() {
   s := psv.Unquote(row.Field("string"),`"`)  // remove quotes before processing
   ...
}

Types

type Document added in v0.4.16

type Document = document.Document // alias of internal document.Document

func NewDocument added in v0.4.16

func NewDocument() *Document

type Layout added in v0.4.16

type Layout = layout.Layout // alias of internal layout.Layout

func NewLayout added in v0.4.16

func NewLayout(opts ...LayoutOption) (*Layout, error)

type LayoutOption added in v0.4.16

type LayoutOption func(*Layout) error

func WithCommandArgs added in v0.4.16

func WithCommandArgs(args []string) LayoutOption

func WithLocaleTag added in v0.4.16

func WithLocaleTag(localeTag string) LayoutOption

func WithPrefixPattern added in v0.4.16

func WithPrefixPattern(pattern string) LayoutOption

func WithProfile added in v0.4.16

func WithProfile(name string) LayoutOption

type Ruler

type Ruler = ruler.Ruler // characters to use for horizontal lines

func NewRulerFromTemplate added in v0.4.16

func NewRulerFromTemplate(template string) Ruler

type Table

type Table = table.Table // alias of internal table.Table

func NewTable

func NewTable() *Table

Directories

Path Synopsis
cmd
psv command
internal
cli
data
data package is used to encode/decode data within psv tables
data package is used to encode/decode data within psv tables
log
row
Data Encoding and Decoding entails the protection of data characters from corruption after being rendered as a PSV table, and restoring the original data from a PSV table.
Data Encoding and Decoding entails the protection of data characters from corruption after being rendered as a PSV table, and restoring the original data from a PSV table.
ruler
Rulers are horizontal separators which may be used in `psv` tables to help visually separate rows within a table.
Rulers are horizontal separators which may be used in `psv` tables to help visually separate rows within a table.
ui
This is a simple web-server for re-formatting PSV tables.
This is a simple web-server for re-formatting PSV tables.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL