A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package util
18
19import (
20 "bytes"
21 "io"
22 "strings"
23
24 "github.com/facette/natsort"
25 "golang.org/x/text/encoding/simplifiedchinese"
26 "golang.org/x/text/transform"
27)
28
29func NaturalCompare(str1, str2 string) bool {
30 str1 = RemoveEmojiInvisible(str1)
31 str2 = RemoveEmojiInvisible(str2)
32 return natsort.Compare(str1, str2)
33}
34
35func EmojiPinYinCompare(str1, str2 string) bool {
36 str1_ := strings.TrimSpace(RemoveEmojiInvisible(str1))
37 str2_ := strings.TrimSpace(RemoveEmojiInvisible(str2))
38 if str1_ == str2_ && 0 == len(str1_) {
39 // 全部都是 emoji 的情况按 emoji 字符串排序
40 return strings.Compare(str1, str2) < 0
41 }
42 return PinYinCompare(str1, str2)
43}
44
45func PinYinCompare(str1, str2 string) bool {
46 str1 = RemoveEmojiInvisible(str1)
47 str2 = RemoveEmojiInvisible(str2)
48
49 // Doc tree, backlinks, tags and templates ignores case when sorting alphabetically by name https://github.com/siyuan-note/siyuan/issues/8360
50 str1 = strings.ToLower(str1)
51 str2 = strings.ToLower(str2)
52
53 a, _ := UTF82GBK(str1)
54 b, _ := UTF82GBK(str2)
55 bLen := len(b)
56 for idx, chr := range a {
57 if idx > bLen-1 {
58 return false
59 }
60 if chr != b[idx] {
61 return chr < b[idx]
62 }
63 }
64 return true
65}
66
67func PinYinCompare4FileTree(str1, str2 string) bool {
68 // 文档树字母排序不复用 PinYinCompare 而是单独实现
69 // Improve doc tree Name Alphabet sorting https://github.com/siyuan-note/siyuan/issues/14773
70
71 str1 = RemoveEmojiInvisible(str1)
72 str1 = strings.TrimSuffix(str1, ".sy")
73 str2 = RemoveEmojiInvisible(str2)
74 str2 = strings.TrimSuffix(str2, ".sy")
75
76 // Doc tree, backlinks, tags and templates ignores case when sorting alphabetically by name https://github.com/siyuan-note/siyuan/issues/8360
77 str1 = strings.ToLower(str1)
78 str2 = strings.ToLower(str2)
79
80 a, _ := UTF82GBK(str1)
81 b, _ := UTF82GBK(str2)
82
83 // 长度相等的情况下,直接比较字节数组
84 if len(a) == len(b) {
85 return bytes.Compare(a, b) < 0
86 }
87
88 // 长度不相等的情况下,比较前面相等的部分
89 if len(a) < len(b) {
90 if 0 == bytes.Compare(a, b[:len(a)]) { // 前面相等的情况下短的在前
91 return true
92 }
93 return bytes.Compare(a, b[:len(a)]) < 0
94 }
95 if 0 == bytes.Compare(a[:len(b)], b) {
96 return false
97 }
98 return bytes.Compare(a[:len(b)], b) < 0
99}
100
101// UTF82GBK transform UTF8 rune into GBK byte array.
102func UTF82GBK(src string) ([]byte, error) {
103 GB18030 := simplifiedchinese.All[0]
104 return io.ReadAll(transform.NewReader(bytes.NewReader([]byte(src)), GB18030.NewEncoder()))
105}
106
107// GBK2UTF8 transform GBK byte array into UTF8 string.
108func GBK2UTF8(src []byte) (string, error) {
109 GB18030 := simplifiedchinese.All[0]
110 bytes, err := io.ReadAll(transform.NewReader(bytes.NewReader(src), GB18030.NewDecoder()))
111 return string(bytes), err
112}
113
114const (
115 SortModeNameASC = iota // 0:文件名字母升序
116 SortModeNameDESC // 1:文件名字母降序
117 SortModeUpdatedASC // 2:文件更新时间升序
118 SortModeUpdatedDESC // 3:文件更新时间降序
119 SortModeAlphanumASC // 4:文件名自然数升序
120 SortModeAlphanumDESC // 5:文件名自然数降序
121 SortModeCustom // 6:自定义排序
122 SortModeRefCountASC // 7:引用数升序
123 SortModeRefCountDESC // 8:引用数降序
124 SortModeCreatedASC // 9:文件创建时间升序
125 SortModeCreatedDESC // 10:文件创建时间降序
126 SortModeSizeASC // 11:文件大小升序
127 SortModeSizeDESC // 12:文件大小降序
128 SortModeSubDocCountASC // 13:子文档数升序
129 SortModeSubDocCountDESC // 14:子文档数降序
130 SortModeFileTree // 15:使用文档树排序规则
131
132 SortModeUnassigned = 256 // 256:未指定排序规则,按照笔记本优先于文档树获取排序规则
133)