Skip to content

Commit 9b7298b

Browse files
committed
Add isDecoratedCommandBarAvailable() to general, and update others to use it
1 parent e7b0682 commit 9b7298b

File tree

5 files changed

+67
-45
lines changed

5 files changed

+67
-45
lines changed

helpers/NPnote.js

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
// import moment from 'moment/min/moment-with-locales'
77
import moment from 'moment/min/moment-with-locales'
8-
import { getBlockUnderHeading } from './NPParagraph'
98
import * as dt from '@helpers/dateTime'
109
import { clo, JSP, logDebug, logError, logInfo, logTimer, logWarn, timer } from '@helpers/dev'
1110
import { getFolderDisplayName, getFolderFromFilename, getRegularNotesInFolder } from '@helpers/folders'
12-
import { displayTitle, isValidUUID } from '@helpers/general'
11+
import { displayTitle, isDecoratedCommandBarAvailable, isValidUUID } from '@helpers/general'
1312
import { calendarNotesSortedByChanged,noteType } from '@helpers/note'
1413
import { displayTitleWithRelDate, getDateStrFromRelativeDateString, getRelativeDates } from '@helpers/NPdateTime'
1514
import { endOfFrontmatterLineIndex, ensureFrontmatter, getFrontmatterAttributes, getFrontmatterAttribute } from '@helpers/NPFrontMatter'
1615
import { findStartOfActivePartOfNote, findEndOfActivePartOfNote } from '@helpers/paragraph'
16+
import { getBlockUnderHeading, getSelectedParagraphsWithCorrectLineIndex } from '@helpers/NPParagraph'
1717
import { caseInsensitiveIncludes, caseInsensitiveSubstringMatch, getCorrectedHashtagsFromNote } from '@helpers/search'
1818
import { parseTeamspaceFilename } from '@helpers/teamspace'
1919
import { isOpen, isClosed, isDone, isScheduled } from '@helpers/utils'
@@ -81,7 +81,7 @@ export async function chooseNoteV2(
8181
const sortedNoteList = noteList.sort((first, second) => second.changedDate - first.changedDate) // most recent first
8282

8383
// Form the options to give to the CommandBar
84-
// Note: We will set up the more advanced options for the `CommandBar.showOptions` call, but downgrade them if we're not running v3.18+ (b1413)
84+
// Note: We will set up the more advanced options for the `CommandBar.showOptions` call, but downgrade them if we're not running v3.18+
8585
/**
8686
* type TCommandBarOptionObject = {
8787
* text: string,
@@ -180,7 +180,7 @@ export async function chooseNoteV2(
180180

181181
// Now show the options to the user
182182
let noteToReturn = null
183-
if (NotePlan.environment.buildVersion >= 1413) {
183+
if (isDecoratedCommandBarAvailable()) {
184184
// logDebug('chooseNoteV2', `Using 3.18.0's advanced options for CommandBar.showOptions call`)
185185
// use the more advanced options to the `CommandBar.showOptions` call
186186
const { index } = await CommandBar.showOptions(opts, promptText)
@@ -211,8 +211,10 @@ export async function printNote(noteIn: ?TNote, alsoShowParagraphs: boolean = fa
211211
logWarn('note/printNote()', `No valid note found. Stopping.`)
212212
return
213213
}
214+
const usingEditor = (noteIn == null || note.filename === Editor.filename)
214215

215-
console.log(`# ${note.type} Note: '${displayTitle(note)}'${noteIn == null ? ' from Editor' : ''}:`)
216+
console.log(`# '${displayTitle(note)}'${usingEditor ? ' (from Editor)' : ''}:`)
217+
console.log(`- type ${note.type}`)
216218
// If it's a Teamspace note, show some details
217219
if (note.isTeamspaceNote) {
218220
// $FlowIgnore[incompatible-type]
@@ -225,7 +227,7 @@ export async function printNote(noteIn: ?TNote, alsoShowParagraphs: boolean = fa
225227
if (note.type === 'Notes') {
226228
const startOfActive = findStartOfActivePartOfNote(note)
227229
const endOfActive = findEndOfActivePartOfNote(note)
228-
console.log(`- # paragraphs: ${note.paragraphs.length} (Active part: ${String(startOfActive)} -${String(endOfActive)})`)
230+
console.log(`- # paragraphs: ${note.paragraphs.length} (Active part: ${String(startOfActive)}-${String(endOfActive)})`)
229231
} else {
230232
// Calendar note
231233
console.log(dt.getDateStringFromCalendarFilename(note.filename))
@@ -237,29 +239,38 @@ export async function printNote(noteIn: ?TNote, alsoShowParagraphs: boolean = fa
237239
console.log(`- hashtags: ${note.hashtags?.join(', ') ?? '-'}`)
238240
console.log(`- mentions: ${note.mentions?.join(', ') ?? '-'}`)
239241

240-
// Get frontmatter details
241-
const FMAttribs = getFrontmatterAttributes(note)
242-
console.log(`- has ${Object.keys(FMAttribs).length} frontmatter keys: ${Object.keys(FMAttribs).join('\n ')}`)
243-
244242
if (note.paragraphs.length > 0) {
245243
const open = note.paragraphs.filter((p) => isOpen(p)).length
246244
const done = note.paragraphs.filter((p) => isDone(p)).length
247245
const closed = note.paragraphs.filter((p) => isClosed(p)).length
248246
const scheduled = note.paragraphs.filter((p) => isScheduled(p)).length
249247
console.log(`- open: ${String(open)}\n- done: ${String(done)}\n- closed: ${String(closed)}\n- scheduled: ${String(scheduled)}`)
250248
if (alsoShowParagraphs) {
251-
console.log(`Paragraphs`)
249+
console.log(`Paragraphs:`)
252250
note.paragraphs.map((p) => {
253251
const referencedParas = DataStore.referencedBlocks(p)
254252
console.log(` ${p.lineIndex}: ${p.type} ${p.rawContent}${ (referencedParas.length >= 1) ? ` 🆔 has ${referencedParas.length} sync copies` : ''}`)
255253
})
256254
}
257255
}
258256

257+
// Get frontmatter details
258+
const FMAttribs = getFrontmatterAttributes(note)
259+
console.log(`- ${String(Object.keys(FMAttribs).length)} frontmatter keys: ${Object.keys(FMAttribs).join('\n ')}`)
260+
261+
// If using the Editor, now show the selection and selected paragraphs
262+
if (usingEditor) {
263+
console.log(`Selection: start: ${String(Editor.selection?.start)}, end: ${String(Editor.selection?.end)} {${Editor.selectedText ?? '-'}}`)
264+
console.log(`Rendered Selection: start: ${String(Editor.renderedSelection?.start)}, end: ${String(Editor.renderedSelection?.end)}`)
265+
console.log(`${Editor.selectedParagraphs.length} Selected paragraph(s):\n${String(Editor.selectedParagraphs.map((p) => `- ${p.lineIndex}: ${p.content}`).join('\n'))}`)
266+
const correctedSelectedParagraphs = getSelectedParagraphsWithCorrectLineIndex()
267+
console.log(`${correctedSelectedParagraphs.length} Corrected selected paragraph(s) with lineIndex taking into account frontmatter lines:\n${String(correctedSelectedParagraphs.map((p) => `- ${p.lineIndex}: ${p.content}`).join('\n'))}`)
268+
}
269+
259270
// Now show .backlinks
260271
if (note.backlinks?.length > 0) {
261-
console.log(`Backlinks`)
262-
console.log(`- ${String(note.backlinks.length)} backlinked notes`)
272+
console.log(`Backlinks:`)
273+
console.log(`- ${String(note.backlinks.length)} backlinked note(s)`)
263274
// $FlowIgnore[prop-missing]
264275
const flatBacklinkParas = getFlatListOfBacklinks(note) ?? [] // Note: this requires DataStore
265276
console.log(`- ${String(flatBacklinkParas.length)} backlink paras:`)
@@ -342,7 +353,11 @@ export function getNoteFromFilename(filenameIn: string): TNote | null {
342353
foundNote = DataStore.noteByFilename(filenameIn, 'Notes', teamspaceID)
343354
?? DataStore.noteByFilename(filenameIn, 'Calendar', teamspaceID)
344355
?? null
345-
logDebug('NPnote/getNoteFromFilename', `Found teamspace note '${displayTitle(foundNote)}' from ${filenameIn}`)
356+
if (foundNote != null) {
357+
logDebug('NPnote/getNoteFromFilename', `Found teamspace note '${displayTitle(foundNote)}' from ${filenameIn}`)
358+
} else {
359+
throw new Error(`No teamspace note found for ${filenameIn}`)
360+
}
346361
} else {
347362
// Check for private notes
348363
foundNote = DataStore.projectNoteByFilename(filenameIn) ?? null
@@ -1262,10 +1277,10 @@ export async function getNoteFromParamOrUser(
12621277
purpose: string,
12631278
noteTitleArg: string = '',
12641279
notesIn?: Array<TNote>,
1265-
): Promise<TNote | null> {
1280+
): Promise<?TNote> {
12661281
// Note: deliberately no try/catch so that failure can stop processing
12671282
const startTime = new Date()
1268-
let note: TNote | null
1283+
let note: ?TNote
12691284
let noteTitleArgIsCalendarNote: boolean = false
12701285
logDebug('getNoteFromParamOrUser', `starting with purpose '${purpose}' / noteTitleArg '${noteTitleArg}' / with ${notesIn?.length ?? 0} notesIn`)
12711286

@@ -1276,8 +1291,9 @@ export async function getNoteFromParamOrUser(
12761291
const possDateStr = getDateStrFromRelativeDateString(noteTitleArg)
12771292
if (possDateStr) {
12781293
noteTitleArgIsCalendarNote = true
1294+
// $FlowFixMe[incompatible-type]
12791295
note = getOrMakeCalendarNote(possDateStr)
1280-
if (note) {
1296+
if (note != null) {
12811297
logDebug('getNoteFromParamOrUser', `Found match with relative date '${noteTitleArg}' = filename ${note?.filename ?? '(error)'}`)
12821298
return note
12831299
}
@@ -1317,8 +1333,9 @@ export async function getNoteFromParamOrUser(
13171333
// Preferably we'll use the last parameter, but if not calculate the list of notes to check
13181334
// const notesToCheck = getNotesToCheck(notesIn)
13191335
const result = await chooseNoteV2(`Select note for new ${purpose}`, notesIn, true, true, false, false)
1320-
if (typeof result !== 'boolean') {
1336+
if (note != null && typeof result !== 'boolean') {
13211337
note = result
1338+
// $FlowIgnore[incompatible-call] tested note is not null here
13221339
logDebug('getNoteFromParamOrUser', `- found note '${displayTitle(note)}'`)
13231340
}
13241341
}

helpers/general.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,22 @@ import { getDateStringFromCalendarFilename } from './dateTime'
1010
import { getFolderFromFilename } from './folders'
1111
import { parseTeamspaceFilename } from './teamspace'
1212

13+
//-------------------------------------------------------------------------------
14+
// Types
15+
1316
export type headingLevelType = 1 | 2 | 3 | 4 | 5
1417

1518
//-------------------------------------------------------------------------------
19+
// Version-related functions
20+
21+
export function isDecoratedCommandBarAvailable(): boolean {
22+
// From a v3.18.0 beta
23+
return ((NotePlan.environment.platform === 'macOS' && NotePlan.environment.buildVersion >= 1413)
24+
|| (NotePlan.environment.platform !== 'macOS' && NotePlan.environment.buildVersion >= 1338))
25+
}
26+
27+
//-------------------------------------------------------------------------------
28+
1629
/**
1730
* Case Insensitive version of Map
1831
* Keeps the first seen capitalasiation of a given key in a private #keysMap

helpers/userInput.js

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,18 @@ import { RE_DATE, RE_DATE_INTERVAL } from './dateTime'
1010
import { displayTitleWithRelDate } from './NPdateTime'
1111
import { clo, logDebug, logError, logInfo, logWarn, JSP } from './dev'
1212
import { getFoldersMatching } from './folders'
13+
import { isDecoratedCommandBarAvailable } from './general'
1314
import { getAllTeamspaceIDsAndTitles, getTeamspaceTitleFromID } from './NPTeamspace'
1415
import { getHeadingsFromNote, getOrMakeCalendarNote } from './NPnote'
1516
import { findStartOfActivePartOfNote, findEndOfActivePartOfNote } from './paragraph'
1617
import { parseTeamspaceFilename } from './teamspace'
1718

18-
//-------------------------------- Types --------------------------------------
19-
20-
type TFolderIcon = {
21-
firstLevelFolder: string,
22-
icon: string,
23-
emoji: string, // fallback to use before v3.18 (
24-
color: string,
25-
alpha?: number,
26-
darkAlpha?: number,
27-
}
28-
2919
//------------------------------ Constants ------------------------------------
3020

3121
const TEAMSPACE_ICON_COLOR = 'green-700'
3222

3323
//--------------------------- Local functions ---------------------------------
24+
3425
// NB: This fn is a local copy from helpers/general.js, to avoid a circular dependency
3526
function parseJSON5(contents: string): ?{ [string]: ?mixed } {
3627
try {
@@ -92,7 +83,7 @@ export async function chooseOptionWithModifiers<T, TDefault = T>(
9283
displayOptions = [{ label: '➕ Add new ' + addCreateItemDescriptor, value: '__ADD_NEW__' }, ...options]
9384
}
9485

95-
logDebug('userInput / chooseOptionWithModifiers()', `displayOptions: ${displayOptions.length} options`)
86+
// logDebug('userInput / chooseOptionWithModifiers()', `displayOptions: ${ displayOptions.length } options`)
9687

9788
// $FlowFixMe[prop-missing]
9889
const { index, keyModifiers } = await CommandBar.showOptions(
@@ -154,8 +145,8 @@ export async function chooseDecoratedOptionWithModifiers(
154145
// Use newer CommandBar.showOptions() from v3.18
155146
const result = await CommandBar.showOptions(displayOptions, message, '')
156147
const { index, keyModifiers } = result
157-
clo(result, `chooseDecoratedOptionWithModifiers chosen result`)
158-
clo(displayOptions[index], `from relevant displayOption`)
148+
// clo(result, `chooseDecoratedOptionWithModifiers chosen result`)
149+
// clo(displayOptions[index], `from relevant displayOption`)
159150

160151
// Check if the user selected "Add new item"
161152
if (additionalCreateNewOption && index === 0) {
@@ -361,7 +352,7 @@ export async function chooseFolder(
361352

362353
// Get user selection. Use newer CommandBar.showOptions() from v3.18 if available.
363354
let result: TCommandBarOptionObject | any
364-
if (NotePlan.environment.buildVersion >= 1413 && !forceOriginalCommandBar) {
355+
if (isDecoratedCommandBarAvailable() && !forceOriginalCommandBar) {
365356
// ✅ for list with add new option
366357
// ✅ for list without add new option
367358
// ✅ for both private + teamspace
@@ -481,7 +472,7 @@ export async function chooseFolder(
481472
}
482473

483474
/**
484-
* Create folder options for display (private function).
475+
* Create folder options for display.
485476
* Note: can't just have opt-click to create a new folder, because this doesn't work on iOS/iPadOS.
486477
* @param {Array} folders to create options for
487478
* @param {Array} teamspaceDefs - teamspace definitions
@@ -490,7 +481,7 @@ export async function chooseFolder(
490481
*
491482
* @returns {Array<{ label: string, value: string }> | Array<TCommandBarOptionObject>} formatted folder options
492483
*/
493-
function createFolderOptions(
484+
export function createFolderOptions(
494485
folders: Array<string>,
495486
teamspaceDefs: Array<TTeamspace>,
496487
includeFolderPath: boolean,
@@ -741,8 +732,8 @@ export async function chooseHeadingV2(
741732
headingLevel: number = 2,
742733
): Promise<string> {
743734
try {
744-
// If running on v3.17 or earlier, use the older chooseHeading() function
745-
if (NotePlan.environment.buildVersion < 1413) {
735+
// If running on v3.18 or earlier, use the older chooseHeading() function
736+
if (!isDecoratedCommandBarAvailable()) {
746737
return await chooseHeading(note, optionAddAtTopAndBottom, optionCreateNewHeading, includeArchive, headingLevel)
747738
}
748739

jgclark.Summaries/src/stats.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//-----------------------------------------------------------------------------
44
// Create statistics for hasthtags and mentions for time periods
55
// Jonathan Clark, @jgclark
6-
// Last updated 2025-10-07 for v1.0.0 by @jgclark
6+
// Last updated 2025-10-30 for v1.0.0+ by @jgclark
77
//-----------------------------------------------------------------------------
88

99
//-----------------------------------------------------------------------------
@@ -30,7 +30,7 @@ import { getPeriodStartEndDates, getPeriodStartEndDatesFromPeriodCode } from '@h
3030
import type { TPeriodCode } from '@helpers/NPdateTime'
3131
import { getOrMakeRegularNoteInFolder } from '@helpers/NPnote'
3232
import { noteOpenInEditor, openNoteInNewSplitIfNeeded } from '@helpers/NPWindows'
33-
import { chooseDecoratedOptionWithModifiers, chooseOption, showMessage } from '@helpers/userInput'
33+
import { chooseDecoratedOptionWithModifiers, chooseOption, isDecoratedCommandBarAvailable, showMessage } from '@helpers/userInput'
3434

3535
//-------------------------------------------------------------------------------
3636
// Main function
@@ -274,7 +274,7 @@ async function selectOutputDestination(
274274
return 'current'
275275
}
276276
let result = ''
277-
if (NotePlan.environment.buildVersion >= 1413) { // = 3.18.0
277+
if (isDecoratedCommandBarAvailable()) {
278278
// Start by tailoring the set of options to present
279279
const decoratedOutputOptions: Array<TCommandBarOptionObject> = [
280280
{ text: `Add/Update the ${calendarTimeframe}ly calendar note '${periodString}'`, icon: 'calendar-days', color: 'gray-500', shortDescription: ``, alpha: 0.8, darkAlpha: 0.8 },

np.Tidy/src/fileRoot.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
//-----------------------------------------------------------------------------
33
// Main functions for Tidy plugin
44
// Jonathan Clark
5-
// Last updated 2025-10-14 for v1.15.1, @jgclark
5+
// Last updated 2025-10-31 for v1.15.1+, @jgclark
66
//-----------------------------------------------------------------------------
77

88
import { getSettings, type TidyConfig } from './tidyHelpers'
99
import pluginJson from '../plugin.json'
1010
import { clo, JSP, logDebug, logError, logInfo, logWarn } from '@helpers/dev'
1111
import { getFolderDisplayName, getFolderListMinusExclusions, getProjectNotesInFolder } from '@helpers/folders'
12+
import { isDecoratedCommandBarAvailable } from '@helpers/general'
1213
import { appendStringToSettingArray } from '@helpers/NPSettings'
1314
import { getAllTeamspaceIDsAndTitles } from '@helpers/NPTeamspace'
14-
import { chooseOption, chooseHeading, chooseDecoratedOption, createFolderOptions, getInputTrimmed, showMessage, showMessageYesNo } from '@helpers/userInput'
15+
import { chooseOption, chooseHeading, chooseDecoratedOptionWithModifiers, createFolderOptions, getInputTrimmed, showMessage, showMessageYesNo } from '@helpers/userInput'
1516

1617
/**
1718
* For each root-level note, asks user which folder to move it to. (There's a setting for ones to ignore.)
@@ -40,7 +41,7 @@ export async function fileRootNotes(): Promise<void> {
4041
// Form options to present to user for each root note.
4142
// Form both simple and decorated options, ready for both versions of CommandBar.showOptions()
4243
const [simpleFolderOptions, decoratedFolderOptions] = createFolderOptions(allRelevantFolders, teamspaceDefs, true)
43-
if (NotePlan.environment.buildVersion >= 1413) {
44+
if (isDecoratedCommandBarAvailable()) {
4445
// Prepend some special items
4546
decoratedFolderOptions.unshift({icon: 'folder-plus', text: `Move to a new folder`, color: 'orange-500', shortDescription: 'Add new', alpha: 0.8, darkAlpha: 0.8})
4647
decoratedFolderOptions.unshift({icon: 'trash-can', text: `Delete this note`, color: 'red-500', shortDescription: 'Delete', alpha: 0.8, darkAlpha: 0.8})
@@ -76,8 +77,8 @@ export async function fileRootNotes(): Promise<void> {
7677

7778
// Ask user which folder to move to. Use newer CommandBar.showOptions() from v3.18 if available.
7879
let chosenOption: string = ''
79-
if (NotePlan.environment.buildVersion >= 1413) {
80-
const chosenDecoratedOption = await chooseDecoratedOption(`Move '${thisTitle}' to which folder?`, decoratedFolderOptions)
80+
if (isDecoratedCommandBarAvailable()) {
81+
const chosenDecoratedOption = await chooseDecoratedOptionWithModifiers(`Move '${thisTitle}' to which folder?`, decoratedFolderOptions)
8182
chosenOption = chosenDecoratedOption.value
8283
} else {
8384
chosenOption = await chooseOption(`Move '${thisTitle}' to which folder?`, simpleFolderOptions)

0 commit comments

Comments
 (0)