From 742bdf1b809a7c7431ff6544651b1232c2d60037 Mon Sep 17 00:00:00 2001 From: SebastianMC <23032356+SebastianMC@users.noreply.github.com> Date: Thu, 10 Nov 2022 00:10:16 +0100 Subject: [PATCH] #27 - support for true alphabetical order - added new token 'true a-z' - unit tests coverage of the extended logic - added example in README.md --- README.md | 31 +++++++++++++- src/custom-sort/custom-sort-types.ts | 2 + src/custom-sort/custom-sort.ts | 8 ++++ .../sorting-spec-processor.spec.ts | 40 +++++++++++++++++++ src/custom-sort/sorting-spec-processor.ts | 1 + 5 files changed, 81 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5387f9..15af2e9 100644 --- a/README.md +++ b/README.md @@ -308,7 +308,7 @@ sorting-spec: | the line `... part \d+` says: group all notes and folders with name ending with 'part' followed by a number. Then order them by the number. And for clarity the subsequent (indented) line is added ` < a-z` which sets the order to -alphanumerical ascending. +alphabetical ascending. The effect is: @@ -411,6 +411,35 @@ sorting-spec: | --- ``` +## Alphabetical, Natural and True Alphabetical sorting orders + +The 'A-Z' sorting (visible in Obsidian UI of file explorer) at some point before the 1.0.0 release of Obsidian actually became the so-called 'natural' sort order. +For explanation of the term go to [Natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order) on Wikipedia. +The plugin follows the convention and the sorting specified by `< a-z` or `> a-z` triggers the _'natural sort order'_. + +To allow the true alphabetical sort order, as suggested by the ticket [27: Not alphanumeric, but natural sort order?](https://github.com/SebastianMC/obsidian-custom-sort/issues/27) +a distinct syntax was introduced: `< true a-z` and `> true a-z` + +What is the difference? +Using the example from the mentioned ticket: the items '0x01FF', '0x02FF' and '0x0200' sorted in _natural order_ go as: +- 0x01FF -> the number 01 in the text is recognized +- 0x02FF -> the number 02 in the text is recognized +- 0x0200 -> the number 0200 in the text is recognized and it causes the third position of the item, because 0200 > 02 + +The same items when sorted in _true alphabetical_ order go as: +- 0x01FF +- 0x0200 +- 0x02FF -> the character 'F' following '2' goes after the character '0', that's why 0x02FF follows the 0x0200 + +You can use the order `< true a-z` or `> true a-z` to trigger the true alphabetical sorting, like in the ticket: +```yaml +sorting-spec: | + target-folder: MaDo/... + > true a-z + target-folder: MaDo/Sandbox/SortingBug + < true a-z +``` + ## Location of sorting specification YAML entry You can keep the custom sorting specifications in any of the following locations (or in all of them): diff --git a/src/custom-sort/custom-sort-types.ts b/src/custom-sort/custom-sort-types.ts index 8a65ab0..448a53b 100644 --- a/src/custom-sort/custom-sort-types.ts +++ b/src/custom-sort/custom-sort-types.ts @@ -9,7 +9,9 @@ export enum CustomSortGroupType { export enum CustomSortOrder { alphabetical = 1, // = 1 to allow: if (customSortOrder) { ... + trueAlphabetical, alphabeticalReverse, + trueAlphabeticalReverse, byModifiedTime, // New to old byModifiedTimeAdvanced, byModifiedTimeReverse, // Old to new diff --git a/src/custom-sort/custom-sort.ts b/src/custom-sort/custom-sort.ts index 69578be..c1685ba 100644 --- a/src/custom-sort/custom-sort.ts +++ b/src/custom-sort/custom-sort.ts @@ -8,6 +8,12 @@ let Collator = new Intl.Collator(undefined, { numeric: true, }).compare; +let CollatorTrueAlphabetical = new Intl.Collator(undefined, { + usage: "sort", + sensitivity: "base", + numeric: false, +}).compare; + export interface FolderItemForSorting { path: string groupIdx?: number // the index itself represents order for groups @@ -24,7 +30,9 @@ 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.trueAlphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabetical(a.sortString, b.sortString), [CustomSortOrder.alphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(b.sortString, a.sortString), + [CustomSortOrder.trueAlphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabetical(b.sortString, a.sortString), [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) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.mtime - a.mtime), diff --git a/src/custom-sort/sorting-spec-processor.spec.ts b/src/custom-sort/sorting-spec-processor.spec.ts index 0871221..54d4048 100644 --- a/src/custom-sort/sorting-spec-processor.spec.ts +++ b/src/custom-sort/sorting-spec-processor.spec.ts @@ -436,6 +436,46 @@ describe('SortingSpecProcessor', () => { }) }) +const txtInputTrueAlphabeticalSortAttr: string = ` +target-folder: AAA +< true a-z +target-folder: BBB +> true a-z +` + +const expectedSortSpecForTrueAlphabeticalSorting: { [key: string]: CustomSortSpec } = { + "AAA": { + defaultOrder: CustomSortOrder.trueAlphabetical, + groups: [{ + order: CustomSortOrder.trueAlphabetical, + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['AAA'] + }, + "BBB": { + defaultOrder: CustomSortOrder.trueAlphabeticalReverse, + groups: [{ + order: CustomSortOrder.trueAlphabeticalReverse, + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['BBB'] + } +} + +describe('SortingSpecProcessor', () => { + let processor: SortingSpecProcessor; + beforeEach(() => { + processor = new SortingSpecProcessor(); + }); + it('should recognize the true alphabetical (and reverse) sorting attribute for a folder', () => { + const inputTxtArr: Array = txtInputTrueAlphabeticalSortAttr.split('\n') + const result = processor.parseSortSpecFromText(inputTxtArr, 'mock-folder', 'custom-name-note.md') + expect(result?.sortSpecByPath).toEqual(expectedSortSpecForTrueAlphabeticalSorting) + }) +}) + const txtInputSimplistic1: string = ` target-folder: /* /:files diff --git a/src/custom-sort/sorting-spec-processor.ts b/src/custom-sort/sorting-spec-processor.ts index 4ac55a3..6009f0a 100644 --- a/src/custom-sort/sorting-spec-processor.ts +++ b/src/custom-sort/sorting-spec-processor.ts @@ -84,6 +84,7 @@ interface CustomSortOrderAscDescPair { // remember about .toLowerCase() before comparison! const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { 'a-z': {asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse}, + 'true a-z': {asc: CustomSortOrder.trueAlphabetical, desc: CustomSortOrder.trueAlphabeticalReverse}, 'created': {asc: CustomSortOrder.byCreatedTime, desc: CustomSortOrder.byCreatedTimeReverse}, 'modified': {asc: CustomSortOrder.byModifiedTime, desc: CustomSortOrder.byModifiedTimeReverse}, 'advanced modified': {asc: CustomSortOrder.byModifiedTimeAdvanced, desc: CustomSortOrder.byModifiedTimeReverseAdvanced},