diff --git a/README.md b/README.md index 6c928d6..975113d 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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. diff --git a/manifest.json b/manifest.json index 6bb444d..eeefd04 100644 --- a/manifest.json +++ b/manifest.json @@ -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", diff --git a/package-lock.json b/package-lock.json index bec993a..6fedb09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "simple-table-math", - "version": "0.2.3", + "version": "0.2.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "simple-table-math", - "version": "0.2.3", + "version": "0.2.4", "license": "MIT", "devDependencies": { "@types/lodash": "^4.17.16", diff --git a/package.json b/package.json index 270b5b0..bdc1b2f 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/src/main.ts b/src/main.ts index 429e735..de1c335 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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. @@ -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; @@ -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;