From a2a808e78b2bcb67300b919495607394eda7139d Mon Sep 17 00:00:00 2001 From: SebastianMC <23032356+SebastianMC@users.noreply.github.com> Date: Sat, 27 Jan 2024 23:25:59 +0100 Subject: [PATCH] Two experimental features + version bump before release - `aaa-z` and `a-zzz` sort orders (uppercase first, alphanumeric order and lowercase first, alphanumeric) - `vsc-unicode` sort order, which is equivalent to what VS Code refers to as 'unicode' sorting (which name is arbitrary and confusing, yet familar to VS Code users) --- manifest.json | 2 +- package.json | 2 +- src/custom-sort/custom-sort-types.ts | 8 +- src/custom-sort/custom-sort.ts | 48 ++++++++---- .../sorting-spec-processor.spec.ts | 78 +++++++++++++++++++ src/custom-sort/sorting-spec-processor.ts | 5 +- versions.json | 3 +- 7 files changed, 127 insertions(+), 19 deletions(-) diff --git a/manifest.json b/manifest.json index e0de7ba..9583bb9 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "custom-sort", "name": "Custom File Explorer sorting", - "version": "2.1.4", + "version": "2.1.5", "minAppVersion": "0.16.2", "description": "Allows for manual and automatic, config-driven reordering and sorting of files and folders in File Explorer", "author": "SebastianMC", diff --git a/package.json b/package.json index f3e37ae..fd99cd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-custom-sort", - "version": "2.1.4", + "version": "2.1.5", "description": "Custom Sort plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { diff --git a/src/custom-sort/custom-sort-types.ts b/src/custom-sort/custom-sort-types.ts index 688cd4a..b9461d2 100644 --- a/src/custom-sort/custom-sort-types.ts +++ b/src/custom-sort/custom-sort-types.ts @@ -13,10 +13,14 @@ export enum CustomSortGroupType { export enum CustomSortOrder { alphabetical = 1, // = 1 to allow: if (customSortOrder) { ... + alphabeticalLowerFirst, + alphabeticalUpperFirst, alphabeticalWithFileExt, trueAlphabetical, trueAlphabeticalWithFileExt, alphabeticalReverse, + alphabeticalLowerFirstReverse, + alphabeticalUpperFirstReverse, alphabeticalReverseWithFileExt, trueAlphabeticalReverse, trueAlphabeticalReverseWithFileExt, @@ -38,7 +42,9 @@ export enum CustomSortOrder { fileFirst, folderFirst, alphabeticalWithFilesPreferred, // When the (base)names are equal, the file has precedence over a folder - alphabeticalWithFoldersPreferred, // When the (base)names are equal, the file has precedence over a folder + alphabeticalWithFoldersPreferred, // When the (base)names are equal, the file has precedence over a folder, + vscUnicode, // the Visual Studio Code lexicographic order named 'unicode' (which is very misleading, at the same time familiar to VS Code users + vscUnicodeReverse, // ... see compareFilesUnicode function https://github.com/microsoft/vscode/blob/a19b2d5fb0202e00fb930dc850d2695ec512e495/src/vs/base/common/comparers.ts#L80 default = alphabeticalWithFilesPreferred } diff --git a/src/custom-sort/custom-sort.ts b/src/custom-sort/custom-sort.ts index e043d3c..d088bde 100644 --- a/src/custom-sort/custom-sort.ts +++ b/src/custom-sort/custom-sort.ts @@ -49,6 +49,20 @@ export const CollatorCompare = new Intl.Collator(undefined, { numeric: true, }).compare; +export const CollatorCompareUpperFirst = new Intl.Collator(undefined, { + usage: "sort", + sensitivity: "base", + numeric: true, + caseFirst: "upper" +}).compare; + +export const CollatorCompareLowerFirst = new Intl.Collator(undefined, { + usage: "sort", + sensitivity: "base", + numeric: true, + caseFirst: "lower" +}).compare; + export const CollatorTrueAlphabeticalCompare = new Intl.Collator(undefined, { usage: "sort", sensitivity: "base", @@ -178,23 +192,27 @@ const folderGoesFirstWhenSameBasenameAsFolder = (stringCompareResult: number, a: (!!stringCompareResult) ? stringCompareResult : (a.isFolder === b.isFolder ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? -1 : 1) ); const Sorters: { [key in CustomSortOrder]: SorterFn } = { - [CustomSortOrder.alphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortString, b.sortString), + [CustomSortOrder.alphabetical]: (a: FIFS, b: FIFS) => CollatorCompare(a.sortString, b.sortString), + [CustomSortOrder.alphabeticalLowerFirst]: (a: FIFS, b: FIFS) => CollatorCompareLowerFirst(a.sortString, b.sortString), + [CustomSortOrder.alphabeticalUpperFirst]: (a: FIFS, b: FIFS) => CollatorCompareUpperFirst(a.sortString, b.sortString), [CustomSortOrder.alphabeticalWithFilesPreferred]: (a: FIFS, b: FIFS) => fileGoesFirstWhenSameBasenameAsFolder(CollatorCompare(a.sortString, b.sortString),a,b), [CustomSortOrder.alphabeticalWithFoldersPreferred]: (a: FIFS, b: FIFS) => fileGoesFirstWhenSameBasenameAsFolder(CollatorCompare(a.sortString, b.sortString),a,b), - [CustomSortOrder.alphabeticalWithFileExt]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortStringWithExt, b.sortStringWithExt), - [CustomSortOrder.trueAlphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabeticalCompare(a.sortString, b.sortString), - [CustomSortOrder.trueAlphabeticalWithFileExt]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabeticalCompare(a.sortStringWithExt, b.sortStringWithExt), - [CustomSortOrder.alphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(b.sortString, a.sortString), - [CustomSortOrder.alphabeticalReverseWithFileExt]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(b.sortStringWithExt, a.sortStringWithExt), - [CustomSortOrder.trueAlphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabeticalCompare(b.sortString, a.sortString), - [CustomSortOrder.trueAlphabeticalReverseWithFileExt]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabeticalCompare(b.sortStringWithExt, a.sortStringWithExt), - [CustomSortOrder.byModifiedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (a.mtime - b.mtime), + [CustomSortOrder.alphabeticalWithFileExt]: (a: FIFS, b: FIFS) => CollatorCompare(a.sortStringWithExt, b.sortStringWithExt), + [CustomSortOrder.trueAlphabetical]: (a: FIFS, b: FIFS) => CollatorTrueAlphabeticalCompare(a.sortString, b.sortString), + [CustomSortOrder.trueAlphabeticalWithFileExt]: (a: FIFS, b: FIFS) => CollatorTrueAlphabeticalCompare(a.sortStringWithExt, b.sortStringWithExt), + [CustomSortOrder.alphabeticalReverse]: (a: FIFS, b: FIFS) => CollatorCompare(b.sortString, a.sortString), + [CustomSortOrder.alphabeticalLowerFirstReverse]: (a: FIFS, b: FIFS) => CollatorCompareLowerFirst(b.sortString, a.sortString), + [CustomSortOrder.alphabeticalUpperFirstReverse]: (a: FIFS, b: FIFS) => CollatorCompareUpperFirst(b.sortString, a.sortString), + [CustomSortOrder.alphabeticalReverseWithFileExt]: (a: FIFS, b: FIFS) => CollatorCompare(b.sortStringWithExt, a.sortStringWithExt), + [CustomSortOrder.trueAlphabeticalReverse]: (a: FIFS, b: FIFS) => CollatorTrueAlphabeticalCompare(b.sortString, a.sortString), + [CustomSortOrder.trueAlphabeticalReverseWithFileExt]: (a: FIFS, b: FIFS) => CollatorTrueAlphabeticalCompare(b.sortStringWithExt, a.sortStringWithExt), + [CustomSortOrder.byModifiedTime]: (a: FIFS, b: FIFS) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (a.mtime - b.mtime), [CustomSortOrder.byModifiedTimeAdvanced]: sorterByFolderMDate(), - [CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (b.mtime - a.mtime), + [CustomSortOrder.byModifiedTimeReverse]: (a: FIFS, b: FIFS) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (b.mtime - a.mtime), [CustomSortOrder.byModifiedTimeReverseAdvanced]: sorterByFolderMDate(true), - [CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (a.ctime - b.ctime), + [CustomSortOrder.byCreatedTime]: (a: FIFS, b: FIFS) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (a.ctime - b.ctime), [CustomSortOrder.byCreatedTimeAdvanced]: sorterByFolderCDate(), - [CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (b.ctime - a.ctime), + [CustomSortOrder.byCreatedTimeReverse]: (a: FIFS, b: FIFS) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (b.ctime - a.ctime), [CustomSortOrder.byCreatedTimeReverseAdvanced]: sorterByFolderCDate(true), [CustomSortOrder.byMetadataFieldAlphabetical]: sorterByMetadataField(StraightOrder, !TrueAlphabetical, SortingLevelId.forPrimary), [CustomSortOrder.byMetadataFieldTrueAlphabetical]: sorterByMetadataField(StraightOrder, TrueAlphabetical, SortingLevelId.forPrimary), @@ -202,8 +220,10 @@ const Sorters: { [key in CustomSortOrder]: SorterFn } = { [CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical, SortingLevelId.forPrimary), [CustomSortOrder.byBookmarkOrder]: sorterByBookmarkOrder(StraightOrder), [CustomSortOrder.byBookmarkOrderReverse]: sorterByBookmarkOrder(ReverseOrder), - [CustomSortOrder.fileFirst]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder === b.isFolder) ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? 1 : -1), - [CustomSortOrder.folderFirst]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder === b.isFolder) ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? -1 : 1), + [CustomSortOrder.fileFirst]: (a: FIFS, b: FIFS) => (a.isFolder === b.isFolder) ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? 1 : -1), + [CustomSortOrder.folderFirst]: (a: FIFS, b: FIFS) => (a.isFolder === b.isFolder) ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? -1 : 1), + [CustomSortOrder.vscUnicode]: (a: FIFS, b: FIFS) => (a.sortString === b.sortString) ? EQUAL_OR_UNCOMPARABLE : (a.sortString < b.sortString ? -1 : 1), + [CustomSortOrder.vscUnicodeReverse]: (a: FIFS, b: FIFS) => (a.sortString === b.sortString) ? EQUAL_OR_UNCOMPARABLE : (b.sortString < a.sortString ? -1 : 1), // A fallback entry which should not be used - the getSorterFor() function below should protect against it [CustomSortOrder.standardObsidian]: (a: FIFS, b: FIFS) => CollatorCompare(a.sortString, b.sortString), diff --git a/src/custom-sort/sorting-spec-processor.spec.ts b/src/custom-sort/sorting-spec-processor.spec.ts index 348a88b..7ffb127 100644 --- a/src/custom-sort/sorting-spec-processor.spec.ts +++ b/src/custom-sort/sorting-spec-processor.spec.ts @@ -711,6 +711,84 @@ describe('SortingSpecProcessor', () => { }) }) +const txtInputExoticExperimentalSortAttr: string = ` +target-folder: upper first +< aaa-z +target-folder: upper first Rev +> aaa-z +target-folder: lower first +< a-zzz +target-folder: lower first Rev +> a-zzz +target-folder: VS Code unicode lexicographic +< vsc-unicode +target-folder: VS Code unicode lexicographic reverse +> vsc-unicode +` + +const expectedSortSpecForExoticExperimentalSorting: { [key: string]: CustomSortSpec } = { + "upper first": { + defaultOrder: CustomSortOrder.alphabeticalUpperFirst, + groups: [{ + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['upper first'] + }, + "upper first Rev": { + defaultOrder: CustomSortOrder.alphabeticalUpperFirstReverse, + groups: [{ + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['upper first Rev'] + }, + "lower first": { + defaultOrder: CustomSortOrder.alphabeticalLowerFirst, + groups: [{ + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['lower first'] + }, + "lower first Rev": { + defaultOrder: CustomSortOrder.alphabeticalLowerFirstReverse, + groups: [{ + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['lower first Rev'] + }, + "VS Code unicode lexicographic": { + defaultOrder: CustomSortOrder.vscUnicode, + groups: [{ + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['VS Code unicode lexicographic'] + }, + "VS Code unicode lexicographic reverse": { + defaultOrder: CustomSortOrder.vscUnicodeReverse, + groups: [{ + type: CustomSortGroupType.Outsiders + }], + outsidersGroupIdx: 0, + targetFoldersPaths: ['VS Code unicode lexicographic reverse'] + } +} + +describe('SortingSpecProcessor', () => { + let processor: SortingSpecProcessor; + beforeEach(() => { + processor = new SortingSpecProcessor(); + }); + it('should recognize the exotic experimental sorting attribute for a folder', () => { + const inputTxtArr: Array = txtInputExoticExperimentalSortAttr.split('\n') + const result = processor.parseSortSpecFromText(inputTxtArr, 'mock-folder', 'custom-name-note.md') + expect(result?.sortSpecByPath).toEqual(expectedSortSpecForExoticExperimentalSorting) + }) +}) + 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 6a06762..4fc8e79 100644 --- a/src/custom-sort/sorting-spec-processor.ts +++ b/src/custom-sort/sorting-spec-processor.ts @@ -116,8 +116,10 @@ const MAX_SORT_LEVEL: number = 1 // remember about .toLowerCase() before comparison! const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { + 'a-zzz': {asc: CustomSortOrder.alphabeticalLowerFirst, desc: CustomSortOrder.alphabeticalLowerFirstReverse}, 'a-z.': {asc: CustomSortOrder.alphabeticalWithFileExt, desc: CustomSortOrder.alphabeticalReverseWithFileExt}, 'a-z': {asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse}, + 'aaa-z': {asc: CustomSortOrder.alphabeticalUpperFirst, desc: CustomSortOrder.alphabeticalUpperFirstReverse}, 'true a-z.': {asc: CustomSortOrder.trueAlphabeticalWithFileExt, desc: CustomSortOrder.trueAlphabeticalReverseWithFileExt}, 'true a-z': {asc: CustomSortOrder.trueAlphabetical, desc: CustomSortOrder.trueAlphabeticalReverse}, 'created': {asc: CustomSortOrder.byCreatedTime, desc: CustomSortOrder.byCreatedTimeReverse}, @@ -128,7 +130,8 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = { 'ui selected': {asc: CustomSortOrder.standardObsidian, desc: CustomSortOrder.standardObsidian}, 'by-bookmarks-order': {asc: CustomSortOrder.byBookmarkOrder, desc: CustomSortOrder.byBookmarkOrderReverse}, 'files-first': {asc: CustomSortOrder.fileFirst, desc: CustomSortOrder.fileFirst}, - 'folders-first': {asc: CustomSortOrder.folderFirst, desc: CustomSortOrder.folderFirst} + 'folders-first': {asc: CustomSortOrder.folderFirst, desc: CustomSortOrder.folderFirst}, + 'vsc-unicode': {asc: CustomSortOrder.vscUnicode, desc: CustomSortOrder.vscUnicodeReverse} } const OrderByMetadataLexeme: string = 'by-metadata:' diff --git a/versions.json b/versions.json index ae0299a..aa25d45 100644 --- a/versions.json +++ b/versions.json @@ -38,5 +38,6 @@ "2.1.1": "0.16.2", "2.1.2": "0.16.2", "2.1.3": "0.16.2", - "2.1.4": "0.16.2" + "2.1.4": "0.16.2", + "2.1.5": "0.16.2" }