Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ The tag follows this format: `[operation][direction][start:end][currency]`
* `MAX`: Finds the maximum value.
* `SUB`: Subtracts the subsequent values from the first value.
* `MUL`: Multiplies all the values together.
* `DIV`: Divides the first value by each subsequent value in sequence.
* **`[direction]`**: Indicates the direction of the values to operate on:
* `^`: Looks at the cells above the current cell in the same column.
* `<`: Looks at the cells to the left of the current cell in the same row.
* `v`: Looks at the cells below the current cell in the same column.
* `>`: Looks at the cells to the right of the current cell in the same row.
* **`[start:end]`** (Optional): Specifies a range of cells to include in the calculation.
* If omitted, it defaults to all applicable cells in the specified direction.
* Use a colon-separated format (e.g., `1:3` for the first three cells). The indices are 1-based.
Expand Down Expand Up @@ -66,7 +69,7 @@ The tag follows this format: `[operation][direction][start:end][currency]`
## Key Features

* **Real-time Updates:** Calculations are performed automatically as you type and edit your tables.
* **Directional Operations:** Calculate based on values above or to the left of the tag.
* **Directional Operations:** Calculate based on values relative to the tag.
* **Optional Range Selection:** Target specific cells for your calculations.
* **Currency Formatting:** Display results with currency symbols for better readability.
* **Locale-Aware Formatting:** Respects your system's locale for number formatting by default, with an option to override.
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "simple-table-math",
"name": "Simple Table Math",
"version": "0.2.3",
"version": "0.2.4",
"minAppVersion": "1.8.9",
"description": "Do some math (sum, average, etc.) in your markdown tables.",
"author": "Sandro Ducceschi",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-table-math",
"version": "0.2.3",
"version": "0.2.4",
"description": "Do some math (sum, average, etc.) in your markdown tables for Obsidian (https://obsidian.md).",
"main": "src/main.js",
"scripts": {
Expand Down
81 changes: 52 additions & 29 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ const DEFAULT_SETTINGS: SimpleTableMathSettings = {
styleLastRow: true,
}

const OperationSymbols = ["sum", "avg", "min", "max", "sub", "mul", "div"] as const;
type OperationSymbol = typeof OperationSymbols[number];

const DirectionSymbols = ["<", "^", ">", "v"] as const;
type DirectionSymbol = (typeof DirectionSymbols)[number];

const TABLE_MATH_REGEX = new RegExp(
`^(${OperationSymbols.join('|')})([${DirectionSymbols.join('')}])(\\d+)?(?::(\\d+))?([a-z]{2,4})?$`,
'i'
);

/**
* A plugin that performs mathematical operations on Markdown tables in Obsidian.
* The plugin actively listens to user interactions and processes table data accordingly.
Expand Down Expand Up @@ -129,11 +140,11 @@ export default class SimpleTableMath extends Plugin {
const cells = Array.from(row.children) as HTMLTableCellElement[];
cells.forEach((cell, colIndex) => {
const rawText = this.extractCellContent(cell).trim().toLowerCase() || '';
const match = rawText.match(/^([a-z]{3})([<^])(?:(\d+)(?::(\d+))?)?([a-z]{2,4})?$/i);
const match = rawText.match(TABLE_MATH_REGEX);
const isActiveElement = this.isDocumentActiveElementChildOf(cell)
if (match && !isActiveElement) {
const operation = match[1].toLowerCase();
const direction = match[2];
const operation = match[1].toLowerCase() as OperationSymbol;
const direction = match[2] as DirectionSymbol;
const startStr = match[3];
const endStr = match[4];
const currency = match[5]?.toUpperCase() || null;
Expand All @@ -149,34 +160,46 @@ export default class SimpleTableMath extends Plugin {
endIndex = -1;
}

if (direction === '^') {
const actualStartRow = Math.max(0, startIndex);
const actualEndRow = endIndex !== -1 ? endIndex : rowIndex - 1;
const finalEndRow = Math.min(actualEndRow, rowIndex - 1);
if (actualStartRow <= finalEndRow) {
for (let r = actualStartRow; r <= finalEndRow; r++) {
const aboveCell = rows[r]?.children?.[colIndex] as HTMLTableCellElement | undefined | null;
const textContent = this.extractCellContent(aboveCell, true);
const value = this.extractNumber(textContent);
if (value !== null) {
values.push(value);
}
}
const getCellValue = (r: number, c: number) => {
const cell = rows[r]?.children?.[c] as HTMLTableCellElement | undefined | null;
const text = this.extractCellContent(cell, true);
return this.extractNumber(text);
};
let range: number[] = [];
const isEndIndexSet = endIndex !== -1;
switch (direction) {
case '^': { // Up
range = Array.from({ length: isEndIndexSet ? Math.min(endIndex, rowIndex - 1) : rowIndex - 1 - startIndex + 1 },
(_, i) => startIndex + i);
break;
}
} else if (direction === '<') {
const actualStartCol = Math.max(0, startIndex);
const actualEndCol = endIndex !== -1 ? endIndex : colIndex - 1;
const finalEndCol = Math.min(actualEndCol, colIndex - 1);
if (actualStartCol <= finalEndCol) {
for (let c = actualStartCol; c <= finalEndCol; c++) {
const leftCell = cells[c] as HTMLTableCellElement | undefined | null;
const textContent = this.extractCellContent(leftCell, true);
const value = this.extractNumber(textContent);
if (value !== null) {
values.push(value);
}
}
case '<': { // Left
range = Array.from({ length: isEndIndexSet ? Math.min(endIndex, colIndex - 1) : colIndex - 1 - startIndex + 1 },
(_, i) => startIndex + i);
break;
}
case '>': { // Right
range = Array.from({ length: (isEndIndexSet ? Math.min(endIndex, cells.length - 1) : cells.length - 1) - colIndex },
(_, i) => colIndex + 1 + i);
break;
}
case 'v': { // Down
range = Array.from({ length: (isEndIndexSet ? Math.min(endIndex, rows.length - 1) : rows.length - 1) - rowIndex },
(_, i) => rowIndex + 1 + i);
break;
}
}

if (direction === '^' || direction === 'v') { // Vertical direction
range.forEach(r => {
const value = getCellValue(r, colIndex);
if (value !== null) values.push(value);
});
} else { // Horizontal direction
range.forEach(c => {
const value = getCellValue(rowIndex, c);
if (value !== null) values.push(value);
});
}

let result: number | null = null;
Expand Down