From 5aed85c0bd572436604ba25a6810265c7a5de27b Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Fri, 23 Sep 2022 20:10:31 +0200 Subject: [PATCH 1/8] 13 - Feature request: Sort by modification date, treating folder and files equally - working solution - added new explicitly named sort method 'advanced modified' on top of 'modified' - unit tests to be added before merge and release --- src/custom-sort/custom-sort-types.ts | 2 + src/custom-sort/custom-sort.ts | 61 ++++++++++++++++--- .../sorting-spec-processor.spec.ts | 6 +- src/custom-sort/sorting-spec-processor.ts | 3 +- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/custom-sort/custom-sort-types.ts b/src/custom-sort/custom-sort-types.ts index ed79c19..bc727d9 100644 --- a/src/custom-sort/custom-sort-types.ts +++ b/src/custom-sort/custom-sort-types.ts @@ -11,7 +11,9 @@ export enum CustomSortOrder { alphabetical = 1, // = 1 to allow: if (customSortOrder) { ... alphabeticalReverse, byModifiedTime, + byModifiedTimeAdvanced, byModifiedTimeReverse, + byModifiedTimeReverseAdvanced, byCreatedTime, byCreatedTimeReverse, standardObsidian, // Let the folder sorting be in hands of Obsidian, whatever user selected in the UI diff --git a/src/custom-sort/custom-sort.ts b/src/custom-sort/custom-sort.ts index 460de86..39637a6 100644 --- a/src/custom-sort/custom-sort.ts +++ b/src/custom-sort/custom-sort.ts @@ -1,4 +1,4 @@ -import {requireApiVersion, TFile, TFolder} from 'obsidian'; +import {requireApiVersion, TAbstractFile, TFile, TFolder} from 'obsidian'; import {CustomSortGroup, CustomSortGroupType, CustomSortOrder, CustomSortSpec} from "./custom-sort-types"; import {isDefined} from "../utils/utils"; @@ -16,6 +16,7 @@ interface FolderItemForSorting { ctime: number mtime: number isFolder: boolean + folder?: TFolder } type SorterFn = (a: FolderItemForSorting, b: FolderItemForSorting) => number @@ -24,7 +25,9 @@ let Sorters: { [key in CustomSortOrder]: SorterFn } = { [CustomSortOrder.alphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString), [CustomSortOrder.alphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(b.sortString, a.sortString), [CustomSortOrder.byModifiedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime, + [CustomSortOrder.byModifiedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime, [CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime, + [CustomSortOrder.byModifiedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime, [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime, [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime, @@ -52,11 +55,14 @@ function compareTwoItems(itA: FolderItemForSorting, itB: FolderItemForSorting, s } } -const isFolder = (entry: TFile | TFolder) => { +const isFolder = (entry: TAbstractFile) => { // The plain obvious 'entry instanceof TFolder' doesn't work inside Jest unit tests, hence a workaround below return !!((entry as any).isRoot); } +export const DEFAULT_FOLDER_MTIME: number = 0 +export const DEFAULT_FOLDER_CTIME: number = 0 + export const determineSortingGroup = function (entry: TFile | TFolder, spec: CustomSortSpec): FolderItemForSorting { let groupIdx: number let determined: boolean = false @@ -165,14 +171,37 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus sortString: matchedGroup ? (matchedGroup + '//' + entry.name) : entry.name, matchGroup: matchedGroup ?? undefined, isFolder: aFolder, + folder: aFolder ? (entry as TFolder) : undefined, path: entry.path, - ctime: aFile ? entryAsTFile.stat.ctime : 0, - mtime: aFile ? entryAsTFile.stat.mtime : 0 + ctime: aFile ? entryAsTFile.stat.ctime : DEFAULT_FOLDER_CTIME, + mtime: aFile ? entryAsTFile.stat.mtime : DEFAULT_FOLDER_MTIME } } +export const sortOrderNeedsFoldersMDate = (order: CustomSortOrder | undefined): boolean => { + return order === CustomSortOrder.byModifiedTimeAdvanced || order === CustomSortOrder.byModifiedTimeReverseAdvanced +} + +// Syntax sugar for readability +export type ModifiedTime = number + +export const determineModifiedDateForFolder = (folder: TFolder): ModifiedTime => { + let mtimeOfFolder: ModifiedTime = DEFAULT_FOLDER_MTIME + folder.children.forEach((item) => { + if (!isFolder(item)) { + const file: TFile = item as TFile + if (file.stat.mtime > mtimeOfFolder) { + mtimeOfFolder = file.stat.mtime + } + } + }) + return mtimeOfFolder +} + + export const folderSort = function (sortingSpec: CustomSortSpec, order: string[]) { let fileExplorer = this.fileExplorer + const sortingGroupsCardinality: {[key: number]: number} = {} const folderItems: Array = (sortingSpec.itemsToHide ? this.file.children.filter((entry: TFile | TFolder) => { @@ -180,9 +209,27 @@ export const folderSort = function (sortingSpec: CustomSortSpec, order: string[] }) : this.file.children) - .map((entry: TFile | TFolder) => - determineSortingGroup(entry, sortingSpec) - ) + .map((entry: TFile | TFolder) => { + const itemForSorting: FolderItemForSorting = determineSortingGroup(entry, sortingSpec) + const groupIdx: number | undefined = itemForSorting.groupIdx + if (groupIdx !== undefined) { + sortingGroupsCardinality[groupIdx] = 1 + (sortingGroupsCardinality[groupIdx] ?? 0) + } + return itemForSorting + }) + + // Finally, for advanced sorting by modified date, for some of the folders the modified date has to be determined + folderItems.forEach((item) => { + const groupIdx: number | undefined = item.groupIdx + if (groupIdx !== undefined) { + const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].order + if (sortOrderNeedsFoldersMDate(groupOrder)) { + if (item.folder) { + item.mtime = determineModifiedDateForFolder(item.folder) + } + } + } + }) folderItems.sort(function (itA: FolderItemForSorting, itB: FolderItemForSorting) { return compareTwoItems(itA, itB, sortingSpec); diff --git a/src/custom-sort/sorting-spec-processor.spec.ts b/src/custom-sort/sorting-spec-processor.spec.ts index d680158..b96eef4 100644 --- a/src/custom-sort/sorting-spec-processor.spec.ts +++ b/src/custom-sort/sorting-spec-processor.spec.ts @@ -31,7 +31,7 @@ target-folder: tricky folder target-folder: / /: Con... / - > modified + > advanced modified /: < modified /: Ref... @@ -78,7 +78,7 @@ target-folder: tricky folder target-folder: / /:files Con... /folders - > modified + > advanced modified /:files < modified /:files Ref... @@ -163,7 +163,7 @@ const expectedSortSpecsExampleA: { [key: string]: CustomSortSpec } = { type: CustomSortGroupType.ExactPrefix }, { foldersOnly: true, - order: CustomSortOrder.byModifiedTimeReverse, + order: CustomSortOrder.byModifiedTimeReverseAdvanced, type: CustomSortGroupType.Outsiders }, { filesOnly: true, diff --git a/src/custom-sort/sorting-spec-processor.ts b/src/custom-sort/sorting-spec-processor.ts index 3f0050d..146e835 100644 --- a/src/custom-sort/sorting-spec-processor.ts +++ b/src/custom-sort/sorting-spec-processor.ts @@ -86,6 +86,7 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { 'a-z': {asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse}, 'created': {asc: CustomSortOrder.byCreatedTime, desc: CustomSortOrder.byCreatedTimeReverse}, 'modified': {asc: CustomSortOrder.byModifiedTime, desc: CustomSortOrder.byModifiedTimeReverse}, + 'advanced modified': {asc: CustomSortOrder.byModifiedTimeAdvanced, desc: CustomSortOrder.byModifiedTimeReverseAdvanced}, // Advanced, for edge cases of secondary sorting, when if regexp match is the same, override the alphabetical sorting by full name 'a-z, created': { @@ -399,7 +400,7 @@ export class SortingSpecProcessor { lineIdx++ this.currentEntryLine = entryLine this.currentEntryLineIdx = lineIdx - this.currentSortingSpecContainerFilePath = `${folderPath}/${sortingSpecFileName}` + this.currentSortingSpecContainerFilePath = `${folderPath === '/' ? '' : folderPath}/${sortingSpecFileName}` this.problemAlreadyReportedForCurrentLine = false const trimmedEntryLine: string = entryLine.trim() From 2b77ce058dfe8fc0bf1ae112b1258693dbb5064f Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Sun, 25 Sep 2022 22:50:27 +0200 Subject: [PATCH 2/8] 13 - Feature request: Sort by modification date, treating folder and files equally - finetuned the 'modified' sorting method - not the folders are ordered alphabetically, as the standard Obsidiand sort by 'modified date' does - finetuned the 'created' sorting method in the same way as 'modified' - added some initial content to syntax-reference.md ;-) - extended the 'advanced modified' sorting method to also support the edge-case secondary sorting methods for groups --- docs/syntax-reference.md | 42 +++++++++++++++++++++-- src/custom-sort/custom-sort.ts | 15 ++++---- src/custom-sort/sorting-spec-processor.ts | 10 ++++++ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/docs/syntax-reference.md b/docs/syntax-reference.md index da2dd93..6c6618a 100644 --- a/docs/syntax-reference.md +++ b/docs/syntax-reference.md @@ -1,3 +1,41 @@ -Yet to be filled with content ;-) +> Document is partial, creation in progress +> Please refer to [README.md](../../README.md) for usage examples +> Check [manual.md](), maybe that file has already some content? -Check [manual.md](), maybe that file has already some content? +### Supported sorting methods + +#### At folder level only + +- `sorting: standard` - gives back the control on order of items in hands of standard Obsidian mechanisms (UI driven). + Typical (and intended) use: exclude a folder (or folders subtree) from a custom sorting resulting from wilcard-based target folder rule + +#### At folder and group level + +- `< a-z` - alphabetical +- `> a-z` - alphabetical reverse, aka alphabetical descending, 'z' goes before 'a' +- `< modified` - by modified time, the long untouched item goes first (modified time of folder is assumed the beginning of the world, so folders go first and alphabetical) +- `> modified` - by modified time reverse, the most recently modified item goes first (modified time of folder is assumed the beginning of the world, so folders land in the bottom and alphabetical) +- `< created` - by created time, the oldest item goes first (modified time of folder is assumed the beginning of the world, so folders go first and alphabetical) +- `> created` - by created time reverse, the newest item goes first (modified time of folder is assumed the beginning of the world, so folders land in the bottom and alphabetical) +- `< advanced modified` - by modified time, the long untouched item goes first. For folders, their modification date is derived from the most recently modified direct child file. + For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's modified date +- `> advanced modified` - by modified time reverse, the most recently modified item goes first. For folders, their modification date is derived from the most recently modified direct child file. + For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's modified date + +#### At group level only (aka secondary sorting rule) + +> Only applicable in edge cases based on numerical symbols, when the regex-based match is equal for more than one item + and need to apply a secondary order on same matches. + +- `< a-z, created` +- `> a-z, created` +- `< a-z, created desc` +- `> a-z, created desc` +- `< a-z, modified` +- `> a-z, modified` +- `< a-z, modified desc` +- `> a-z, modified desc` +- `< a-z, advanced modified` +- `> a-z, advanced modified` +- `< a-z, advanced modified desc` +- `> a-z, advanced modified desc` diff --git a/src/custom-sort/custom-sort.ts b/src/custom-sort/custom-sort.ts index 39637a6..7169e14 100644 --- a/src/custom-sort/custom-sort.ts +++ b/src/custom-sort/custom-sort.ts @@ -24,12 +24,12 @@ type SorterFn = (a: FolderItemForSorting, b: FolderItemForSorting) => number let Sorters: { [key in CustomSortOrder]: SorterFn } = { [CustomSortOrder.alphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString), [CustomSortOrder.alphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(b.sortString, a.sortString), - [CustomSortOrder.byModifiedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime, + [CustomSortOrder.byModifiedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (a.mtime - b.mtime), [CustomSortOrder.byModifiedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime, - [CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime, + [CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.mtime - a.mtime), [CustomSortOrder.byModifiedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime, - [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime, - [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime, + [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (a.ctime - b.ctime), + [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.ctime - a.ctime), // This is a fallback entry which should not be used - the plugin code should refrain from custom sorting at all [CustomSortOrder.standardObsidian]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString), @@ -178,8 +178,11 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus } } -export const sortOrderNeedsFoldersMDate = (order: CustomSortOrder | undefined): boolean => { - return order === CustomSortOrder.byModifiedTimeAdvanced || order === CustomSortOrder.byModifiedTimeReverseAdvanced +export const sortOrderNeedsFoldersMDate = (order: CustomSortOrder | undefined, secondary?: CustomSortOrder): boolean => { + return order === CustomSortOrder.byModifiedTimeAdvanced + || order === CustomSortOrder.byModifiedTimeReverseAdvanced + || secondary === CustomSortOrder.byModifiedTimeAdvanced + || secondary === CustomSortOrder.byModifiedTimeReverseAdvanced } // Syntax sugar for readability diff --git a/src/custom-sort/sorting-spec-processor.ts b/src/custom-sort/sorting-spec-processor.ts index 146e835..28d2fb7 100644 --- a/src/custom-sort/sorting-spec-processor.ts +++ b/src/custom-sort/sorting-spec-processor.ts @@ -108,6 +108,16 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse, secondary: CustomSortOrder.byModifiedTimeReverse + }, + 'a-z, advanced modified': { + asc: CustomSortOrder.alphabetical, + desc: CustomSortOrder.alphabeticalReverse, + secondary: CustomSortOrder.byModifiedTimeAdvanced + }, + 'a-z, advanced modified desc': { + asc: CustomSortOrder.alphabetical, + desc: CustomSortOrder.alphabeticalReverse, + secondary: CustomSortOrder.byModifiedTimeReverseAdvanced } } From 1b8e0878af224bae4b989ced4612ce866575b319 Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Mon, 26 Sep 2022 16:18:35 +0200 Subject: [PATCH 3/8] 13 - Feature request: Sort by modification date, treating folder and files equally - extended the advanced folder date handling also on the creation date --- src/custom-sort/custom-sort-types.ts | 2 ++ src/custom-sort/custom-sort.ts | 31 ++++++++++++++++------- src/custom-sort/sorting-spec-processor.ts | 11 ++++++++ 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/custom-sort/custom-sort-types.ts b/src/custom-sort/custom-sort-types.ts index bc727d9..df30449 100644 --- a/src/custom-sort/custom-sort-types.ts +++ b/src/custom-sort/custom-sort-types.ts @@ -15,7 +15,9 @@ export enum CustomSortOrder { byModifiedTimeReverse, byModifiedTimeReverseAdvanced, byCreatedTime, + byCreatedTimeAdvanced, byCreatedTimeReverse, + byCreatedTimeReverseAdvanced, standardObsidian, // Let the folder sorting be in hands of Obsidian, whatever user selected in the UI default = alphabetical } diff --git a/src/custom-sort/custom-sort.ts b/src/custom-sort/custom-sort.ts index 7169e14..3800adc 100644 --- a/src/custom-sort/custom-sort.ts +++ b/src/custom-sort/custom-sort.ts @@ -29,7 +29,9 @@ let Sorters: { [key in CustomSortOrder]: SorterFn } = { [CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.mtime - a.mtime), [CustomSortOrder.byModifiedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime, [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (a.ctime - b.ctime), + [CustomSortOrder.byCreatedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime, [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.ctime - a.ctime), + [CustomSortOrder.byCreatedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime, // This is a fallback entry which should not be used - the plugin code should refrain from custom sorting at all [CustomSortOrder.standardObsidian]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString), @@ -178,27 +180,38 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus } } -export const sortOrderNeedsFoldersMDate = (order: CustomSortOrder | undefined, secondary?: CustomSortOrder): boolean => { - return order === CustomSortOrder.byModifiedTimeAdvanced - || order === CustomSortOrder.byModifiedTimeReverseAdvanced - || secondary === CustomSortOrder.byModifiedTimeAdvanced - || secondary === CustomSortOrder.byModifiedTimeReverseAdvanced +const SortOrderRequiringFolderDate = new Set([ + CustomSortOrder.byModifiedTimeAdvanced, + CustomSortOrder.byModifiedTimeReverseAdvanced, + CustomSortOrder.byCreatedTimeAdvanced, + CustomSortOrder.byCreatedTimeReverseAdvanced +]) + +export const sortOrderNeedsFolderDates = (order: CustomSortOrder | undefined, secondary?: CustomSortOrder): boolean => { + // The CustomSortOrder.standardObsidian used as default because it doesn't require date on folders + return SortOrderRequiringFolderDate.has(order ?? CustomSortOrder.standardObsidian) + || SortOrderRequiringFolderDate.has(secondary ?? CustomSortOrder.standardObsidian) } // Syntax sugar for readability export type ModifiedTime = number +export type CreatedTime = number -export const determineModifiedDateForFolder = (folder: TFolder): ModifiedTime => { +export const determineDatesForFolder = (folder: TFolder): [ModifiedTime, CreatedTime] => { let mtimeOfFolder: ModifiedTime = DEFAULT_FOLDER_MTIME + let ctimeOfFolder: CreatedTime = DEFAULT_FOLDER_CTIME folder.children.forEach((item) => { if (!isFolder(item)) { const file: TFile = item as TFile if (file.stat.mtime > mtimeOfFolder) { mtimeOfFolder = file.stat.mtime } + if (file.stat.ctime > ctimeOfFolder) { + ctimeOfFolder = file.stat.ctime + } } }) - return mtimeOfFolder + return [mtimeOfFolder, ctimeOfFolder] } @@ -226,9 +239,9 @@ export const folderSort = function (sortingSpec: CustomSortSpec, order: string[] const groupIdx: number | undefined = item.groupIdx if (groupIdx !== undefined) { const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].order - if (sortOrderNeedsFoldersMDate(groupOrder)) { + if (sortOrderNeedsFolderDates(groupOrder)) { if (item.folder) { - item.mtime = determineModifiedDateForFolder(item.folder) + [item.mtime, item.ctime] = determineDatesForFolder(item.folder) } } } diff --git a/src/custom-sort/sorting-spec-processor.ts b/src/custom-sort/sorting-spec-processor.ts index 28d2fb7..e281af1 100644 --- a/src/custom-sort/sorting-spec-processor.ts +++ b/src/custom-sort/sorting-spec-processor.ts @@ -87,6 +87,7 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { 'created': {asc: CustomSortOrder.byCreatedTime, desc: CustomSortOrder.byCreatedTimeReverse}, 'modified': {asc: CustomSortOrder.byModifiedTime, desc: CustomSortOrder.byModifiedTimeReverse}, 'advanced modified': {asc: CustomSortOrder.byModifiedTimeAdvanced, desc: CustomSortOrder.byModifiedTimeReverseAdvanced}, + 'advanced created': {asc: CustomSortOrder.byCreatedTimeAdvanced, desc: CustomSortOrder.byCreatedTimeReverseAdvanced}, // Advanced, for edge cases of secondary sorting, when if regexp match is the same, override the alphabetical sorting by full name 'a-z, created': { @@ -109,6 +110,16 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { desc: CustomSortOrder.alphabeticalReverse, secondary: CustomSortOrder.byModifiedTimeReverse }, + 'a-z, advanced created': { + asc: CustomSortOrder.alphabetical, + desc: CustomSortOrder.alphabeticalReverse, + secondary: CustomSortOrder.byCreatedTimeAdvanced + }, + 'a-z, advanced created desc': { + asc: CustomSortOrder.alphabetical, + desc: CustomSortOrder.alphabeticalReverse, + secondary: CustomSortOrder.byCreatedTimeReverseAdvanced + }, 'a-z, advanced modified': { asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse, From bfd093bbf2c90d2e5a9f960a238466db83546fc5 Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Mon, 26 Sep 2022 16:40:24 +0200 Subject: [PATCH 4/8] 13 - Feature request: Sort by modification date, treating folder and files equally - added unit tests coverage for the extended sorting methods in sorting specification processor --- .../sorting-spec-processor.spec.ts | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/custom-sort/sorting-spec-processor.spec.ts b/src/custom-sort/sorting-spec-processor.spec.ts index b96eef4..288d0b7 100644 --- a/src/custom-sort/sorting-spec-processor.spec.ts +++ b/src/custom-sort/sorting-spec-processor.spec.ts @@ -865,6 +865,102 @@ describe('SortingSpecProcessor path wildcard priorities', () => { }) }) +const txtInputAdvancedFolderDateSortingMethods: string = ` +target-folder: A +< advanced modified +target-folder: B +> advanced modified +target-folder: C +< advanced created +target-folder: D +> advanced created +target-folder: AA +/folders + < advanced modified +/:files + > advanced modified +/folders Archive... + < advanced created +/:files Archive... + > advanced created +` + +const expectedSortSpecForAdvancedFolderDateSortingMethods: { [key: string]: CustomSortSpec } = { + 'A': { + defaultOrder: CustomSortOrder.byModifiedTimeAdvanced, + groups: [{ + order: CustomSortOrder.byModifiedTimeAdvanced, + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['A'] + }, + 'B': { + defaultOrder: CustomSortOrder.byModifiedTimeReverseAdvanced, + groups: [{ + order: CustomSortOrder.byModifiedTimeReverseAdvanced, + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['B'] + }, + 'C': { + defaultOrder: CustomSortOrder.byCreatedTimeAdvanced, + groups: [{ + order: CustomSortOrder.byCreatedTimeAdvanced, + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['C'] + }, + 'D': { + defaultOrder: CustomSortOrder.byCreatedTimeReverseAdvanced, + groups: [{ + order: CustomSortOrder.byCreatedTimeReverseAdvanced, + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['D'] + }, + 'AA': { + groups: [{ + foldersOnly: true, + order: CustomSortOrder.byModifiedTimeAdvanced, + type: CustomSortGroupType.Outsiders + }, { + filesOnly: true, + order: CustomSortOrder.byModifiedTimeReverseAdvanced, + type: CustomSortGroupType.Outsiders + }, { + exactPrefix: 'Archive', + foldersOnly: true, + order: CustomSortOrder.byCreatedTimeAdvanced, + type: 3 + }, { + exactPrefix: 'Archive', + filesOnly: true, + order: CustomSortOrder.byCreatedTimeReverseAdvanced, + type: 3 + }], + outsidersFilesGroupIdx: 1, + outsidersFoldersGroupIdx: 0, + targetFoldersPaths: ['AA'] + } +} + +describe('SortingSpecProcessor advanced folder-date based sorting methods', () => { + let processor: SortingSpecProcessor; + beforeEach(() => { + processor = new SortingSpecProcessor(); + }); + it('should not raise error for multiple spec for the same path and choose correct spec, case A', () => { + const inputTxtArr: Array = txtInputAdvancedFolderDateSortingMethods.split('\n') + const result = processor.parseSortSpecFromText(inputTxtArr, 'mock-folder', 'custom-name-note.md') + expect(result?.sortSpecByPath).toEqual(expectedSortSpecForAdvancedFolderDateSortingMethods) + expect(result?.sortSpecByWildcard).toBeUndefined() + }) +}) + const errorsLogger = jest.fn(); const ERR_PREFIX = 'Sorting specification problem:' From 72550fc01ddedf92993406da64e4cc2e19034293 Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Mon, 26 Sep 2022 19:00:23 +0200 Subject: [PATCH 5/8] 13 - Feature request: Sort by modification date, treating folder and files equally - added unit tests coverage the logic of determining dates for folders --- src/custom-sort/custom-sort-types.ts | 6 +- src/custom-sort/custom-sort.spec.ts | 132 ++++++++++++++++++++++++--- src/custom-sort/custom-sort.ts | 59 +++++++----- 3 files changed, 159 insertions(+), 38 deletions(-) diff --git a/src/custom-sort/custom-sort-types.ts b/src/custom-sort/custom-sort-types.ts index df30449..8a65ab0 100644 --- a/src/custom-sort/custom-sort-types.ts +++ b/src/custom-sort/custom-sort-types.ts @@ -10,11 +10,11 @@ export enum CustomSortGroupType { export enum CustomSortOrder { alphabetical = 1, // = 1 to allow: if (customSortOrder) { ... alphabeticalReverse, - byModifiedTime, + byModifiedTime, // New to old byModifiedTimeAdvanced, - byModifiedTimeReverse, + byModifiedTimeReverse, // Old to new byModifiedTimeReverseAdvanced, - byCreatedTime, + byCreatedTime, // New to old byCreatedTimeAdvanced, byCreatedTimeReverse, byCreatedTimeReverseAdvanced, diff --git a/src/custom-sort/custom-sort.spec.ts b/src/custom-sort/custom-sort.spec.ts index e70c65f..e0f1d88 100644 --- a/src/custom-sort/custom-sort.spec.ts +++ b/src/custom-sort/custom-sort.spec.ts @@ -1,6 +1,11 @@ import {TFile, TFolder, Vault} from 'obsidian'; -import {determineSortingGroup} from './custom-sort'; -import {CustomSortGroupType, CustomSortSpec} from './custom-sort-types'; +import { + DEFAULT_FOLDER_CTIME, + determineFolderDatesIfNeeded, + determineSortingGroup, + FolderItemForSorting +} from './custom-sort'; +import {CustomSortGroupType, CustomSortOrder, CustomSortSpec} from './custom-sort-types'; import {CompoundDashNumberNormalizerFn, CompoundDotRomanNumberNormalizerFn} from "./sorting-spec-processor"; const mockTFile = (basename: string, ext: string, size?: number, ctime?: number, mtime?: number): TFile => { @@ -19,7 +24,31 @@ const mockTFile = (basename: string, ext: string, size?: number, ctime?: number, } } +const mockTFolder = (name: string, children?: Array, parent?: TFolder): TFolder => { + return { + isRoot(): boolean { return name === '/' }, + vault: {} as Vault, // To satisfy TS typechecking + path: `/${name}`, + name: name, + parent: parent ?? ({} as TFolder), // To satisfy TS typechecking + children: children ?? [] + } +} + const MOCK_TIMESTAMP: number = 1656417542418 +const TIMESTAMP_OLDEST: number = MOCK_TIMESTAMP +const TIMESTAMP_NEWEST: number = MOCK_TIMESTAMP + 1000 +const TIMESTAMP_INBETWEEN: number = MOCK_TIMESTAMP + 500 + +const mockTFolderWithChildren = (name: string): TFolder => { + const child1: TFolder = mockTFolder('Section A') + const child2: TFolder = mockTFolder('Section B') + const child3: TFile = mockTFile('Child file 1 created as oldest, modified recently', 'md', 100, TIMESTAMP_OLDEST, TIMESTAMP_NEWEST) + const child4: TFile = mockTFile('Child file 2 created as newest, not modified at all', 'md', 100, TIMESTAMP_NEWEST, TIMESTAMP_NEWEST) + const child5: TFile = mockTFile('Child file 3 created inbetween, modified inbetween', 'md', 100, TIMESTAMP_INBETWEEN, TIMESTAMP_INBETWEEN) + + return mockTFolder('Mock parent folder', [child1, child2, child3, child4, child5]) +} describe('determineSortingGroup', () => { describe('CustomSortGroupType.ExactHeadAndTail', () => { @@ -43,7 +72,8 @@ describe('determineSortingGroup', () => { groupIdx: 0, isFolder: false, sortString: "References.md", - ctime: MOCK_TIMESTAMP + 222, + ctimeNewest: MOCK_TIMESTAMP + 222, + ctimeOldest: MOCK_TIMESTAMP + 222, mtime: MOCK_TIMESTAMP + 333, path: 'Some parent folder/References.md' }); @@ -68,7 +98,8 @@ describe('determineSortingGroup', () => { groupIdx: 1, // This indicates the last+1 idx isFolder: false, sortString: "References.md", - ctime: MOCK_TIMESTAMP + 555, + ctimeNewest: MOCK_TIMESTAMP + 555, + ctimeOldest: MOCK_TIMESTAMP + 555, mtime: MOCK_TIMESTAMP + 666, path: 'Some parent folder/References.md' }); @@ -96,7 +127,8 @@ describe('determineSortingGroup', () => { groupIdx: 1, // This indicates the last+1 idx isFolder: false, sortString: "Part123:-icle.md", - ctime: MOCK_TIMESTAMP + 555, + ctimeNewest: MOCK_TIMESTAMP + 555, + ctimeOldest: MOCK_TIMESTAMP + 555, mtime: MOCK_TIMESTAMP + 666, path: 'Some parent folder/Part123:-icle.md' }); @@ -125,7 +157,8 @@ describe('determineSortingGroup', () => { isFolder: false, sortString: "00000123////Part123:-icle.md", matchGroup: '00000123//', - ctime: MOCK_TIMESTAMP + 555, + ctimeNewest: MOCK_TIMESTAMP + 555, + ctimeOldest: MOCK_TIMESTAMP + 555, mtime: MOCK_TIMESTAMP + 666, path: 'Some parent folder/Part123:-icle.md' }); @@ -153,7 +186,8 @@ describe('determineSortingGroup', () => { groupIdx: 1, // This indicates the last+1 idx isFolder: false, sortString: "Part:123-icle.md", - ctime: MOCK_TIMESTAMP + 555, + ctimeNewest: MOCK_TIMESTAMP + 555, + ctimeOldest: MOCK_TIMESTAMP + 555, mtime: MOCK_TIMESTAMP + 666, path: 'Some parent folder/Part:123-icle.md' }); @@ -182,7 +216,8 @@ describe('determineSortingGroup', () => { isFolder: false, sortString: "00000123////Part:123-icle.md", matchGroup: '00000123//', - ctime: MOCK_TIMESTAMP + 555, + ctimeNewest: MOCK_TIMESTAMP + 555, + ctimeOldest: MOCK_TIMESTAMP + 555, mtime: MOCK_TIMESTAMP + 666, path: 'Some parent folder/Part:123-icle.md' }); @@ -208,7 +243,8 @@ describe('determineSortingGroup', () => { groupIdx: 0, isFolder: false, sortString: "References.md", - ctime: MOCK_TIMESTAMP + 222, + ctimeNewest: MOCK_TIMESTAMP + 222, + ctimeOldest: MOCK_TIMESTAMP + 222, mtime: MOCK_TIMESTAMP + 333, path: 'Some parent folder/References.md' }); @@ -236,7 +272,8 @@ describe('determineSortingGroup', () => { isFolder: false, sortString: '00000001|00000030|00000006|00001900////Reference i.xxx.vi.mcm.md', matchGroup: "00000001|00000030|00000006|00001900//", - ctime: MOCK_TIMESTAMP + 222, + ctimeNewest: MOCK_TIMESTAMP + 222, + ctimeOldest: MOCK_TIMESTAMP + 222, mtime: MOCK_TIMESTAMP + 333, path: 'Some parent folder/Reference i.xxx.vi.mcm.md' }); @@ -260,10 +297,83 @@ describe('determineSortingGroup', () => { groupIdx: 1, // This indicates the last+1 idx isFolder: false, sortString: "References.md", - ctime: MOCK_TIMESTAMP + 222, + ctimeNewest: MOCK_TIMESTAMP + 222, + ctimeOldest: MOCK_TIMESTAMP + 222, mtime: MOCK_TIMESTAMP + 333, path: 'Some parent folder/References.md' }); }) }) }) + +describe('determineFolderDatesIfNeeded', () => { + it('should not be triggered if not needed - sorting method does not require it', () => { + // given + const folder: TFolder = mockTFolderWithChildren('Test folder 1') + const OUTSIDERS_GROUP_IDX = 0 + const sortSpec: CustomSortSpec = { + targetFoldersPaths: ['/'], + groups: [{ + type: CustomSortGroupType.Outsiders, + order: CustomSortOrder.alphabetical + }], + outsidersGroupIdx: OUTSIDERS_GROUP_IDX + } + const cardinality = {[OUTSIDERS_GROUP_IDX]: 10} // Group 0 contains 10 items + + // when + const result: FolderItemForSorting = determineSortingGroup(folder, sortSpec) + determineFolderDatesIfNeeded([result], sortSpec, cardinality) + + // then + expect(result.ctimeOldest).toEqual(DEFAULT_FOLDER_CTIME) + expect(result.ctimeNewest).toEqual(DEFAULT_FOLDER_CTIME) + expect(result.mtime).toEqual(DEFAULT_FOLDER_CTIME) + }) + it('should not be triggered if not needed - the folder is an only item', () => { + // given + const folder: TFolder = mockTFolderWithChildren('Test folder 1') + const OUTSIDERS_GROUP_IDX = 0 + const sortSpec: CustomSortSpec = { + targetFoldersPaths: ['/'], + groups: [{ + type: CustomSortGroupType.Outsiders, + order: CustomSortOrder.byModifiedTimeAdvanced + }], + outsidersGroupIdx: OUTSIDERS_GROUP_IDX + } + const cardinality = {[OUTSIDERS_GROUP_IDX]: 1} // Group 0 contains the folder alone + + // when + const result: FolderItemForSorting = determineSortingGroup(folder, sortSpec) + determineFolderDatesIfNeeded([result], sortSpec, cardinality) + + // then + expect(result.ctimeOldest).toEqual(DEFAULT_FOLDER_CTIME) + expect(result.ctimeNewest).toEqual(DEFAULT_FOLDER_CTIME) + expect(result.mtime).toEqual(DEFAULT_FOLDER_CTIME) + }) + it('should correctly determine dates, if triggered', () => { + // given + const folder: TFolder = mockTFolderWithChildren('Test folder 1') + const OUTSIDERS_GROUP_IDX = 0 + const sortSpec: CustomSortSpec = { + targetFoldersPaths: ['/'], + groups: [{ + type: CustomSortGroupType.Outsiders, + order: CustomSortOrder.byCreatedTimeReverseAdvanced + }], + outsidersGroupIdx: OUTSIDERS_GROUP_IDX + } + const cardinality = {[OUTSIDERS_GROUP_IDX]: 10} // Group 0 contains 10 items + + // when + const result: FolderItemForSorting = determineSortingGroup(folder, sortSpec) + determineFolderDatesIfNeeded([result], sortSpec, cardinality) + + // then + expect(result.ctimeOldest).toEqual(TIMESTAMP_OLDEST) + expect(result.ctimeNewest).toEqual(TIMESTAMP_NEWEST) + expect(result.mtime).toEqual(TIMESTAMP_NEWEST) + }) +}) diff --git a/src/custom-sort/custom-sort.ts b/src/custom-sort/custom-sort.ts index 3800adc..69578be 100644 --- a/src/custom-sort/custom-sort.ts +++ b/src/custom-sort/custom-sort.ts @@ -8,12 +8,13 @@ let Collator = new Intl.Collator(undefined, { numeric: true, }).compare; -interface FolderItemForSorting { +export interface FolderItemForSorting { path: string groupIdx?: number // the index itself represents order for groups sortString: string // fragment (or full name) to be used for sorting matchGroup?: string // advanced - used for secondary sorting rule, to recognize 'same regex match' - ctime: number + ctimeOldest: number // for a file, both ctime values are the same. For folder they can be different: + ctimeNewest: number // ctimeOldest = ctime of oldest child file, ctimeNewest = ctime of newest child file mtime: number isFolder: boolean folder?: TFolder @@ -28,10 +29,10 @@ let Sorters: { [key in CustomSortOrder]: SorterFn } = { [CustomSortOrder.byModifiedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime, [CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.mtime - a.mtime), [CustomSortOrder.byModifiedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime, - [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (a.ctime - b.ctime), - [CustomSortOrder.byCreatedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime, - [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.ctime - a.ctime), - [CustomSortOrder.byCreatedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime, + [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (a.ctimeNewest - b.ctimeNewest), + [CustomSortOrder.byCreatedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctimeNewest - b.ctimeNewest, + [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.ctimeOldest - a.ctimeOldest), + [CustomSortOrder.byCreatedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctimeOldest - a.ctimeOldest, // This is a fallback entry which should not be used - the plugin code should refrain from custom sorting at all [CustomSortOrder.standardObsidian]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString), @@ -175,7 +176,8 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus isFolder: aFolder, folder: aFolder ? (entry as TFolder) : undefined, path: entry.path, - ctime: aFile ? entryAsTFile.stat.ctime : DEFAULT_FOLDER_CTIME, + ctimeNewest: aFile ? entryAsTFile.stat.ctime : DEFAULT_FOLDER_CTIME, + ctimeOldest: aFile ? entryAsTFile.stat.ctime : DEFAULT_FOLDER_CTIME, mtime: aFile ? entryAsTFile.stat.mtime : DEFAULT_FOLDER_MTIME } } @@ -195,25 +197,44 @@ export const sortOrderNeedsFolderDates = (order: CustomSortOrder | undefined, se // Syntax sugar for readability export type ModifiedTime = number -export type CreatedTime = number +export type CreatedTimeNewest = number +export type CreatedTimeOldest = number -export const determineDatesForFolder = (folder: TFolder): [ModifiedTime, CreatedTime] => { +export const determineDatesForFolder = (folder: TFolder, now: number): [ModifiedTime, CreatedTimeNewest, CreatedTimeOldest] => { let mtimeOfFolder: ModifiedTime = DEFAULT_FOLDER_MTIME - let ctimeOfFolder: CreatedTime = DEFAULT_FOLDER_CTIME + let ctimeNewestOfFolder: CreatedTimeNewest = DEFAULT_FOLDER_CTIME + let ctimeOldestOfFolder: CreatedTimeOldest = now folder.children.forEach((item) => { if (!isFolder(item)) { const file: TFile = item as TFile if (file.stat.mtime > mtimeOfFolder) { mtimeOfFolder = file.stat.mtime } - if (file.stat.ctime > ctimeOfFolder) { - ctimeOfFolder = file.stat.ctime + if (file.stat.ctime > ctimeNewestOfFolder) { + ctimeNewestOfFolder = file.stat.ctime + } + if (file.stat.ctime < ctimeOldestOfFolder) { + ctimeOldestOfFolder = file.stat.ctime } } }) - return [mtimeOfFolder, ctimeOfFolder] + return [mtimeOfFolder, ctimeNewestOfFolder, ctimeOldestOfFolder] } +export const determineFolderDatesIfNeeded = (folderItems: Array, sortingSpec: CustomSortSpec, sortingGroupsCardinality: {[key: number]: number} = {}) => { + const Now: number = Date.now() + folderItems.forEach((item) => { + const groupIdx: number | undefined = item.groupIdx + if (groupIdx !== undefined && sortingGroupsCardinality[groupIdx] > 1) { + const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].order + if (sortOrderNeedsFolderDates(groupOrder)) { + if (item.folder) { + [item.mtime, item.ctimeNewest, item.ctimeOldest] = determineDatesForFolder(item.folder, Now) + } + } + } + }) +} export const folderSort = function (sortingSpec: CustomSortSpec, order: string[]) { let fileExplorer = this.fileExplorer @@ -235,17 +256,7 @@ export const folderSort = function (sortingSpec: CustomSortSpec, order: string[] }) // Finally, for advanced sorting by modified date, for some of the folders the modified date has to be determined - folderItems.forEach((item) => { - const groupIdx: number | undefined = item.groupIdx - if (groupIdx !== undefined) { - const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].order - if (sortOrderNeedsFolderDates(groupOrder)) { - if (item.folder) { - [item.mtime, item.ctime] = determineDatesForFolder(item.folder) - } - } - } - }) + determineFolderDatesIfNeeded(folderItems, sortingSpec, sortingGroupsCardinality) folderItems.sort(function (itA: FolderItemForSorting, itB: FolderItemForSorting) { return compareTwoItems(itA, itB, sortingSpec); From afa10afd7d90bdc5cac55677ed56e2ff74694823 Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Mon, 26 Sep 2022 19:06:20 +0200 Subject: [PATCH 6/8] 13 - Feature request: Sort by modification date, treating folder and files equally - syntax reference update --- docs/syntax-reference.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/syntax-reference.md b/docs/syntax-reference.md index 6c6618a..6f465fc 100644 --- a/docs/syntax-reference.md +++ b/docs/syntax-reference.md @@ -20,7 +20,11 @@ - `< advanced modified` - by modified time, the long untouched item goes first. For folders, their modification date is derived from the most recently modified direct child file. For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's modified date - `> advanced modified` - by modified time reverse, the most recently modified item goes first. For folders, their modification date is derived from the most recently modified direct child file. - For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's modified date + For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's modified date +- `< advanced created` - by created time, the oldest item goes first. For folders, their creation date is derived from the oldest direct child file. + For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's created date +- `> advanced created` - by created time reverse, the newest item goes first. For folders, their creation date is derived from the newest direct child file. + For extremely large vaults use with caution, as the sorting needs to scan all files inside a folder to determine the folder's created date #### At group level only (aka secondary sorting rule) From 200333fb31b1e6b9404bc4e2e65ed216fed50625 Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Mon, 26 Sep 2022 19:12:15 +0200 Subject: [PATCH 7/8] 13 - Feature request: Sort by modification date, treating folder and files equally - README.md update, adjusted one of examples to use the `> advanced modified` sorting method --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0c07eeb..f9142d7 100644 --- a/README.md +++ b/README.md @@ -359,8 +359,9 @@ the result is: ### Example 12: Apply same sorting to all folders in the vault -Apply the alphabetical sorting to all folders in the Vault. The alphabetical sorting treats the folders and files equally -(which is different from the standard Obsidian sort, which groups folders in the top of File Explorer) +Apply the same advanced modified date sorting to all folders in the Vault. The advanced modified sorting treats the folders + and files equally (which is different from the standard Obsidian sort, which groups folders in the top of File Explorer) + The modified date for a folder is derived from its newest direct child file (if any), otherwise a folder is considered old This involves the wildcard suffix syntax `*` which means _apply the sorting rule to the specified folder and all of its subfolders, including descendants. In other words, this is imposing a deep inheritance @@ -371,7 +372,7 @@ Applying the wildcard suffix to root folder path `/*` actually means _apply the --- sorting-spec: | target-folder: /* - < a-z + > advanced modified --- ``` From 4b7849c422f20276baec2b6cfebad37152c4055c Mon Sep 17 00:00:00 2001 From: SebastianMC Date: Mon, 26 Sep 2022 21:06:34 +0200 Subject: [PATCH 8/8] 13 - Feature request: Sort by modification date, treating folder and files equally - README.md update, typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f9142d7..6733b47 100644 --- a/README.md +++ b/README.md @@ -355,7 +355,7 @@ sorting-spec: | the result is: -![Book - Roman compond suffixes](./docs/svg/roman-suffix.svg) +![Book - Roman compound suffixes](./docs/svg/roman-suffix.svg) ### Example 12: Apply same sorting to all folders in the vault