csv++ is a superset of CSV which allows you to author spreadsheets in a text file then compile that to your target spreadsheet (Excel, Google Sheets or even back to CSV).
Since csv++ is a superset of CSV any CSV document is valid:
Sum,Column 1,Column 2,
=5*SUM(B2,C2),,,
However you can extract reusable variables and functions by making a code section at the top,
separated from the cells with a ---
. Here's the same spreadsheet but extracted out into
variables and functions:
# you can define variables with `:=`
multiplier := 5
# functions look like this and have a single expression as their body
fn my_fn(a, b)
multiplier * SUM(a, b)
---
Sum , Column 1, Column 2,
"=my_fn(B2, C2)" , , ,
One more useful feature is the ability to bind variables to a cell. You can use the [[
/]]
syntax on the cell you want to bind it on.
fn my_complex_fn(a, b)
a * a + SQRT(b)
---
Complex function , Column 1 , Column 2 ,
"=my_complex_fn(a, b)", [[var=a]] , [[var=b]],
NOTE: The following is just a brief walkthrough, for the full documentation please refer to the user guide.
Another useful feature is to define a range of rows which fill out (either infinitely or by a
finite amount) in the compiled spreadsheet. To specify one you use the row-option syntax
which is similar to above, you just prefix it with !
: ![[
/]]
.
Product Name , Quantity , Price per Unit , =SUM(D2:D12)
![[fill=10]] , [[var=quantity]] , [[var=price]] , =quantity * price
This will take the second row and repeat it 10 times in the final spreadsheet. If you wanted
it to be repeated until the end of the spreadsheet just leave off the =10
and specify it as
![[fill]]
.
The variable scoping semantics are pretty unique because every function call is evaluated relative
to the cell where it is used. As you've seen above you can use [[var=...]]
to bind a variable
name to a given cell. As an example of scoping semantics we'll use this csv++ template:
foo_from_code_section := 42
---
[[var=bar_outside_fill]] , , , , ,
![[fill=2]]bar , [[var=bar_in_fill]] , =bar_in_fill , =bar_outside_fill , =foo_from_code_section,
which will compile to:
, , , ,
bar , , =B2 , =A1 , =42
bar , , =B3 , =A1 , =42
Breaking this down:
foo_from_code_section
- Is always42
no matter where it is used.bar_in_fill
- Since it is defined within an![[fill]]
, it's value depends on the final row, which will beB2
orB3
bar_outside_fill
- Will always beA1
, pointing to the cell where it was defined. There is no relative aspect to it since it's not defined in anfill
.
csv++ allows you to import and re-use functions and variables with the use
statement:
pi := 3.14159
e := 2.7182818284
---
use my_math_constants
fn circumference_from_diameter(r)
r * 2 * pi
fn radius_to_diameter(r)
2 * r
fn circumference_from_radius(r)
radius_from_diameter(radius_to_diameter(r))
---
Radius ,Circumference ,
[[var=radius]] ,"=circumference_from_radius(radius)" ,
You can apply basic cell formatting which will either apply for the entire row or just for
individual cells. To apply formatting to individual cells use the [[
/]]
syntax:
[[text=bold text=underline]]foo,[[fontsize=20]]bar,baz,
and here is the same thing using short-hand:
[[t=b t=u]]foo,[[fs=20]]bar,baz,
To format the entire row you can use ![[
/]]
at the beginning of the line
![[t=b t=u]]foo,bar,baz,
For a full list of formatting features, take a look at the user guide