Skip to content

Commit

Permalink
Merge pull request #174 from SebastianMC/nov-2024-refactoring-regroup…
Browse files Browse the repository at this point in the history
…-sorting-structures

Major refactoring of sorting structures.
  • Loading branch information
SebastianMC authored Jan 3, 2025
2 parents de15f48 + 5cb7e54 commit 2c2053d
Show file tree
Hide file tree
Showing 9 changed files with 411 additions and 396 deletions.
36 changes: 15 additions & 21 deletions src/custom-sort/custom-sort-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,6 @@ export enum CustomSortOrder {
default = alphabeticalWithFilesPreferred
}

export interface RecognizedOrderValue {
order: CustomSortOrder
applyToMetadataField?: string
metadataValueExtractor?: MDataExtractor
secondaryOrder?: CustomSortOrder
secondaryApplyToMetadataField?: string
secondaryMetadataValueExtractor?: MDataExtractor
}

export type NormalizerFn = (s: string) => string | null
export const IdentityNormalizerFn: NormalizerFn = (s: string) => s

Expand All @@ -66,19 +57,26 @@ export interface RegExpSpec {
normalizerFn?: NormalizerFn
}

export interface CustomSort {
order: CustomSortOrder // mandatory
byMetadata?: string
metadataValueExtractor?: MDataExtractor
}

export interface RecognizedSorting {
primary?: CustomSort
secondary?: CustomSort
}

export interface CustomSortGroup {
type: CustomSortGroupType
exactText?: string
exactPrefix?: string
regexPrefix?: RegExpSpec
exactSuffix?: string
regexSuffix?: RegExpSpec
order?: CustomSortOrder
byMetadataField?: string // for 'by-metadata:' sorting if the order is by metadata alphabetical or reverse
metadataFieldValueExtractor?: MDataExtractor // and its sorting value extractor
secondaryOrder?: CustomSortOrder
byMetadataFieldSecondary?: string // for 'by-metadata:' sorting if the order is by metadata alphabetical or reverse
metadataFieldSecondaryValueExtractor?: MDataExtractor
sorting?: CustomSort
secondarySorting?: CustomSort
filesOnly?: boolean
matchFilenameWithExt?: boolean
foldersOnly?: boolean
Expand All @@ -91,12 +89,8 @@ export interface CustomSortGroup {
export interface CustomSortSpec {
// plays only informative role about the original parsed 'target-folder:' values
targetFoldersPaths: Array<string> // For root use '/'
defaultOrder?: CustomSortOrder
defaultSecondaryOrder?: CustomSortOrder
byMetadataField?: string // for 'by-metadata:' if the defaultOrder is by metadata
metadataFieldValueExtractor?: MDataExtractor // and its sorting value extractor
byMetadataFieldSecondary?: string
metadataFieldSecondaryValueExtractor?: MDataExtractor
defaultSorting?: CustomSort
defaultSecondarySorting?: CustomSort
groups: Array<CustomSortGroup>
groupsShadow?: Array<CustomSortGroup> // A shallow copy of groups, used at applying sorting for items in a folder.
// Stores folder-specific values (e.g. macros expanded with folder-specific values)
Expand Down
8 changes: 4 additions & 4 deletions src/custom-sort/custom-sort-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ export const collectSortingAndGroupingTypes = (sortSpec?: CustomSortSpec|null):
}
}
if (!sortSpec) return has
doCheck(has, sortSpec.defaultOrder)
doCheck(has, sortSpec.defaultSecondaryOrder)
doCheck(has, sortSpec.defaultSorting?.order)
doCheck(has, sortSpec.defaultSecondarySorting?.order)
if (sortSpec.groups) {
for (let group of sortSpec.groups) {
doCheck(has, group.order, group.type)
doCheck(has, group.secondaryOrder)
doCheck(has, group.sorting?.order, group.type)
doCheck(has, group.secondarySorting?.order)
}
}
return has
Expand Down
63 changes: 32 additions & 31 deletions src/custom-sort/custom-sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ObsidianIconFolder_PluginInstance
} from '../utils/ObsidianIconFolderPluginSignature'
import {
CustomSort,
CustomSortGroup,
CustomSortGroupType,
CustomSortOrder,
Expand Down Expand Up @@ -287,18 +288,18 @@ export const StandardPlainObsidianComparator = (order: string): PlainSorterFn =>
}
}

export const getSorterFnFor = (sorting: CustomSortOrder, currentUIselectedSorting?: string, sortLevelId?: SortingLevelId): SorterFn => {
if (sorting === CustomSortOrder.standardObsidian) {
sorting = StandardObsidianToCustomSort[currentUIselectedSorting ?? 'alphabetical'] ?? CustomSortOrder.alphabetical
return StandardObsidianComparator(sorting)
export const getSorterFnFor = (order: CustomSortOrder, currentUIselectedSorting?: string, sortLevelId?: SortingLevelId): SorterFn => {
if (order === CustomSortOrder.standardObsidian) {
order = StandardObsidianToCustomSort[currentUIselectedSorting ?? 'alphabetical'] ?? CustomSortOrder.alphabetical
return StandardObsidianComparator(order)
} else {
// Some sorters have to know at which sorting level they are used
switch(sortLevelId) {
case SortingLevelId.forSecondary: return SortersForSecondary[sorting] ?? Sorters[sorting]
case SortingLevelId.forDerivedPrimary: return SortersForDerivedPrimary[sorting] ?? Sorters[sorting]
case SortingLevelId.forDerivedSecondary: return SortersForDerivedSecondary[sorting] ?? Sorters[sorting]
case SortingLevelId.forSecondary: return SortersForSecondary[order] ?? Sorters[order]
case SortingLevelId.forDerivedPrimary: return SortersForDerivedPrimary[order] ?? Sorters[order]
case SortingLevelId.forDerivedSecondary: return SortersForDerivedSecondary[order] ?? Sorters[order]
case SortingLevelId.forPrimary:
default: return Sorters[sorting]
default: return Sorters[order]
}
}
}
Expand All @@ -308,13 +309,13 @@ export const getComparator = (sortSpec: CustomSortSpec, currentUIselectedSorting
if (itA.groupIdx != undefined && itB.groupIdx != undefined) {
if (itA.groupIdx === itB.groupIdx) {
const group: CustomSortGroup | undefined = sortSpec.groups[itA.groupIdx]
const primary: number = group?.order ? getSorterFnFor(group.order, currentUIselectedSorting, SortingLevelId.forPrimary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
const primary: number = group?.sorting ? getSorterFnFor(group.sorting.order, currentUIselectedSorting, SortingLevelId.forPrimary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
if (primary !== EQUAL_OR_UNCOMPARABLE) return primary
const secondary: number = group?.secondaryOrder ? getSorterFnFor(group.secondaryOrder, currentUIselectedSorting, SortingLevelId.forSecondary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
const secondary: number = group?.secondarySorting ? getSorterFnFor(group.secondarySorting.order, currentUIselectedSorting, SortingLevelId.forSecondary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
if (secondary !== EQUAL_OR_UNCOMPARABLE) return secondary
const folderLevel: number = sortSpec.defaultOrder ? getSorterFnFor(sortSpec.defaultOrder, currentUIselectedSorting, SortingLevelId.forDerivedPrimary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
const folderLevel: number = sortSpec.defaultSorting ? getSorterFnFor(sortSpec.defaultSorting.order, currentUIselectedSorting, SortingLevelId.forDerivedPrimary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
if (folderLevel !== EQUAL_OR_UNCOMPARABLE) return folderLevel
const folderLevelSecondary: number = sortSpec.defaultSecondaryOrder ? getSorterFnFor(sortSpec.defaultSecondaryOrder, currentUIselectedSorting, SortingLevelId.forDerivedSecondary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
const folderLevelSecondary: number = sortSpec.defaultSecondarySorting ? getSorterFnFor(sortSpec.defaultSecondarySorting.order, currentUIselectedSorting, SortingLevelId.forDerivedSecondary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
if (folderLevelSecondary !== EQUAL_OR_UNCOMPARABLE) return folderLevelSecondary
const defaultForUnspecified: number = getSorterFnFor(CustomSortOrder.default, undefined, SortingLevelId.forDefaultWhenUnspecified)(itA, itB)
return defaultForUnspecified
Expand Down Expand Up @@ -552,10 +553,10 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus

if (determined && determinedGroupIdx !== undefined) { // <-- defensive code, maybe too defensive
const group: CustomSortGroup = spec.groups[determinedGroupIdx];
const isPrimaryOrderByMetadata: boolean = isByMetadata(group?.order)
const isSecondaryOrderByMetadata: boolean = isByMetadata(group?.secondaryOrder)
const isDerivedPrimaryByMetadata: boolean = isByMetadata(spec.defaultOrder)
const isDerivedSecondaryByMetadata: boolean = isByMetadata(spec.defaultSecondaryOrder)
const isPrimaryOrderByMetadata: boolean = isByMetadata(group?.sorting?.order)
const isSecondaryOrderByMetadata: boolean = isByMetadata(group?.secondarySorting?.order)
const isDerivedPrimaryByMetadata: boolean = isByMetadata(spec.defaultSorting?.order)
const isDerivedSecondaryByMetadata: boolean = isByMetadata(spec.defaultSecondarySorting?.order)
if (isPrimaryOrderByMetadata || isSecondaryOrderByMetadata || isDerivedPrimaryByMetadata || isDerivedSecondaryByMetadata) {
if (ctx?._mCache) {
// For folders - scan metadata of 'folder note'
Expand All @@ -571,26 +572,26 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus
}
if (isPrimaryOrderByMetadata) metadataValueToSortBy =
mdataValueFromFMCaches (
group?.byMetadataField || group?.withMetadataFieldName || DEFAULT_METADATA_FIELD_FOR_SORTING,
group?.metadataFieldValueExtractor,
group.sorting!.byMetadata || group.withMetadataFieldName || DEFAULT_METADATA_FIELD_FOR_SORTING,
group.sorting!.metadataValueExtractor,
frontMatterCache,
prioFrontMatterCache)
if (isSecondaryOrderByMetadata) metadataValueSecondaryToSortBy =
mdataValueFromFMCaches (
group?.byMetadataFieldSecondary || group?.withMetadataFieldName || DEFAULT_METADATA_FIELD_FOR_SORTING,
group?.metadataFieldSecondaryValueExtractor,
group.secondarySorting!.byMetadata || group.withMetadataFieldName || DEFAULT_METADATA_FIELD_FOR_SORTING,
group.secondarySorting!.metadataValueExtractor,
frontMatterCache,
prioFrontMatterCache)
if (isDerivedPrimaryByMetadata) metadataValueDerivedPrimaryToSortBy =
mdataValueFromFMCaches (
spec.byMetadataField || DEFAULT_METADATA_FIELD_FOR_SORTING,
spec.metadataFieldValueExtractor,
spec.defaultSorting!.byMetadata || DEFAULT_METADATA_FIELD_FOR_SORTING,
spec.defaultSorting!.metadataValueExtractor,
frontMatterCache,
prioFrontMatterCache)
if (isDerivedSecondaryByMetadata) metadataValueDerivedSecondaryToSortBy =
mdataValueFromFMCaches (
spec.byMetadataFieldSecondary || DEFAULT_METADATA_FIELD_FOR_SORTING,
spec.metadataFieldSecondaryValueExtractor,
spec.defaultSecondarySorting!.byMetadata || DEFAULT_METADATA_FIELD_FOR_SORTING,
spec.defaultSecondarySorting!.metadataValueExtractor,
frontMatterCache,
prioFrontMatterCache)
}
Expand Down Expand Up @@ -692,12 +693,12 @@ export const determineDatesForFolder = (folder: TFolder, recursive?: boolean): [
}

export const determineFolderDatesIfNeeded = (folderItems: Array<FolderItemForSorting>, sortingSpec: CustomSortSpec) => {
const foldersDatesNeeded = sortOrderNeedsFolderDates(sortingSpec.defaultOrder, sortingSpec.defaultSecondaryOrder)
const foldersDeepDatesNeeded = sortOrderNeedsFolderDeepDates(sortingSpec.defaultOrder, sortingSpec.defaultSecondaryOrder)
const foldersDatesNeeded = sortOrderNeedsFolderDates(sortingSpec.defaultSorting?.order, sortingSpec.defaultSecondarySorting?.order)
const foldersDeepDatesNeeded = sortOrderNeedsFolderDeepDates(sortingSpec.defaultSorting?.order, sortingSpec.defaultSecondarySorting?.order)

const groupOrders = sortingSpec.groups?.map((group) => ({
foldersDatesNeeded: sortOrderNeedsFolderDates(group.order, group.secondaryOrder),
foldersDeepDatesNeeded: sortOrderNeedsFolderDeepDates(group.order, group.secondaryOrder)
foldersDatesNeeded: sortOrderNeedsFolderDates(group.sorting?.order, group.secondarySorting?.order),
foldersDeepDatesNeeded: sortOrderNeedsFolderDeepDates(group.sorting?.order, group.secondarySorting?.order)
}))

folderItems.forEach((item) => {
Expand All @@ -717,15 +718,15 @@ export const determineFolderDatesIfNeeded = (folderItems: Array<FolderItemForSor
export const determineBookmarksOrderIfNeeded = (folderItems: Array<FolderItemForSorting>, sortingSpec: CustomSortSpec, plugin: BookmarksPluginInterface) => {
if (!plugin) return

const folderDefaultSortRequiresBookmarksOrder: boolean = !!(sortingSpec.defaultOrder && sortOrderNeedsBookmarksOrder(sortingSpec.defaultOrder, sortingSpec.defaultSecondaryOrder))
const folderDefaultSortRequiresBookmarksOrder: boolean = !!(sortingSpec.defaultSorting && sortOrderNeedsBookmarksOrder(sortingSpec.defaultSorting.order, sortingSpec.defaultSecondarySorting?.order))

folderItems.forEach((item) => {
let groupSortRequiresBookmarksOrder: boolean = false
if (!folderDefaultSortRequiresBookmarksOrder) {
const groupIdx: number | undefined = item.groupIdx
if (groupIdx !== undefined) {
const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].order
const groupSecondaryOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].secondaryOrder
const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].sorting?.order
const groupSecondaryOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].secondarySorting?.order
groupSortRequiresBookmarksOrder = sortOrderNeedsBookmarksOrder(groupOrder, groupSecondaryOrder)
}
}
Expand Down
Loading

0 comments on commit 2c2053d

Please sign in to comment.