tblcalc is a table calculation tool that applies formulas to CSV/TSV tables. Formulas can be embedded in the data file using special comment directives (e.g., #+TBLFM:) or placed in external files that are automatically discovered based on the data file's name. This functionality is inspired by Emacs Org-mode's table formulas and Miller scripts.
Formula Processing:
-
+TBLFM Directive - Applies table formulas specified in comment lines to CSV/TSV data files. Formulas use column references (e.g.,
$2,$3,$4) to perform calculations across table cells. -
+MLR Directive - Applies Miller commands specified in comment lines to CSV/TSV data files. For more details on Miller's DSL, refer to the official Miller documentation.
-
Comment Preservation - Maintains all comment lines (lines starting with
#) in their original positions while processing table data. -
Format Support - Supports both CSV (Comma-Separated Values) and TSV (Tab-Separated Values) formats for input and output.
-
In-Place Editing - Allows direct file modification with the
-iflag, preserving hard links.
Install via: go install github.com/knaka/tblcalc/cmd/tblcalc@latest
Basic commands:
- Process CSV file:
tblcalc input.csv >output.csv - In-place editing:
tblcalc -i file.csv - Force format:
tblcalc --icsv --ocsv file.txt
Input file (test.csv):
# Product list
#
#+TBLFM: $4=$2*$3
#
"Product","Unit Price",Stock,Total
Apple,100,50,
Banana,80,30,
Orange,120,20,After processing with tblcalc test.csv:
# Product list
#
#+TBLFM: $4=$2*$3
#
"Product","Unit Price",Stock,Total
Apple,100,50,5000
Banana,80,30,2400
Orange,120,20,2400Input file (mlr-test1.csv):
# Product list
#
#+MLR: ${Total}=${Unit Price}*${Stock}
#+MLR: ${Total2}=${Unit Price}*${Stock}
#
Product,Unit Price,Stock,Total,Total2
Apple,100,50,,
"Banana ""Cavendish"", Premium",80,30,,
# Another comment
Orange,120,20,,After processing with tblcalc mlr-test1.csv:
# Product list
#
#+MLR: ${Total}=${Unit Price}*${Stock}
#+MLR: ${Total2}=${Unit Price}*${Stock}
#
Product,Unit Price,Stock,Total,Total2
Apple,100,50,5000,5000
"Banana ""Cavendish"", Premium",80,30,2400,2400
# Another comment
Orange,120,20,2400,2400tblcalc can automatically discover and apply external script files (.tblfm, .mlr) or skip processing (.skip) based on the input CSV/TSV file's name. This allows for cleaner data files and enables applying the same rules to multiple data files that follow a naming convention.
When processing an input file (e.g., testdata/ledger-2025-01.csv), tblcalc will search for these special files in the same directory using a pattern matching mechanism. For instance, tblcalc will look for files like testdata/ledger-%.csv.tblfm or testdata/ledger-2025-01.csv.skip. The % acts as a wildcard, matching any string.
- If a matching
.skipfile is found,tblcalcwill perform no processing and simply output the original file content. This is useful for explicitly excluding certain files from calculations. - If a matching
.tblfmor.mlrfile is found, its content is treated as if the directives (e.g.,#+TBLFM:,#+MLR:) were embedded in the input data file itself.
Consider the following input data and an external tblfm file:
Input file (testdata/ledger-2025-01.csv):
Date,Description,Amount,Category
2025-01-01,Groceries at local store,-5000,Food
2025-01-05,Monthly Salary,300000,Income
# This is a sample ledger data for January 2025.
2025-01-20,Electricity Bill,-8000,Utilities
2025-01-25,Freelance Project Payment,50000,Income
2025-01-28,Internet Service,-6500,Utilities
TOTAL,,0,External formula file (testdata/ledger-%.csv.tblfm):
@>${Amount}=vsum(@2..@>>)
After processing with tblcalc testdata/ledger-2025-01.csv:
Date,Description,Amount,Category
2025-01-01,Groceries at local store,-5000,Food
2025-01-05,Monthly Salary,300000,Income
# This is a sample ledger data for January 2025.
2025-01-20,Electricity Bill,-8000,Utilities
2025-01-25,Freelance Project Payment,50000,Income
2025-01-28,Internet Service,-6500,Utilities
TOTAL,,330500,In this example, tblcalc automatically finds testdata/ledger-%.csv.tblfm because it matches the input filename pattern. The formula @>${Amount}=vsum(@2..@>>) is then applied, calculating the sum of the Amount column and placing it in the TOTAL row.
-h, --help- Show help message-i, --in-place- Edit file(s) in-place-v, --verbose- Enable verbose output--icsv- Force CSV for input format--itsv- Force TSV for input format--ocsv- Force CSV for output format--otsv- Force TSV for output format
The +TBLFM directive uses Org-mode-style cell references:
$2,$3,$4- Column references (1-indexed)${Header Name}- Column reference by header name (supports spaces)@2- Row 2 (first data row after header)$>- Last column@>- Last row@>>- Second-to-last row@<- First row (including header)@2$3- Cell at row 2, column 3- Ranges:
@<<$>..@>>$>(range notation using..)
Instead of numeric column indices, you can reference columns by their header names using ${Header Name} syntax. This makes formulas more readable and resilient to column reordering.
Note: Org-mode's "named field" syntax (e.g., $name) is not supported. Instead, tblcalc uses the ${Header Name} syntax to directly reference columns by their header values.
Input file (prices.csv):
# Price calculation
#
#+TBLFM: @2${Total}..@>> = ${Unit Price} * ${Qty}
#+TBLFM: @2${Tax}..@>>=${Total}*0.1
#+TBLFM: @2${Grand Total}..@>> = ${Total} + ${Tax}
#+TBLFM: @>${Grand Total}=vsum(@2..@>>)
#
Product,Unit Price,Qty,Total,Tax,Grand Total
Apple,100,5,,,
Orange,150,3,,,
Banana,80,10,,,
TOTAL,,,,,After processing with tblcalc prices.csv:
# Price calculation
#
#+TBLFM: @2${Total}..@>> = ${Unit Price} * ${Qty}
#+TBLFM: @2${Tax}..@>>=${Total}*0.1
#+TBLFM: @2${Grand Total}..@>> = ${Total} + ${Tax}
#+TBLFM: @>${Grand Total}=vsum(@2..@>>)
#
Product,Unit Price,Qty,Total,Tax,Grand Total
Apple,100,5,500,50,550
Orange,150,3,450,45,495
Banana,80,10,800,80,880
TOTAL,,,,,1925Header name references can also be used in range expressions: vsum(${Q1}..${Q4})
Formulas are evaluated using Lua, providing flexible syntax for:
- Arithmetic operations:
$2*$3,$2+$3-10 - String operations: String concatenation and manipulation
- Conditional expressions:
$2 > 100 and $2*0.9 or $2 - All standard Lua built-in functions and libraries
Available aggregation functions for ranges:
vsum(range)- Sum of valuesvmean(range)- Average of valuesvmedian(range)- Median of valuesvmax(range)- Maximum valuevmin(range)- Minimum value
Example: vsum(@2$3..@>$3) calculates the sum of column 3 from row 2 to the last row.
Multiple formulas can be specified with:
- Multiple
#+TBLFM:lines - Separated by
::in a single line:#+TBLFM: $4=$2*$3::$5=$2+$3
Lua's string concatenation operator .. visually resembles the range operator ... To prevent confusion:
- Add spaces around concatenation:
$2 .. " items" - Use parentheses around cell references:
($2)..($3)
You can configure VSCode to automatically apply formulas when saving CSV/TSV files using the Run on Save extension.
Add this to your .vscode/settings.json:
{
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.csv$",
"cmd": "tblcalc -i ${file}"
},
{
"match": "\\.tsv$",
"cmd": "tblcalc -i ${file}"
},
],
},
}This automatically processes files with +TBLFM directives whenever you save them.
If you use the Rainbow CSV extension for better CSV/TSV visualization, configure it to recognize comment lines:
{
"rainbow_csv.comment_prefix": "#"
}This ensures that comment lines (including +TBLFM directives) are properly displayed and not treated as data rows.
Released under the Apache 2.0 License.