Skip to content

Commit ff46a6e

Browse files
committed
Snapshot of work-in-progress.
Current state reflected in the initial-auto-sort-and-notifications.md
1 parent 458f9d7 commit ff46a6e

File tree

2 files changed

+68
-34
lines changed

2 files changed

+68
-34
lines changed

docs/tech/initial-auto-sort-and-notifications.md

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,33 @@ Additional remarks:
3737

3838
Before all, capture the sequences of key execution points and events (related to #161)
3939

40-
Log below shows some unexpected edge cases and sequences of events, e.g. Lazy Plugin Loader, when
41-
the metadata-cache-populated event never reaches the plugin
42-
43-
Is it possible / feasible to both:
44-
- handle the optimistic scenario of auto-sorting on start on the first display of File Explorer? AND
45-
- gracefully handle the delayed scenario, e.g. Lazy Plugin Loader or for whatever reason?
46-
47-
The delayed scenario, should be handled with a popup and explicit user confirmation
48-
- can this scenario be indeed correctly recognised and not confused with other scenarios
49-
in which the automatic sorting should not be applied?
40+
Logs below show some unexpected edge cases and sequences of events, e.g. Lazy Plugin Loader, when
41+
the metadataCache-resolved event never reaches the plugin
42+
43+
The metadataCache-resolved event becomes very problematic and thus useless. At the same current
44+
implementation of the plugin relies on it heavily
45+
46+
Scenarios under consideration:
47+
(1a) optimistic scenario of auto-sorting on start on the first display of File Explorer.
48+
- theoretically can happen, never observed on 1.7.2
49+
- metadataCache-resolved event is ignored in this scenario
50+
- UX is excellent
51+
(1b) optimistic scenario of auto-sorting on start in response to metadataCache-resolved event
52+
- happens on desktop as the most frequent one
53+
- metadataCache-resolved event is triggering the custom sort almost immediately
54+
- UX also good, File Explorer appears with custom sorting, even if technically the std sorting was applied
55+
- on mobile the long-taking 'Obsidian is indexing your vault' can prevent the custom sort from being applied quickly
56+
(2) the delayed scenario, e.g. Lazy Plugin Loader or for whatever reason
57+
- happens with Lazy Plugin Loader, by definition
58+
- can happen in regular cases when there a many plugins, slow machine or a large vault
59+
- metadataCache-resolved event is never raised for the plugin until an explicit edit made by user
60+
- File Explorer appears in std order, then is reloaded with custom order
61+
62+
Conclusions based on the above scenarios:
63+
- the metadataCache-resolved event can be useful for (1b) both for quick and very delayed metadata cache population (e.g. on mobile)
64+
- detection of the scenario can be tricky: only first execution, not trigger heavy processing when unprepared
65+
- relating to onLayoutReady could be helpful (do nothing before that)
66+
- for (2) introduce a delayed checker of was-sorting-applied, e.g. every second, repeated N times (e.g. N=3) to support large vaults on slower devices
5067

5168
---
5269
Log

src/main.ts

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import {
22
apiVersion,
33
App,
4+
debounce,
45
FileExplorerView,
5-
Menu,
6-
MenuItem,
6+
Menu,
7+
MenuItem,
78
MetadataCache,
89
normalizePath,
910
Notice,
1011
Platform,
1112
Plugin,
1213
PluginSettingTab,
13-
requireApiVersion,
14+
requireApiVersion,
1415
sanitizeHTMLToDom,
1516
setIcon,
1617
Setting,
@@ -95,12 +96,9 @@ export default class CustomSortPlugin
9596
ribbonIconStateInaccurate: boolean // each time when displayed
9697

9798
sortSpecCache?: SortSpecsCollection | null
98-
initialAutoOrManualSortingTriggered: boolean
99+
initialAutoOrManualSortingTriggered: boolean = false
99100

100-
// Indicator of correct hooking up the plugin-integration-point:
101-
// - on initialization, OR
102-
// - after explicit user actions like enabling the custom sort
103-
fileExplorerFolderPatched: boolean
101+
fileExplorerPatched: boolean
104102

105103
showNotice(message: string, timeout?: number) {
106104
if (this.settings.notificationsEnabled || (Platform.isMobile && this.settings.mobileNotificationsEnabled)) {
@@ -224,10 +222,10 @@ export default class CustomSortPlugin
224222
// Safe to suspend when suspended and re-enable when enabled
225223
switchPluginStateTo(enabled: boolean, updateRibbonBtnIcon: boolean = true) {
226224
let fileExplorerView: FileExplorerView | undefined = this.checkFileExplorerIsAvailableAndPatchable()
227-
if (fileExplorerView && !this.fileExplorerFolderPatched) {
228-
this.fileExplorerFolderPatched = this.patchFileExplorerFolder(fileExplorerView);
225+
if (fileExplorerView && !this.fileExplorerPatched) {
226+
this.patchFileExplorer(fileExplorerView);
229227

230-
if (!this.fileExplorerFolderPatched) {
228+
if (!this.fileExplorerPatched) {
231229
fileExplorerView = undefined
232230
}
233231
}
@@ -264,9 +262,10 @@ export default class CustomSortPlugin
264262
}
265263

266264
if (fileExplorerView) {
267-
if (this.fileExplorerFolderPatched) {
268-
fileExplorerView.requestSort();
265+
if (this.fileExplorerPatched) {
266+
cl('trued via switchPluginState')
269267
this.initialAutoOrManualSortingTriggered = true
268+
fileExplorerView.requestSort();
270269
}
271270
} else {
272271
if (iconToSet === ICON_SORT_ENABLED_ACTIVE) {
@@ -315,7 +314,7 @@ export default class CustomSortPlugin
315314
});
316315

317316
if (!this.settings.suspended) {
318-
this.ribbonIconStateInaccurate = true
317+
this.ribbonIconStateInaccurate = true // sort enabled but not (yet) applied automatically
319318
}
320319

321320
this.addSettingTab(new CustomSortSettingTab(this.app, this));
@@ -341,17 +340,18 @@ export default class CustomSortPlugin
341340
if (this.sortSpecCache) { // successful read of sorting specifications?
342341
this.showNotice('Custom sort ON')
343342
let fileExplorerView: FileExplorerView | undefined = this.checkFileExplorerIsAvailableAndPatchable(false)
344-
if (fileExplorerView && !this.fileExplorerFolderPatched) {
345-
this.fileExplorerFolderPatched = this.patchFileExplorerFolder(fileExplorerView);
343+
if (fileExplorerView && !this.fileExplorerPatched) {
344+
this.patchFileExplorer(fileExplorerView);
346345

347-
if (!this.fileExplorerFolderPatched) {
346+
if (!this.fileExplorerPatched) {
348347
fileExplorerView = undefined
349348
}
350349
}
351350
if (fileExplorerView) {
352351
setIcon(this.ribbonIconEl, ICON_SORT_ENABLED_ACTIVE)
353-
fileExplorerView.requestSort()
352+
cl('trued via on metadataCache')
354353
this.initialAutoOrManualSortingTriggered = true
354+
fileExplorerView.requestSort()
355355
} else {
356356
// Remark: in this case the File Explorer will render later on with standard Obsidian sort
357357
// and a different event will be responsible for patching it and applying the custom sort
@@ -580,8 +580,11 @@ export default class CustomSortPlugin
580580
}
581581

582582
initialize() {
583+
const plugin = this
583584
this.app.workspace.onLayoutReady(() => {
584-
this.fileExplorerFolderPatched = this.patchFileExplorerFolder();
585+
cl('on layout ready - registering delayed')
586+
setTimeout(() => { plugin.delayedPostLoadCheck.apply(this) }, 1000)
587+
this.patchFileExplorer();
585588
})
586589
}
587590

@@ -635,8 +638,9 @@ export default class CustomSortPlugin
635638
}
636639

637640
// For the idea of monkey-patching credits go to https://github.com/nothingislost/obsidian-bartender
638-
patchFileExplorerFolder(patchableFileExplorer?: FileExplorerView): boolean {
641+
patchFileExplorer(patchableFileExplorer?: FileExplorerView): void {
639642
let plugin = this;
643+
plugin.fileExplorerPatched = false
640644
const requestStandardObsidianSortAfter = (patchUninstaller: MonkeyAroundUninstaller|undefined) => {
641645
return () => {
642646
if (patchUninstaller) patchUninstaller()
@@ -660,7 +664,7 @@ export default class CustomSortPlugin
660664
getSortedFolderItems(old: any) {
661665
cl('f pre-1', 'patched getSortedFolderItems factory!')
662666
return function (...args: any[]) {
663-
cl('f', 'patched getSortedFolderItems invoked!')
667+
cl('f', `patched getSortedFolderItems invoked with ${plugin.settings.suspended ? 'std' : 'custom'}!`)
664668
// quick check for plugin status
665669
if (plugin.settings.suspended) {
666670
return old.call(this, ...args);
@@ -672,6 +676,7 @@ export default class CustomSortPlugin
672676
const sortingData = plugin.determineAndPrepareSortingDataForFolder(folder)
673677

674678
if (sortingData.sortSpec) {
679+
cl('f', `patched getSortedFolderItems invoked with custom and applied!`)
675680
return getSortedFolderItems_vFrom_1_6_0.call(this, folder, sortingData.sortSpec, plugin.createProcessingContextForSorting(sortingData.sortingAndGroupingStats))
676681
} else {
677682
return old.call(this, ...args);
@@ -681,7 +686,7 @@ export default class CustomSortPlugin
681686
})
682687
this.register(requestStandardObsidianSortAfter(uninstallerOfFolderSortFunctionWrapper))
683688
cl('b', '1.6.0+ and patched getSortedFolderItems()')
684-
return true
689+
plugin.fileExplorerPatched = true
685690
} else {
686691
// Up to Obsidian 1.6.0
687692
// @ts-ignore
@@ -712,11 +717,10 @@ export default class CustomSortPlugin
712717
})
713718
this.register(requestStandardObsidianSortAfter(uninstallerOfFolderSortFunctionWrapper))
714719
cl('b', '<1.6.0 and patched sort() on Folder thanks to createFolderDom()')
715-
return true
720+
plugin.fileExplorerPatched = true
716721
}
717722
} else {
718723
cl('b', 'failed')
719-
return false
720724
}
721725
}
722726

@@ -767,6 +771,19 @@ export default class CustomSortPlugin
767771
await this.saveData(this.settings);
768772
}
769773

774+
delayedPostLoadCheck() {
775+
// should be applied? yes (based on settings)
776+
const shouldSortingBeApplied = !this.settings.suspended
777+
778+
// has been applied? no (based on status)
779+
const hasSortingBeenApplied1 = this.initialAutoOrManualSortingTriggered
780+
const hasSortingBeenApplied2 = !this.ribbonIconStateInaccurate
781+
782+
const dododo = shouldSortingBeApplied && !hasSortingBeenApplied1 ? 'DO!!! ' : ''
783+
784+
cl('delayed post-load check', `${dododo}should? ${shouldSortingBeApplied} has been? ${hasSortingBeenApplied1} ${hasSortingBeenApplied2}`)
785+
}
786+
770787
// API
771788
derivedIndexNoteNameForFolderNotes: string | undefined
772789
indexNoteNameForFolderNotesDerivedFrom: any

0 commit comments

Comments
 (0)