Help  /  The view file

The view file

A CSV cannot hold a calculation, a colour or a hidden row. Plaintable keeps those in a markdown file beside the data — one you can read, edit by hand, diff and commit. This is everything you can write in it.

Where the file lives

The view file is the CSV's whole file name plus .md, in the same folder:

sales.csv        the data
sales.csv.md     how Plaintable shows it

The full name is used deliberately, so a sales.md you wrote yourself is never mistaken for it.

Plaintable creates the file the first time you change something about the view, and rewrites it whenever the view changes after that. It also watches it: save the file from another editor and the open window follows along within a moment. Nothing written in the view file ever changes the CSV — calculated columns are shown in the table and left out of the file entirely.

Folder access. Plaintable is sandboxed. Opening sales.csv does not by itself grant access to sales.csv.md, because the sandbox's related-item rule only covers a file with the same base name. The first time a view file is needed, macOS asks for access to the containing folder; Plaintable keeps a bookmark and does not ask again. Decline it and the table still works — only the view file is disabled.

The shape of the file

It is ordinary markdown. A # title, then a ## heading per section, and inside most sections either a pipe table or a short list of - Key: value lines.

# sales.csv

## Columns

| Column | Show | Pin | Width | Align | Format        | Formula                      |
| ------ | ---- | --- | ----- | ----- | ------------- | ---------------------------- |
| Order  | yes  | yes | 115   | left  |               |                              |
| Units  | yes  | no  | 85    | right | number        |                              |
| Price  | yes  | no  | 110   | right | currency(EUR) |                              |
| Total  | yes  | no  | 140   | right | currency(EUR) | `[Units] * [Price]`          |

## Rows

- Hidden: 6, 40-44

## Sort

1. Total — descending

The sections Plaintable understands, in the order it writes them:

HeadingAlso acceptedHolds
## ColumnsOrder, visibility, pinning, width, alignment, format, formula
## RowsHidden rows and per-row heights
## Row formattingRow styles, FormattingConditional row colouring
## Cell formulasCellsFormulas pinned to one cell
## SortSortingSort keys, in priority order
## FiltersFilterThe active filter set
## Saved filtersNamed filter sets
## Formula referenceA cheat sheet Plaintable writes for you. Ignored on read.

Heading names are matched case-insensitively, and the order of sections in the file does not matter. Any ## section Plaintable does not recognise is kept exactly as written and re-emitted at the end, so you can add notes of your own. Text before the first ## heading is the generated preamble and will be replaced.

In a table, only the row order and the column positions matter — the header row is read for its shape, not its words, and the | --- | separator line is optional. Leading and trailing pipes may be left off. A literal pipe inside a cell is written \|. Backticks around a formula are optional; they are stripped on read and added back when Plaintable rewrites the file.

Columns

Seven cells per row. Columns appear in the table in the order they are listed here.

| Column   | Show | Pin | Width | Align | Format        | Formula                                |
| -------- | ---- | --- | ----- | ----- | ------------- | -------------------------------------- |
| Order    | yes  | yes | 115   | left  |               |                                        |
| Date     | yes  | no  | 105   | left  | date(d MMM)   |                                        |
| Category | no   | no  | 100   | left  |               |                                        |
| Units    | yes  | no  | 85    | right | number        |                                        |
| Price    | yes  | no  | 110   | right | currency(EUR) |                                        |
| Discount | yes  | no  | 110   | right | percent(0)    |                                        |
| Revenue  | yes  | no  | 140   | right | currency(EUR) | `[Units] * [Price] * (1 - [Discount])` |
CellValuesMeaning
Columna header name Must match a header in the CSV — unless it also has a Formula, in which case it is a new calculated column. Required; a row with an empty name is skipped.
Showyes noHides the column without touching the CSV. Default yes.
Pinyes noFreezes the column to the left so it stays put while you scroll sideways. Default no.
Widtha number, or autoWidth in points. Anything that is not a number — auto, or blank — lets Plaintable pick.
Alignleft center rightl/start, centre/c/middle and r/end also work. Blank or unrecognised means automatic: numbers right, everything else left.
Formatsee FormatsPresentation only. Sorting, filtering and saving always see the raw value.
Formulaan expression Makes the column calculated. It is shown in the table and never written to the CSV. See the formula language.

Yes and no are generous: yes, y, true, t and 1 all mean yes; no, n, false, f and 0 all mean no. Anything else falls back to the default.

You may leave trailing cells off a row entirely. | Notes | no | is a valid way to hide a column and say nothing else about it.

Formats

A format changes how a value is drawn, never what is stored. A value the format cannot make sense of is shown as it is, so a stray n/a in a number column stays n/a.

FormatExampleResult
(blank)Automatic — the value exactly as stored.
texttextNever interpreted as anything but text. string is a synonym.
numbernumber · number(2)Grouped thousands. The argument is the number of decimals; omit it to keep the value's own.
plainplain · plain(0)The same, without the thousands separator.
percentpercent(0)0.1515%. The argument is the number of decimals; the default is 1.
currencycurrency(EUR) · currency(USD, 0)Currency code, then optionally the number of decimals. The default code is USD; without a decimal count the currency's own is used.
datedate(d MMM yyyy)A date pattern. datetime is a synonym; with no argument the pattern is yyyy-MM-dd.

Format names are case-insensitive; arguments are not. Date patterns keep their case exactly as you type them, which matters — MM is the month and mm is the minute. Currency codes are upper-cased for you. A format Plaintable cannot read falls back to automatic rather than erroring, so a typo hides nothing.

Common date patterns:

Pattern2026-01-06 becomes
date(yyyy-MM-dd)2026-01-06
date(d MMM)6 Jan
date(d MMMM yyyy)6 January 2026
date(EEE, d MMM)Tue, 6 Jan
date(MM/dd/yy)01/06/26

Rows

Two bullets, both optional. Line numbers are the ones in the CSV, counting the header as line 1 — the same numbers the gutter shows.

## Rows

- Hidden: 6, 40-44, 512
- Heights: 12 = 60, 13 = 44
  • Hidden — rows to leave out of the table. Single line numbers and low-high ranges, separated by commas, spaces or semicolons. Hidden rows are kept apart from the filters, so clearing the filters does not bring them back. Aliases: Hidden rows, Hide.
  • Heights — an explicit row height in points, as line = height pairs separated by commas. Aliases: Row heights, Height.

Row formatting

A table of when and style. The condition is a formula read as a yes/no and evaluated per row.

## Row formatting

| When                        | Style                       |
| --------------------------- | --------------------------- |
| `[Discount] >= 0.2`         | background amber            |
| `[Revenue] > 9000`          | bold                        |
| `[Status] = "Refunded"`     | strikethrough, text red     |
| `ISEMPTY([Rep])`            | off — italic, text gray     |

Every rule that matches applies, top to bottom, so a later rule layers over an earlier one rather than replacing it. A row that is both discounted and large comes out bold on amber without the two rules knowing about each other.

Styles

A comma-separated list, in any order:

StyleAlso accepted
bold
italic
strikethroughstrike, struck
background <colour>bg, fill, highlight
text <colour>color, colour, foreground
<colour>a colour on its own means background

Prefix the style with off — to keep a rule in the file but switch it off. off -, off, and off: work too.

Colours

Either one of the built-in names, or a hex value: #RGB, #RRGGBB, or #RRGGBBAA with an alpha channel.

NameHexNameHex
red#E5484Dteal#12A594
orange#F76B15blue#3E63DD
amber#FFB224purple#8E4EC6
yellow#F5D90Apink#D6409F
green#30A46Cgray / grey#8B8D98
black#000000white#FFFFFF

Cell formulas

A calculation that overrides one single cell, addressed by CSV line number and column name. This is what typing = into a cell writes.

## Cell formulas

| Line | Column  | Formula                  |
| ---- | ------- | ------------------------ |
| 41   | Revenue | `SUM([Units]) * 12.5`    |
| 87   | Notes   | `"checked " & TODAY()`   |

All three cells are required; a row missing any of them is skipped.

Sort

A list, in priority order: the first entry is the primary key, the second breaks its ties, and so on.

## Sort

1. Region — ascending
2. Revenue — descending

Numbered lists, - bullets and bare lines all work. The direction may be separated by an em dash, an en dash, a hyphen, a colon or a comma. Anything starting with desc, z or means descending; anything else, including a missing direction, means ascending.

Comparison is type-aware — numeric, chronological, boolean, or localised natural-order text — and stable, so equal rows keep their file order. Empty values are pinned to one end regardless of direction; which end is a preference in Settings.

Filters

A few options as bullets, then a table of one filter per row. A row is shown when the filters agree, according to Match.

## Filters

- Match: all
- Search: keyboard

| Column  | Test          | Value             |
| ------- | ------------- | ----------------- |
| Region  | is one of     | East, North, West |
| Revenue | at least      | 1500              |
| Status  | not is one of | Refunded          |

Options

BulletValuesMeaning
- Match:all · anyAND or OR across every filter. Default all. Alias: Combine.
- Search:any textThe quick filter — a substring match across every column. Aliases: Quick filter, Find.
- Only modified rows:yes · noShow only rows you have edited in this session.
- Invert:yes · noShow exactly the rows the filters would have hidden. Alias: Inverted.

Tests

Put not in front of any test to negate it — not contains, not is one of. ! and ¬ work as well.

TestAlso acceptedValue
Text
containshasa substring
does not containexcludesa substring
equalsis exactlythe whole value
does not equalis notthe whole value
begins withstarts witha prefix
ends witha suffix
matches regexregex, matchesa regular expression
Numbers
===, equals to, is equal toa number
<>!=, , is not equal toa number
<less than, is less thana number
<=, at most, less than or equal toa number
>greater than, is greater thana number
>=, at least, greater than or equal toa number
betweenbetween numbers10 and 20
Dates
beforea date, e.g. 2026-01-01
aftera date
between2026-01-01 and 2026-03-31
in the last daysin the last n days, in the lasta number of days
Lists, emptiness, yes/no
is one ofone of, in, any ofa comma-separated list
is emptyempty, blank(none)
is not emptynot empty, filled(none)
istrue or false
is true / is false(none)

A common slip. is is the yes/no test, so | Status | not is | Refunded | does nothing — Refunded is not a yes or a no. For one text value use not is one of or does not equal.

Lists and ranges

A list is comma-separated. An item that itself contains a comma or a quote is wrapped in double quotes, and a quote inside such an item is doubled — the same rule the CSV underneath uses:

| Product | is one of | Atlas Keyboard, "Monitor 27, refurbished", Vector Mouse |

A range may be written 10 and 20, 10 to 20, 10 - 20, 10 … 20 or 10, 20.

Saved filters

Named filter sets — the ones in the toolbar's funnel menu. Each gets a ### heading and then exactly the same body as Filters, minus Only modified rows and Invert.

## Saved filters

### Big open deals

- Match: all

| Column  | Test      | Value             |
| ------- | --------- | ----------------- |
| Status  | is one of | Invoiced, Pending |
| Revenue | at least  | 3000              |

### Refunds to chase

- Match: all

| Column | Test      | Value    |
| ------ | --------- | -------- |
| Status | is one of | Refunded |

The formula language

The same language is used for calculated columns, cell formulas and row-formatting conditions.

Values

  • A column — its name in square brackets: [Unit Price].
  • Text — in double quotes: "Paid".
  • Numbers12, 0.075, 1e3.
  • Yes and notrue, false.
  • Nothingempty, blank or null.
  • πpi.

Operators

Listed loosest-binding first; everything associates to the left except ^.

OperatorsDoes
oreither side is true
andboth sides are true
= <> < <= > >=comparison. !=, , , and == are accepted too
&joins two pieces of text
+ -add, subtract
* / %multiply, divide, remainder
^raise to a power

not(…) negates. Arguments may be separated by either a comma or a semicolon.

Functions

GroupFunctions
LogicIF(test, then, else), IFERROR(value, fallback), AND(…), OR(…), NOT(x), COALESCE(…), ISEMPTY(x), ISNUMBER(x), ISERROR(x)
NumbersABS, ROUND(n, places), ROUNDUP, ROUNDDOWN, FLOOR, CEILING, INT, MOD(a, b), POWER(a, b), SQRT, EXP, LN, LOG10, SIGN, MIN(a, b, …), MAX(a, b, …), CLAMP(n, low, high)
TextLEN, UPPER, LOWER, TRIM, CONCAT(…), LEFT(t, n), RIGHT(t, n), MID(t, from, n), FIND(t, needle), CONTAINS(t, needle), STARTSWITH(t, p), ENDSWITH(t, s), SUBSTITUTE(t, old, new), REPEAT(t, n), MATCHES(t, regex)
ConversionNUMBER(x), TEXT(x, format)
DatesTODAY(), YEAR, MONTH, DAY, DATEDIFF(later, earlier) in whole days
PositionROW() — this row's line number in the CSV

Three spellings are aliases: VALUE for NUMBER, LOG for LOG10, TRUNC for INT.

Whole-column summaries

Given one column, these read every row in the file — not just the rows a filter leaves on screen — so [Revenue] / SUM([Revenue]) is each row's share of the whole.

FunctionReturns
SUM([c])the total
AVG([c])the mean. AVERAGE and MEAN are synonyms
MEDIAN([c])the median
MIN([c]) / MAX([c])the smallest / largest value
COUNT([c])how many rows
COUNTA([c])how many are not empty
COUNTBLANK([c])how many are empty
DISTINCT([c])how many different values
STDEV([c])the standard deviation

MIN and MAX are both.MIN([Price]) — one argument, a column — summarizes the whole column. MIN([Price], 10) — two or more arguments — compares values within the row.

When a formula cannot be worked out

Errors are values, not failures: a broken formula shows why in its own cell and leaves every other cell alone.

ShownMeans
#SYNTAX?The formula could not be read — check the brackets and quotes.
#NAME?No column by that name.
#FUNC?No function by that name.
#ARGS?A function got the wrong number of arguments.
#VALUE?A value was not a number where one was needed.
#DIV/0!Division by zero.
#CYCLE!The formula refers back to itself, directly or through another column.

Examples

[Units] * [Price] * (1 - [Discount])

ROUND([Revenue] / SUM([Revenue]) * 100, 2)

IF([Discount] > 0, ROUND([Revenue] * 0.05, 2), ROUND([Revenue] * 0.07, 2))

UPPER(LEFT([Region], 1)) & LOWER(MID([Region], 2, 99))

IF(DATEDIFF(TODAY(), [Date]) > 30, "overdue", "")

IFERROR(NUMBER([Weight]) / NUMBER([Volume]), "")

[Status] = "Refunded" or [Status] = "Pending"

MATCHES([Order], "^SO-1[0-9]{4}$")

Notes and edge cases

  • Plaintable rewrites the file. Whenever the view changes in the app, the whole file is written out in its canonical shape: padded table pipes, sections in a fixed order, backticks around formulas. Your content survives; your spacing may not.
  • Your own sections survive. Any ## heading Plaintable does not recognise is preserved verbatim and written back at the end of the file. It is the place to leave a note about what the view is for.
  • Nothing here changes the CSV. Hiding a column does not delete it, hiding a row does not remove it, and a calculated column is never saved. Export the current view if you want the calculated values in a file.
  • Bad input is ignored, not fatal. An unreadable format falls back to automatic, an unknown alignment to the default, a filter row that makes no sense is dropped. A typo can never hide your data.
  • Editing it while the file is open works both ways. Plaintable watches the view file with a file presenter and a plain filesystem watch, so changes from sed, git checkout or vim are picked up just as well as changes from a coordinating editor.
  • Line numbers are CSV line numbers. The header is line 1, so the first data row is line 2 — the same numbering the gutter shows, and it does not move when you sort or filter.

← Back to Help