Skip to content

Commit c6ac5a9

Browse files
committed
Improve logging and docs
1 parent 1896489 commit c6ac5a9

2 files changed

Lines changed: 39 additions & 40 deletions

File tree

np.Tidy/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,26 @@ This command catches any such completed repeats that haven't had the next repeat
4343
### Details on /Remove empty blocks
4444
The **/Remove empty blocks** command intelligently cleans up your notes while preserving important structure:
4545

46-
**What it removes:**
46+
#### What it removes
47+
- Empty task or checklists (e.g. `* ` or `+ ` with no further content)
4748
- Empty list items (e.g., `- ` or `* ` with no content)
4849
- Empty quotations (e.g., `> ` with no content)
4950
- Empty headings (e.g., `# ` with no text)
5051
- Multiple consecutive empty lines (reduces to single empty lines)
5152

52-
**Smart heading behavior:**
53+
#### Smart heading behavior
5354
- **Preserves parent headings** when their subheadings contain content
5455
- **Removes headings** only when they have no content AND no subheadings with content
5556
- This ensures your note hierarchy stays intact when subheadings contain valuable information
5657

57-
**Empty line handling:**
58+
#### Empty line handling
5859
- **Default behavior**: Reduces multiple consecutive empty lines to a single empty line
5960
- **Strip all empty lines**: Available as an x-callback setting to remove ALL empty lines completely
6061
```
6162
noteplan://x-callback-url/runPlugin?pluginID=np.Tidy&command=Remove%20empty%20elements&arg0=Editor&arg1=true
6263
```
6364

64-
**Advanced options:**
65+
#### Advanced options
6566
- **Preserve heading structure**: Availabe as an x-callback setting. When arg2 is true, keeps ALL headings (even empty ones) to maintain note templates and structure
6667
- This is useful for note templates where you want to keep the heading hierarchy intact
6768
```

np.Tidy/src/emptyElements.js

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22
//-----------------------------------------------------------------------------
33
// Remove empty blocks functionality for Tidy plugin
4-
// Last updated 2025-09-24 for v1.0.0 by @jgclark
4+
// Last updated 2025-11-13 for v1.16.0 by @jgclark
55
//-----------------------------------------------------------------------------
66

77
import pluginJson from '../plugin.json'
@@ -19,28 +19,25 @@ import { showMessage } from '@helpers/userInput'
1919
*
2020
* @param {TNote} note - The note to process
2121
* @param {boolean} preserveHeadings - Whether to preserve heading structure (skip removing empty headings)
22-
* @returns {boolean} - Whether any changes were made
22+
* @returns {number} - Number of changes made
2323
*
2424
* @example
2525
* When preserveHeadings = false (default):
2626
* - Removes: "- " (empty list item)
2727
* - Removes: "> " (empty quote)
2828
* - Removes: "# " (empty heading)
29+
* - Removes: "* " (empty task)
30+
* - Removes: "+ " (empty checklist)
2931
* - Preserves: "- Some content" (list with content)
3032
* - Preserves: "> Some quote" (quote with content)
3133
* - Preserves: "# Some heading" (heading with content)
3234
*
3335
* When preserveHeadings = true:
34-
* - Removes: "- " (empty list item)
35-
* - Removes: "> " (empty quote)
3636
* - Preserves: "# " (empty heading - structure preserved)
37-
* - Preserves: "- Some content" (list with content)
38-
* - Preserves: "> Some quote" (quote with content)
39-
* - Preserves: "# Some heading" (heading with content)
4037
*/
41-
function removeEmptyListItemsAndHeadings(note: TNote, preserveHeadings: boolean = false): boolean {
38+
function removeEmptyParagraphs(note: TNote, preserveHeadings: boolean = false): number {
4239
const paragraphs = note.paragraphs
43-
let changesMade = false
40+
let numChangesMade = 0
4441

4542
for (const para of paragraphs) {
4643
const trimmedContent = para.content.trim()
@@ -56,18 +53,17 @@ function removeEmptyListItemsAndHeadings(note: TNote, preserveHeadings: boolean
5653
// Remove empty headings when not preserving structure
5754
shouldRemove = isEmptyContent
5855
} else {
59-
// For list and quote items, remove if empty
60-
shouldRemove = isEmptyContent && ['list', 'quote'].includes(para.type)
56+
// For most other paragraph types, remove if empty
57+
shouldRemove = isEmptyContent && ['open', 'checklist', 'scheduled', 'checklistScheduled', 'list', 'quote'].includes(para.type)
6158
}
62-
6359
if (shouldRemove) {
6460
logDebug('removeEmptyElements', `Removing empty ${para.type} para on line ${String(para.lineIndex)}`)
6561
note.removeParagraph(para)
66-
changesMade = true
62+
numChangesMade++
6763
}
6864
}
69-
70-
return changesMade
65+
logInfo('removeEmptyElements', `Removed ${String(numChangesMade)} empty paras`)
66+
return numChangesMade
7167
}
7268

7369
/**
@@ -85,7 +81,7 @@ function removeEmptyListItemsAndHeadings(note: TNote, preserveHeadings: boolean
8581
* - It has no content in its section AND no subheadings with content
8682
*
8783
* @param {TNote} note - The note to process
88-
* @returns {boolean} - Whether any changes were made
84+
* @returns {number} - Number of changes made
8985
*
9086
* @example
9187
* // This heading is PRESERVED because its subheading has content:
@@ -98,10 +94,10 @@ function removeEmptyListItemsAndHeadings(note: TNote, preserveHeadings: boolean
9894
* // ## Empty Subsection
9995
* // (no content)
10096
*/
101-
function removeEmptySections(note: TNote): boolean {
97+
function removeEmptySections(note: TNote): number {
10298
const paragraphs = note.paragraphs
10399
const titleParas = paragraphs.filter((para) => para.type === 'title')
104-
let changesMade = false
100+
let numChangesMade = 0
105101

106102
// First, mark which headings have content (including subheadings)
107103
const headingHasContent = new Map<number, boolean>()
@@ -151,11 +147,11 @@ function removeEmptySections(note: TNote): boolean {
151147
if (!hasContent) {
152148
logDebug('removeEmptyElements', `Removing heading para on line ${String(para.lineIndex)} (no content and no subheadings with content)`)
153149
note.removeParagraph(para)
154-
changesMade = true
150+
numChangesMade++
155151
}
156152
}
157-
158-
return changesMade
153+
logInfo('removeEmptyElements', `Removed ${String(numChangesMade)} empty headings`)
154+
return numChangesMade
159155
}
160156

161157
/**
@@ -168,7 +164,7 @@ function removeEmptySections(note: TNote): boolean {
168164
* @param {TNote} note - The note to process
169165
* @param {boolean} stripAllEmptyLines - Whether to remove all empty lines or just consecutive ones
170166
* @param {boolean} preserveHeadings - Whether to preserve heading structure (skip removing empty headings)
171-
* @returns {boolean} - Whether any changes were made
167+
* @returns {number} - Number of changes made
172168
*
173169
* @example
174170
* // When stripAllEmptyLines = false (default):
@@ -179,9 +175,9 @@ function removeEmptySections(note: TNote): boolean {
179175
* // Before: "Line 1\n\n\n\nLine 2"
180176
* // After: "Line 1\nLine 2" (removes all empty lines)
181177
*/
182-
function removeConsecutiveEmptyLines(note: TNote, stripAllEmptyLines: boolean, preserveHeadings: boolean = false): boolean {
178+
function removeConsecutiveEmptyLines(note: TNote, stripAllEmptyLines: boolean, preserveHeadings: boolean = false): number {
183179
const paragraphs = note.paragraphs
184-
let changesMade = false
180+
let numChangesMade = 0
185181

186182
if (stripAllEmptyLines) {
187183
// Delete *all* empty paras, but preserve headings if preserveHeadings is true
@@ -193,7 +189,7 @@ function removeConsecutiveEmptyLines(note: TNote, stripAllEmptyLines: boolean, p
193189
for (const para of emptyParasToRemove) {
194190
logDebug('removeEmptyElements', `Removing empty para on line ${String(para.lineIndex)}`)
195191
note.removeParagraph(para)
196-
changesMade = true
192+
numChangesMade++
197193
}
198194
} else {
199195
// Delete multiple consecutive empty paras, leaving only one empty line
@@ -223,15 +219,17 @@ function removeConsecutiveEmptyLines(note: TNote, stripAllEmptyLines: boolean, p
223219
}
224220

225221
// Remove the marked paragraphs in reverse order to avoid index shifting
226-
for (let i = parasToRemove.length - 1; i >= 0; i--) {
227-
const para = parasToRemove[i]
228-
logDebug('removeEmptyElements', `Removing empty para on line ${String(para.lineIndex)}`)
229-
note.removeParagraph(para)
230-
changesMade = true
222+
if (parasToRemove.length > 0) {
223+
for (let i = parasToRemove.length - 1; i >= 0; i--) {
224+
const para = parasToRemove[i]
225+
logDebug('removeEmptyElements', `Removing empty para on line ${String(para.lineIndex)}`)
226+
note.removeParagraph(para)
227+
numChangesMade++
228+
}
231229
}
232230
}
233-
234-
return changesMade
231+
logInfo('removeEmptyElements', `Removed ${String(numChangesMade)} empty paras`)
232+
return numChangesMade
235233
}
236234

237235
/**
@@ -300,14 +298,14 @@ export async function removeEmptyElements(filenameIn: string = 'Editor', stripAl
300298
logDebug(pluginJson, `preserveHeadingStructure: ${String(preserveHeadingStructure)} typeof=${typeof preserveHeadingStructure} / preserveHeadings: ${String(preserveHeadings)}`)
301299

302300
// Execute the phases of cleanup
303-
const changes1 = removeEmptyListItemsAndHeadings(note, preserveHeadings)
301+
const changes1 = removeEmptyParagraphs(note, preserveHeadings)
304302
const changes2 = preserveHeadings ? false : removeEmptySections(note)
305303
const changes3 = removeConsecutiveEmptyLines(note, Boolean(stripAllEmptyLines), preserveHeadings)
306304

307-
const changesMade = changes1 || changes2 || changes3
305+
const numChangesMade = changes1 + changes2 + changes3
308306

309-
if (changesMade) {
310-
logInfo('removeEmptyElements', `Removed empty elements from note '${displayTitle(note)}'`)
307+
if (numChangesMade > 0) {
308+
logInfo('removeEmptyElements', `Removed ${String(numChangesMade)} empty elements from note '${displayTitle(note)}'`)
311309
// Save Editor (if that's where we're working)
312310
if (workingInEditor) {
313311
await Editor.save()

0 commit comments

Comments
 (0)