├── .github └── FUNDING.yml ├── .gitignore ├── EverythingExt ├── EverythingExt.vcxproj ├── EverythingExt.vcxproj.filters ├── PinyinSearch.cpp ├── PinyinSearch.hpp ├── PinyinSearchEdit.cpp ├── PinyinSearchEdit.hpp ├── PinyinSearchPcre.cpp ├── PinyinSearchPcre.hpp ├── common.hpp ├── config.cpp ├── config.hpp ├── dllmain.cpp ├── framework.h ├── helper.cpp ├── helper.hpp ├── ipc.cpp ├── ipc.hpp ├── ipc_window.cpp ├── ipc_window.hpp ├── match.cpp ├── match.hpp ├── pch.cpp ├── pch.h ├── pinyin.cpp ├── pinyin.hpp ├── quick_select.cpp ├── quick_select.hpp ├── resource.h ├── resource.rc ├── search_history.cpp ├── search_history.hpp └── toupper_gen.py ├── IbEverythingExt.sln ├── LICENSE.txt ├── README.md ├── Updater ├── Updater.vcxproj ├── Updater.vcxproj.filters └── updater.cpp ├── docs ├── Disk space │ └── images │ │ ├── VisualStudio.png │ │ └── dupe.png ├── development.md ├── pinyin_search.png ├── pinyin_search │ ├── edit_mode.md │ └── edit_mode.png ├── preview.png ├── quick_select_dark_mode.png └── third_party │ ├── EverythingToolbar.png │ ├── FlowLauncher.png │ ├── HuoChat.png │ ├── PowerToys.png │ ├── README.md │ ├── Wox.png │ └── uTools.png ├── external └── CMakeLists.txt └── test ├── common.hpp ├── main.cpp ├── match.cpp ├── pcre.cpp ├── test.vcxproj ├── test.vcxproj.filters ├── v1.4.cpp └── v1.5a.cpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://chaoses-ib.github.io/funding/微信赞赏码.png", "https://chaoses-ib.github.io/funding/支付宝收款码.png", "感谢捐赠,捐赠时请备注仓库名,便于记录。"] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | private/ 4 | *.private 5 | *.private.* 6 | 7 | ## Ignore Visual Studio temporary files, build results, and 8 | ## files generated by popular Visual Studio add-ons. 9 | ## 10 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 11 | 12 | # User-specific files 13 | *.rsuser 14 | *.suo 15 | *.user 16 | *.userosscache 17 | *.sln.docstates 18 | 19 | # User-specific files (MonoDevelop/Xamarin Studio) 20 | *.userprefs 21 | 22 | # Build results 23 | [Dd]ebug/ 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | [Aa][Rr][Mm]/ 30 | [Aa][Rr][Mm]64/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Ll]og/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUNIT 49 | *.VisualState.xml 50 | TestResult.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # StyleCop 66 | StyleCopReport.xml 67 | 68 | # Files built by Visual Studio 69 | *_i.c 70 | *_p.c 71 | *_h.h 72 | *.ilk 73 | *.meta 74 | *.obj 75 | *.iobj 76 | *.pch 77 | *.pdb 78 | *.ipdb 79 | *.pgc 80 | *.pgd 81 | *.rsp 82 | *.sbr 83 | *.tlb 84 | *.tli 85 | *.tlh 86 | *.tmp 87 | *.tmp_proj 88 | *_wpftmp.csproj 89 | *.log 90 | *.vspscc 91 | *.vssscc 92 | .builds 93 | *.pidb 94 | *.svclog 95 | *.scc 96 | 97 | # Chutzpah Test files 98 | _Chutzpah* 99 | 100 | # Visual C++ cache files 101 | ipch/ 102 | *.aps 103 | *.ncb 104 | *.opendb 105 | *.opensdf 106 | *.sdf 107 | *.cachefile 108 | *.VC.db 109 | *.VC.VC.opendb 110 | 111 | # Visual Studio profiler 112 | *.psess 113 | *.vsp 114 | *.vspx 115 | *.sap 116 | 117 | # Visual Studio Trace Files 118 | *.e2e 119 | 120 | # TFS 2012 Local Workspace 121 | $tf/ 122 | 123 | # Guidance Automation Toolkit 124 | *.gpState 125 | 126 | # ReSharper is a .NET coding add-in 127 | _ReSharper*/ 128 | *.[Rr]e[Ss]harper 129 | *.DotSettings.user 130 | 131 | # JustCode is a .NET coding add-in 132 | .JustCode 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Visual Studio code coverage results 145 | *.coverage 146 | *.coveragexml 147 | 148 | # NCrunch 149 | _NCrunch_* 150 | .*crunch*.local.xml 151 | nCrunchTemp_* 152 | 153 | # MightyMoose 154 | *.mm.* 155 | AutoTest.Net/ 156 | 157 | # Web workbench (sass) 158 | .sass-cache/ 159 | 160 | # Installshield output folder 161 | [Ee]xpress/ 162 | 163 | # DocProject is a documentation generator add-in 164 | DocProject/buildhelp/ 165 | DocProject/Help/*.HxT 166 | DocProject/Help/*.HxC 167 | DocProject/Help/*.hhc 168 | DocProject/Help/*.hhk 169 | DocProject/Help/*.hhp 170 | DocProject/Help/Html2 171 | DocProject/Help/html 172 | 173 | # Click-Once directory 174 | publish/ 175 | 176 | # Publish Web Output 177 | *.[Pp]ublish.xml 178 | *.azurePubxml 179 | # Note: Comment the next line if you want to checkin your web deploy settings, 180 | # but database connection strings (with potential passwords) will be unencrypted 181 | *.pubxml 182 | *.publishproj 183 | 184 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 185 | # checkin your Azure Web App publish settings, but sensitive information contained 186 | # in these scripts will be unencrypted 187 | PublishScripts/ 188 | 189 | # NuGet Packages 190 | *.nupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- Backup*.rdl 265 | 266 | # Microsoft Fakes 267 | FakesAssemblies/ 268 | 269 | # GhostDoc plugin setting file 270 | *.GhostDoc.xml 271 | 272 | # Node.js Tools for Visual Studio 273 | .ntvs_analysis.dat 274 | node_modules/ 275 | 276 | # Visual Studio 6 build log 277 | *.plg 278 | 279 | # Visual Studio 6 workspace options file 280 | *.opt 281 | 282 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 283 | *.vbw 284 | 285 | # Visual Studio LightSwitch build output 286 | **/*.HTMLClient/GeneratedArtifacts 287 | **/*.DesktopClient/GeneratedArtifacts 288 | **/*.DesktopClient/ModelManifest.xml 289 | **/*.Server/GeneratedArtifacts 290 | **/*.Server/ModelManifest.xml 291 | _Pvt_Extensions 292 | 293 | # Paket dependency manager 294 | .paket/paket.exe 295 | paket-files/ 296 | 297 | # FAKE - F# Make 298 | .fake/ 299 | 300 | # JetBrains Rider 301 | .idea/ 302 | *.sln.iml 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb -------------------------------------------------------------------------------- /EverythingExt/EverythingExt.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {102eefa7-f37c-4fa7-ac25-d4ddc2e797e7} 25 | EverythingExt 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | WindowsCodecs 76 | 77 | 78 | false 79 | WindowsCodecs 80 | 81 | 82 | true 83 | WindowsCodecs 84 | 85 | 86 | false 87 | WindowsCodecs 88 | 89 | 90 | x64-windows-static-md 91 | 92 | 93 | x64-windows-static-md 94 | 95 | 96 | 97 | Level3 98 | true 99 | IB_DEBUG;WIN32;_DEBUG;EVERYTHINGEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 100 | true 101 | Use 102 | pch.h 103 | stdcpplatest 104 | $(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include;$(SolutionDir)external\build\_deps\sigmatch-src\include;$(SolutionDir)external\build\_deps\ibdllhijack-src\include;%(AdditionalIncludeDirectories) 105 | 106 | 107 | Windows 108 | true 109 | false 110 | 111 | 112 | 113 | 114 | Level3 115 | true 116 | true 117 | true 118 | WIN32;NDEBUG;EVERYTHINGEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 119 | true 120 | Use 121 | pch.h 122 | stdcpplatest 123 | $(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include;$(SolutionDir)external\build\_deps\sigmatch-src\include;$(SolutionDir)external\build\_deps\ibdllhijack-src\include;%(AdditionalIncludeDirectories) 124 | 125 | 126 | Windows 127 | true 128 | true 129 | true 130 | false 131 | /PDBALTPATH:https://github.com/Chaoses-Ib/IbEverythingExt %(AdditionalOptions) 132 | 133 | 134 | 135 | 136 | Level3 137 | true 138 | IB_DEBUG;_DEBUG;EVERYTHINGEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 139 | true 140 | Use 141 | pch.h 142 | stdcpplatest 143 | $(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include;$(SolutionDir)external\build\_deps\sigmatch-src\include;$(SolutionDir)external\build\_deps\ibdllhijack-src\include;%(AdditionalIncludeDirectories) 144 | 145 | 146 | Windows 147 | true 148 | false 149 | 150 | 151 | 152 | 153 | Level3 154 | true 155 | true 156 | true 157 | NDEBUG;EVERYTHINGEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 158 | true 159 | Use 160 | pch.h 161 | stdcpplatest 162 | $(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include;$(SolutionDir)external\build\_deps\sigmatch-src\include;$(SolutionDir)external\build\_deps\ibdllhijack-src\include;%(AdditionalIncludeDirectories) 163 | 164 | 165 | Windows 166 | true 167 | true 168 | true 169 | false 170 | /PDBALTPATH:https://github.com/Chaoses-Ib/IbEverythingExt %(AdditionalOptions) 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | Create 199 | Create 200 | Create 201 | Create 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | {1dbb8594-6baf-34c0-9998-6aa359588998} 216 | 217 | 218 | {169d9787-0f47-3ee4-9056-c52dfc6e922a} 219 | 220 | 221 | {81a0272a-5ef3-30a8-9154-3a5a8df9aa70} 222 | 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /EverythingExt/EverythingExt.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | Header Files 62 | 63 | 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | Source Files 85 | 86 | 87 | Source Files 88 | 89 | 90 | Source Files 91 | 92 | 93 | Source Files 94 | 95 | 96 | Source Files 97 | 98 | 99 | Source Files 100 | 101 | 102 | Source Files 103 | 104 | 105 | 106 | 107 | Resource Files 108 | 109 | 110 | -------------------------------------------------------------------------------- /EverythingExt/PinyinSearch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "PinyinSearch.hpp" 3 | #include "PinyinSearchPcre.hpp" 4 | #include "PinyinSearchEdit.hpp" 5 | #include 6 | 7 | std::unique_ptr make_pinyin_search(PinyinSearchMode mode, std::wstring& instance_name, HWND ipc_window) { 8 | switch (mode) { 9 | case PinyinSearchMode::Pcre: 10 | return std::make_unique(); 11 | case PinyinSearchMode::Edit: 12 | return std::make_unique(instance_name, ipc_window); 13 | default: 14 | assert(false); 15 | } 16 | } -------------------------------------------------------------------------------- /EverythingExt/PinyinSearch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hpp" 3 | #include 4 | #include 5 | 6 | #include 7 | #define IB_PINYIN_ENCODING 32 8 | #include 9 | 10 | enum class PinyinSearchMode { 11 | Pcre, 12 | Edit 13 | }; 14 | 15 | class PinyinSearch { 16 | public: 17 | virtual ~PinyinSearch() {} 18 | 19 | virtual void everything_created() {} 20 | virtual void edit_created(HWND edit) {} 21 | }; 22 | 23 | // std::runtime_error: current version is not supported 24 | std::unique_ptr make_pinyin_search(PinyinSearchMode mode, std::wstring& instance_name, HWND ipc_window); -------------------------------------------------------------------------------- /EverythingExt/PinyinSearchEdit.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "PinyinSearchEdit.hpp" 3 | #include 4 | #include 5 | #include "helper.hpp" 6 | #include "pinyin.hpp" 7 | #include "search_history.hpp" 8 | #include "ipc_window.hpp" 9 | 10 | bool is_modifier_in_blacklist(std::wstring_view modifier) { 11 | using namespace std::literals; 12 | 13 | // must be sorted 14 | static constexpr std::wstring_view blacklist[]{ 15 | L"attrib:"sv, 16 | L"attributes:"sv, 17 | L"bitdepth:"sv, 18 | L"case:"sv, 19 | L"childcount:"sv, 20 | L"childfilecount:"sv, 21 | L"childfoldercount:"sv, 22 | L"count:"sv, 23 | L"da:"sv, 24 | L"dateaccessed:"sv, 25 | L"datecreated:"sv, 26 | L"datemodified:"sv, 27 | L"daterun:"sv, 28 | L"dc:"sv, 29 | L"dimensions:"sv, 30 | L"dm:"sv, 31 | L"dr:"sv, 32 | L"ext:"sv, 33 | L"frn:"sv, 34 | L"fsi:"sv, 35 | L"height:"sv, 36 | L"len:"sv, 37 | L"orientation:"sv, 38 | L"parents:"sv, 39 | L"rc:"sv, 40 | L"recentchange:"sv, 41 | L"regex:"sv, 42 | L"runcount:"sv, 43 | L"size:"sv, 44 | L"track:"sv, 45 | L"type:"sv, 46 | L"width:"sv 47 | }; 48 | return std::ranges::binary_search(blacklist, modifier); 49 | } 50 | 51 | // #TODO: may be buggy, need tests 52 | std::wstring* edit_process_content(const std::wstring& content) { 53 | using namespace std::literals; 54 | 55 | if (content.size() <= 1) { // ignore empty and single-char contents 56 | return new std::wstring(content); 57 | } else if (content.starts_with(L"nopy:"sv)) { 58 | return new std::wstring(content, L"nopy:"sv.size()); 59 | } 60 | 61 | std::wistringstream in{ content }; // (content.data(), content.size()) is not what we want 62 | std::wostringstream out; 63 | 64 | bool disabled = false; 65 | struct { 66 | bool py = false; 67 | bool endwith = false; 68 | bool startwith = false; 69 | bool nowholefilename = false; 70 | bool nowildcards = false; 71 | } modifiers; 72 | 73 | auto process_keyword = [&out, &disabled, &modifiers](const std::wstring_view& keyword) { 74 | if (keyword.empty()) 75 | disabled = true; 76 | else if (keyword[0] == L'"') { 77 | if (keyword.size() >= 4 && keyword[2] == L':') // '"C:"' 78 | disabled = true; 79 | } else { 80 | if (keyword.size() >= 2 && keyword[1] == L':') // 'C:' 81 | disabled = true; 82 | } 83 | 84 | if (disabled) { 85 | disabled = false; 86 | if (modifiers.startwith) 87 | out << L"startwith:"; 88 | if (modifiers.endwith) 89 | out << L"endwith:"; 90 | out << keyword; 91 | return; 92 | } 93 | 94 | // check whether wildcards exist 95 | bool wildcards = false; 96 | if (!modifiers.nowildcards) { 97 | bool escape = false; 98 | uint32_t i = 0; 99 | while (!wildcards && i < keyword.size()) { 100 | wchar_t c = keyword[i++]; 101 | 102 | if (escape) { 103 | escape = false; 104 | continue; 105 | } 106 | 107 | switch (c) { 108 | case L'\\': 109 | escape = true; 110 | break; 111 | case L'*': 112 | case L'?': 113 | wildcards = true; 114 | break; 115 | } 116 | } 117 | } 118 | 119 | out << L"regex:"; 120 | 121 | /* 122 | // keyword must be quoted if you use branch in the group of your regex 123 | bool quoted = keyword[0] == L'"'; 124 | if (!quoted) 125 | out << L'"'; 126 | */ 127 | 128 | if (modifiers.startwith || (wildcards && !modifiers.nowildcards && !modifiers.nowholefilename)) { 129 | out << L'^'; 130 | } 131 | 132 | // pinyin output functions 133 | auto output_pinyin_common = [&out, &modifiers](wchar_t cur, std::wstring_view regex) { 134 | out << L'['; 135 | if (!modifiers.py) 136 | out << cur; 137 | out << regex << L']'; 138 | }; 139 | auto output_pinyin = [&output_pinyin_common](wchar_t cur) { 140 | output_pinyin_common(cur, pinyin_regexs[cur - L'a']); 141 | }; 142 | auto output_pinyin_next = [&output_pinyin_common](wchar_t cur, wchar_t next) { 143 | output_pinyin_common(cur, pinyin_pair_regexs[cur - L'a'][next - L'a'].first); 144 | }; 145 | auto output_pinyin_last = [&output_pinyin_common](wchar_t last, wchar_t cur) { 146 | output_pinyin_common(cur, pinyin_pair_regexs[last - L'a'][cur - L'a'].second); 147 | }; 148 | auto output_pinyin_last_next = [&out, &modifiers](wchar_t last, wchar_t cur, wchar_t next) { 149 | out << L'['; 150 | if (!modifiers.py) 151 | out << cur; 152 | 153 | std::wstring& first = pinyin_pair_regexs[cur - L'a'][next - L'a'].first; 154 | std::wstring& second = pinyin_pair_regexs[last - L'a'][cur - L'a'].second; 155 | 156 | // intersect 157 | uint32_t i = 0; 158 | while (i < first.size()) { 159 | wchar_t c = first[i++]; 160 | 161 | Utf16Pair cur; 162 | if (0xD800 <= c && c <= 0xDBFF) { 163 | if (i < first.size()) 164 | cur = { c, first[i++] }; 165 | else 166 | break; 167 | } else { 168 | cur = { c }; 169 | } 170 | 171 | if (cur.in(second)) { 172 | out << cur.l; 173 | if (cur.h) 174 | out << cur.h; 175 | } 176 | } 177 | 178 | out << L']'; 179 | }; 180 | 181 | wchar_t last = L'\0'; 182 | bool escape = false; 183 | uint32_t i = 0; 184 | while (i < keyword.size()) { 185 | wchar_t c = keyword[i++]; 186 | 187 | if (escape) { 188 | escape = false; 189 | 190 | // only \! is escaped 191 | if (c == L'!') { 192 | out << c; 193 | continue; 194 | } 195 | out << L'\\'; 196 | } 197 | if (L'a' <= c && c <= L'z') { // only process lowercase letters 198 | wchar_t next = L'\0'; 199 | if (i < keyword.size()) { 200 | next = keyword[i]; 201 | if (!(L'a' <= next && next <= L'z')) 202 | next = L'\0'; 203 | } 204 | 205 | if (next) { 206 | if (last) 207 | output_pinyin_last_next(last, c, next); 208 | else 209 | output_pinyin_next(c, next); 210 | } else { 211 | if (last) 212 | output_pinyin_last(last, c); 213 | else 214 | output_pinyin(c); 215 | } 216 | last = c; 217 | } else if (L'A' <= c && c <= L'Z') { 218 | last = static_cast(c - 'A' + 'a'); 219 | out << c; 220 | } else { 221 | switch (c) { 222 | case L'\\': 223 | escape = true; 224 | out << c; 225 | break; 226 | 227 | // escape regex chars 228 | case L'.': 229 | case L'[': 230 | case L']': 231 | case L'^': 232 | case L'$': 233 | case L'+': 234 | case L'{': 235 | case L'}': 236 | case L'(': 237 | case L')': 238 | out << L'\\' << c; 239 | break; 240 | 241 | // wildcards to regex 242 | case L'*': 243 | if (!modifiers.nowildcards) 244 | out << L".*"; 245 | else 246 | out << L'\\' << c; 247 | break; 248 | case L'?': 249 | if (!modifiers.nowildcards) 250 | out << L"."; 251 | else 252 | out << L'\\' << c; 253 | break; 254 | 255 | default: 256 | out << c; 257 | } 258 | 259 | last = L'\0'; 260 | } 261 | } 262 | if (escape) //R"(abc\)" 263 | out << L'\\'; 264 | 265 | if (modifiers.endwith || (wildcards && !modifiers.nowildcards && !modifiers.nowholefilename)) { 266 | out << L'$'; 267 | } 268 | 269 | /* 270 | if (!quoted) 271 | out << L'"'; 272 | */ 273 | }; 274 | 275 | wchar_t c; 276 | bool in_quotes = false; 277 | std::wistringstream::pos_type last_colon_next{}; 278 | while (in.get(c)) { 279 | switch (c) { 280 | case L'"': 281 | in_quotes = !in_quotes; 282 | break; 283 | case L':': 284 | if (!in_quotes) { 285 | // modifier/function 286 | 287 | auto colon_next = in.tellg(); 288 | size_t size = colon_next - last_colon_next; 289 | if (size <= 2) // "C:" 290 | break; 291 | std::wstring modifier(size, L'\0'); 292 | in.seekg(last_colon_next); 293 | in.read(modifier.data(), size); 294 | last_colon_next = colon_next; 295 | 296 | if (disabled || is_modifier_in_blacklist(modifier)) { 297 | disabled = true; 298 | out << modifier; 299 | } else if (modifier == L"py:"sv || modifier == L"endwith:"sv || modifier == L"startwith:"sv) { 300 | if (modifier == L"py:"sv) 301 | modifiers.py = true; 302 | else if (modifier == L"endwith:"sv) 303 | modifiers.endwith = true; 304 | else if (modifier == L"startwith:"sv) 305 | modifiers.startwith = true; 306 | // remove (these modifiers will be implemented with regex) 307 | } else { 308 | if (modifier == L"nowholefilename:"sv) 309 | modifiers.nowholefilename = true; 310 | else if (modifier == L"nowildcards:"sv) 311 | modifiers.nowildcards = true; 312 | out << modifier; 313 | } 314 | } 315 | break; 316 | case L'!': 317 | if (in.tellg() == last_colon_next + std::streamoff(1)) { 318 | out << c; 319 | last_colon_next += 1; 320 | } 321 | break; 322 | case L' ': 323 | if (!in_quotes) { 324 | // keyword 325 | 326 | size_t size = in.tellg() - last_colon_next - 1; 327 | std::wstring keyword(size, L'\0'); 328 | if (size) { 329 | in.seekg(last_colon_next); 330 | in.read(keyword.data(), size); 331 | in.ignore(); // ignore L' ' 332 | } 333 | 334 | process_keyword(keyword); 335 | out << L' '; 336 | 337 | modifiers = {}; 338 | last_colon_next = in.tellg(); 339 | } 340 | break; 341 | } 342 | } 343 | // stream EOF 344 | in.clear(); 345 | 346 | size_t size = in.tellg() - last_colon_next; 347 | std::wstring keyword(size, L'\0'); 348 | in.seekg(last_colon_next); 349 | in.read(keyword.data(), size); 350 | 351 | process_keyword(keyword); 352 | 353 | // return the result 354 | if constexpr (debug) 355 | DebugOStream() << content << L" -> " << out.str() << std::endl; 356 | return new std::wstring(out.str()); 357 | } 358 | 359 | constexpr wchar_t prop_main_title[] = L"IbEverythingExt.Title"; 360 | constexpr wchar_t prop_edit_content[] = L"IbEverythingExt.Content"; 361 | constexpr wchar_t prop_edit_processed_content[] = L"IbEverythingExt.ProcessedContent"; 362 | 363 | std::wstring title_suffix = L" - Everything"; 364 | std::unordered_map content_map{}; 365 | 366 | WNDPROC edit_window_proc_0; 367 | LRESULT CALLBACK edit_window_proc_1( 368 | _In_ HWND hwnd, 369 | _In_ UINT uMsg, 370 | _In_ WPARAM wParam, 371 | _In_ LPARAM lParam) 372 | { 373 | switch (uMsg) { 374 | case WM_GETTEXTLENGTH: 375 | { 376 | if constexpr (debug) 377 | DebugOStream() << L"WM_GETTEXTLENGTH\n"; 378 | 379 | // retrieve the content 380 | LRESULT result = CallWindowProcW(edit_window_proc_0, hwnd, uMsg, wParam, lParam); 381 | wchar_t* buf = new wchar_t[result + 1 + title_suffix.size()]; // for both the content and the title 382 | LRESULT content_len = CallWindowProcW(edit_window_proc_0, hwnd, WM_GETTEXT, result + 1, (LPARAM)buf); 383 | 384 | // save the content 385 | auto content = (std::wstring*)GetPropW(hwnd, prop_edit_content); 386 | auto processed_content = (std::wstring*)GetPropW(hwnd, prop_edit_processed_content); 387 | if (content && *content == std::wstring_view(buf, content_len)) { 388 | delete[] buf; 389 | return processed_content->size(); 390 | } 391 | delete content; 392 | delete processed_content; 393 | content = new std::wstring(buf, content_len); 394 | SetPropW(hwnd, prop_edit_content, content); 395 | 396 | // process the content 397 | processed_content = edit_process_content(*content); 398 | SetPropW(hwnd, prop_edit_processed_content, processed_content); 399 | 400 | // make the title 401 | if (content_len) 402 | std::copy_n(title_suffix.c_str(), title_suffix.size() + 1, buf + content_len); 403 | else 404 | std::copy_n(title_suffix.c_str() + std::size(L" - ") - 1, title_suffix.size() + 1 - (std::size(L" - ") - 1), buf); 405 | 406 | // save the title 407 | HWND main = GetAncestor(hwnd, GA_ROOT); 408 | delete[] (wchar_t*)GetPropW(main, prop_main_title); 409 | SetPropW(main, prop_main_title, buf); 410 | 411 | return processed_content->size(); 412 | } 413 | break; 414 | case WM_GETTEXT: 415 | { 416 | if constexpr (debug) 417 | DebugOStream() << L"WM_GETTEXT\n"; 418 | 419 | if (auto processed_content = (std::wstring*)GetPropW(hwnd, prop_edit_processed_content)) { 420 | LRESULT n = min(processed_content->size() + 1, wParam); 421 | std::copy_n(processed_content->c_str(), n, (wchar_t*)lParam); 422 | return n - 1; 423 | } 424 | } 425 | break; 426 | case WM_KILLFOCUS: 427 | { 428 | if constexpr (debug) 429 | DebugOStream() << L"WM_KILLFOCUS\n"; 430 | 431 | // save the content to map 432 | if (auto content = (std::wstring*)GetPropW(hwnd, prop_edit_content)) { 433 | auto processed_content = (std::wstring*)GetPropW(hwnd, prop_edit_processed_content); 434 | content_map[*processed_content] = *content; 435 | } 436 | } 437 | break; 438 | } 439 | return CallWindowProcW(edit_window_proc_0, hwnd, uMsg, wParam, lParam); 440 | } 441 | 442 | /* 443 | WNDPROC edit_window_proc_2; 444 | LRESULT CALLBACK edit_window_proc_3( 445 | _In_ HWND hwnd, 446 | _In_ UINT uMsg, 447 | _In_ WPARAM wParam, 448 | _In_ LPARAM lParam) 449 | { 450 | switch (uMsg) { 451 | case WM_KEYDOWN: 452 | case WM_SYSKEYDOWN: 453 | if constexpr (debug) 454 | DebugOStream() << (uMsg == WM_KEYDOWN ? L"WM_KEYDOWN: " : L"WM_SYSKEYDOWN: ") << wParam << L'\n'; 455 | break; 456 | } 457 | return CallWindowProcW(edit_window_proc_2, hwnd, uMsg, wParam, lParam); 458 | } 459 | */ 460 | 461 | extern std::wstring class_everything; 462 | 463 | auto SetWindowTextW_real = SetWindowTextW; 464 | BOOL WINAPI SetWindowTextW_detour( 465 | _In_ HWND hWnd, 466 | _In_opt_ LPCWSTR lpString) 467 | { 468 | using namespace std::literals; 469 | 470 | wchar_t buf[256]; 471 | if (int len = GetClassNameW(hWnd, buf, std::size(buf))) { 472 | std::wstring_view sv(buf, len); 473 | 474 | if (sv == class_everything) { 475 | // set the title 476 | if (auto title = (const wchar_t*)GetPropW(hWnd, prop_main_title)) { 477 | SetWindowTextW_real(hWnd, title); 478 | return true; 479 | } 480 | } else if (sv == L"Edit"sv) { 481 | auto processed_content = (std::wstring*)GetPropW(hWnd, prop_edit_processed_content); 482 | if (processed_content && *processed_content == lpString) { 483 | // prevent modifying edit 484 | return true; 485 | } 486 | 487 | auto iter = content_map.find(lpString); 488 | if (iter != content_map.end()) 489 | return SetWindowTextW_real(hWnd, iter->second.c_str()); 490 | } 491 | } 492 | return SetWindowTextW_real(hWnd, lpString); 493 | } 494 | 495 | PinyinSearchEdit::PinyinSearchEdit(const std::wstring& instance_name, HWND ipc_window) { 496 | using namespace std::literals; 497 | 498 | std::thread t(pinyin_query_and_merge); 499 | t.detach(); 500 | 501 | title_suffix += L" ("sv; 502 | if (!instance_name.empty()) { 503 | title_suffix += instance_name; 504 | title_suffix += L", "sv; 505 | } 506 | title_suffix += L"Edit 模式)"sv; 507 | 508 | IbDetourAttach(&SetWindowTextW_real, SetWindowTextW_detour); 509 | 510 | search_history_init(); 511 | 512 | ipc_window_init(ipc_window); 513 | } 514 | 515 | PinyinSearchEdit::~PinyinSearchEdit() { 516 | ipc_window_destroy(); 517 | 518 | search_history_destroy(); 519 | 520 | IbDetourDetach(&SetWindowTextW_real, SetWindowTextW_detour); 521 | } 522 | 523 | void PinyinSearchEdit::everything_created() { 524 | std::thread t(pinyin_query_and_merge); 525 | t.detach(); 526 | } 527 | 528 | void PinyinSearchEdit::edit_created(HWND edit) { 529 | edit_window_proc_0 = (WNDPROC)SetWindowLongPtrW(edit, GWLP_WNDPROC, (LONG_PTR)edit_window_proc_1); 530 | } -------------------------------------------------------------------------------- /EverythingExt/PinyinSearchEdit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PinyinSearch.hpp" 3 | 4 | class PinyinSearchEdit : public PinyinSearch { 5 | public: 6 | PinyinSearchEdit(const std::wstring& instance_name, HWND ipc_window); 7 | ~PinyinSearchEdit() override; 8 | 9 | void everything_created() override; 10 | void edit_created(HWND edit) override; 11 | }; -------------------------------------------------------------------------------- /EverythingExt/PinyinSearchPcre.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "PinyinSearch.hpp" 4 | 5 | class PinyinSearchPcre : public PinyinSearch { 6 | public: 7 | // throw std::runtime_error for unsupported Everything version 8 | PinyinSearchPcre(); 9 | ~PinyinSearchPcre() override; 10 | }; -------------------------------------------------------------------------------- /EverythingExt/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include -------------------------------------------------------------------------------- /EverythingExt/config.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "common.hpp" 3 | #include "config.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #pragma comment(lib, "Shlwapi.lib") 10 | 11 | Config config{}; 12 | 13 | std::wstring u8_to_u16(const std::string& u8) { 14 | std::wstring u16; 15 | u16.resize(MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), u8.size(), nullptr, 0)); 16 | MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), u8.size(), u16.data(), u16.size()); 17 | return u16; 18 | } 19 | 20 | bool config_init() { 21 | using namespace std::literals; 22 | 23 | config.enable = false; 24 | 25 | wchar_t root_path[MAX_PATH]; 26 | GetModuleFileNameW(nullptr, root_path, std::size(root_path)); 27 | PathRemoveFileSpecW(root_path); 28 | PathAppendW(root_path, LR"(IbEverythingExt\)"); 29 | 30 | wchar_t config_path[MAX_PATH]; 31 | wcscpy_s(config_path, root_path); 32 | PathAppendW(config_path, LR"(config.yaml)"); 33 | 34 | std::ifstream in(config_path); 35 | if (!in) { 36 | MessageBoxW(nullptr, L"配置文件 config.yaml 不存在!", L"IbEverythingExt", MB_ICONERROR); 37 | return false; 38 | } 39 | try { 40 | YAML::Node root = YAML::Load(in); 41 | 42 | { 43 | YAML::Node node = root["pinyin_search"]; 44 | config.pinyin_search = { 45 | .enable = node["enable"].as(), 46 | .mode = [&node] { 47 | auto mode = node["mode"].as(); 48 | if (mode == "Pcre") 49 | return PinyinSearchMode::Pcre; 50 | else if (mode == "Edit") 51 | return PinyinSearchMode::Edit; 52 | throw YAML::Exception(YAML::Mark::null_mark(), "Invalid pinyin_search.mode"); 53 | }(), 54 | .flags = [&node] { 55 | std::vector flags; 56 | 57 | // mind the order 58 | if (node["pinyin_ascii_digit"].as()) 59 | flags.push_back(pinyin::PinyinFlag::PinyinAsciiDigit); 60 | if (node["pinyin_ascii"].as()) 61 | flags.push_back(pinyin::PinyinFlag::PinyinAscii); 62 | if (node["double_pinyin_abc"].as()) 63 | flags.push_back(pinyin::PinyinFlag::DoublePinyinAbc); 64 | if (node["double_pinyin_jiajia"].as()) 65 | flags.push_back(pinyin::PinyinFlag::DoublePinyinJiajia); 66 | if (node["double_pinyin_microsoft"].as()) 67 | flags.push_back(pinyin::PinyinFlag::DoublePinyinMicrosoft); 68 | if (node["double_pinyin_thunisoft"].as()) 69 | flags.push_back(pinyin::PinyinFlag::DoublePinyinThunisoft); 70 | if (node["double_pinyin_xiaohe"].as()) 71 | flags.push_back(pinyin::PinyinFlag::DoublePinyinXiaohe); 72 | if (node["double_pinyin_zrm"].as()) 73 | flags.push_back(pinyin::PinyinFlag::DoublePinyinZrm); 74 | if (node["initial_letter"].as()) 75 | flags.push_back(pinyin::PinyinFlag::InitialLetter); 76 | return flags; 77 | }() 78 | }; 79 | } 80 | 81 | { 82 | YAML::Node node = root["quick_select"]; 83 | config.quick_select = { 84 | .enable = node["enable"].as(), 85 | 86 | .search_edit = [](const YAML::Node& node) { 87 | return decltype(config.quick_select.search_edit) { 88 | .alt = node["alt"].as() 89 | }; 90 | }(node["search_edit"]), 91 | 92 | .result_list = [](const YAML::Node& node) { 93 | decltype(config.quick_select.result_list) result_list { 94 | .select = node["select"].as(), 95 | .alt = node["alt"].as() 96 | }; 97 | std::wstring terminal = u8_to_u16(node["terminal"].as()); 98 | if (terminal.size()) { 99 | std::wregex reg(LR"__((?:"([^"]*)"|([^ ]*)) ?(.*))__"); 100 | std::wsmatch match; 101 | std::regex_match(terminal, match, reg); 102 | result_list.terminal_file = match[1].str() + match[2].str(); 103 | result_list.terminal_parameter = match[3].str(); 104 | } 105 | return result_list; 106 | }(node["result_list"]), 107 | 108 | .close_everything = node["close_everything"].as(), 109 | 110 | .input_mode = [&node] { 111 | auto mode = node["input_mode"].as(); 112 | if (mode == "Auto") 113 | return quick::InputMode::Auto; 114 | else if (mode == "WmKey") 115 | return quick::InputMode::WmKey; 116 | else if (mode == "SendInput") 117 | return quick::InputMode::SendInput; 118 | throw YAML::Exception(YAML::Mark::null_mark(), "Invalid quick_select.input_mode"); 119 | }() 120 | }; 121 | } 122 | 123 | if (config.update.check = root["update"]["check"].as()) { 124 | wchar_t update_path[MAX_PATH]; 125 | wcscpy_s(update_path, root_path); 126 | PathAppendW(update_path, L"Updater.exe"); 127 | config.update.update_path = update_path; 128 | 129 | // to avoid checking on system startup and when calling Everything through command line, 130 | // we do the check after the main window is created 131 | } 132 | } 133 | catch (YAML::Exception& e) { 134 | MessageBoxA(nullptr, ("配置文件读取错误:\n"s + e.what()).c_str(), "IbEverythingExt", MB_ICONERROR); 135 | return false; 136 | } 137 | 138 | pinyin::PinyinFlagValue flags{}; 139 | for (pinyin::PinyinFlagValue flag : config.pinyin_search.flags) 140 | flags |= flag; 141 | pinyin::init(flags); 142 | 143 | config.enable = true; 144 | return true; 145 | } 146 | 147 | void config_destroy() { 148 | pinyin::destroy(); 149 | } -------------------------------------------------------------------------------- /EverythingExt/config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PinyinSearch.hpp" 3 | #include "quick_select.hpp" 4 | 5 | struct Config { 6 | // set to false when config_init fails 7 | bool enable; 8 | 9 | struct { 10 | bool enable; 11 | PinyinSearchMode mode; 12 | std::vector flags; 13 | } pinyin_search; 14 | 15 | struct { 16 | bool enable; 17 | 18 | struct { 19 | uint8_t alt; 20 | } search_edit; 21 | 22 | struct { 23 | bool select; 24 | uint8_t alt; 25 | std::wstring terminal_file; 26 | std::wstring terminal_parameter; 27 | } result_list; 28 | 29 | bool close_everything; 30 | 31 | quick::InputMode input_mode; 32 | } quick_select; 33 | 34 | struct { 35 | bool check; 36 | std::wstring update_path; 37 | } update; 38 | }; 39 | extern Config config; 40 | 41 | bool config_init(); 42 | void config_destroy(); -------------------------------------------------------------------------------- /EverythingExt/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "common.hpp" 3 | #include "helper.hpp" 4 | #include "config.hpp" 5 | #include "ipc.hpp" 6 | #include "PinyinSearch.hpp" 7 | #include "quick_select.hpp" 8 | 9 | std::wstring instance_name{}; 10 | std::wstring class_everything = L"EVERYTHING"; 11 | 12 | std::unique_ptr pinyin_search; 13 | 14 | /* 15 | WNDPROC list_window_proc_0; 16 | LRESULT CALLBACK list_window_proc_1( 17 | _In_ HWND hwnd, 18 | _In_ UINT uMsg, 19 | _In_ WPARAM wParam, 20 | _In_ LPARAM lParam) 21 | { 22 | switch (uMsg) { 23 | } 24 | return CallWindowProcW(list_window_proc_0, hwnd, uMsg, wParam, lParam); 25 | } 26 | */ 27 | 28 | WNDPROC list_window_proc_2; 29 | LRESULT CALLBACK list_window_proc_3( 30 | _In_ HWND hwnd, 31 | _In_ UINT uMsg, 32 | _In_ WPARAM wParam, 33 | _In_ LPARAM lParam) 34 | { 35 | return quick::list_window_proc(list_window_proc_2, hwnd, uMsg, wParam, lParam); 36 | } 37 | 38 | auto SetWindowLongPtrW_real = SetWindowLongPtrW; 39 | LONG_PTR WINAPI SetWindowLongPtrW_detour( 40 | _In_ HWND hWnd, 41 | _In_ int nIndex, 42 | _In_ LONG_PTR dwNewLong) 43 | { 44 | using namespace std::literals; 45 | 46 | if (nIndex == GWLP_WNDPROC) { 47 | wchar_t buf[256]; 48 | if (int len = GetClassNameW(hWnd, buf, std::size(buf))) { 49 | std::wstring_view class_name(buf, len); 50 | /* 51 | if (class_name == L"Edit"sv) { 52 | if (int len = GetClassNameW(GetParent(hWnd), buf, std::size(buf)); 53 | std::wstring_view(buf, len) == L"EVERYTHING_TOOLBAR"sv) 54 | { 55 | edit_window_proc_0 = (WNDPROC)SetWindowLongPtrW_real(hWnd, nIndex, (LONG_PTR)edit_window_proc_3); 56 | edit_window_proc_2 = (WNDPROC)dwNewLong; 57 | return (LONG_PTR)edit_window_proc_1; 58 | } 59 | } 60 | */ 61 | if (class_name == L"SysListView32"sv) { 62 | if (int len = GetClassNameW(GetParent(hWnd), buf, std::size(buf)); 63 | std::wstring_view(buf, len) == class_everything) 64 | { 65 | // the caller could be Everything.exe or comctl32.dll 66 | HMODULE module, everything; 67 | GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)_ReturnAddress(), &module); 68 | GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, nullptr, &everything); 69 | if (module == everything) { 70 | /* 71 | list_window_proc_0 = (WNDPROC)SetWindowLongPtrW_real(hWnd, nIndex, (LONG_PTR)list_window_proc_3); 72 | list_window_proc_2 = (WNDPROC)dwNewLong; 73 | return (LONG_PTR)list_window_proc_1; 74 | */ 75 | list_window_proc_2 = (WNDPROC)dwNewLong; 76 | return (LONG_PTR)SetWindowLongPtrW_real(hWnd, nIndex, (LONG_PTR)list_window_proc_3); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | return SetWindowLongPtrW_real(hWnd, nIndex, dwNewLong); 83 | } 84 | 85 | auto CreateWindowExW_real = CreateWindowExW; 86 | HWND WINAPI CreateWindowExW_detour( 87 | _In_ DWORD dwExStyle, 88 | _In_opt_ LPCWSTR lpClassName, 89 | _In_opt_ LPCWSTR lpWindowName, 90 | _In_ DWORD dwStyle, 91 | _In_ int X, 92 | _In_ int Y, 93 | _In_ int nWidth, 94 | _In_ int nHeight, 95 | _In_opt_ HWND hWndParent, 96 | _In_opt_ HMENU hMenu, 97 | _In_opt_ HINSTANCE hInstance, 98 | _In_opt_ LPVOID lpParam) 99 | { 100 | using namespace std::literals; 101 | 102 | // EVERYTHING 103 | // EVERYTHING_TOOLBAR 104 | // Edit 105 | // SysListView32 106 | // msctls_statusbar32 107 | // ComboBox 108 | // EVERYTHING_PREVIEW 109 | 110 | HWND wnd = CreateWindowExW_real(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); 111 | 112 | if ((uintptr_t)lpClassName > 0xFFFF) { 113 | std::wstring_view class_name(lpClassName); 114 | if constexpr (debug) 115 | DebugOStream() << class_name << L", parent: " << hWndParent << L'\n'; 116 | 117 | // named instances 118 | if (class_name.ends_with(L')') && instance_name.empty()) { 119 | size_t n = class_name.find(L"_("sv); 120 | if (n != class_name.npos) { 121 | size_t begin = n + std::size(L"_("sv); 122 | instance_name = class_name.substr(begin, class_name.size() - 1 - begin); 123 | 124 | class_everything += class_name.substr(n); 125 | } 126 | } 127 | 128 | if (class_name == class_everything) { 129 | if (config.pinyin_search.enable) 130 | pinyin_search->everything_created(); 131 | 132 | if (config.update.check) { 133 | // We only want to check for updates when the main window is (first) displayed. 134 | // However: 135 | // * `Everything64.exe` will create a window without WS_VISIBLE 136 | // * `-startup` will not create a window **but with some unknown exceptions** 137 | // * `-minimized` will create the same window as `(empty)` 138 | // To solve this, we use a simple trick - only check for updates when the main window is created at the second time. 139 | 140 | static bool created = false; 141 | if (created) { 142 | wchar_t cmd_line[] = L"--quiet"; 143 | STARTUPINFOW startup_info{ sizeof STARTUPINFOW }; 144 | PROCESS_INFORMATION process_info{}; 145 | 146 | if (CreateProcessW(config.update.update_path.c_str(), cmd_line, nullptr, nullptr, false, 0, nullptr, nullptr, &startup_info, &process_info)) { 147 | CloseHandle(process_info.hThread); 148 | CloseHandle(process_info.hProcess); 149 | } 150 | 151 | // only check once 152 | config.update.check = false; 153 | config.update.update_path = {}; 154 | } 155 | created = true; 156 | } 157 | } else if (class_name == L"Edit"sv) { 158 | if (config.pinyin_search.enable) { 159 | wchar_t buf[std::size(L"EVERYTHING_TOOLBAR")]; 160 | if (int len = GetClassNameW(hWndParent, buf, std::size(buf))) { 161 | if (std::wstring_view(buf, len) == L"EVERYTHING_TOOLBAR"sv) { 162 | pinyin_search->edit_created(wnd); 163 | } 164 | } 165 | } 166 | } else if (class_name == L"SysListView32"sv) { 167 | if (config.quick_select.enable) { 168 | wchar_t buf[256]; 169 | if (int len = GetClassNameW(hWndParent, buf, std::size(buf))) { 170 | if (std::wstring_view(buf, len) == class_everything) { 171 | // find Edit 172 | HWND toolbar = FindWindowExW(hWndParent, nullptr, L"EVERYTHING_TOOLBAR", nullptr); 173 | HWND edit = FindWindowExW(toolbar, nullptr, L"Edit", nullptr); 174 | 175 | // create quick list 176 | // X == Y == nWidth == nHeight == 0 177 | HWND quick_list = quick::create_quick_list(hWndParent, wnd, edit, hInstance); 178 | } 179 | } 180 | } 181 | } else if (class_name.starts_with(L"EVERYTHING_TASKBAR_NOTIFICATION"sv)) { 182 | ipc_init(instance_name); 183 | 184 | if (config.pinyin_search.enable) { 185 | try { 186 | pinyin_search = make_pinyin_search(config.pinyin_search.mode, instance_name, wnd); 187 | } 188 | catch (std::runtime_error& e) { 189 | config.pinyin_search.enable = false; 190 | MessageBoxW(0, L"拼音搜索 PCRE 模式不支持当前 Everything 版本,请更换至受支持的版本或禁用拼音搜索", L"IbEverythingExt", MB_ICONERROR); 191 | } 192 | } 193 | 194 | if (config.quick_select.enable) 195 | quick::init(); 196 | } 197 | } 198 | return wnd; 199 | } 200 | 201 | /* 202 | BOOL CALLBACK enum_window_proc( 203 | _In_ HWND hwnd, 204 | _In_ LPARAM lParam) 205 | { 206 | using namespace std::literals; 207 | 208 | if (GetWindowThreadProcessId(hwnd, nullptr) == static_cast(lParam)) { 209 | // hwnd may be a window other than EVERYTHING, such as "#32770 (Dialog)" (Everything Options). 210 | wchar_t buf[std::size(L"EVERYTHING")]; 211 | if (int len = GetClassNameW(hwnd, buf, std::size(buf))) { 212 | if (std::wstring_view(buf, len) == L"EVERYTHING"sv) { 213 | if (HWND toolbar = FindWindowExW(hwnd, 0, L"EVERYTHING_TOOLBAR", nullptr)) 214 | if (HWND edit = FindWindowExW(toolbar, 0, L"Edit", nullptr)) 215 | edit_window_proc_0 = (WNDPROC)SetWindowLongPtrW(edit, GWLP_WNDPROC, (LONG_PTR)edit_window_proc_1); 216 | } 217 | } 218 | } 219 | 220 | return true; 221 | } 222 | */ 223 | 224 | #include 225 | 226 | BOOL APIENTRY DllMain( HMODULE hModule, 227 | DWORD ul_reason_for_call, 228 | LPVOID lpReserved 229 | ) 230 | { 231 | switch (ul_reason_for_call) 232 | { 233 | case DLL_PROCESS_ATTACH: 234 | if constexpr (debug) 235 | DebugOStream() << L"DLL_PROCESS_ATTACH\n"; 236 | 237 | if (!config_init()) 238 | break; 239 | 240 | IbDetourAttach(&CreateWindowExW_real, CreateWindowExW_detour); 241 | if (config.quick_select.enable) 242 | IbDetourAttach(&SetWindowLongPtrW_real, SetWindowLongPtrW_detour); 243 | 244 | // may be loaded after creating windows? it seems that only netutil.dll does 245 | //EnumWindows(enum_window_proc, GetCurrentThreadId()); 246 | break; 247 | case DLL_THREAD_ATTACH: 248 | break; 249 | case DLL_THREAD_DETACH: 250 | break; 251 | case DLL_PROCESS_DETACH: 252 | if constexpr (debug) 253 | DebugOStream() << L"DLL_PROCESS_DETACH\n"; 254 | 255 | if (!config.enable) 256 | break; 257 | 258 | if (config.quick_select.enable) 259 | quick::destroy(); 260 | if (config.pinyin_search.enable) 261 | pinyin_search.reset(); 262 | 263 | ipc_destroy(); 264 | 265 | if (config.quick_select.enable) 266 | IbDetourDetach(&SetWindowLongPtrW_real, SetWindowLongPtrW_detour); 267 | IbDetourDetach(&CreateWindowExW_real, CreateWindowExW_detour); 268 | 269 | config_destroy(); 270 | break; 271 | } 272 | return TRUE; 273 | } -------------------------------------------------------------------------------- /EverythingExt/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 4 | // Windows Header Files 5 | #include 6 | -------------------------------------------------------------------------------- /EverythingExt/helper.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "helper.hpp" 3 | 4 | namespace ib { 5 | char8_t toupper(char8_t c) { 6 | // toupper_gen.py 7 | static char8_t table[] = { 8 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 9 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 10 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 11 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 12 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 13 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 14 | 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 15 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 16 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 17 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 18 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 19 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 20 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 21 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 22 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 23 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 24 | }; 25 | return table[c]; 26 | } 27 | } -------------------------------------------------------------------------------- /EverythingExt/helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | constexpr bool debug = 6 | #ifdef IB_DEBUG 7 | 1; 8 | #else 9 | 0; 10 | #endif 11 | 12 | constexpr bool debug_verbose = 13 | #ifdef IB_DEBUG_VERBOSE 14 | 1; 15 | #else 16 | 0; 17 | #endif 18 | 19 | inline ib::DebugOStream<> DebugOStream() { 20 | return ib::DebugOStream(L"IbEverythingExt: "); 21 | } 22 | 23 | template 24 | LONG IbDetourAttach(_Inout_ T* ppPointer, _In_ T pDetour) { 25 | DetourTransactionBegin(); 26 | DetourUpdateThread(GetCurrentThread()); 27 | DetourAttach((void**)ppPointer, pDetour); 28 | return DetourTransactionCommit(); 29 | } 30 | 31 | template 32 | LONG IbDetourDetach(_Inout_ T* ppPointer, _In_ T pDetour) { 33 | DetourTransactionBegin(); 34 | DetourUpdateThread(GetCurrentThread()); 35 | DetourDetach((void**)ppPointer, pDetour); 36 | return DetourTransactionCommit(); 37 | } 38 | 39 | namespace ib { 40 | // MSVC's implementation has lower performance since it doesn't use a map 41 | // (_mbbtoupper uses a map, but it's a two-way case map and therefore needs a check). 42 | char8_t toupper(char8_t c); 43 | } -------------------------------------------------------------------------------- /EverythingExt/ipc.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ipc.hpp" 3 | #include "helper.hpp" 4 | 5 | ib::Holder ipc_ev; 6 | Everythings::EverythingMT::Version ipc_version; 7 | 8 | void ipc_init(std::wstring_view instance_name) { 9 | ipc_ev.create(instance_name); 10 | ipc_version = ipc_ev->get_version(); 11 | } 12 | 13 | void ipc_destroy() { 14 | ipc_ev.destroy(); 15 | } -------------------------------------------------------------------------------- /EverythingExt/ipc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern ib::Holder ipc_ev; 5 | extern Everythings::EverythingMT::Version ipc_version; 6 | 7 | void ipc_init(std::wstring_view instance_name); 8 | void ipc_destroy(); -------------------------------------------------------------------------------- /EverythingExt/ipc_window.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ipc_window.hpp" 3 | #include 4 | #include "helper.hpp" 5 | 6 | extern std::wstring* edit_process_content(const std::wstring& content); 7 | 8 | #pragma pack(push, 1) 9 | template 10 | struct EVERYTHING_IPC_QUERY2 { 11 | // something wrong with MSVC 12 | //using namespace Everythings; 13 | 14 | DWORD reply_hwnd; // !: not sizeof(HWND) 15 | DWORD reply_copydata_message; 16 | Everythings::SearchFlags search_flags; 17 | DWORD offset; 18 | DWORD max_results; 19 | Everythings::RequestFlags request_flags; 20 | Everythings::Sort sort_type; 21 | CharT search_string[1]; // '\0' 22 | 23 | static size_t query_size() { 24 | return sizeof(EVERYTHING_IPC_QUERY2) - sizeof(CharT); 25 | } 26 | }; 27 | 28 | template 29 | struct EVERYTHING_IPC_QUERY { 30 | // something wrong with MSVC 31 | //using namespace Everythings; 32 | 33 | DWORD reply_hwnd; // !: not sizeof(HWND) 34 | DWORD reply_copydata_message; 35 | Everythings::SearchFlags search_flags; 36 | DWORD offset; 37 | DWORD max_results; 38 | CharT search_string[1]; // '\0' 39 | 40 | static size_t query_size() { 41 | return sizeof(EVERYTHING_IPC_QUERY) - sizeof(CharT); 42 | } 43 | }; 44 | #pragma pack(pop) 45 | 46 | WNDPROC ipc_window_proc_prev; 47 | LRESULT CALLBACK ipc_window_proc( 48 | _In_ HWND hwnd, 49 | _In_ UINT uMsg, 50 | _In_ WPARAM wParam, 51 | _In_ LPARAM lParam) 52 | { 53 | using namespace Everythings; 54 | 55 | switch (uMsg) { 56 | case WM_COPYDATA: 57 | { 58 | if constexpr (debug) 59 | DebugOStream() << L"WM_COPYDATA\n"; 60 | if (!wParam) 61 | break; 62 | 63 | bool known = false; 64 | 65 | static DWORD last_pid = 0; // window will be different every time when using the official SDK 66 | static bool last_known = false; 67 | DWORD pid; 68 | GetWindowThreadProcessId((HWND)wParam, &pid); 69 | if (pid == last_pid) 70 | known = last_known; 71 | else { 72 | HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid); 73 | 74 | wchar_t path_buf[MAX_PATH]; 75 | DWORD size = std::size(path_buf); 76 | QueryFullProcessImageNameW(process, 0, path_buf, &size); 77 | std::wstring_view path(path_buf, size); 78 | if constexpr (debug) 79 | DebugOStream() << path << L'\n'; 80 | 81 | if (path.ends_with(L"\\explorer.exe")) // stnkl/EverythingToolbar 82 | known = true; 83 | else if (path.ends_with(L"\\Flow.Launcher.exe")) // Flow Launcher 84 | known = true; 85 | else if (path.ends_with(L"\\HuoChat.exe")) // HuoChat 86 | known = true; 87 | else if (path.ends_with(L"\\uTools.exe")) // uTools 88 | known = true; 89 | else if (path.ends_with(L"\\Wox.exe")) // Wox 90 | known = true; 91 | 92 | CloseHandle(process); 93 | 94 | last_pid = pid; 95 | last_known = known; 96 | } 97 | if (!known) 98 | break; 99 | 100 | constexpr uintptr_t EVERYTHING_IPC_COPYDATAQUERYA = 1; 101 | constexpr uintptr_t EVERYTHING_IPC_COPYDATAQUERYW = 2; 102 | constexpr uintptr_t EVERYTHING_IPC_COPYDATA_QUERY2A = 17; 103 | constexpr uintptr_t EVERYTHING_IPC_COPYDATA_QUERY2W = 18; 104 | auto common_process = [hwnd, uMsg, wParam](uintptr_t command, uint8_t* query, size_t query_size, std::wstring_view search) { 105 | std::unique_ptr processed_search{ edit_process_content(std::wstring(search)) }; 106 | 107 | size_t size = query_size + processed_search->size() * sizeof(wchar_t) + sizeof L'\0'; 108 | auto buf = std::make_unique(size); 109 | std::copy_n(query, query_size, buf.get()); 110 | processed_search->copy((wchar_t*)(buf.get() + query_size), processed_search->size() + 1); 111 | 112 | COPYDATASTRUCT processed_copydata{ 113 | command, 114 | size, 115 | (PVOID)buf.get() 116 | }; 117 | 118 | return CallWindowProcW(ipc_window_proc_prev, hwnd, uMsg, wParam, (LPARAM)&processed_copydata); 119 | }; 120 | COPYDATASTRUCT* copydata = ib::Addr(lParam); 121 | switch (copydata->dwData) { 122 | case EVERYTHING_IPC_COPYDATA_QUERY2W: 123 | { 124 | EVERYTHING_IPC_QUERY2 *query = ib::Addr(copydata->lpData); 125 | if (query->search_flags & Search::Regex) 126 | break; 127 | 128 | std::wstring_view search{ query->search_string, (copydata->cbData - query->query_size()) / sizeof(wchar_t) - 1 }; 129 | return common_process(copydata->dwData, (uint8_t*)query, query->query_size(), search); 130 | } 131 | break; 132 | case EVERYTHING_IPC_COPYDATA_QUERY2A: 133 | { 134 | EVERYTHING_IPC_QUERY2 *query = ib::Addr(copydata->lpData); 135 | if (query->search_flags & Search::Regex) 136 | break; 137 | 138 | size_t search_len = copydata->cbData - query->query_size() - sizeof(char); 139 | auto search_buf = std::make_unique(search_len); 140 | 141 | std::wstring_view search{ search_buf.get(), (size_t)MultiByteToWideChar(CP_ACP, 0, query->search_string, search_len, search_buf.get(), search_len) }; 142 | return common_process(EVERYTHING_IPC_COPYDATA_QUERY2W, (uint8_t*)query, query->query_size(), search); 143 | } 144 | break; 145 | case EVERYTHING_IPC_COPYDATAQUERYW: 146 | { 147 | EVERYTHING_IPC_QUERY *query = ib::Addr(copydata->lpData); 148 | if (query->search_flags & Search::Regex) 149 | break; 150 | 151 | std::wstring_view search{ query->search_string, (copydata->cbData - query->query_size()) / sizeof(wchar_t) - 1 }; 152 | return common_process(copydata->dwData, (uint8_t*)query, query->query_size(), search); 153 | } 154 | break; 155 | case EVERYTHING_IPC_COPYDATAQUERYA: 156 | { 157 | EVERYTHING_IPC_QUERY *query = ib::Addr(copydata->lpData); 158 | if (query->search_flags & Search::Regex) 159 | break; 160 | 161 | size_t search_len = copydata->cbData - query->query_size() - sizeof(char); 162 | auto search_buf = std::make_unique(search_len); 163 | 164 | std::wstring_view search{ search_buf.get(), (size_t)MultiByteToWideChar(CP_ACP, 0, query->search_string, search_len, search_buf.get(), search_len) }; 165 | return common_process(EVERYTHING_IPC_COPYDATAQUERYW, (uint8_t*)query, query->query_size(), search); 166 | } 167 | break; 168 | default: 169 | if constexpr (debug) 170 | DebugOStream() << L"command: " << copydata->dwData << L'\n'; 171 | } 172 | } 173 | break; 174 | } 175 | return CallWindowProcW(ipc_window_proc_prev, hwnd, uMsg, wParam, lParam); 176 | } 177 | 178 | void ipc_window_init(HWND ipc_window) { 179 | ipc_window_proc_prev = (WNDPROC)SetWindowLongPtrW(ipc_window, GWLP_WNDPROC, (LONG_PTR)ipc_window_proc); 180 | } 181 | 182 | void ipc_window_destroy() {} -------------------------------------------------------------------------------- /EverythingExt/ipc_window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hpp" 3 | 4 | void ipc_window_init(HWND ipc_window); 5 | void ipc_window_destroy(); -------------------------------------------------------------------------------- /EverythingExt/match.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "match.hpp" 3 | 4 | #ifndef NDEBUG 5 | #pragma optimize("gt", on) 6 | #endif 7 | 8 | char32_t read_char32(const char8_t* str, int* length) { 9 | char c = str[0]; 10 | switch (*length = 1 + ((c & 0b11000000) == 0b11000000) + ((c & 0b11100000) == 0b11100000) + ((c & 0b11110000) == 0b11110000)) { 11 | case 1: return c; 12 | case 2: return (c & 0b11111) << 6 | (str[1] & 0b111111); 13 | case 3: return (c & 0b1111) << 12 | (str[1] & 0b111111) << 6 | (str[2] & 0b111111); 14 | case 4: return (c & 0b111) << 18 | (str[1] & 0b111111) << 12 | (str[2] & 0b111111) << 6 | (str[3] & 0b111111); 15 | } 16 | } 17 | 18 | Pattern* compile(const char8_t* pattern, CompileFlag flags, std::vector* pinyin_flags) { 19 | // get length 20 | size_t length = 0; 21 | size_t length_u8 = 0; 22 | { 23 | const char8_t* p = pattern; 24 | int char_len; 25 | for (char32_t c = read_char32(p, &char_len); c; c = read_char32(p += char_len, &char_len)) { 26 | length++; 27 | length_u8 += char_len; 28 | } 29 | } 30 | 31 | // parse parse post-modifiers 32 | PatternFlag temp_flags{ 33 | .match_at_start = flags.match_at_start, 34 | .match_at_end = flags.match_at_end 35 | }; 36 | { 37 | // parse post-modifiers 38 | std::u8string_view pat(pattern, length_u8); 39 | if (pat.ends_with(u8";py")) { 40 | temp_flags.pinyin = true; 41 | length -= 3; 42 | length_u8 -= 3; 43 | } 44 | } 45 | 46 | // make Pattern 47 | std::u8string pattern_u8_upper(length_u8, u8'\0'); 48 | std::transform(pattern, pattern + length_u8, pattern_u8_upper.begin(), [](char8_t c) { 49 | return ib::toupper(c); 50 | }); 51 | 52 | #ifdef SEARCH_BOOST_XPRESSIVE 53 | boost::xpressive::regex_traits traits; 54 | #endif 55 | Pattern* pat = new Pattern{ 56 | .flags = temp_flags, 57 | .pinyin_flags = pinyin_flags, 58 | .pattern = std::u32string(length, U'\0'), 59 | .pattern_u8_upper = pattern_u8_upper, 60 | .pattern_u8_len = length_u8, 61 | #ifdef SEARCH_STD_SEARCHER 62 | .searcher{ ((std::u8string_view)pattern_u8_upper).begin(), ((std::u8string_view)pattern_u8_upper).end() } 63 | #endif 64 | #ifdef SEARCH_BOOST_XPRESSIVE 65 | .traits = traits, 66 | .searcher{ pattern, pattern + length_u8, traits, true } 67 | #endif 68 | }; 69 | 70 | const char8_t* p = pattern; 71 | int char_len; 72 | for (size_t i = 0; i < length; i++) { 73 | char32_t c = read_char32(p, &char_len); 74 | pat->pattern[i] = c; 75 | p += char_len; 76 | } 77 | 78 | // flags 79 | pat->flags.no_lower_letter = std::find_if(pat->pattern.begin(), pat->pattern.end(), [](char32_t c) { 80 | return U'a' <= c && c <= U'z'; 81 | }) == pat->pattern.end(); 82 | 83 | // match at the start if pattern is an absolute path 84 | if (!pat->flags.match_at_start && pattern_u8_upper[1] == u8':' && u8'A' <= pattern_u8_upper[0] && pattern_u8_upper[0] <= u8'Z') { 85 | pat->flags.match_at_start = true; 86 | } 87 | 88 | return pat; 89 | } 90 | 91 | int exec(Pattern* pattern, const char8_t* subject, int length, size_t nmatch, int pmatch[], ExecuteFlag exec_flags) 92 | { 93 | PatternFlag flags = pattern->flags; 94 | if (flags.match_at_start && exec_flags.not_begin_of_line) 95 | return -1; 96 | 97 | const char8_t* subject_end = subject + length; 98 | 99 | // no-hanzi text match 100 | bool no_hanzi = flags.no_lower_letter; 101 | if (!no_hanzi) [[likely]] { 102 | no_hanzi = true; 103 | 104 | /* 105 | const char8_t* s = subject; 106 | int char_len; 107 | for (char32_t c = read_char32(s, &char_len); s != subject_end; c = read_char32(s += char_len, &char_len)) { 108 | if (c >= 0x3007) [[unlikely]] { 109 | no_hanzi = false; 110 | break; 111 | } 112 | } 113 | */ 114 | 115 | // 6.9% 116 | for (const char8_t* s = subject; s != subject_end; s++) { 117 | char8_t c = *s; 118 | // U+3007: 1110[0011] 10[000000] 10[000111] 119 | if (c >= 0b1110'0011) [[unlikely]] { 120 | no_hanzi = false; 121 | break; 122 | } 123 | } 124 | 125 | // 8.1% 126 | /* 127 | if (std::find_if(subject, subject_end, [](char8_t c) { return c >= 0b1110'0011; }) != subject_end) 128 | no_hanzi = false; 129 | */ 130 | } 131 | if (no_hanzi) { 132 | // main performance influencing code 133 | 134 | // default: a -> [aA嗷] -> [aA], A -> [aA] 135 | // pinyin: a -> [嗷] -> (?!), A -> [aA] 136 | 137 | std::u8string_view sv(subject, length); 138 | std::u8string_view pt = pattern->pattern_u8_upper; 139 | if (sv.size() < pt.size()) 140 | return -1; 141 | 142 | std::u8string_view::const_iterator begin = sv.begin(), end = sv.end(); 143 | if (flags.match_at_start && flags.match_at_end) [[unlikely]] { 144 | if (sv.size() != pt.size()) 145 | return -1; 146 | } 147 | else { 148 | if (flags.match_at_end) [[unlikely]] { 149 | begin = sv.end() - pt.size(); 150 | } 151 | if (flags.match_at_start) [[unlikely]] { 152 | end = sv.begin() + pt.size(); 153 | } 154 | } 155 | 156 | /* 157 | std::search: 57% 158 | // std::boyer_moore_searcher 159 | // std::boyer_moore_horspool_searcher 160 | boost::algorithm::ifind_first: unbelievably slow 161 | boost::xpressive::detail::boyer_moore: 58% 162 | */ 163 | #ifdef SEARCH_STD 164 | std::function pred; 165 | std::u8string_view::const_iterator it; 166 | if (!flags.pinyin) /* default */ [[likely]] { 167 | pred = [](char8_t c1, char8_t c2) { 168 | return ib::toupper(c1) == c2; // don't use std::toupper, it's slow 169 | }; 170 | } 171 | else /* pinyin */ { 172 | if (!flags.no_lower_letter) [[likely]] 173 | return -1; 174 | else /* pattern is all-caps */ 175 | ; 176 | 177 | pred = [](char8_t c1, char8_t c2) { 178 | return ib::toupper(c1) == c2; // don't use std::toupper, it's slow 179 | }; 180 | } 181 | it = std::search(begin, end, pt.begin(), pt.end(), pred); 182 | #endif 183 | #ifdef SEARCH_STD_SEARCHER 184 | auto it = std::search(begin, end, pattern->searcher); 185 | #endif 186 | #ifdef SEARCH_BOOST_ALGORITHM 187 | auto input = boost::make_iterator_range(begin, end); 188 | auto match = boost::algorithm::ifind_first(input, pattern->pattern_u8_upper); 189 | auto it = match.begin(); 190 | #endif 191 | #ifdef SEARCH_BOOST_XPRESSIVE 192 | auto it = pattern->searcher.find(begin, end, pattern->traits); 193 | #endif 194 | 195 | if (it == end) [[likely]] { 196 | return -1; 197 | } else { 198 | if (nmatch) { 199 | pmatch[0] = it - sv.begin(); 200 | pmatch[1] = it - sv.begin() + pt.size(); 201 | return 1; 202 | } else { 203 | return 0; 204 | } 205 | } 206 | } 207 | 208 | // DFA? 209 | auto char_match = [pattern, flags](char32_t c, const char32_t* pat) -> std::vector { 210 | std::vector v; 211 | if (flags.pinyin) { 212 | if (c >= 0x3007) { 213 | for (pinyin::PinyinFlagValue flag : *pattern->pinyin_flags) { 214 | if (size_t size = pinyin::match_pinyin(c, pat, flag)) [[unlikely]] 215 | v.push_back(size); 216 | } 217 | } 218 | } 219 | else [[likely]] { 220 | if (c == *pat) 221 | v.push_back(1); 222 | else { 223 | if (c < 0x3007) { 224 | /* 225 | if (U'A' <= c && c <= U'Z') { 226 | if (*pat == c - U'A' + U'a') 227 | v.push_back(1); 228 | } 229 | else if (U'a' <= c && c <= U'z') { 230 | if (*pat == c - U'a' + U'A') 231 | v.push_back(1); 232 | } 233 | */ 234 | if (c <= U'z' && ib::toupper(*pat) == ib::toupper(c)) 235 | v.push_back(1); 236 | } 237 | else { 238 | for (pinyin::PinyinFlagValue flag : *pattern->pinyin_flags) { 239 | if (size_t size = pinyin::match_pinyin(c, pat, flag)) [[unlikely]] 240 | v.push_back(size); 241 | } 242 | } 243 | } 244 | } 245 | return v; 246 | }; 247 | std::function subject_match = [&char_match, &subject_match, subject_end](const char8_t* sub, const char32_t* pattern) -> const char8_t* { 248 | if (!*pattern) 249 | return sub; 250 | 251 | if (sub == subject_end) 252 | return nullptr; 253 | int char_len; 254 | char32_t c = read_char32(sub, &char_len); 255 | 256 | std::vector v = char_match(c, pattern); 257 | for (size_t size : v) { 258 | if (const char8_t* s = subject_match(sub + char_len, pattern + size)) 259 | return s; 260 | } 261 | return nullptr; 262 | }; 263 | 264 | // global match 265 | const char8_t* sub = subject; 266 | int char_len; 267 | while (sub != subject_end) { 268 | if (const char8_t* s = subject_match(sub, pattern->pattern.c_str())) { 269 | if (flags.match_at_end && s != subject_end) 270 | goto next; 271 | 272 | if (nmatch) { 273 | pmatch[0] = sub - subject; 274 | pmatch[1] = s - subject; 275 | return 1; 276 | } else { 277 | return 0; 278 | } 279 | /* 280 | sub = s; 281 | continue; 282 | */ 283 | } 284 | next: 285 | if (flags.match_at_start) [[unlikely]] 286 | break; 287 | 288 | read_char32(sub, &char_len); 289 | sub += char_len; 290 | } 291 | 292 | return -1; 293 | } 294 | 295 | // because match.cpp is included by test/match.cpp, we need to reset the optimizations 296 | #ifndef NDEBUG 297 | #pragma optimize("", on) 298 | #endif -------------------------------------------------------------------------------- /EverythingExt/match.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "helper.hpp" 3 | #include 4 | #include 5 | #include 6 | #define IB_PINYIN_ENCODING 32 7 | #include 8 | 9 | /* 10 | SEARCH_STD 11 | // SEARCH_STD_SEARCHER 12 | SEARCH_BOOST_ALGORITHM 13 | SEARCH_BOOST_XPRESSIVE 14 | */ 15 | #define SEARCH_STD 16 | 17 | #ifdef SEARCH_BOOST_ALGORITHM 18 | #include 19 | #endif 20 | #ifdef SEARCH_BOOST_XPRESSIVE 21 | #include 22 | #endif 23 | 24 | struct CompileFlag { 25 | bool match_at_start : 1; 26 | bool match_at_end : 1; 27 | }; 28 | 29 | struct PatternFlag { 30 | bool pinyin : 1; 31 | 32 | // note that regcomp_p2 will filter out content containing no lower letter 33 | // completely 34 | bool no_lower_letter : 1; 35 | 36 | bool match_at_start : 1; 37 | bool match_at_end : 1; 38 | }; 39 | 40 | struct ExecuteFlag { 41 | bool not_begin_of_line : 1; 42 | }; 43 | 44 | struct Pattern { 45 | PatternFlag flags; 46 | std::vector* pinyin_flags; 47 | std::u32string pattern; 48 | std::u8string pattern_u8_upper; 49 | size_t pattern_u8_len; 50 | #ifdef SEARCH_STD_SEARCHER 51 | std::boyer_moore_horspool_searcher()(ib::toupper(c)); }), 53 | decltype([](char8_t c1, char8_t c2) { 54 | //DebugOStream() << wchar_t(c1) << L' ' << wchar_t(c2) << L'\n'; 55 | // c2 is not guaranteed to be from pattern? 56 | return ib::toupper(c1) == ib::toupper(c2); // don't use std::toupper, it's slow 57 | }) 58 | > searcher; 59 | #endif 60 | #ifdef SEARCH_BOOST_XPRESSIVE 61 | boost::xpressive::regex_traits traits; 62 | boost::xpressive::detail::boyer_moore> searcher; 63 | #endif 64 | }; 65 | 66 | Pattern* compile(const char8_t* pattern, CompileFlag flags, std::vector* pinyin_flags); 67 | 68 | int exec(Pattern* pattern, const char8_t* subject, int length, size_t nmatch, int pmatch[], ExecuteFlag flags); -------------------------------------------------------------------------------- /EverythingExt/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: source file corresponding to the pre-compiled header 2 | 3 | #include "pch.h" 4 | 5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed. 6 | -------------------------------------------------------------------------------- /EverythingExt/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: This is a precompiled header file. 2 | // Files listed below are compiled only once, improving build performance for future builds. 3 | // This also affects IntelliSense performance, including code completion and many code browsing features. 4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds. 5 | // Do not add files here that you will be updating frequently as this negates the performance advantage. 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // add headers that you want to pre-compile here 11 | #include "framework.h" 12 | 13 | #endif //PCH_H 14 | -------------------------------------------------------------------------------- /EverythingExt/pinyin.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "common.hpp" 3 | #include "pinyin.hpp" 4 | #include 5 | #include 6 | #include "helper.hpp" 7 | #include "ipc.hpp" 8 | 9 | std::wstring pinyin_regexs[26]{}; 10 | std::pair pinyin_pair_regexs[26][26]{}; 11 | std::set pinyin_merged_set; 12 | 13 | bool Utf16Pair::in(std::wstring_view sv) const { 14 | if (!h) { 15 | return sv.find(l) != sv.npos; 16 | } else { 17 | size_t pos = sv.find(l); 18 | while (pos != sv.npos && pos != sv.size() - 1) { 19 | if (sv[pos + 1] == h) 20 | return true; 21 | pos = sv.find(l, pos + 1); 22 | } 23 | return false; 24 | } 25 | } 26 | 27 | struct Utf16PairOrd : Utf16Pair { 28 | char32_t ord; 29 | 30 | Utf16PairOrd() : Utf16Pair(), ord(0) {} 31 | Utf16PairOrd(wchar_t l) : Utf16Pair(l), ord(l) {} 32 | Utf16PairOrd(wchar_t l, wchar_t h) : Utf16Pair(l, h), ord(to_ord(l, h)) {} 33 | 34 | protected: 35 | static char32_t to_ord(wchar_t l, wchar_t h) { 36 | return 0x10000 + ((l - 0xD800) << 10) + (h - 0xDC00); 37 | } 38 | }; 39 | 40 | void pinyin_query_and_merge() { 41 | using namespace Everythings; 42 | using namespace std::literals; 43 | 44 | static DWORD last_query = 0; 45 | 46 | static std::mutex mutex; // be careful 47 | if (!mutex.try_lock()) 48 | return; 49 | 50 | // query 51 | std::wstring query; 52 | if (!last_query) { 53 | query = L"regex:[〇-𰻞]"; 54 | ipc_ev->database_loaded_future().get(); 55 | last_query = GetTickCount() / 1000; 56 | } else { 57 | DWORD time = GetTickCount() / 1000; 58 | query = L"rc:last" + std::to_wstring(time - last_query + 1) + L"secs regex:[〇-𰻞]"; 59 | last_query = time; 60 | } 61 | QueryResults results = ipc_ev->query_send(query, Search::MatchCase, Request::FileName).get(); 62 | 63 | // merge functions 64 | //"拼" 65 | auto merge = [](Utf16PairOrd pair) -> uint32_t { 66 | uint32_t flags = pinyin::get_initial_pinyin_letters(pair.ord); 67 | if (!flags) 68 | return 0; 69 | 70 | if (!pinyin_merged_set.contains(pair.ord)) { 71 | pinyin_merged_set.insert(pair.ord); 72 | 73 | for (int i = 0; i < 26; i++) { 74 | if (flags & 1 << i) { 75 | pinyin_regexs[i].push_back(pair.l); 76 | if (pair.h) pinyin_regexs[i].push_back(pair.h); 77 | } 78 | } 79 | } 80 | 81 | return flags; 82 | }; 83 | //"拼音" 84 | auto merge_pair = [&merge](Utf16PairOrd pair1, Utf16PairOrd pair2, uint32_t py1) -> uint32_t { 85 | uint32_t py2 = merge(pair2); 86 | if (!py1 || !py2) 87 | return py2; 88 | for (int i = 0; i < 26; i++) { 89 | if (py1 & 1 << i) { 90 | for (int j = 0; j < 26; j++) { 91 | if (py2 & 1 << j) { 92 | auto& [first, second] = pinyin_pair_regexs[i][j]; 93 | 94 | if (!pair1.in(first)) { 95 | first.push_back(pair1.l); 96 | if (pair1.h) first.push_back(pair1.h); 97 | } 98 | 99 | if (!pair2.in(second)) { 100 | second.push_back(pair2.l); 101 | if (pair2.h) second.push_back(pair2.h); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | return py2; 108 | }; 109 | // "p音" 110 | auto merge_letter_hanzi = [&merge](wchar_t letter, Utf16PairOrd hanzi) -> uint32_t { 111 | uint32_t py = merge(hanzi); 112 | if (!py) 113 | return py; 114 | 115 | uint32_t i = letter - 'a'; 116 | for (int j = 0; j < 26; j++) { 117 | if (py & 1 << j) { 118 | std::wstring& second = pinyin_pair_regexs[i][j].second; 119 | if (!hanzi.in(second)) { 120 | second.push_back(hanzi.l); 121 | if (hanzi.h) second.push_back(hanzi.h); 122 | } 123 | } 124 | } 125 | return py; 126 | }; 127 | // "拼y" 128 | auto merge_hanzi_letter = [](Utf16PairOrd hanzi, wchar_t letter, uint32_t py) -> void { 129 | if (!py) 130 | return; 131 | 132 | uint32_t j = letter - 'a'; 133 | for (int i = 0; i < 26; i++) { 134 | if (py & 1 << i) { 135 | std::wstring& first = pinyin_pair_regexs[i][j].first; 136 | if (!hanzi.in(first)) { 137 | first.push_back(hanzi.l); 138 | if (hanzi.h) first.push_back(hanzi.h); 139 | } 140 | } 141 | } 142 | }; 143 | 144 | // merge chars in results 145 | for (DWORD j = 0; j < results.available_num; j++) { 146 | std::wstring_view filename = results[j].get_str(Request::FileName); 147 | 148 | Utf16PairOrd last_hanzi{}; 149 | uint32_t last_py = 0; 150 | wchar_t last_letter = L'\0'; 151 | uint32_t i = 0; 152 | while (i < filename.size()) { 153 | wchar_t c = filename[i++]; 154 | if (c < 0x3007) { 155 | last_letter = L'\0'; 156 | if (c <= L'z') { 157 | if (c <= L'Z') 158 | c += L'a' - L'A'; 159 | if (L'a' <= c) { // [a-z] 160 | if (last_hanzi.l) { 161 | merge_hanzi_letter(last_hanzi, c, last_py); 162 | last_hanzi = {}; 163 | } 164 | last_letter = c; 165 | } 166 | } 167 | } else { 168 | Utf16PairOrd cur; 169 | if (0xD800 <= c && c <= 0xDBFF) { 170 | if (i < filename.size()) 171 | cur = { c, filename[i++] }; 172 | else 173 | break; 174 | } else { 175 | cur = { c }; 176 | } 177 | 178 | if (last_letter) { 179 | last_py = merge_letter_hanzi(last_letter, cur); 180 | last_letter = L'\0'; 181 | } else if (last_hanzi.l) 182 | last_py = merge_pair(last_hanzi, cur, last_py); 183 | else 184 | last_py = merge(cur); 185 | 186 | last_hanzi = cur; 187 | } 188 | } 189 | } 190 | 191 | mutex.unlock(); 192 | 193 | if constexpr (debug) { 194 | for (uint32_t i = 0; i < std::size(pinyin_regexs); i++) 195 | DebugOStream() << static_cast(L'a' + i) << L": " << pinyin_regexs[i] << L"\n"; 196 | /* 197 | // may be very long 198 | for (uint32_t i = 0; i < std::size(pinyin_regexs); i++) { 199 | ib::DebugOStream dout = DebugOStream(); 200 | for (uint32_t j = 0; j < std::size(pinyin_regexs); j++) 201 | dout << static_cast(L'a' + i) << static_cast(L'a' + j) << L": " 202 | << pinyin_pair_regexs[i][j].first << L' ' << pinyin_pair_regexs[i][j].second << L", "; 203 | dout << L'\n'; 204 | } 205 | */ 206 | } 207 | } -------------------------------------------------------------------------------- /EverythingExt/pinyin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #define IB_PINYIN_ENCODING 32 6 | #include 7 | 8 | extern std::wstring pinyin_regexs[26]; 9 | extern std::pair pinyin_pair_regexs[26][26]; 10 | 11 | struct Utf16Pair { 12 | wchar_t l; 13 | wchar_t h; 14 | 15 | Utf16Pair() : l(0), h(0) {} 16 | Utf16Pair(wchar_t l) : l(l), h(0) {} 17 | Utf16Pair(wchar_t l, wchar_t h) : l(l), h(h) {} 18 | 19 | bool in(std::wstring_view sv) const; 20 | }; 21 | 22 | // require ipc_init 23 | void pinyin_query_and_merge(); -------------------------------------------------------------------------------- /EverythingExt/quick_select.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hpp" 3 | 4 | namespace quick { 5 | enum InputMode { 6 | Auto, 7 | WmKey, 8 | SendInput 9 | }; 10 | 11 | // require ipc_init 12 | void init(); 13 | void destroy(); 14 | 15 | HWND create_quick_list(HWND everything, HWND list, HWND edit, HINSTANCE instance); 16 | LRESULT CALLBACK list_window_proc( 17 | WNDPROC prev_proc, 18 | _In_ HWND hwnd, 19 | _In_ UINT uMsg, 20 | _In_ WPARAM wParam, 21 | _In_ LPARAM lParam); 22 | } -------------------------------------------------------------------------------- /EverythingExt/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by resource.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /EverythingExt/resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/EverythingExt/resource.rc -------------------------------------------------------------------------------- /EverythingExt/search_history.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "common.hpp" 3 | #include "search_history.hpp" 4 | #include 5 | #include 6 | #include "helper.hpp" 7 | 8 | extern std::unordered_map content_map; 9 | 10 | static HANDLE search_history_handle = nullptr; 11 | static std::string search_history_to_write{}; 12 | 13 | auto WriteFile_real = WriteFile; 14 | BOOL WINAPI WriteFile_detour( 15 | _In_ HANDLE hFile, 16 | _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, 17 | _In_ DWORD nNumberOfBytesToWrite, 18 | _Out_opt_ LPDWORD lpNumberOfBytesWritten, 19 | _Inout_opt_ LPOVERLAPPED lpOverlapped 20 | ) { 21 | // UTF-8 22 | // the max size is 0x10000 23 | 24 | using namespace std::literals; 25 | 26 | do { 27 | std::string_view sv(static_cast(lpBuffer), nNumberOfBytesToWrite); 28 | if (!search_history_handle) { 29 | if (!sv.starts_with("Search,Search Count,Last Search Date\r\n"sv)) 30 | break; 31 | search_history_handle = hFile; 32 | } else if (hFile != search_history_handle) 33 | break; 34 | 35 | search_history_to_write += sv; 36 | 37 | *lpNumberOfBytesWritten = nNumberOfBytesToWrite; // required 38 | return true; // be careful 39 | } while (false); 40 | 41 | return WriteFile_real(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); 42 | } 43 | 44 | auto MoveFileExW_real = MoveFileExW; 45 | BOOL WINAPI MoveFileExW_detour( 46 | _In_ LPCWSTR lpExistingFileName, 47 | _In_opt_ LPCWSTR lpNewFileName, 48 | _In_ DWORD dwFlags 49 | ) { 50 | using namespace std::literals; 51 | 52 | if (search_history_handle) { 53 | if (std::wstring_view existing_file(lpExistingFileName); 54 | existing_file.ends_with(L".csv.tmp"sv) && existing_file.find(L"\\Search History") != existing_file.npos) 55 | { 56 | search_history_handle = nullptr; 57 | 58 | /* 59 | Search,Search Count,Last Search Date 60 | "a",4,132767094406609228 61 | "case:regex:""[aA][bB][cC]""[dD单到的]",2,132767108299260960 62 | */ 63 | auto& history = search_history_to_write; 64 | 65 | std::ostringstream out(std::ios_base::binary); // may be longer than buffer (such as "a" -> "nopy:a") 66 | out << "Search,Search Count,Last Search Date\r\n"sv; 67 | 68 | std::unordered_map search_map{}; 69 | uint32_t i = "Search,Search Count,Last Search Date\r\n"sv.size(); 70 | while (i < history.size()) { 71 | if (history[i++] != '"') 72 | break; 73 | out << '"'; 74 | 75 | // parse Search and convert processed content to raw content 76 | std::string search; 77 | while (i < history.size()) { 78 | char c = history[i++]; 79 | if (c == '"') { 80 | if (i < history.size() && history[i] == '"') { // "" 81 | search.push_back('"'); 82 | i++; 83 | } else 84 | break; 85 | } else 86 | search.push_back(c); 87 | } 88 | { 89 | // search to search_u16 90 | // std::wstring_convert is deprecated in C++ 17 91 | std::wstring search_u16(search.size(), L'\0'); 92 | search_u16.resize(MultiByteToWideChar(CP_UTF8, 0, search.data(), search.size(), search_u16.data(), search_u16.size())); 93 | 94 | // processed content -> content 95 | auto iter = content_map.find(search_u16); 96 | if (iter != content_map.end()) { 97 | // content to content_u8 98 | std::string content_u8(iter->second.size() * 3, '\0'); 99 | int length = WideCharToMultiByte(CP_UTF8, 0, iter->second.data(), iter->second.size(), content_u8.data(), content_u8.size(), nullptr, nullptr); 100 | if (!length) { 101 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 102 | break; 103 | content_u8.resize(iter->second.size() * 4); 104 | length = WideCharToMultiByte(CP_UTF8, 0, iter->second.data(), iter->second.size(), content_u8.data(), content_u8.size(), nullptr, nullptr); 105 | } 106 | content_u8.resize(length); 107 | 108 | search = content_u8; 109 | } 110 | } 111 | for (char c : search) { 112 | if (c == '"') 113 | out << '"'; 114 | out << c; 115 | } 116 | out << '"' << ','; 117 | i++; // ',' 118 | 119 | // parse Search Count and do sums 120 | uint32_t j = i; 121 | while (j < history.size()) { 122 | if (history[j++] == ',') 123 | break; 124 | } 125 | j--; 126 | uint32_t count = std::atoi(&history[i]); // (i, j - i) 127 | auto iter = search_map.find(search); 128 | if (iter == search_map.end()) { 129 | search_map[search] = count; 130 | } else { 131 | count += iter->second; 132 | search_map.erase(iter); 133 | out << count; 134 | i = j; 135 | } 136 | 137 | // the remaining 138 | while (i < history.size()) { 139 | char c = history[i++]; 140 | out << c; 141 | if (c == '\n') 142 | break; 143 | } 144 | } 145 | history.clear(); 146 | 147 | HANDLE file = CreateFileW(lpExistingFileName, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, 0, nullptr); 148 | if (!file) 149 | return false; 150 | 151 | const std::string& out_str = out.str(); 152 | DWORD written; 153 | bool result = WriteFile_real(file, out_str.data(), out_str.size(), &written, nullptr); 154 | 155 | CloseHandle(file); 156 | if (!result) 157 | return false; 158 | } 159 | } 160 | return MoveFileExW_real(lpExistingFileName, lpNewFileName, dwFlags); 161 | } 162 | 163 | auto TextOutW_real = TextOutW; 164 | BOOL WINAPI TextOutW_detour(_In_ HDC hdc, _In_ int x, _In_ int y, _In_reads_(c) LPCWSTR lpString, _In_ int c) { 165 | // TextOutW will only be called from: 166 | // DropdownList 167 | // WindowFromDC() == NULL 168 | // Options: Fonts and Colors 169 | // WindowFromDC() != NULL 170 | 171 | /* 172 | using namespace std::literals; 173 | 174 | static HDC last_hdc = 0; 175 | static bool is_dropdown_list = false; 176 | if (hdc != last_hdc) { // there may be a collision? 177 | last_hdc = hdc; 178 | is_dropdown_list = false; 179 | 180 | HWND hwnd = WindowFromDC(hdc); 181 | wchar_t buf[std::size(L"EVERYTHING_DROPDOWNLIST")]; 182 | if (int len = GetClassNameW(hwnd, buf, std::size(buf))) { 183 | if (std::wstring_view(buf, len) == L"EVERYTHING_DROPDOWNLIST"sv) { 184 | is_dropdown_list = true; 185 | } 186 | } 187 | } 188 | if (is_dropdown_list) { 189 | } 190 | */ 191 | 192 | if (!WindowFromDC(hdc)) { 193 | std::wstring_view sv(lpString, c); 194 | if (c == 4096) { // max length 195 | sv = std::wstring_view(lpString); // #TODO: is it always zero-terminated? 196 | } 197 | 198 | auto iter = content_map.find(std::wstring(sv)); // #TODO: directly use sv 199 | if (iter != content_map.end()) { 200 | return TextOutW_real(hdc, x, y, iter->second.c_str(), iter->second.size()); 201 | } 202 | } 203 | return TextOutW_real(hdc, x, y, lpString, c); 204 | } 205 | 206 | void search_history_init() { 207 | // #TODO: transaction 208 | IbDetourAttach(&WriteFile_real, WriteFile_detour); 209 | IbDetourAttach(&MoveFileExW_real, MoveFileExW_detour); 210 | IbDetourAttach(&TextOutW_real, TextOutW_detour); 211 | } 212 | 213 | void search_history_destroy() { 214 | IbDetourDetach(&TextOutW_real, TextOutW_detour); 215 | IbDetourDetach(&MoveFileExW_real, MoveFileExW_detour); 216 | IbDetourDetach(&WriteFile_real, WriteFile_detour); 217 | } -------------------------------------------------------------------------------- /EverythingExt/search_history.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void search_history_init(); 4 | void search_history_destroy(); -------------------------------------------------------------------------------- /EverythingExt/toupper_gen.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | table = [i for i in range(256)] 4 | 5 | for letter in string.ascii_lowercase: 6 | table[ord(letter)] = ord(letter.upper()) 7 | 8 | code = '' 9 | for i in range(0, 256, 16): 10 | code += ', '.join(hex(table[j]) for j in range(i, i+16)) + ',\n' 11 | 12 | print(code) -------------------------------------------------------------------------------- /IbEverythingExt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32319.34 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EverythingExt", "EverythingExt\EverythingExt.vcxproj", "{102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{80718343-F2B4-4358-8D44-321CBE687F92}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IbWinCpp", "external\build\_deps\ibwincpp-build\IbWinCpp.vcxproj", "{81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IbEverything", "external\build\_deps\ibeverything-build\IbEverything.vcxproj", "{1DBB8594-6BAF-34C0-9998-6AA359588998}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IbPinyin", "external\build\_deps\ibpinyin-build\IbPinyin.vcxproj", "{169D9787-0F47-3EE4-9056-C52DFC6E922A}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IbUpdate", "external\build\_deps\ibupdate-build\C++\IbUpdate.vcxproj", "{90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}" 17 | EndProject 18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Updater\Updater.vcxproj", "{F1492EF6-27C2-44CD-A34B-E55F45DA5222}" 19 | EndProject 20 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "github_api", "external\build\_deps\github_api-build\github_api.vcxproj", "{9A48DEA3-C71B-30FC-AC03-8929973872CE}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|x64 = Debug|x64 25 | Debug|x86 = Debug|x86 26 | MinSizeRel|x64 = MinSizeRel|x64 27 | MinSizeRel|x86 = MinSizeRel|x86 28 | Release|x64 = Release|x64 29 | Release|x86 = Release|x86 30 | RelWithDebInfo|x64 = RelWithDebInfo|x64 31 | RelWithDebInfo|x86 = RelWithDebInfo|x86 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Debug|x64.ActiveCfg = Debug|x64 35 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Debug|x64.Build.0 = Debug|x64 36 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Debug|x86.ActiveCfg = Debug|Win32 37 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Debug|x86.Build.0 = Debug|Win32 38 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.MinSizeRel|x64.ActiveCfg = Release|x64 39 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.MinSizeRel|x64.Build.0 = Release|x64 40 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.MinSizeRel|x86.ActiveCfg = Release|Win32 41 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.MinSizeRel|x86.Build.0 = Release|Win32 42 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Release|x64.ActiveCfg = Release|x64 43 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Release|x64.Build.0 = Release|x64 44 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Release|x86.ActiveCfg = Release|Win32 45 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.Release|x86.Build.0 = Release|Win32 46 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.RelWithDebInfo|x64.ActiveCfg = Release|x64 47 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.RelWithDebInfo|x64.Build.0 = Release|x64 48 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 49 | {102EEFA7-F37C-4FA7-AC25-D4DDC2E797E7}.RelWithDebInfo|x86.Build.0 = Release|Win32 50 | {80718343-F2B4-4358-8D44-321CBE687F92}.Debug|x64.ActiveCfg = Debug|x64 51 | {80718343-F2B4-4358-8D44-321CBE687F92}.Debug|x64.Build.0 = Debug|x64 52 | {80718343-F2B4-4358-8D44-321CBE687F92}.Debug|x86.ActiveCfg = Debug|Win32 53 | {80718343-F2B4-4358-8D44-321CBE687F92}.Debug|x86.Build.0 = Debug|Win32 54 | {80718343-F2B4-4358-8D44-321CBE687F92}.MinSizeRel|x64.ActiveCfg = Debug|x64 55 | {80718343-F2B4-4358-8D44-321CBE687F92}.MinSizeRel|x64.Build.0 = Debug|x64 56 | {80718343-F2B4-4358-8D44-321CBE687F92}.MinSizeRel|x86.ActiveCfg = Debug|Win32 57 | {80718343-F2B4-4358-8D44-321CBE687F92}.MinSizeRel|x86.Build.0 = Debug|Win32 58 | {80718343-F2B4-4358-8D44-321CBE687F92}.Release|x64.ActiveCfg = Release|x64 59 | {80718343-F2B4-4358-8D44-321CBE687F92}.Release|x64.Build.0 = Release|x64 60 | {80718343-F2B4-4358-8D44-321CBE687F92}.Release|x86.ActiveCfg = Release|Win32 61 | {80718343-F2B4-4358-8D44-321CBE687F92}.Release|x86.Build.0 = Release|Win32 62 | {80718343-F2B4-4358-8D44-321CBE687F92}.RelWithDebInfo|x64.ActiveCfg = Release|x64 63 | {80718343-F2B4-4358-8D44-321CBE687F92}.RelWithDebInfo|x64.Build.0 = Release|x64 64 | {80718343-F2B4-4358-8D44-321CBE687F92}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 65 | {80718343-F2B4-4358-8D44-321CBE687F92}.RelWithDebInfo|x86.Build.0 = Release|Win32 66 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Debug|x64.ActiveCfg = Debug|x64 67 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Debug|x64.Build.0 = Debug|x64 68 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Debug|x86.ActiveCfg = Debug|x64 69 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Debug|x86.Build.0 = Debug|x64 70 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 71 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 72 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 73 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 74 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Release|x64.ActiveCfg = Release|x64 75 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Release|x64.Build.0 = Release|x64 76 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Release|x86.ActiveCfg = Release|x64 77 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.Release|x86.Build.0 = Release|x64 78 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 79 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 80 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 81 | {81A0272A-5EF3-30A8-9154-3A5A8DF9AA70}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 82 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Debug|x64.ActiveCfg = Debug|x64 83 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Debug|x64.Build.0 = Debug|x64 84 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Debug|x86.ActiveCfg = Debug|x64 85 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Debug|x86.Build.0 = Debug|x64 86 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 87 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 88 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 89 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 90 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Release|x64.ActiveCfg = Release|x64 91 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Release|x64.Build.0 = Release|x64 92 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Release|x86.ActiveCfg = Release|x64 93 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.Release|x86.Build.0 = Release|x64 94 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 95 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 96 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 97 | {1DBB8594-6BAF-34C0-9998-6AA359588998}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 98 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Debug|x64.ActiveCfg = Debug|x64 99 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Debug|x64.Build.0 = Debug|x64 100 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Debug|x86.ActiveCfg = Debug|x64 101 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Debug|x86.Build.0 = Debug|x64 102 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 103 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 104 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 105 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 106 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Release|x64.ActiveCfg = Release|x64 107 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Release|x64.Build.0 = Release|x64 108 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Release|x86.ActiveCfg = Release|x64 109 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.Release|x86.Build.0 = Release|x64 110 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 111 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 112 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 113 | {169D9787-0F47-3EE4-9056-C52DFC6E922A}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 114 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Debug|x64.ActiveCfg = Debug|x64 115 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Debug|x64.Build.0 = Debug|x64 116 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Debug|x86.ActiveCfg = Debug|x64 117 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Debug|x86.Build.0 = Debug|x64 118 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 119 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 120 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 121 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 122 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Release|x64.ActiveCfg = Release|x64 123 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Release|x64.Build.0 = Release|x64 124 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Release|x86.ActiveCfg = Release|x64 125 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.Release|x86.Build.0 = Release|x64 126 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 127 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 128 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 129 | {90572FC6-3F72-3CB1-A7E3-14D1FC6BF226}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 130 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Debug|x64.ActiveCfg = Debug|x64 131 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Debug|x64.Build.0 = Debug|x64 132 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Debug|x86.ActiveCfg = Debug|Win32 133 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Debug|x86.Build.0 = Debug|Win32 134 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.MinSizeRel|x64.ActiveCfg = Debug|x64 135 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.MinSizeRel|x64.Build.0 = Debug|x64 136 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.MinSizeRel|x86.ActiveCfg = Debug|Win32 137 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.MinSizeRel|x86.Build.0 = Debug|Win32 138 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Release|x64.ActiveCfg = Release|x64 139 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Release|x64.Build.0 = Release|x64 140 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Release|x86.ActiveCfg = Release|Win32 141 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.Release|x86.Build.0 = Release|Win32 142 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.RelWithDebInfo|x64.ActiveCfg = Release|x64 143 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.RelWithDebInfo|x64.Build.0 = Release|x64 144 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 145 | {F1492EF6-27C2-44CD-A34B-E55F45DA5222}.RelWithDebInfo|x86.Build.0 = Release|Win32 146 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Debug|x64.ActiveCfg = Debug|x64 147 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Debug|x64.Build.0 = Debug|x64 148 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Debug|x86.ActiveCfg = Debug|x64 149 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Debug|x86.Build.0 = Debug|x64 150 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 151 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 152 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 153 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 154 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Release|x64.ActiveCfg = Release|x64 155 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Release|x64.Build.0 = Release|x64 156 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Release|x86.ActiveCfg = Release|x64 157 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.Release|x86.Build.0 = Release|x64 158 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 159 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 160 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 161 | {9A48DEA3-C71B-30FC-AC03-8929973872CE}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 162 | EndGlobalSection 163 | GlobalSection(SolutionProperties) = preSolution 164 | HideSolutionNode = FALSE 165 | EndGlobalSection 166 | GlobalSection(ExtensibilityGlobals) = postSolution 167 | SolutionGuid = {D8EC0771-ED08-4A28-8799-80ABD0EF07C9} 168 | EndGlobalSection 169 | EndGlobal 170 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Chaoses-Ib 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IbEverythingExt 2 | [Everything](https://www.voidtools.com/) 拼音搜索、快速选择扩展。 3 | 4 | ![](docs/preview.png) 5 | 6 | ## 目录 7 | * [安装](#安装) 8 | * [拼音搜索](#拼音搜索) 9 | * [第三方程序支持](#第三方程序支持) 10 | * [配置](#配置) 11 | * [快速选择](#快速选择) 12 | * [热键](#热键) 13 | * [键列表](#键列表) 14 | * [配置](#配置-1) 15 | * [其它](#其它) 16 | * [快速启动器](#快速启动器) 17 | * [硬盘占用分析](#硬盘占用分析) 18 | * [检查更新](#检查更新) 19 | * [→开发](docs/development.md) 20 | * [致谢](#致谢) 21 | * [相关链接](#相关链接) 22 | 23 | ## 安装 24 | 1. 安装 [Everything](https://www.voidtools.com/zh-cn/downloads/) x64 安装版或便携版(不支持其它架构和精简版) 25 | 如果你能接受英文界面,也可以选择安装 [Everything 1.5 预览版](https://www.voidtools.com/forum/viewtopic.php?f=12&t=9787#download)。 26 | 2. 安装 [VC++ 2022 x64 运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe) 27 | ([PowerToys](https://github.com/microsoft/PowerToys) 在安装时会同时安装 VC++ 2022 运行库,如果你安装了 PowerToys 就可以跳过这一步) 28 | 3. 从 [Releases](../../releases) 下载压缩包 29 | 4. 解压压缩包,将文件放入 Everything 安装目录( `C:\Program Files\Everything` ) 30 | 5. 重启 Everything 31 | 32 | ## 拼音搜索 33 | 允许用拼音在 Everything 中搜索文件。 34 | 35 | * 默认小写字母匹配拼音或字母,大写字母只匹配字母。 36 | * 支持简拼、全拼、带声调全拼和双拼搜索,默认只开启简拼和全拼。 37 | 双拼搜索支持以下方案: 38 | * 微软双拼 39 | * 自然码双拼 40 | * 小鹤双拼 41 | * 拼音加加双拼 42 | * 智能 ABC 双拼 43 | * 华宇双拼(紫光双拼) 44 | 45 | 支持多音字和 Unicode 辅助平面汉字。 46 | * 后置修饰符: 47 | * `;py`:小写字母只匹配拼音 48 | * `;np`:禁用拼音搜索 49 | 50 | 51 | 52 | ### [第三方程序支持](docs/third_party/README.md) 53 | 拼音搜索对调用 Everything 进行搜索的第三方程序同样生效,例如: 54 | * [EverythingToolbar](https://github.com/stnkl/EverythingToolbar) 55 | 56 | * [Flow Launcher](https://github.com/Flow-Launcher/Flow.Launcher) 的 [Everything 插件](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.Everything) 57 | 58 | * [PowerToys Run](https://learn.microsoft.com/windows/powertoys/run) 的 [Everything 插件](https://github.com/lin-ycv/EverythingPowerToys) 59 | 60 | * [uTools](https://u.tools) 本地搜索 61 | 62 | * [Wox](https://github.com/Wox-launcher/Wox) 的 Everything 插件 63 | * [火柴(火萤酱)](https://www.huochaipro.com/)本地搜索 64 | 65 | 如果使用的是 Everything 1.5 预览版,因为预览版默认启用了命名实例,大部分程序都不支持调用,需要[通过配置关闭命名实例](https://github.com/Chaoses-Ib/IbEverythingExt/issues/5)。 66 | 67 | ### 配置 68 | `config.yaml` 文件: 69 | ```yaml 70 | # 拼音搜索 71 | pinyin_search: 72 | # true:开启,false:关闭 73 | enable: true 74 | 75 | # 模式 76 | # Pcre:默认模式 77 | # Edit:版本兼容性好,但只支持简拼搜索,性能较低,且存在许多 bug 78 | mode: Pcre 79 | 80 | initial_letter: true # 简拼 81 | pinyin_ascii: true # 全拼 82 | pinyin_ascii_digit: false # 带声调全拼 83 | double_pinyin_abc: false # 智能 ABC 双拼 84 | double_pinyin_jiajia: false # 拼音加加双拼 85 | double_pinyin_microsoft: false # 微软双拼 86 | double_pinyin_thunisoft: false # 华宇双拼(紫光双拼) 87 | double_pinyin_xiaohe: false # 小鹤双拼 88 | double_pinyin_zrm: false # 自然码双拼 89 | ``` 90 | Edit 模式详见 [Edit 模式](docs/pinyin_search/edit_mode.md)。 91 | 92 | ## 快速选择 93 | 在 Everything 结果列表的左侧插入一个显示 0\~9、A\~Z 的键列表,并允许在搜索编辑框和结果列表中通过热键快速打开对应文件。 94 | 95 | ### 热键 96 | 搜索编辑框: 97 | 热键 | 功能 98 | --- | --- 99 | `Alt+0~9` | 打开文件(Enter)并关闭窗口 100 | `Alt+Ctrl+0~9` | 定位文件(Ctrl+Enter)并关闭窗口 101 | `Alt+Shift+0~9` | 打开右键菜单 102 | `Alt+Shift+0~9, R` | 查看文件属性 103 | `Tab` / `Enter` | 转移焦点到结果列表\* 104 | `Esc` / `Ctrl+W` | 关闭窗口\* 105 | 106 | 结果列表: 107 | 热键 | 功能 108 | --- | --- 109 | `[0-9A-Z]` | 选中项目 110 | `Enter` | 打开文件\* 111 | `Ctrl+Enter` | 定位文件\* 112 | `Shift+F10` / `Menu` | 打开右键菜单\* 113 | `Alt+Enter` | 查看文件属性\* 114 | `Esc` / `Ctrl+W` | 关闭窗口\* 115 | `$ (Shift+4)` | 复制文件名,在文件所属目录下启动终端 116 | `# (Shift+3)` | 复制文件名,以管理员身份在文件所属目录下启动终端 117 | 118 | 注: 119 | * 操作之后是否关闭窗口可以通过配置进行控制。 120 | * 标 \* 的热键为 Everything 默认热键,不是扩展增加的,在这里列出是为了完整性。 121 | 122 | ### 键列表 123 | 键列表支持高 DPI,但只在 Everything v1.5a 上支持缩放(热键为 `Ctrl+=` 和 `Ctrl+-`),在 Everything v1.4 上则不支持。 124 | 125 | 支持 Everything v1.5a 深色模式: 126 | ![](docs/quick_select_dark_mode.png) 127 | 128 | ### 配置 129 | `config.yaml` 文件: 130 | ```yaml 131 | # 快速选择 132 | quick_select: 133 | # true:开启,false:关闭 134 | enable: true 135 | 136 | # 搜索编辑框 137 | search_edit: 138 | # Alt 组合键范围 139 | # 0:禁用 140 | # 10:Alt+0~9 141 | # 36:Alt+[0-9A-Z] 142 | # 原本的 Alt+A~Z 访问菜单功能可以通过先单击 Alt 键再按 A~Z 实现 143 | # 默认的 Alt+1~4 调整窗口大小、Alt+P 预览和 Alt+D 聚焦搜索编辑框则无法使用,可以通过更改 Everything 选项来绑定到其它热键上(其中 Alt+D 也可使用相同功能的 Ctrl+F 和 F3 来代替) 144 | alt: 10 145 | 146 | # 结果列表 147 | result_list: 148 | # 同上 149 | alt: 0 150 | 151 | # [0-9A-Z] 选中项目 152 | select: true 153 | 154 | # 终端 155 | # Windows Terminal:"wt -d ${fileDirname}" 156 | # Windows Console:"conhost"(不支持以管理员身份启动) 157 | # 禁用:"" 158 | terminal: "wt -d ${fileDirname}" 159 | 160 | # 打开或定位文件后关闭窗口(不对 Everything 默认热键生效) 161 | # 如果想要默认 Enter 热键也关闭窗口,可在 Everything 快捷键选项中将“打开选中对象,并退出 Everything”设置为 Enter 162 | close_everything: true 163 | 164 | # 输入模拟模式 165 | # Auto:v1.5a→WmKey,v1.4→SendInput 166 | # WmKey 167 | # SendInput 168 | input_mode: Auto 169 | ``` 170 | 171 | ## 其它 172 | ### 快速启动器 173 | 相较于使用传统的快速启动器,使用 Everything 这类文件搜索器的主要好处是可以实现去中心化——不必将所有的启动入口集中到一个地方,而是可以在任意个文件夹下分散放置启动入口(快捷方式、笔记文件等),不仅降低了维护成本,还能让个人的文件管理结构更加统一,更适合有大量启动入口的情况。 174 | 175 | 若要将 Everything 用作快速启动器,推荐进行以下配置: 176 | 1. 添加运行次数列:右键结果列表表头,选中运行次数 177 | 2. 设置默认按运行次数排序:`选项 → 常规 → 首页 → 排序 → 运行次数(降序)` 178 | 3. 配合扩展的拼音搜索和快速选择启动文件 179 | 180 | 若要更进一步地提高启动效率,可以建立限定路径和扩展名的过滤器或书签,并通过快捷方式或 AutoHotkey 等工具注册全局热键,通过命令行新建 Everything 窗口并应用指定的过滤器或书签。 181 | 182 | ### 硬盘占用分析 183 | * 重复文件 184 | `dupe: sizedupe:` 185 | 其中 `dupe:` 用于限定文件名重复,`sizedupe:` 用于限定文件大小重复。 186 | 187 | ![](docs/Disk%20space/images/dupe.png) 188 | * 大于 100MB 的文件 189 | `size:>100mb` 190 | * 空文件夹 191 | `empty:` 192 | * Visual Studio 解决方案缓存 193 | `wfn:.vs` 194 | 195 | ![](docs/Disk%20space/images/VisualStudio.png) 196 | 197 | 或者也可使用基于 Everything 实现的专用于清理 `.vs` 的工具 [VsCacheCleaner](https://github.com/SpriteOvO/VsCacheCleaner)。 198 | 199 | 注意,显示文件夹大小需要在 Everything 选项中开启 `索引 → 索引文件夹大小`。 200 | 201 | 对于文件管理器 [Directory Opus](https://github.com/Chaoses-Ib/DirectoryOpus) 的用户,亦可使用 [IbDOpusExt](https://github.com/Chaoses-Ib/IbDOpusExt) 从 Everything 获取文件夹大小并显示为列,便于分析硬盘占用: 202 | ![](https://github.com/Chaoses-Ib/IbDOpusExt/blob/develop/docs/images/SizeCol.png?raw=true) 203 | 204 | ### 检查更新 205 | `config.yaml` 文件: 206 | ```yaml 207 | # 更新 208 | update: 209 | # 检查更新 210 | check: true 211 | 212 | # 包括预览版 213 | prerelease: false 214 | ``` 215 | 216 | ## 开发 217 | 见 [开发](docs/development.md)。 218 | 219 | ## 致谢 220 | 日期 | 捐赠者 | 备注 221 | --- | --- | --- 222 | 2023-04-28 | Xudong.He@CN | 223 | 2024-07-09 | 田昊 \| JLL仲量联行 | 224 | 225 | ## 相关链接 226 | 群组: 227 | - [Telegram 文件管理交流群](https://t.me/IbDirectoryOpusGroup) 228 | 229 | 库: 230 | - [IbPinyinLib: 一个高性能 Rust 拼音匹配库,支持 C、AHK2](https://github.com/Chaoses-Ib/IbPinyinLib) 231 | - [IbDllHijackLib: A C library for Windows DLL hijacking.](https://github.com/Chaoses-Ib/IbDllHijackLib) 232 | - [IbEverythingLib: A C++17 library for voidtool's Everything.](https://github.com/Chaoses-Ib/IbEverythingLib) 233 | 234 | 项目: 235 | - [DirectoryOpus: 一款上手简单、系统集成度高、功能强大的 Windows 文件管理器](https://github.com/Chaoses-Ib/DirectoryOpus) 236 | - [ObsidianShell: 关联 Markdown 文件到 Obsidian](https://github.com/Chaoses-Ib/ObsidianShell) 237 | -------------------------------------------------------------------------------- /Updater/Updater.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {f1492ef6-27c2-44cd-a34b-e55f45da5222} 25 | Updater 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | x64-windows-static-md 87 | 88 | 89 | x64-windows-static-md 90 | 91 | 92 | 93 | 94 | Level3 95 | true 96 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 97 | true 98 | $(SolutionDir)external\build\_deps\ibupdate-src\C++\include 99 | stdcpp20 100 | 101 | 102 | Windows 103 | true 104 | 105 | 106 | 107 | 108 | Level3 109 | true 110 | true 111 | true 112 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 113 | true 114 | $(SolutionDir)external\build\_deps\ibupdate-src\C++\include 115 | stdcpp20 116 | 117 | 118 | Windows 119 | true 120 | true 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | true 128 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 129 | true 130 | $(SolutionDir)external\build\_deps\ibupdate-src\C++\include 131 | stdcpp20 132 | 133 | 134 | Windows 135 | true 136 | 137 | 138 | 139 | 140 | Level3 141 | true 142 | true 143 | true 144 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 145 | true 146 | $(SolutionDir)external\build\_deps\ibupdate-src\C++\include 147 | stdcpp20 148 | 149 | 150 | Windows 151 | true 152 | true 153 | true 154 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | {90572fc6-3f72-3cb1-a7e3-14d1fc6bf226} 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /Updater/Updater.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /Updater/updater.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // IbUpdate -> github_api -> cURL 7 | // See https://github.com/microsoft/vcpkg/issues/2621 8 | #pragma comment(lib, "Ws2_32.Lib") 9 | //#pragma comment(lib, "Wldap32.Lib") 10 | #pragma comment(lib, "Crypt32.Lib") 11 | 12 | #pragma comment(lib, "Shlwapi.lib") 13 | 14 | std::wstring u8_to_u16(std::string u8) { 15 | int u16_size = MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), (int)u8.length(), nullptr, 0); 16 | std::wstring u16(u16_size, L'\0'); 17 | MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), (int)u8.length(), u16.data(), u16_size); 18 | return u16; 19 | } 20 | 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// Ends with '\n' 27 | std::string truncate_lines(std::string s, size_t lines) { 28 | std::istringstream in(s); 29 | std::ostringstream out; 30 | 31 | size_t i = 0; 32 | for (std::string line; i < lines && std::getline(in, line); i++) { 33 | out << line << '\n'; 34 | } 35 | if (i == lines) 36 | out << (const char*)u8"……\n"; 37 | return out.str(); 38 | } 39 | 40 | bool check_for_update(bool prerelease, bool quiet, bool silent_error) { 41 | try { 42 | GitHubUpdater updater{ "Chaoses-Ib", "IbEverythingExt", "v0.6-alpha.5" }; 43 | YAML::Node release = updater.check_for_new_release(prerelease); 44 | if (release.IsNull()) { 45 | if (!quiet) 46 | MessageBoxW(nullptr, L"无可用更新", L"IbEverythingExt", MB_ICONINFORMATION); 47 | return true; 48 | } 49 | 50 | std::wostringstream ss; 51 | ss << L"检测到新版本 " << u8_to_u16(release["tag_name"].as()) 52 | << L"\n发布时间:" << u8_to_u16(release["published_at"].as()) 53 | << L"\n更新内容:\n" << u8_to_u16(truncate_lines(release["body"].as(), 10)) 54 | << L"\n是否打开发布页面?"; 55 | if (MessageBoxW(nullptr, ss.str().c_str(), L"IbEverythingExt", MB_ICONINFORMATION | MB_YESNO) == IDYES) { 56 | ShellExecuteW(nullptr, nullptr, u8_to_u16(release["html_url"].as()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); 57 | } 58 | return true; 59 | } 60 | catch (std::runtime_error& e) { 61 | if (!silent_error) { 62 | std::ostringstream ss; 63 | ss << "检查更新失败:\n" << e.what(); 64 | MessageBoxA(nullptr, ss.str().c_str(), "IbEverythingExt", MB_ICONWARNING); 65 | } 66 | return false; 67 | } 68 | } 69 | 70 | int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nShowCmd) { 71 | using namespace std::literals; 72 | 73 | // lpCmdLine is empty for unknown reason 74 | //MessageBoxW(nullptr, lpCmdLine, nullptr, 0); 75 | //MessageBoxW(nullptr, GetCommandLineW(), nullptr, 0); 76 | lpCmdLine = GetCommandLineW(); 77 | 78 | bool quiet = false; 79 | if (std::wstring_view(lpCmdLine) == L"--quiet") 80 | quiet = true; 81 | 82 | wchar_t path[MAX_PATH]; 83 | GetModuleFileNameW(nullptr, path, std::size(path)); 84 | PathRemoveFileSpecW(path); 85 | PathAppendW(path, L"config.yaml"); 86 | 87 | std::ifstream in(path); 88 | if (!in) { 89 | MessageBoxW(nullptr, L"配置文件 config.yaml 不存在!", L"IbEverythingExt", MB_ICONERROR); 90 | return 1; 91 | } 92 | try { 93 | YAML::Node root = YAML::Load(in); 94 | YAML::Node update = root["update"]; 95 | if (update["check"].as()) { 96 | // try twice 97 | if (!check_for_update(update["prerelease"].as(), quiet, true)) 98 | check_for_update(update["prerelease"].as(), quiet, false); 99 | } 100 | } 101 | catch (YAML::Exception& e) { 102 | MessageBoxA(nullptr, ("配置文件读取错误:\n"s + e.what()).c_str(), "IbEverythingExt", MB_ICONERROR); 103 | return 1; 104 | } 105 | return 0; 106 | } -------------------------------------------------------------------------------- /docs/Disk space/images/VisualStudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/Disk space/images/VisualStudio.png -------------------------------------------------------------------------------- /docs/Disk space/images/dupe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/Disk space/images/dupe.png -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | # 开发 2 | ## 构建 3 | [vcpkg](https://github.com/microsoft/vcpkg): 4 | ```cmd 5 | vcpkg install fmt detours yaml-cpp curl --triplet=x64-windows-static-md 6 | ``` 7 | [CMake](https://cliutils.gitlab.io/modern-cmake/): 8 | ```cmd 9 | cd IbEverythingExt 10 | cd external 11 | cmake -B build -DCMAKE_TOOLCHAIN_FILE="C:\...\vcpkg\scripts\buildsystems\vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static-md 12 | ``` 13 | 14 | 对于 test 还需要: 15 | ``` 16 | vcpkg install boost-test pcre pcre2 --triplet=x64-windows-static-md 17 | ``` 18 | 19 | ## Bump version 20 | - EverythingExt\resource.rc 21 | - Updater\updater.cpp -------------------------------------------------------------------------------- /docs/pinyin_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/pinyin_search.png -------------------------------------------------------------------------------- /docs/pinyin_search/edit_mode.md: -------------------------------------------------------------------------------- 1 | # Edit 模式(停止维护) 2 | * 默认小写字母匹配拼音或字母,大写字母只匹配字母。 3 | * 只支持简拼搜索。 4 | * 支持多音字和 Unicode 辅助平面汉字。 5 | * 支持 Everything x64 安装版和便携版,不支持精简版。 6 | * 修饰符: 7 | * `py:` 小写字母只匹配拼音 8 | * `nopy:` 禁用拼音搜索(对所有关键字生效) 9 | * 出于稳定性考虑,Edit 模式只支持 [第三方程序](../third_party/README.md) 中列出的第三方程序。 10 | 11 | ![](edit_mode.png) 12 | 13 | 已知问题: 14 | * [搜索历史功能破坏 #4](https://github.com/Chaoses-Ib/IbEverythingExt/issues/4) 15 | * [不支持正则表达式 #8](https://github.com/Chaoses-Ib/IbEverythingExt/issues/8) 16 | * [提高性能 #13](https://github.com/Chaoses-Ib/IbEverythingExt/issues/13) 17 | * [拼音搜索不支持命令行搜索选项 #26](https://github.com/Chaoses-Ib/IbEverythingExt/issues/26) 18 | * [filters don't wrok #32](https://github.com/Chaoses-Ib/IbEverythingExt/issues/32) 19 | * [输入搜索并切换窗口,everything输入框出现乱码 #33](https://github.com/Chaoses-Ib/IbEverythingExt/issues/33) 20 | * [搜索框中文输入变成从右至左了 #38](https://github.com/Chaoses-Ib/IbEverythingExt/issues/38) -------------------------------------------------------------------------------- /docs/pinyin_search/edit_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/pinyin_search/edit_mode.png -------------------------------------------------------------------------------- /docs/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/preview.png -------------------------------------------------------------------------------- /docs/quick_select_dark_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/quick_select_dark_mode.png -------------------------------------------------------------------------------- /docs/third_party/EverythingToolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/third_party/EverythingToolbar.png -------------------------------------------------------------------------------- /docs/third_party/FlowLauncher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/third_party/FlowLauncher.png -------------------------------------------------------------------------------- /docs/third_party/HuoChat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/third_party/HuoChat.png -------------------------------------------------------------------------------- /docs/third_party/PowerToys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/third_party/PowerToys.png -------------------------------------------------------------------------------- /docs/third_party/README.md: -------------------------------------------------------------------------------- 1 | # 第三方程序 2 | ## [EverythingToolbar](https://github.com/stnkl/EverythingToolbar) 3 | > Everything integration for the Windows taskbar. 4 | 5 | 6 | 7 | ## [Flow Launcher](https://github.com/Flow-Launcher/Flow.Launcher) 8 | > Quick file search & app launcher for Windows with community-made plugins. 9 | 10 | [Everything 插件](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.Everything): 11 | 12 | 13 | ## [PowerToys Run](https://learn.microsoft.com/windows/powertoys/run) 14 | [Everything 插件](https://github.com/lin-ycv/EverythingPowerToys): 15 | 16 | 17 | ## [uTools](https://u.tools) 18 | > 新一代效率工具平台 19 | > 自由组合丰富插件,打造随手可取的终极神器 20 | 21 | 本地搜索: 22 | 23 | 24 | ## [Wox](https://github.com/Wox-launcher/Wox) 25 | > Launcher for Windows, an alternative to Alfred and Launchy. 26 | 27 | Everything 插件: 28 | 29 | 30 | ## [火柴(火萤酱)](https://www.huochaipro.com/) 31 | > “电脑必备,效率神器。快速查找文件、打开应用程序、局域网秒传文件、局域网聊天...” 32 | 33 | 本地搜索: 34 | 35 | 36 | ## [Total Commander](https://www.ghisler.com/) 37 | > Total Commander is a Shareware file manager for Windows® 95/98/ME/NT/2000/XP/Vista/7/8/8.1/10/11, and Windows® 3.1. 38 | 39 | 由于 TC 调用 Everything 搜索时是先获取所有文件,再通过自己的匹配机制匹配文件,扩展的拼音搜索无法对 TC 生效。 -------------------------------------------------------------------------------- /docs/third_party/Wox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/third_party/Wox.png -------------------------------------------------------------------------------- /docs/third_party/uTools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaoses-Ib/IbEverythingExt/6c5b33636eaae51e9eea48e7d1434c579053a668/docs/third_party/uTools.png -------------------------------------------------------------------------------- /external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(external) 4 | 5 | include(FetchContent) 6 | FetchContent_Declare(IbWinCpp 7 | GIT_REPOSITORY https://github.com/Chaoses-Ib/IbWinCppLib.git 8 | GIT_TAG a29ac95537f403ac5ae221cb744d3e82076efbf7 9 | ) 10 | FetchContent_Declare(IbDllHijack 11 | GIT_REPOSITORY https://github.com/Chaoses-Ib/IbDllHijackLib.git 12 | GIT_TAG a82533aff8a73129aee2a3757069f7aa89e7dd6a 13 | ) 14 | FetchContent_Declare(IbEverything 15 | GIT_REPOSITORY https://github.com/Chaoses-Ib/IbEverythingLib.git 16 | GIT_TAG 0fda1b6a2db79112b08ebdfb1443a84959ddc042 17 | ) 18 | FetchContent_Declare(IbPinyin 19 | GIT_REPOSITORY https://github.com/Chaoses-Ib/IbPinyinLib.git 20 | GIT_TAG e576e81ca06a297436bba7b124630b5d64e3106f 21 | ) 22 | FetchContent_Declare(IbUpdate 23 | GIT_REPOSITORY https://github.com/Chaoses-Ib/IbUpdateLib.git 24 | GIT_TAG eaa36c76e29409aeb89b1d7f493f48d0b54d819c 25 | ) 26 | FetchContent_Declare(sigmatch 27 | GIT_REPOSITORY https://github.com/SpriteOvO/sigmatch.git 28 | GIT_TAG 2ca983dc0cb78fe4f4406b67655e7ee132ecf5da 29 | ) 30 | FetchContent_MakeAvailable(IbWinCpp IbDllHijack IbEverything IbPinyin IbUpdate sigmatch) -------------------------------------------------------------------------------- /test/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #pragma comment(lib, "winmm.lib") 9 | 10 | using namespace std::literals; 11 | 12 | // GBK 13 | inline std::wstring pinyin_regex = L"〇一丂与业丣严丫丿乁乂么义乊乐乑乙乚乛也乵乻亄予于-云亚亜亞亦亪亱亴亿仡以仪仰仸伃伇伊伒众优伛伝伢伿佁但佑佒佗余佚佣佯佻佾侇侌侑依侥俁俋俑俓俞俣俨俹俺俼倄倚倻偀偃偊偐偞偠偣偤偯傆傊傛傜傟傭傴傿僌僥僪僷儀億儗儥優儼允元兖兗兪养兿円冘冝冤冶凐刈刖剈剡剦劓劜劮劷勇勈勚勜勩勻匀匇匋匜匬医匽卣卬印厂厃厊压厌厑厓原厡厣厭厳厴厵又友叕台右叶叹吁吆吋吔吖吚吟听吲吳吾呀呎呓员呦呭呹呾咉咏咦咬咽咿哊哑哕哟員哩哽哾唀唁唈唌唖唡唫唷唹啘啞啢啨啱喁喅喐喑喓喗喛喝喦喩喭喲営喻嗂嗈嗌嘢嘤噊噎噖噞噟噢噦噫噮噰噳噾嚈嚘-嚛嚥嚴嚶囈囐囙囝因囦囩园囿圁圄圆圉圎園圓圔圛圜圠圧圩圪圫圯圻坄均块坨坱坳垔垚垟垠垣垦垭垸垼垽埇埏埜域埡埯埶埸堉堊堐堙堣堨堬堯堰堷塋塎塩塬墅墉墕墷墿壄壅壓壛壧壱壹夁夃夕夗夜夤夭央失夵夷夽奄奇奕奥奫妁妋妍妖妘妜妟妤妧妪妴妷姎姚姨姬姲姶姷姸姻娅娛娪娫娮娯娱婣婬婭婴婸婹媀媐媕媖媛媪媮媱媴媵嫄嫈嫕嫗嫚嫛嫞嫣嬄嬈嬊嬐嬑嬟嬩嬮嬰嬳嬴嬽嬿孆孍孕孧孲孴孾它宇宎宐宛宜宥宧宴容寃寅寓寙寱寲射將尉尢尤尧尭尹尾屵屹屿岄岆岈岟岩岳峄峓峟峣峪峫峳峾峿崎崕崖崛崟崤崦崯崳崵崸崺崾嵃嵎嵒嵓嵛嵤嵱嶎嶖嶢嶤嶧嶪嶫嶬嶮嶷嶼嶽嶾巆巊巌巖巗巘巚巡已巳巸币帟帠幆幺幼幽广庌应庘庡庮庵庸庽庾廕廙廮廱廴延异弇弈弋弌引弬弲彛-彠彥彦彧彮影彵役徉御徭徼忆忔応忧忬怈怏怞怠怡怣怨怮怺怿恌恙恞恱恹恽恿悀悁悅悆悇悒悘悠悥悦惌惐惥惲愈愉意愑愓愔愚愝愠愥愪愮愹愿慂慃慇慍慭慵慾憂憖憗憶應懊懌懕懙懚懨懩懮懿戉或戫戭戲戺扅扆扊扚扜扡扬扰扵抁抈抎抑抣抭抰抴押拁拗拥拸拽挜挧挹挻捐捓捙捝捥捳掎掖掗掜掞掩掾揂揄揅揖揘揚揜揞揠揲援揶揺搋搖搤摇摬摿撄撎撽擁擇擖擛擨擪擫擽攁攍攖攸攺敔敡敥敭敼斁斔斜斞斦於施斿旑旕旖旟旲旸昀昂易昖昙昜映昱昳晏晔晕景晹晻暆暈暍暎暘暚暥曀曄曅曎曕曗曜曣曮曰曱曳曵朄月有朓朠札杅杙杝杨杬杳枂枍枒枖枟枻枼枽柂柍柚柡柼栎栐栘栧栩栯栶样栺桋桙桜桠桯梀梄梎梧梬棛棜棩棪棫棭椅椏椬椰椸椻椼楀楆楊楌楡楢楥楧楪業楰楹榅榆榏榚榞榣榬様槦槱槷槸樂樣樮樱樴樾橒橪橼檃檍檐檥檭檹檼檿櫌櫞櫟櫩櫲櫻櫽櫾櫿欎欕欝欤欥欭欲欹欽歅歇歈歋歍歖歝歟歶殀殃殒殔殕殗殞殥殪殷殹殽毅毉毓毹氀氜氤氧氩氬氱氲氳永汋汓汙汧汩汼汽沂沄沅沇沋沶油沿泂泄泅泆泑泱泳泿洂洇洋洕洝洢洩洫洮浂浟浥浧浳浴涂涌涎涒涓涢涯液涴淊淡淢淤淫淯淵淹淾渁渆渊渏渔渕渝温渫渰渶渷游湙湚湛湡湧湮湯湲湵溁溋溎源溒溔溢溳溵滎滛滟滢滧滪滺滽漁漄演漜漪漹漾潁潆潏潒潝潩潭潯潱澐澚澞澤澦澭澲澳澺濙濚濥濦濴瀀瀁瀅瀛瀠瀯瀴瀷瀹灁灉灎灐灔灜灧灩灪灹炀炈炎炏炴烄烊烎烏烑烟烨烻焆焉焑焔焬焰焱焲焴焸煇煐煙煜煠煨煬煴煾熀熅熉熎熒熖熙熠熤熨熪熼燁燄燏燕燚營燠燡燱燿爍爓爗爚爩爰爷爺爻牅牏牖牗牙牪牰犄犹犽犾狁狋狏狕狖狠狱狳狺狿猌猒猗猚猨猰猶猷猺猿獂獄獈獝獟獶玅玉王玗玙玚玡玥玧玪玴珆珚珜珢珧珱琂琊琙琟琰瑀瑒瑗瑘瑛瑜瑤瑩瑶瑿璌璍璎璵瓔瓛瓵甇甖甗用甬由甴甸畇畩畬畭異畹疋疑疙疟疡疣疨疫痈痍痏痒痖痬痷瘀瘂瘉瘍瘐瘖瘗瘞瘟瘧瘱瘾瘿癊癌癒癔癕癢癭癮癰皣盁盂盈益盐盓盶盾眃眏眑眙眢眻眼睚睪睮瞖瞱瞸矅矆矞矣矨矱砑研砚砡砽硍硏硛硢硧硪硬硯硲硽碒碞碣碤磍磒磘磤礇礏礒礖礙礜礢礯礹礿祅祎祐祤禉禋禐禓禕禜禦禴禹禺秇秐秗秞秧秵移稏稢稦稶穎穓穥穵穻穾穿窅窈窑窔窨窫窬窯窰窳竩竽笌笎笖筃筄筍筠筩筵筼箊箢箷箹篔篗篶篽簃簷籅籆籎籝籞籥籯籰籲粌粤粥粵糿約紆紜紲紻絏絪綖維綺緎緓緣緤緰緷緸緼縁縈縊縕縜縯繄繇繘繧繩繶繹纅纋纓纡约纭绎绬缊缘缢缨罂罃罌罨罭羊羏羐羑羕羗羛羠羡義羪羬羭羱羽羿翊翌翳翼耀耘耛耰耴耶耺聈聐聱聶聿肀肄肊肙肬育肴胤胦胭胰脜脩腋腌腧腪腰腴膁膉膡膺臃臆臒臙臾舀舁舆與舒舣艅艈艗艞艤艳艶艷艺艾芅芋芌芩芫芸芽苂苃苅苑苚苡苢苭英茒茔茚茟茰茵荑荥荧荫药荶荺荼莖莚莜莠莤莸莹莺菀菴菸萒萓萟萤营萦萭萮萸萾葉葕葯葽葾蒀蒏蒑蒕蒝蒬蒮蒷蓔蓣蓥蓹蓺蔅蔚蔩蔫蔭蕍蕓蕕蕘蕥蕰蕴蕷蕹薀薁薏薗薟薬薳藀藇藙藝藥藴蘊蘌蘙蘛蘟蘡蘥蘨虉虞虤虵虶蚁蚎蚏蚓蚖蚘蚜蚰蚴蛇蛍蛘蛜蛡蛦蛹蛾蜍蜎蜏蜒蜕蜟蜮蜴蜵蝆蝇蝓蝘蝝蝣蝤蝧蝯蝹蝺蝿螈螔螘螠螢螸螾蟈蟫蟻蠅蠖蠮蠱蠳衍衏衘衙衣衤衧衪衵袁袂袎袘袣袬裀裔裕裛裫裷裺裿褎褑褕褗褘褞褤褮褹襗襼襾要覃覎覞覦覮觃觎觺觾言訁訑訔訚訝訞訡訢訧訮訲訳詇詍詏詑詒詠詣詳詽誃誉誒誘語説誼誾諛諭諲諹諺謁謍謚謜謠謡謣謻譍譩譯議譺譻譽讉讌讑讔讛讞讠议讶译诒诣语诱说谀谊谒谕谚谣谳谷豓豔豙豛豣豫豷貁貍貐貖貗貟貤貽賏賱賹贀贇贋贏贗贠贻赝赟赢赺越趛趯趼跀跃跇跠踊踦踰踴躍躒躽軅軈軉軋軏軮軺軼輅輍輏輐輑輗輢輰輵輶輼輿轅轙轝轧轶轺辕辥辷込迂迃迆迎运迓远迤迭迱迶迻逌逘這逞逰逳逸逺逾遃遇遊運遗遙遠遥遹遺邀邍邎邑邕邘邧邪邮邺郁郓郔郚郢郧郵郺郼郾鄅鄆鄓鄖鄘鄞鄢鄴鄾酀酉酏酑酓酛酝酭酳酽醃醖醞醟醧醫醳醶醷醼釅釉釋野釔釪釴釶釾釿鈅鈏鈗鈘鈝鈠鈨鈺鈾鉇鉈鉛鉞鉠鉯銀銉銕銚銥銦銪銹銿鋆鋊鋋鋙鋣鋭鋺錏錟錡錥鍈鍚鍝鍱鎁鎐鎑鎣鎰鎱鏔鏞鐊鐍鐚鐛鐭鐷鐿鑍鑠鑰钀钇钖钥钰钺铀铅铔铕铘铟铫铱银铻锳镒镛镱閆閘閱閲閹閻閼閾闄闇闉闫阅阈阉阎阏阣-阦阭阮阳阴阽陁陓院陨陭陰陶陻陽隁隂隃隅隐隒隕隠隩險隱隶隿雁雅雉雍雓雝雨雩雲雵霅霒霙霠霣霪霬霱霷靉靥靨靷靾靿鞅鞇鞕韗韞韫音韵韹韺韻韾頁頉預頤頥頨頴頵顊顏顑顒顔顗願顤顩页预颍颐颕颖颙颜颺颻飏飖食飫飬飮飲飴餆養餍餘餚餣餫饁饇饐饔饜饫饮饴馀馌馧馭馻駀駅駌駚駰騐験騕騟騴騵驁驈驗驛驜驠驭驿骃验骬骮髃髺鬰鬱鬳鬻魇魊魘魚魣魭魷鮋鮣鮧鮨鮽鯈鯒鯣鯲鰅鰋鰑鰩鰫鱅鱊鱦鱮鱼鱿鲉鲬鳐鳙鳦鳫鳱鳶鳿鴁鴈鴉鴛鴢鴥-鴨鴪鴬鴳鴹鴺鵒鵪鵶鵷鵺鶂鶃鶍鶑鶠鶢鶧鶯鶰鷁鷂鷃鷊鷕鷖鷛鷠鷣鷧鷪鷰鷸鷹鷾鸃鸆鸈鸉鸎鸑鸒鸙鸚鸢鸦鸭鸯鸳鹆鹓鹝鹞鹢鹥鹦鹬鹰鹽麀麌麙麣麲黓黝黟黡黤黦黫黬黭黰黳黶黿鼋鼘鼝鼬鼴鼹鼼齖齗齞齦齩齫齬齮齳齴齵齸齾龂龈龉龑龠龥"; 14 | inline std::wstring pinyin_branch = L"〇|一|丂|与|业|丣|严|丫|丿|乁|乂|么|义|乊|乐|乑|乙|乚|乛|也|乵|乻|亄|予|于|亏|亐|云|亚|亜|亞|亦|亪|亱|亴|亿|仡|以|仪|仰|仸|伃|伇|伊|伒|众|优|伛|伝|伢|伿|佁|但|佑|佒|佗|余|佚|佣|佯|佻|佾|侇|侌|侑|依|侥|俁|俋|俑|俓|俞|俣|俨|俹|俺|俼|倄|倚|倻|偀|偃|偊|偐|偞|偠|偣|偤|偯|傆|傊|傛|傜|傟|傭|傴|傿|僌|僥|僪|僷|儀|億|儗|儥|優|儼|允|元|兖|兗|兪|养|兿|円|冘|冝|冤|冶|凐|刈|刖|剈|剡|剦|劓|劜|劮|劷|勇|勈|勚|勜|勩|勻|匀|匇|匋|匜|匬|医|匽|卣|卬|印|厂|厃|厊|压|厌|厑|厓|原|厡|厣|厭|厳|厴|厵|又|友|叕|台|右|叶|叹|吁|吆|吋|吔|吖|吚|吟|听|吲|吳|吾|呀|呎|呓|员|呦|呭|呹|呾|咉|咏|咦|咬|咽|咿|哊|哑|哕|哟|員|哩|哽|哾|唀|唁|唈|唌|唖|唡|唫|唷|唹|啘|啞|啢|啨|啱|喁|喅|喐|喑|喓|喗|喛|喝|喦|喩|喭|喲|営|喻|嗂|嗈|嗌|嘢|嘤|噊|噎|噖|噞|噟|噢|噦|噫|噮|噰|噳|噾|嚈|嚘|嚙|嚚|嚛|嚥|嚴|嚶|囈|囐|囙|囝|因|囦|囩|园|囿|圁|圄|圆|圉|圎|園|圓|圔|圛|圜|圠|圧|圩|圪|圫|圯|圻|坄|均|块|坨|坱|坳|垔|垚|垟|垠|垣|垦|垭|垸|垼|垽|埇|埏|埜|域|埡|埯|埶|埸|堉|堊|堐|堙|堣|堨|堬|堯|堰|堷|塋|塎|塩|塬|墅|墉|墕|墷|墿|壄|壅|壓|壛|壧|壱|壹|夁|夃|夕|夗|夜|夤|夭|央|失|夵|夷|夽|奄|奇|奕|奥|奫|妁|妋|妍|妖|妘|妜|妟|妤|妧|妪|妴|妷|姎|姚|姨|姬|姲|姶|姷|姸|姻|娅|娛|娪|娫|娮|娯|娱|婣|婬|婭|婴|婸|婹|媀|媐|媕|媖|媛|媪|媮|媱|媴|媵|嫄|嫈|嫕|嫗|嫚|嫛|嫞|嫣|嬄|嬈|嬊|嬐|嬑|嬟|嬩|嬮|嬰|嬳|嬴|嬽|嬿|孆|孍|孕|孧|孲|孴|孾|它|宇|宎|宐|宛|宜|宥|宧|宴|容|寃|寅|寓|寙|寱|寲|射|將|尉|尢|尤|尧|尭|尹|尾|屵|屹|屿|岄|岆|岈|岟|岩|岳|峄|峓|峟|峣|峪|峫|峳|峾|峿|崎|崕|崖|崛|崟|崤|崦|崯|崳|崵|崸|崺|崾|嵃|嵎|嵒|嵓|嵛|嵤|嵱|嶎|嶖|嶢|嶤|嶧|嶪|嶫|嶬|嶮|嶷|嶼|嶽|嶾|巆|巊|巌|巖|巗|巘|巚|巡|已|巳|巸|币|帟|帠|幆|幺|幼|幽|广|庌|应|庘|庡|庮|庵|庸|庽|庾|廕|廙|廮|廱|廴|延|异|弇|弈|弋|弌|引|弬|弲|彛|彜|彝|彞|彟|彠|彥|彦|彧|彮|影|彵|役|徉|御|徭|徼|忆|忔|応|忧|忬|怈|怏|怞|怠|怡|怣|怨|怮|怺|怿|恌|恙|恞|恱|恹|恽|恿|悀|悁|悅|悆|悇|悒|悘|悠|悥|悦|惌|惐|惥|惲|愈|愉|意|愑|愓|愔|愚|愝|愠|愥|愪|愮|愹|愿|慂|慃|慇|慍|慭|慵|慾|憂|憖|憗|憶|應|懊|懌|懕|懙|懚|懨|懩|懮|懿|戉|或|戫|戭|戲|戺|扅|扆|扊|扚|扜|扡|扬|扰|扵|抁|抈|抎|抑|抣|抭|抰|抴|押|拁|拗|拥|拸|拽|挜|挧|挹|挻|捐|捓|捙|捝|捥|捳|掎|掖|掗|掜|掞|掩|掾|揂|揄|揅|揖|揘|揚|揜|揞|揠|揲|援|揶|揺|搋|搖|搤|摇|摬|摿|撄|撎|撽|擁|擇|擖|擛|擨|擪|擫|擽|攁|攍|攖|攸|攺|敔|敡|敥|敭|敼|斁|斔|斜|斞|斦|於|施|斿|旑|旕|旖|旟|旲|旸|昀|昂|易|昖|昙|昜|映|昱|昳|晏|晔|晕|景|晹|晻|暆|暈|暍|暎|暘|暚|暥|曀|曄|曅|曎|曕|曗|曜|曣|曮|曰|曱|曳|曵|朄|月|有|朓|朠|札|杅|杙|杝|杨|杬|杳|枂|枍|枒|枖|枟|枻|枼|枽|柂|柍|柚|柡|柼|栎|栐|栘|栧|栩|栯|栶|样|栺|桋|桙|桜|桠|桯|梀|梄|梎|梧|梬|棛|棜|棩|棪|棫|棭|椅|椏|椬|椰|椸|椻|椼|楀|楆|楊|楌|楡|楢|楥|楧|楪|業|楰|楹|榅|榆|榏|榚|榞|榣|榬|様|槦|槱|槷|槸|樂|樣|樮|樱|樴|樾|橒|橪|橼|檃|檍|檐|檥|檭|檹|檼|檿|櫌|櫞|櫟|櫩|櫲|櫻|櫽|櫾|櫿|欎|欕|欝|欤|欥|欭|欲|欹|欽|歅|歇|歈|歋|歍|歖|歝|歟|歶|殀|殃|殒|殔|殕|殗|殞|殥|殪|殷|殹|殽|毅|毉|毓|毹|氀|氜|氤|氧|氩|氬|氱|氲|氳|永|汋|汓|汙|汧|汩|汼|汽|沂|沄|沅|沇|沋|沶|油|沿|泂|泄|泅|泆|泑|泱|泳|泿|洂|洇|洋|洕|洝|洢|洩|洫|洮|浂|浟|浥|浧|浳|浴|涂|涌|涎|涒|涓|涢|涯|液|涴|淊|淡|淢|淤|淫|淯|淵|淹|淾|渁|渆|渊|渏|渔|渕|渝|温|渫|渰|渶|渷|游|湙|湚|湛|湡|湧|湮|湯|湲|湵|溁|溋|溎|源|溒|溔|溢|溳|溵|滎|滛|滟|滢|滧|滪|滺|滽|漁|漄|演|漜|漪|漹|漾|潁|潆|潏|潒|潝|潩|潭|潯|潱|澐|澚|澞|澤|澦|澭|澲|澳|澺|濙|濚|濥|濦|濴|瀀|瀁|瀅|瀛|瀠|瀯|瀴|瀷|瀹|灁|灉|灎|灐|灔|灜|灧|灩|灪|灹|炀|炈|炎|炏|炴|烄|烊|烎|烏|烑|烟|烨|烻|焆|焉|焑|焔|焬|焰|焱|焲|焴|焸|煇|煐|煙|煜|煠|煨|煬|煴|煾|熀|熅|熉|熎|熒|熖|熙|熠|熤|熨|熪|熼|燁|燄|燏|燕|燚|營|燠|燡|燱|燿|爍|爓|爗|爚|爩|爰|爷|爺|爻|牅|牏|牖|牗|牙|牪|牰|犄|犹|犽|犾|狁|狋|狏|狕|狖|狠|狱|狳|狺|狿|猌|猒|猗|猚|猨|猰|猶|猷|猺|猿|獂|獄|獈|獝|獟|獶|玅|玉|王|玗|玙|玚|玡|玥|玧|玪|玴|珆|珚|珜|珢|珧|珱|琂|琊|琙|琟|琰|瑀|瑒|瑗|瑘|瑛|瑜|瑤|瑩|瑶|瑿|璌|璍|璎|璵|瓔|瓛|瓵|甇|甖|甗|用|甬|由|甴|甸|畇|畩|畬|畭|異|畹|疋|疑|疙|疟|疡|疣|疨|疫|痈|痍|痏|痒|痖|痬|痷|瘀|瘂|瘉|瘍|瘐|瘖|瘗|瘞|瘟|瘧|瘱|瘾|瘿|癊|癌|癒|癔|癕|癢|癭|癮|癰|皣|盁|盂|盈|益|盐|盓|盶|盾|眃|眏|眑|眙|眢|眻|眼|睚|睪|睮|瞖|瞱|瞸|矅|矆|矞|矣|矨|矱|砑|研|砚|砡|砽|硍|硏|硛|硢|硧|硪|硬|硯|硲|硽|碒|碞|碣|碤|磍|磒|磘|磤|礇|礏|礒|礖|礙|礜|礢|礯|礹|礿|祅|祎|祐|祤|禉|禋|禐|禓|禕|禜|禦|禴|禹|禺|秇|秐|秗|秞|秧|秵|移|稏|稢|稦|稶|穎|穓|穥|穵|穻|穾|穿|窅|窈|窑|窔|窨|窫|窬|窯|窰|窳|竩|竽|笌|笎|笖|筃|筄|筍|筠|筩|筵|筼|箊|箢|箷|箹|篔|篗|篶|篽|簃|簷|籅|籆|籎|籝|籞|籥|籯|籰|籲|粌|粤|粥|粵|糿|約|紆|紜|紲|紻|絏|絪|綖|維|綺|緎|緓|緣|緤|緰|緷|緸|緼|縁|縈|縊|縕|縜|縯|繄|繇|繘|繧|繩|繶|繹|纅|纋|纓|纡|约|纭|绎|绬|缊|缘|缢|缨|罂|罃|罌|罨|罭|羊|羏|羐|羑|羕|羗|羛|羠|羡|義|羪|羬|羭|羱|羽|羿|翊|翌|翳|翼|耀|耘|耛|耰|耴|耶|耺|聈|聐|聱|聶|聿|肀|肄|肊|肙|肬|育|肴|胤|胦|胭|胰|脜|脩|腋|腌|腧|腪|腰|腴|膁|膉|膡|膺|臃|臆|臒|臙|臾|舀|舁|舆|與|舒|舣|艅|艈|艗|艞|艤|艳|艶|艷|艺|艾|芅|芋|芌|芩|芫|芸|芽|苂|苃|苅|苑|苚|苡|苢|苭|英|茒|茔|茚|茟|茰|茵|荑|荥|荧|荫|药|荶|荺|荼|莖|莚|莜|莠|莤|莸|莹|莺|菀|菴|菸|萒|萓|萟|萤|营|萦|萭|萮|萸|萾|葉|葕|葯|葽|葾|蒀|蒏|蒑|蒕|蒝|蒬|蒮|蒷|蓔|蓣|蓥|蓹|蓺|蔅|蔚|蔩|蔫|蔭|蕍|蕓|蕕|蕘|蕥|蕰|蕴|蕷|蕹|薀|薁|薏|薗|薟|薬|薳|藀|藇|藙|藝|藥|藴|蘊|蘌|蘙|蘛|蘟|蘡|蘥|蘨|虉|虞|虤|虵|虶|蚁|蚎|蚏|蚓|蚖|蚘|蚜|蚰|蚴|蛇|蛍|蛘|蛜|蛡|蛦|蛹|蛾|蜍|蜎|蜏|蜒|蜕|蜟|蜮|蜴|蜵|蝆|蝇|蝓|蝘|蝝|蝣|蝤|蝧|蝯|蝹|蝺|蝿|螈|螔|螘|螠|螢|螸|螾|蟈|蟫|蟻|蠅|蠖|蠮|蠱|蠳|衍|衏|衘|衙|衣|衤|衧|衪|衵|袁|袂|袎|袘|袣|袬|裀|裔|裕|裛|裫|裷|裺|裿|褎|褑|褕|褗|褘|褞|褤|褮|褹|襗|襼|襾|要|覃|覎|覞|覦|覮|觃|觎|觺|觾|言|訁|訑|訔|訚|訝|訞|訡|訢|訧|訮|訲|訳|詇|詍|詏|詑|詒|詠|詣|詳|詽|誃|誉|誒|誘|語|説|誼|誾|諛|諭|諲|諹|諺|謁|謍|謚|謜|謠|謡|謣|謻|譍|譩|譯|議|譺|譻|譽|讉|讌|讑|讔|讛|讞|讠|议|讶|译|诒|诣|语|诱|说|谀|谊|谒|谕|谚|谣|谳|谷|豓|豔|豙|豛|豣|豫|豷|貁|貍|貐|貖|貗|貟|貤|貽|賏|賱|賹|贀|贇|贋|贏|贗|贠|贻|赝|赟|赢|赺|越|趛|趯|趼|跀|跃|跇|跠|踊|踦|踰|踴|躍|躒|躽|軅|軈|軉|軋|軏|軮|軺|軼|輅|輍|輏|輐|輑|輗|輢|輰|輵|輶|輼|輿|轅|轙|轝|轧|轶|轺|辕|辥|辷|込|迂|迃|迆|迎|运|迓|远|迤|迭|迱|迶|迻|逌|逘|這|逞|逰|逳|逸|逺|逾|遃|遇|遊|運|遗|遙|遠|遥|遹|遺|邀|邍|邎|邑|邕|邘|邧|邪|邮|邺|郁|郓|郔|郚|郢|郧|郵|郺|郼|郾|鄅|鄆|鄓|鄖|鄘|鄞|鄢|鄴|鄾|酀|酉|酏|酑|酓|酛|酝|酭|酳|酽|醃|醖|醞|醟|醧|醫|醳|醶|醷|醼|釅|釉|釋|野|釔|釪|釴|釶|釾|釿|鈅|鈏|鈗|鈘|鈝|鈠|鈨|鈺|鈾|鉇|鉈|鉛|鉞|鉠|鉯|銀|銉|銕|銚|銥|銦|銪|銹|銿|鋆|鋊|鋋|鋙|鋣|鋭|鋺|錏|錟|錡|錥|鍈|鍚|鍝|鍱|鎁|鎐|鎑|鎣|鎰|鎱|鏔|鏞|鐊|鐍|鐚|鐛|鐭|鐷|鐿|鑍|鑠|鑰|钀|钇|钖|钥|钰|钺|铀|铅|铔|铕|铘|铟|铫|铱|银|铻|锳|镒|镛|镱|閆|閘|閱|閲|閹|閻|閼|閾|闄|闇|闉|闫|阅|阈|阉|阎|阏|阣|阤|阥|阦|阭|阮|阳|阴|阽|陁|陓|院|陨|陭|陰|陶|陻|陽|隁|隂|隃|隅|隐|隒|隕|隠|隩|險|隱|隶|隿|雁|雅|雉|雍|雓|雝|雨|雩|雲|雵|霅|霒|霙|霠|霣|霪|霬|霱|霷|靉|靥|靨|靷|靾|靿|鞅|鞇|鞕|韗|韞|韫|音|韵|韹|韺|韻|韾|頁|頉|預|頤|頥|頨|頴|頵|顊|顏|顑|顒|顔|顗|願|顤|顩|页|预|颍|颐|颕|颖|颙|颜|颺|颻|飏|飖|食|飫|飬|飮|飲|飴|餆|養|餍|餘|餚|餣|餫|饁|饇|饐|饔|饜|饫|饮|饴|馀|馌|馧|馭|馻|駀|駅|駌|駚|駰|騐|験|騕|騟|騴|騵|驁|驈|驗|驛|驜|驠|驭|驿|骃|验|骬|骮|髃|髺|鬰|鬱|鬳|鬻|魇|魊|魘|魚|魣|魭|魷|鮋|鮣|鮧|鮨|鮽|鯈|鯒|鯣|鯲|鰅|鰋|鰑|鰩|鰫|鱅|鱊|鱦|鱮|鱼|鱿|鲉|鲬|鳐|鳙|鳦|鳫|鳱|鳶|鳿|鴁|鴈|鴉|鴛|鴢|鴥|鴦|鴧|鴨|鴪|鴬|鴳|鴹|鴺|鵒|鵪|鵶|鵷|鵺|鶂|鶃|鶍|鶑|鶠|鶢|鶧|鶯|鶰|鷁|鷂|鷃|鷊|鷕|鷖|鷛|鷠|鷣|鷧|鷪|鷰|鷸|鷹|鷾|鸃|鸆|鸈|鸉|鸎|鸑|鸒|鸙|鸚|鸢|鸦|鸭|鸯|鸳|鹆|鹓|鹝|鹞|鹢|鹥|鹦|鹬|鹰|鹽|麀|麌|麙|麣|麲|黓|黝|黟|黡|黤|黦|黫|黬|黭|黰|黳|黶|黿|鼋|鼘|鼝|鼬|鼴|鼹|鼼|齖|齗|齞|齦|齩|齫|齬|齮|齳|齴|齵|齸|齾|龂|龈|龉|龑|龠|龥"; 15 | inline std::wstring pinyin_range = L"〇-龥"; 16 | 17 | inline std::wstring pinyin_regex_gb2312 = L"一与业严丫丿么义乐乙也予于亏云亚亦亿仡以仪仰伊众优伛伢但佑佗余佚佣佯佻佾侑依侥俑俞俣俨俺倚偃允元兖养冤冶刈刖剡劓勇匀医卣印厂压厌原厣又友台右叶叹吁吆吖吟听吲吾呀呓员呦咏咦咬咽咿哑哕哟哩哽唁唷喁喑喝喻嗌嘤噎噢噫囝因园囿圄圆圉圜圩圪圯圻均块坨坳垠垣垦垭垸埏域埯埸堙堰塬墅墉壅壹夕夜夤夭央失夷奄奇奕奥妁妍妖妤妪姚姨姬姻娅娱婴媛媪媵嫣嬴孕它宇宛宜宥宴容寅寓射尉尢尤尧尹尾屹屿岈岩岳峄峪崎崖崛崤崦崾嵛嶷巡已巳币幺幼幽广应庵庸庾廴延异弈弋引彝彦影役徉御徭徼忆忧怏怠怡怨怿恙恹恽恿悒悠悦愈愉意愚愠愿慵懊懿或扬扰抑押拗拥拽挹捐掎掖掩掾揄揖揞揠揲援揶搋摇撄攸斜於施旖昀昂易昙映昱晏晔晕景曜曰曳月有札杨杳柚栎栩样桠梧椅椰楹榆樱樾橼檐欤欲欹歇殃殒殪殷毅毓毹氤氧氩氲永汩汽沂沅油沿泄泅泱泳洇洋洫洮浴涂涌涎涓涯液淡淤淫淹渊渔渝温渫游湛湮源溢滟滢演漪漾潆潭澳瀛瀹炀炎烊烟烨焉焰焱煜煨熙熠熨燕燠爰爷爻牖牙犄犹狁狠狱狳狺猗猷猿玉王珧琊琰瑗瑛瑜瑶璎用甬由甸畹疋疑疙疟疡疣疫痈痍痒痖瘀瘐瘗瘟瘾瘿癌癔盂盈益盐盾眙眢眼睚矣砑研砚硪硬碣禹禺秧移穿窈窑窨窬窳竽筠筵箢粤粥繇纡约纭绎缘缢缨罂罨羊羡羽羿翊翌翳翼耀耘耶聱聿肀肄育肴胤胭胰腋腌腧腰腴膺臃臆臾舀舁舆舒舣艳艺艾芋芩芫芸芽苑苡英茔茚茵荑荥荧荫药荼莜莠莸莹莺菀菸萤营萦萸蓣蓥蔚蔫蕴蕹薏虞蚁蚓蚜蚰蚴蛇蛘蛹蛾蜍蜒蜕蜮蜴蝇蝓蝣蝤螈蠖衍衙衣衤袁袂裔裕要覃觎言誉讠议讶译诒诣语诱说谀谊谒谕谚谣谳谷豫贻赝赢越趼跃踊轧轶轺辕迂迎运迓远迤迭逞逸逾遇遗遥邀邑邕邪邮邺郁郓郢郧郾鄞鄢酉酏酝酽釉野钇钥钰钺铀铅铕铘铟铫铱银镒镛镱闫阅阈阉阎阏阮阳阴阽院陨陶隅隐隶雁雅雉雍雨雩霪靥鞅韫音韵页预颍颐颖颜食餍饔饫饮饴馀驭驿验鬻魇鱼鱿鳐鳙鸢鸦鸭鸯鸳鹆鹞鹦鹬鹰黝黟鼋鼬鼹龈龉龠"; 18 | inline std::wstring pinyin_range_gb2312 = L"[一-龠]"; 19 | 20 | #define _T(x) L##x 21 | #include "dynamic_charset.h.user" // private data 22 | //#define DYNAMIC_CHARSET_Y L"源页议游育娱乐汽语言元一么于音友有影" 23 | //#define DYNAMIC_CHARSET_YY_1 L"娱语" 24 | //#define DYNAMIC_CHARSET_YY_2 L"乐言" -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE test 2 | #include -------------------------------------------------------------------------------- /test/match.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | #include "../EverythingExt/match.cpp" 4 | #include "../EverythingExt/helper.cpp" 5 | 6 | BOOST_AUTO_TEST_SUITE(Match) 7 | BOOST_AUTO_TEST_CASE(Match) { 8 | pinyin::init(pinyin::PinyinFlag::All); 9 | std::vector flags = { pinyin::PinyinFlag::PinyinAsciiDigit, pinyin::PinyinFlag::PinyinAscii, pinyin::PinyinFlag::InitialLetter, pinyin::PinyinFlag::DoublePinyinMicrosoft }; 10 | int pmatch[20]; 11 | auto test = [&flags, &pmatch](const char8_t* pat, const char8_t* subject) { 12 | Pattern* pattern = compile(pat, {}, &flags); 13 | int result = exec(pattern, subject, strlen((const char*)subject), std::size(pmatch) / 2, pmatch, {}); 14 | HeapFree(GetProcessHeap(), 0, pattern); 15 | return result; 16 | }; 17 | 18 | // plain 19 | BOOST_CHECK(test(u8"pinyin", u8"pinyin") == 1 && pmatch[0] == 0 && pmatch[1] == 6); 20 | BOOST_CHECK(test(u8"pinyin", u8"PinYin") == 1 && pmatch[0] == 0 && pmatch[1] == 6); 21 | 22 | // pinyin 23 | BOOST_CHECK(test(u8"py", u8"拼音") == 1 && pmatch[0] == 0 && pmatch[1] == 6); 24 | BOOST_CHECK(test(u8"pinyin", u8"拼音") == 1 && pmatch[0] == 0 && pmatch[1] == 6); 25 | BOOST_CHECK(test(u8"pin1yin1", u8"拼音") == 1 && pmatch[0] == 0 && pmatch[1] == 6); 26 | // DoublePinyinMicrosoft 27 | BOOST_CHECK(test(u8"pn", u8"拼音") == 1 && pmatch[0] == 0 && pmatch[1] == 3); 28 | 29 | // global 30 | BOOST_CHECK(test(u8"pinyin", u8"0123pinyin") == 1 && pmatch[0] == 4 && pmatch[1] == 10); 31 | BOOST_CHECK(test(u8"pinyin", u8"0123拼音") == 1 && pmatch[0] == 4 && pmatch[1] == 10); 32 | 33 | // multiple 34 | //BOOST_CHECK(test(u8"pinyin", u8"01拼音23拼音") == 1 && pmatch[0] == 2 && pmatch[1] == 8); 35 | 36 | // mix 37 | BOOST_CHECK(test(u8"pinyin", u8"拼yin") == 1 && pmatch[0] == 0 && pmatch[1] == 6); 38 | BOOST_CHECK(test(u8"sous", u8"拼音搜索Everything") == 1 && pmatch[0] == 6 && pmatch[1] == 12); 39 | 40 | pinyin::destroy(); 41 | } 42 | 43 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/pcre.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include 3 | #define PCRE2_CODE_UNIT_WIDTH 8 4 | #include 5 | 6 | #undef _T 7 | #define _T(x) u8##x 8 | 9 | BOOST_AUTO_TEST_SUITE(PCRE_Match) 10 | 11 | uint32_t get_pinyin(char32_t c) { 12 | return 0x400; 13 | } 14 | 15 | BOOST_AUTO_TEST_CASE(Match) { 16 | auto match = [](std::string_view pattern, std::string_view subject) -> uint32_t { 17 | for (uint32_t i = 0; i < subject.size(); i++) { 18 | uint32_t j = 0, i_ = i; 19 | for (; j < pattern.size() && i_ < subject.size(); j++, i_++) { 20 | if (subject[i_] == pattern[j] || subject[i_] > 'z' && get_pinyin(subject[i_]) & 1 << (pattern[j] - 'a')) 21 | continue; 22 | break; 23 | } 24 | if (j == pattern.size()) 25 | return i; 26 | } 27 | return (uint32_t)-1; 28 | }; 29 | BOOST_CHECK(match("kk", "abcdefgkk.txt") == 7); 30 | BOOST_CHECK(match("kk", "abcdefg~~.txt") == 7); 31 | 32 | char pattern[] = "yy", subject[] = "abcdefg满天都是小星星.txt"; 33 | DWORD t = timeGetTime(); 34 | for (size_t i = 0; i < 1'000'000; i++) { 35 | if (__rdtsc() == 0) { 36 | pattern[0] = subject[0] = '\0'; 37 | } 38 | match(pattern, subject); 39 | } 40 | t = timeGetTime() - t; 41 | BOOST_TEST_MESSAGE(t << "ms"); 42 | // 10ms 43 | } 44 | 45 | BOOST_AUTO_TEST_SUITE_END() 46 | 47 | 48 | BOOST_AUTO_TEST_SUITE(PCRE) 49 | 50 | BOOST_AUTO_TEST_CASE(Compile) { 51 | DWORD t = timeGetTime(); 52 | std::u8string_view pattern = u8"[y" DYNAMIC_CHARSET_YY_1 u8"][y" DYNAMIC_CHARSET_YY_2 u8"]"; 53 | int errorcode, erroroffset; 54 | const char* error; 55 | pcre* re = pcre_compile2((const char*)pattern.data(), PCRE_UCP | PCRE_UTF8 | PCRE_CASELESS, &errorcode, &error, &erroroffset, nullptr); 56 | 57 | int offsets[30], result; 58 | 59 | result = pcre_exec(re, nullptr, (const char*)u8"测试语言.txt", 16, 0, 0, offsets, std::size(offsets)); 60 | t = timeGetTime() - t; 61 | BOOST_REQUIRE(result > 0 && offsets[0] == 6); 62 | BOOST_TEST_MESSAGE(t << "ms"); 63 | // 0ms 64 | 65 | std::u8string_view subject(u8"abcdefg满天都是小星星.txt"); 66 | t = timeGetTime(); 67 | for (size_t i = 0; i < 1'000'000; i++) { 68 | result = pcre_exec(re, nullptr, (const char*)subject.data(), subject.size(), 0, 0, offsets, std::size(offsets)); 69 | } 70 | t = timeGetTime() - t; 71 | BOOST_CHECK(result == -1); 72 | 73 | pcre_free(re); 74 | 75 | BOOST_TEST_MESSAGE(t << "ms"); 76 | // 4800~5200ms 77 | } 78 | 79 | void JIT_common(std::u8string_view pattern, std::u8string_view test_subject, std::u8string_view subject, int subject_result = -1) { 80 | int errorcode, erroroffset; 81 | const char* error; 82 | DWORD t = timeGetTime(); 83 | pcre* re = pcre_compile2((const char*)pattern.data(), PCRE_UCP | PCRE_UTF8 | PCRE_CASELESS, &errorcode, &error, &erroroffset, nullptr); 84 | 85 | pcre_extra* extra = pcre_study(re, PCRE_STUDY_JIT_COMPILE, &error); 86 | pcre_jit_stack* jit_stack = pcre_jit_stack_alloc(32 * 1024, 512 * 1024); 87 | pcre_assign_jit_stack(extra, nullptr, jit_stack); 88 | 89 | int offsets[30], result; 90 | 91 | result = pcre_exec(re, extra, (const char*)test_subject.data(), test_subject.size(), 0, 0, offsets, std::size(offsets)); 92 | BOOST_REQUIRE(result > 0 && offsets[0] == 6); 93 | t = timeGetTime() - t; 94 | BOOST_TEST_MESSAGE(t << "ms"); 95 | // 0ms 96 | 97 | t = timeGetTime(); 98 | for (size_t i = 0; i < 1'000'000; i++) { 99 | result = pcre_exec(re, extra, (const char*)subject.data(), subject.size(), 0, 0, offsets, std::size(offsets)); 100 | } 101 | t = timeGetTime() - t; 102 | BOOST_CHECK(result == subject_result); 103 | 104 | pcre_free(re); 105 | pcre_free_study(extra); 106 | pcre_jit_stack_free(jit_stack); 107 | 108 | BOOST_TEST_MESSAGE(t << "ms"); 109 | } 110 | 111 | void JIT_common32(std::u32string_view pattern, std::u32string_view test_subject, std::u32string_view subject, int subject_result = -1) { 112 | int errorcode, erroroffset; 113 | const char* error; 114 | DWORD t = timeGetTime(); 115 | pcre32* re = pcre32_compile2((PCRE_SPTR32)pattern.data(), PCRE_UCP | PCRE_UTF8 | PCRE_CASELESS, &errorcode, &error, &erroroffset, nullptr); 116 | 117 | pcre32_extra* extra = pcre32_study(re, PCRE_STUDY_JIT_COMPILE, &error); 118 | pcre32_jit_stack* jit_stack = pcre32_jit_stack_alloc(32 * 1024, 512 * 1024); 119 | pcre32_assign_jit_stack(extra, nullptr, jit_stack); 120 | 121 | int offsets[30], result; 122 | 123 | result = pcre32_exec(re, extra, (PCRE_SPTR32)test_subject.data(), test_subject.size(), 0, 0, offsets, std::size(offsets)); 124 | BOOST_REQUIRE(result > 0 && offsets[0] == 2); 125 | t = timeGetTime() - t; 126 | BOOST_TEST_MESSAGE(t << "ms"); 127 | // 0ms 128 | 129 | t = timeGetTime(); 130 | for (size_t i = 0; i < 1'000'000; i++) { 131 | result = pcre32_exec(re, extra, (PCRE_SPTR32)subject.data(), subject.size(), 0, 0, offsets, std::size(offsets)); 132 | } 133 | t = timeGetTime() - t; 134 | BOOST_CHECK(result == subject_result); 135 | 136 | pcre32_free(re); 137 | pcre32_free_study(extra); 138 | pcre32_jit_stack_free(jit_stack); 139 | 140 | BOOST_TEST_MESSAGE(t << "ms"); 141 | } 142 | 143 | #undef _T 144 | #define _T(x) U##x 145 | 146 | BOOST_AUTO_TEST_CASE(JIT32) { 147 | JIT_common32( 148 | U"[y" DYNAMIC_CHARSET_YY_1 U"][y" DYNAMIC_CHARSET_YY_2 U"]", 149 | U"测试语言.txt", 150 | U"abcdefg满天都是小星星.txt" 151 | ); 152 | // 600~800ms 153 | JIT_common32( 154 | U"[y" DYNAMIC_CHARSET_YY_1 U"][y" DYNAMIC_CHARSET_YY_2 U"]", 155 | U"测试语言.txt", 156 | U"abcdefghijklmnopqrstuvwxyzab.txt" 157 | ); 158 | // 100~150ms 159 | } 160 | 161 | #undef _T 162 | #define _T(x) u8##x 163 | 164 | BOOST_AUTO_TEST_CASE(JIT) { 165 | JIT_common( 166 | u8"[y" DYNAMIC_CHARSET_YY_1 u8"][y" DYNAMIC_CHARSET_YY_2 u8"]", 167 | u8"测试语言.txt", 168 | u8"abcdefg满天都是小星星.txt" 169 | ); 170 | // 930~960ms 171 | JIT_common( 172 | u8"[y" DYNAMIC_CHARSET_YY_1 u8"][y" DYNAMIC_CHARSET_YY_2 u8"]", 173 | u8"测试语言.txt", 174 | u8"abcdefghijklmnopqrstuvwxyzab.txt" 175 | ); 176 | // 150~200ms 177 | } 178 | 179 | BOOST_AUTO_TEST_CASE(JIT_Lookaround) { 180 | JIT_common( 181 | u8"(?>y|(?=[〇-龥])[" DYNAMIC_CHARSET_YY_1 u8"])(?>y|(?=[〇-龥])[" DYNAMIC_CHARSET_YY_2 u8"])", 182 | u8"测试语言.txt", 183 | u8"abcdefg满天都是小星星.txt" 184 | ); 185 | // 700~900ms 186 | JIT_common( 187 | u8"(?>y|(?=[〇-龥])[" DYNAMIC_CHARSET_YY_1 u8"])(?>y|(?=[〇-龥])[" DYNAMIC_CHARSET_YY_2 u8"])", 188 | u8"测试语言.txt", 189 | u8"abcdefghijklmnopqrstuvwxyzab.txt" 190 | ); 191 | // 120~150ms 192 | } 193 | 194 | BOOST_AUTO_TEST_CASE(JIT_CharacterClass) { 195 | JIT_common( 196 | u8"[[:alpha:]][[:alpha:]]", 197 | u8"000111yy.txt", 198 | u8"0123456满天都是小星星.txt", 199 | 1 200 | ); 201 | // 150~200ms 202 | JIT_common( 203 | u8"[[:alpha:]][[:alpha:]]", 204 | u8"000111yy.txt", 205 | u8"0123456789!@#$%^&.....0123456789" 206 | ); 207 | // 270~350ms 208 | } 209 | 210 | BOOST_AUTO_TEST_CASE(JIT_PlainOrHanzi) { 211 | JIT_common( 212 | u8"(?>yy|[y〇-龥]{2})", 213 | u8"000111语言.txt", 214 | u8"abcdefg满天都是小星星.txt", 215 | 1 216 | ); 217 | // 120~150ms 218 | JIT_common( 219 | u8"(?>yy|[y〇-龥]{2})", 220 | u8"000111语言.txt", 221 | u8"abcdefghijklmnopqrstuvwxyzab.txt" 222 | ); 223 | // 130~160ms 224 | } 225 | 226 | BOOST_AUTO_TEST_CASE(JIT_PlainXorHanzi) { 227 | JIT_common( 228 | u8"(?>yy|[〇-龥]{2})", 229 | u8"000111语言.txt", 230 | u8"abcdefg满天都是小星星.txt", 231 | 1 232 | ); 233 | // 120~150ms 234 | } 235 | 236 | BOOST_AUTO_TEST_CASE(JIT_Plain) { 237 | JIT_common( 238 | u8"yy", 239 | u8"测试yy.txt", 240 | u8"abcdefg满天都是小星星.txt" 241 | ); 242 | // 70~90ms 243 | } 244 | 245 | BOOST_AUTO_TEST_CASE(DFA) { 246 | std::u8string_view pattern = u8"[y" DYNAMIC_CHARSET_YY_1 u8"][y" DYNAMIC_CHARSET_YY_2 u8"]"; 247 | int errorcode, erroroffset; 248 | const char* error; 249 | pcre* re = pcre_compile2((const char*)pattern.data(), PCRE_UCP | PCRE_UTF8 | PCRE_CASELESS, &errorcode, &error, &erroroffset, nullptr); 250 | 251 | int offsets[30], result; 252 | int workspace[4096]; 253 | 254 | result = pcre_dfa_exec(re, nullptr, (const char*)u8"测试语言.txt", 16, 0, 0, offsets, std::size(offsets), workspace, std::size(workspace)); 255 | BOOST_REQUIRE(result > 0 && offsets[0] == 6); 256 | 257 | std::u8string_view subject(u8"abcdefg满天都是小星星.txt"); 258 | DWORD t = timeGetTime(); 259 | for (size_t i = 0; i < 1'000'000; i++) { 260 | result = pcre_dfa_exec(re, nullptr, (const char*)subject.data(), subject.size(), 0, 0, offsets, std::size(offsets), workspace, std::size(workspace)); 261 | } 262 | t = timeGetTime() - t; 263 | BOOST_CHECK(result == -1); 264 | 265 | pcre_free(re); 266 | 267 | BOOST_TEST_MESSAGE(t << "ms"); 268 | // 4900~5600ms 269 | } 270 | 271 | BOOST_AUTO_TEST_SUITE_END() 272 | 273 | 274 | BOOST_AUTO_TEST_SUITE(PCRE2) 275 | 276 | BOOST_AUTO_TEST_CASE(Compile) { 277 | std::u8string_view pattern = u8"[y" DYNAMIC_CHARSET_YY_1 u8"][y" DYNAMIC_CHARSET_YY_2 u8"]"; 278 | int errorcode; 279 | PCRE2_SIZE erroroffset; 280 | pcre2_code* re = pcre2_compile((PCRE2_SPTR)pattern.data(), pattern.size(), PCRE2_UCP | PCRE2_UTF | PCRE2_CASELESS, &errorcode, &erroroffset, nullptr); 281 | 282 | pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(re, nullptr); 283 | 284 | int result = pcre2_match(re, (PCRE2_SPTR)u8"测试语言.txt", 16, 0, 0, match_data, nullptr); 285 | BOOST_REQUIRE(result > 0 && pcre2_get_ovector_pointer(match_data)[0] == 6); 286 | 287 | std::u8string_view subject(u8"abcdefg满天都是小星星.txt"); 288 | DWORD t = timeGetTime(); 289 | for (size_t i = 0; i < 1'000'000; i++) { 290 | result = pcre2_match(re, (PCRE2_SPTR)subject.data(), subject.size(), 0, 0, match_data, nullptr); 291 | } 292 | t = timeGetTime() - t; 293 | BOOST_CHECK(result == -1); 294 | 295 | pcre2_match_data_free(match_data); 296 | pcre2_code_free(re); 297 | 298 | BOOST_TEST_MESSAGE(t << "ms"); 299 | // 4700~4900ms 300 | } 301 | 302 | BOOST_AUTO_TEST_CASE(JIT) { 303 | std::u8string_view pattern = u8"[y" DYNAMIC_CHARSET_YY_1 u8"][y" DYNAMIC_CHARSET_YY_2 u8"]"; 304 | int errorcode; 305 | PCRE2_SIZE erroroffset; 306 | pcre2_code* re = pcre2_compile((PCRE2_SPTR)pattern.data(), pattern.size(), PCRE2_UCP | PCRE2_UTF | PCRE2_CASELESS, &errorcode, &erroroffset, nullptr); 307 | 308 | pcre2_jit_compile(re, PCRE2_JIT_COMPLETE); 309 | pcre2_match_context* mcontext = pcre2_match_context_create(nullptr); 310 | pcre2_jit_stack* jit_stack = pcre2_jit_stack_create(32 * 1024, 512 * 1024, nullptr); 311 | pcre2_jit_stack_assign(mcontext, nullptr, jit_stack); 312 | 313 | pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(re, nullptr); 314 | 315 | int result = pcre2_match(re, (PCRE2_SPTR)u8"测试语言.txt", 16, 0, 0, match_data, mcontext); 316 | BOOST_REQUIRE(result > 0 && pcre2_get_ovector_pointer(match_data)[0] == 6); 317 | 318 | std::u8string_view subject(u8"abcdefg满天都是小星星.txt"); 319 | DWORD t = timeGetTime(); 320 | for (size_t i = 0; i < 1'000'000; i++) { 321 | result = pcre2_match(re, (PCRE2_SPTR)subject.data(), subject.size(), 0, 0, match_data, mcontext); 322 | } 323 | t = timeGetTime() - t; 324 | BOOST_CHECK(result == -1); 325 | 326 | pcre2_code_free(re); 327 | pcre2_match_data_free(match_data); 328 | pcre2_match_context_free(mcontext); 329 | pcre2_jit_stack_free(jit_stack); 330 | 331 | BOOST_TEST_MESSAGE(t << "ms"); 332 | // 950~1100ms 333 | } 334 | 335 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/test.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {1dbb8594-6baf-34c0-9998-6aa359588998} 34 | 35 | 36 | {169d9787-0f47-3ee4-9056-c52dfc6e922a} 37 | 38 | 39 | {81a0272a-5ef3-30a8-9154-3a5a8df9aa70} 40 | 41 | 42 | 43 | 16.0 44 | Win32Proj 45 | {80718343-f2b4-4358-8d44-321cbe687f92} 46 | test 47 | 10.0 48 | 49 | 50 | 51 | Application 52 | true 53 | v143 54 | Unicode 55 | 56 | 57 | Application 58 | false 59 | v143 60 | true 61 | Unicode 62 | 63 | 64 | Application 65 | true 66 | v143 67 | Unicode 68 | 69 | 70 | Application 71 | false 72 | v143 73 | true 74 | Unicode 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | true 96 | 97 | 98 | false 99 | 100 | 101 | true 102 | 103 | 104 | false 105 | 106 | 107 | x64-windows-static-md 108 | 109 | 110 | x64-windows-static-md 111 | 112 | 113 | 114 | Level3 115 | true 116 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 117 | true 118 | $(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include 119 | stdcpplatest 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Level3 129 | true 130 | true 131 | true 132 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | $(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include 135 | stdcpplatest 136 | 137 | 138 | Console 139 | true 140 | true 141 | true 142 | /PDBALTPATH:https://github.com/Chaoses-Ib/IbEverythingExt %(AdditionalOptions) 143 | 144 | 145 | 146 | 147 | Level3 148 | true 149 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 150 | true 151 | $(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include 152 | stdcpplatest 153 | 154 | 155 | Console 156 | true 157 | 158 | 159 | 160 | 161 | Level3 162 | true 163 | true 164 | true 165 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 166 | true 167 | $(SolutionDir)external\build\_deps\ibeverything-src\include;$(SolutionDir)external\build\_deps\ibwincpp-src\include;$(SolutionDir)external\build\_deps\ibpinyin-src\include 168 | stdcpplatest 169 | 170 | 171 | Console 172 | true 173 | true 174 | true 175 | /PDBALTPATH:https://github.com/Chaoses-Ib/IbEverythingExt %(AdditionalOptions) 176 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /test/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/v1.4.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | BOOST_AUTO_TEST_SUITE(v1_4) 4 | 5 | BOOST_FIXTURE_TEST_SUITE(SingleCharQueryPerformance, Everythings::Everything) 6 | void test_query(Everythings::Everything& ev, std::wstring_view query) { 7 | using namespace Everythings; 8 | 9 | DWORD t = timeGetTime(); 10 | ev.query_send(query, 0, Request::FileName); 11 | QueryResults results = ev.query_get(); 12 | t = timeGetTime() - t; 13 | 14 | BOOST_CHECK(results.found_num); 15 | BOOST_TEST_MESSAGE(t << "ms"); 16 | Sleep(2000); 17 | } 18 | 19 | BOOST_AUTO_TEST_SUITE(Char) 20 | 21 | BOOST_AUTO_TEST_CASE(Char) { 22 | test_query(*this, L"y"); 23 | } 24 | 25 | BOOST_AUTO_TEST_CASE(Regex) { 26 | test_query(*this, L"regex:y"); 27 | } 28 | 29 | BOOST_AUTO_TEST_CASE(RegexSet) { 30 | test_query(*this, L"regex:[y]"); 31 | } 32 | 33 | BOOST_AUTO_TEST_SUITE_END() 34 | 35 | 36 | BOOST_AUTO_TEST_SUITE(Pinyin) 37 | 38 | BOOST_AUTO_TEST_CASE(Base_v03) { 39 | test_query(*this, L"regex:[y" DYNAMIC_CHARSET_Y L"]"); 40 | } 41 | 42 | // very fast 43 | BOOST_AUTO_TEST_CASE(LetterBranch) { 44 | test_query(*this, L"regex:y|[" DYNAMIC_CHARSET_Y L"]"); 45 | } 46 | 47 | BOOST_AUTO_TEST_CASE(LetterBranchCase) { 48 | test_query(*this, L"case:regex:y|Y|[" DYNAMIC_CHARSET_Y L"]"); 49 | } 50 | 51 | BOOST_AUTO_TEST_CASE(Base_v02) { 52 | test_query(*this, L"case:regex:[yY" DYNAMIC_CHARSET_Y L"]"); 53 | } 54 | 55 | // better 56 | BOOST_AUTO_TEST_CASE(Dynamic) { 57 | test_query(*this, L"regex:[y" DYNAMIC_CHARSET_Y L"]"); 58 | } 59 | 60 | // better 61 | BOOST_AUTO_TEST_CASE(Gb2312) { 62 | test_query(*this, L"regex:[y" + pinyin_regex_gb2312 + L"]"); 63 | } 64 | 65 | // faster but not the same 66 | BOOST_AUTO_TEST_CASE(Count) { 67 | // place count before regex! 68 | test_query(*this, L"count:100 regex:[y" + pinyin_regex + L"]"); 69 | } 70 | 71 | // faster but not the same 72 | BOOST_AUTO_TEST_CASE(Boundary) { 73 | test_query(*this, L"regex:\\b[y" + pinyin_regex + L"]"); 74 | } 75 | 76 | // better 77 | BOOST_AUTO_TEST_CASE(Case) { 78 | test_query(*this, L"case:regex:[yY" + pinyin_regex + L"]"); 79 | } 80 | 81 | BOOST_AUTO_TEST_CASE(Base_v01) { 82 | test_query(*this, L"regex:[y" + pinyin_regex + L"]"); 83 | } 84 | 85 | /* 86 | // cpu killer 87 | BOOST_AUTO_TEST_CASE(Branch) { 88 | test_query(*this, L"regex:y|" + pinyin_branch); 89 | } 90 | */ 91 | 92 | // worse 93 | BOOST_AUTO_TEST_CASE(Lookaround1) { 94 | test_query(*this, L"regex:"); 95 | } 96 | 97 | BOOST_AUTO_TEST_CASE(Lookaround2_1) { 98 | // regex:"(?>y|(?=[一-龠])一)" 99 | test_query(*this, L"regex:\"(?>y|(?=[" + pinyin_range + L"])[" + pinyin_regex + L"])\""); 100 | } 101 | 102 | // worse than 1 103 | BOOST_AUTO_TEST_CASE(Lookaround2) { 104 | // regex:"(y|(?=[一-龠])一)" 105 | test_query(*this, L"regex:\"(y|(?=[" + pinyin_range + L"])[" + pinyin_regex + L"])\""); 106 | } 107 | 108 | // worse than 2 109 | BOOST_AUTO_TEST_CASE(Lookaround3) { 110 | // regex:"(y|(?![\x00-\xff])一)" 111 | test_query(*this, L"regex:\"(y|(?![\\x00-\\xff])[" + pinyin_regex + L"])\""); 112 | } 113 | 114 | // worse than 3 115 | BOOST_AUTO_TEST_CASE(Lookaround4) { 116 | // regex:"(y|(?![一-龠])(?!)|一)" 117 | test_query(*this, L"regex:\"(y|(?![" + pinyin_range + L"])(?!)|[" + pinyin_regex + L"])\""); 118 | } 119 | BOOST_AUTO_TEST_SUITE_END() 120 | 121 | BOOST_AUTO_TEST_SUITE_END() 122 | 123 | 124 | BOOST_FIXTURE_TEST_SUITE(MultiCharsQueryPerformance, Everythings::Everything) 125 | void test_query(Everythings::Everything& ev, std::wstring_view query) { 126 | using namespace Everythings; 127 | 128 | DWORD t = timeGetTime(); 129 | ev.query_send(query, 0, Request::FileName); 130 | QueryResults results = ev.query_get(); 131 | t = timeGetTime() - t; 132 | 133 | BOOST_CHECK(results.found_num); 134 | BOOST_TEST_MESSAGE(t << "ms"); 135 | Sleep(2000); 136 | } 137 | 138 | BOOST_AUTO_TEST_SUITE(Char) 139 | 140 | BOOST_AUTO_TEST_CASE(Branch) { 141 | test_query(*this, L"x|y"); 142 | } 143 | 144 | // faster than set? 145 | BOOST_AUTO_TEST_CASE(RegexBranch) { 146 | test_query(*this, L"regex:x|y"); 147 | } 148 | 149 | BOOST_AUTO_TEST_CASE(RegexSet) { 150 | test_query(*this, L"regex:[xy]"); 151 | } 152 | 153 | BOOST_AUTO_TEST_SUITE_END() 154 | 155 | 156 | BOOST_AUTO_TEST_SUITE(Char100) 157 | 158 | BOOST_AUTO_TEST_CASE(RegexSet) { 159 | test_query(*this, L"regex:[一与业严丫丿么义乐乙也予于亏云亚亦亿仡以仪仰伊众优伛伢但佑佗余佚佣佯佻佾侑依侥俑俞俣俨俺倚偃允元兖养冤冶刈刖剡劓勇匀医卣印厂压厌原厣又友台右叶叹吁吆吖吟听吲吾呀呓员呦咏咦咬咽咿哑哕哟哩哽唁唷喁喑喝喻嗌]"); 160 | } 161 | 162 | // very slow 163 | BOOST_AUTO_TEST_CASE(RegexBranch) { 164 | test_query(*this, L"regex:一|与|业|严|丫|丿|么|义|乐|乙|也|予|于|亏|云|亚|亦|亿|仡|以|仪|仰|伊|众|优|伛|伢|但|佑|佗|余|佚|佣|佯|佻|佾|侑|依|侥|俑|俞|俣|俨|俺|倚|偃|允|元|兖|养|冤|冶|刈|刖|剡|劓|勇|匀|医|卣|印|厂|压|厌|原|厣|又|友|台|右|叶|叹|吁|吆|吖|吟|听|吲|吾|呀|呓|员|呦|咏|咦|咬|咽|咿|哑|哕|哟|哩|哽|唁|唷|喁|喑|喝|喻|嗌"); 165 | } 166 | 167 | // very slow 168 | BOOST_AUTO_TEST_CASE(Branch) { 169 | test_query(*this, L"一|与|业|严|丫|丿|么|义|乐|乙|也|予|于|亏|云|亚|亦|亿|仡|以|仪|仰|伊|众|优|伛|伢|但|佑|佗|余|佚|佣|佯|佻|佾|侑|依|侥|俑|俞|俣|俨|俺|倚|偃|允|元|兖|养|冤|冶|刈|刖|剡|劓|勇|匀|医|卣|印|厂|压|厌|原|厣|又|友|台|右|叶|叹|吁|吆|吖|吟|听|吲|吾|呀|呓|员|呦|咏|咦|咬|咽|咿|哑|哕|哟|哩|哽|唁|唷|喁|喑|喝|喻|嗌"); 170 | } 171 | 172 | BOOST_AUTO_TEST_SUITE_END() 173 | 174 | 175 | BOOST_AUTO_TEST_SUITE(Pinyin) 176 | 177 | BOOST_AUTO_TEST_CASE(Base_v03) { 178 | test_query(*this, L"regex:[y" DYNAMIC_CHARSET_YY_1 L"][y" DYNAMIC_CHARSET_YY_2 L"]"); 179 | } 180 | 181 | // slower than Base_v02 182 | BOOST_AUTO_TEST_CASE(LetterBranch) { 183 | // regex:"(y|[英])(y|[语])" 184 | test_query(*this, L"regex:\"(y|[" DYNAMIC_CHARSET_YY_1 L"])(y|[" DYNAMIC_CHARSET_YY_2 L"])\""); 185 | } 186 | 187 | BOOST_AUTO_TEST_CASE(LetterBranch_1) { 188 | // regex:"(?:y|[英])(?:y|[语])" 189 | test_query(*this, L"regex:\"(?:y|[" DYNAMIC_CHARSET_YY_1 L"])(?:y|[" DYNAMIC_CHARSET_YY_2 L"])\""); 190 | } 191 | 192 | BOOST_AUTO_TEST_CASE(LetterBranch_2) { 193 | // regex:"(?>y|[英])(?>y|[语])" 194 | test_query(*this, L"regex:\"(?>y|[" DYNAMIC_CHARSET_YY_1 L"])(?>y|[" DYNAMIC_CHARSET_YY_2 L"])\""); 195 | } 196 | 197 | BOOST_AUTO_TEST_CASE(Base_v02) { 198 | test_query(*this, L"case:regex:[yY" DYNAMIC_CHARSET_YY_1 L"][yY" DYNAMIC_CHARSET_YY_2 L"]"); 199 | } 200 | 201 | BOOST_AUTO_TEST_CASE(DynamicPair) { 202 | test_query(*this, L"regex:[y" DYNAMIC_CHARSET_YY_1 L"][y" DYNAMIC_CHARSET_YY_2 L"]"); 203 | } 204 | 205 | BOOST_AUTO_TEST_CASE(Dynamic) { 206 | test_query(*this, L"regex:[y" DYNAMIC_CHARSET_Y L"]{2}"); 207 | } 208 | 209 | BOOST_AUTO_TEST_CASE(Base_v01) { 210 | test_query(*this, L"regex:[y" + pinyin_regex + L"]{2}"); 211 | } 212 | 213 | BOOST_AUTO_TEST_CASE(Quantifier) { 214 | test_query(*this, L"regex:[y" + pinyin_regex + L"]{2}"); 215 | } 216 | 217 | BOOST_AUTO_TEST_CASE(Repeat) { 218 | test_query(*this, L"regex:[y" + pinyin_regex + L"][y" + pinyin_regex + L"]"); 219 | } 220 | 221 | BOOST_AUTO_TEST_SUITE_END() 222 | 223 | BOOST_AUTO_TEST_SUITE_END() 224 | 225 | 226 | BOOST_FIXTURE_TEST_SUITE(DynamicCharset, Everythings::Everything) 227 | void test_query(Everythings::Everything& ev, std::wstring_view query) { 228 | using namespace Everythings; 229 | 230 | DWORD t = timeGetTime(); 231 | ev.query_send(query, Search::MatchCase, Request::FileName); 232 | QueryResults results = ev.query_get(); 233 | t = timeGetTime() - t; 234 | 235 | BOOST_TEST_MESSAGE(results.available_num << ", " << t << "ms"); 236 | Sleep(2000); 237 | } 238 | 239 | BOOST_AUTO_TEST_CASE(GenerateQuery) { 240 | test_query(*this, L"regex:[〇-𰻞]"); 241 | } 242 | 243 | BOOST_AUTO_TEST_CASE(UpdateQuery) { 244 | test_query(*this, L"rc:"); 245 | } 246 | 247 | BOOST_AUTO_TEST_CASE(UpdateQueryRegex) { 248 | test_query(*this, L"rc: regex:[〇-𰻞]"); 249 | } 250 | 251 | BOOST_AUTO_TEST_SUITE_END() 252 | 253 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/v1.5a.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | BOOST_AUTO_TEST_SUITE(v1_5a) 4 | 5 | BOOST_FIXTURE_TEST_SUITE(SingleCharQueryPerformance, Everythings::Everything) 6 | void test_query(std::wstring_view query) { 7 | using namespace Everythings; 8 | 9 | Everything ev(L"1.5a"); 10 | DWORD t = timeGetTime(); 11 | ev.query_send(query, 0, Request::FileName); 12 | QueryResults results = ev.query_get(); 13 | t = timeGetTime() - t; 14 | 15 | BOOST_CHECK(results.found_num); 16 | BOOST_TEST_MESSAGE(t << "ms"); 17 | Sleep(2000); 18 | } 19 | 20 | BOOST_AUTO_TEST_SUITE(Char) 21 | 22 | BOOST_AUTO_TEST_CASE(Char) { 23 | test_query(L"y"); 24 | } 25 | 26 | BOOST_AUTO_TEST_CASE(Regex) { 27 | test_query(L"regex:y"); 28 | } 29 | 30 | BOOST_AUTO_TEST_CASE(RegexSet) { 31 | test_query(L"regex:[y]"); 32 | } 33 | 34 | BOOST_AUTO_TEST_SUITE_END() 35 | 36 | 37 | BOOST_AUTO_TEST_SUITE(Pinyin) 38 | 39 | BOOST_AUTO_TEST_CASE(Base_v03) { 40 | test_query(L"regex:[y" DYNAMIC_CHARSET_Y L"]"); 41 | } 42 | 43 | BOOST_AUTO_TEST_CASE(LetterBranch) { 44 | test_query(L"regex:y|[" DYNAMIC_CHARSET_Y L"]"); 45 | } 46 | 47 | BOOST_AUTO_TEST_CASE(LetterBranchCase) { 48 | test_query(L"case:regex:y|Y|[" DYNAMIC_CHARSET_Y L"]"); 49 | } 50 | 51 | BOOST_AUTO_TEST_CASE(Base_v02) { 52 | test_query(L"case:regex:[yY" DYNAMIC_CHARSET_Y L"]"); 53 | } 54 | 55 | // better 56 | BOOST_AUTO_TEST_CASE(Dynamic) { 57 | test_query(L"regex:[y" DYNAMIC_CHARSET_Y L"]"); 58 | } 59 | 60 | // better 61 | BOOST_AUTO_TEST_CASE(Gb2312) { 62 | test_query(L"regex:[y" + pinyin_regex_gb2312 + L"]"); 63 | } 64 | 65 | // faster but not the same 66 | BOOST_AUTO_TEST_CASE(Count) { 67 | // place count before regex! 68 | test_query(L"count:100 regex:[y" + pinyin_regex + L"]"); 69 | } 70 | 71 | // faster but not the same 72 | BOOST_AUTO_TEST_CASE(Boundary) { 73 | test_query(L"regex:\\b[y" + pinyin_regex + L"]"); 74 | } 75 | 76 | // better 77 | BOOST_AUTO_TEST_CASE(Case) { 78 | test_query(L"case:regex:[yY" + pinyin_regex + L"]"); 79 | } 80 | 81 | BOOST_AUTO_TEST_CASE(Base_v01) { 82 | test_query(L"regex:[y" + pinyin_regex + L"]"); 83 | } 84 | 85 | /* 86 | // cpu killer 87 | BOOST_AUTO_TEST_CASE(Branch) { 88 | test_query(L"regex:y|" + pinyin_branch); 89 | } 90 | */ 91 | 92 | // worse 93 | BOOST_AUTO_TEST_CASE(Lookaround1) { 94 | test_query(L"regex:"); 95 | } 96 | 97 | BOOST_AUTO_TEST_CASE(Lookaround2_1) { 98 | // regex:(?>y|(?=[一-龠])一) 99 | test_query(L"regex:(?>y|(?=[" + pinyin_range + L"])[" + pinyin_regex + L"])"); 100 | } 101 | 102 | // worse than 1 103 | BOOST_AUTO_TEST_CASE(Lookaround2) { 104 | // regex:(y|(?=[一-龠])一) 105 | test_query(L"regex:(y|(?=[" + pinyin_range + L"])[" + pinyin_regex + L"])"); 106 | } 107 | 108 | // worse than 2 109 | BOOST_AUTO_TEST_CASE(Lookaround3) { 110 | // regex:(y|(?![\x00-\xff])一) 111 | test_query(L"regex:(y|(?![\\x00-\\xff])[" + pinyin_regex + L"])"); 112 | } 113 | 114 | // worse than 3 115 | BOOST_AUTO_TEST_CASE(Lookaround4) { 116 | // regex:(y|(?![一-龠])(?!)|一) 117 | test_query(L"regex:(y|(?![" + pinyin_range + L"])(?!)|[" + pinyin_regex + L"])"); 118 | } 119 | BOOST_AUTO_TEST_SUITE_END() 120 | 121 | BOOST_AUTO_TEST_SUITE_END() 122 | 123 | 124 | BOOST_AUTO_TEST_SUITE(MultiCharsQueryPerformance) 125 | void test_query(std::wstring_view query) { 126 | using namespace Everythings; 127 | 128 | Everything ev(L"1.5a"); 129 | DWORD t = timeGetTime(); 130 | ev.query_send(query, 0, Request::FileName); 131 | QueryResults results = ev.query_get(); 132 | t = timeGetTime() - t; 133 | 134 | BOOST_CHECK(results.found_num); 135 | BOOST_TEST_MESSAGE(t << "ms"); 136 | Sleep(2000); 137 | } 138 | 139 | BOOST_AUTO_TEST_SUITE(Char) 140 | 141 | BOOST_AUTO_TEST_CASE(Branch) { 142 | test_query(L"x|y"); 143 | } 144 | 145 | BOOST_AUTO_TEST_CASE(WildcardsSet) { 146 | test_query(L"wildcards:*[xy]*"); 147 | } 148 | 149 | // faster than set? 150 | BOOST_AUTO_TEST_CASE(RegexBranch) { 151 | test_query(L"regex:x|y"); 152 | } 153 | 154 | BOOST_AUTO_TEST_CASE(RegexSet) { 155 | test_query(L"regex:[xy]"); 156 | } 157 | 158 | BOOST_AUTO_TEST_SUITE_END() 159 | 160 | 161 | BOOST_AUTO_TEST_SUITE(Char100) 162 | 163 | BOOST_AUTO_TEST_CASE(RegexSet) { 164 | test_query(L"regex:[一与业严丫丿么义乐乙也予于亏云亚亦亿仡以仪仰伊众优伛伢但佑佗余佚佣佯佻佾侑依侥俑俞俣俨俺倚偃允元兖养冤冶刈刖剡劓勇匀医卣印厂压厌原厣又友台右叶叹吁吆吖吟听吲吾呀呓员呦咏咦咬咽咿哑哕哟哩哽唁唷喁喑喝喻嗌]"); 165 | } 166 | 167 | // slow 168 | BOOST_AUTO_TEST_CASE(WildcardsSet) { 169 | test_query(L"wildcards:*[一与业严丫丿么义乐乙也予于亏云亚亦亿仡以仪仰伊众优伛伢但佑佗余佚佣佯佻佾侑依侥俑俞俣俨俺倚偃允元兖养冤冶刈刖剡劓勇匀医卣印厂压厌原厣又友台右叶叹吁吆吖吟听吲吾呀呓员呦咏咦咬咽咿哑哕哟哩哽唁唷喁喑喝喻嗌]*"); 170 | } 171 | 172 | // very slow 173 | BOOST_AUTO_TEST_CASE(RegexBranch) { 174 | test_query(L"regex:一|与|业|严|丫|丿|么|义|乐|乙|也|予|于|亏|云|亚|亦|亿|仡|以|仪|仰|伊|众|优|伛|伢|但|佑|佗|余|佚|佣|佯|佻|佾|侑|依|侥|俑|俞|俣|俨|俺|倚|偃|允|元|兖|养|冤|冶|刈|刖|剡|劓|勇|匀|医|卣|印|厂|压|厌|原|厣|又|友|台|右|叶|叹|吁|吆|吖|吟|听|吲|吾|呀|呓|员|呦|咏|咦|咬|咽|咿|哑|哕|哟|哩|哽|唁|唷|喁|喑|喝|喻|嗌"); 175 | } 176 | 177 | // very slow 178 | BOOST_AUTO_TEST_CASE(Branch) { 179 | test_query(L"一|与|业|严|丫|丿|么|义|乐|乙|也|予|于|亏|云|亚|亦|亿|仡|以|仪|仰|伊|众|优|伛|伢|但|佑|佗|余|佚|佣|佯|佻|佾|侑|依|侥|俑|俞|俣|俨|俺|倚|偃|允|元|兖|养|冤|冶|刈|刖|剡|劓|勇|匀|医|卣|印|厂|压|厌|原|厣|又|友|台|右|叶|叹|吁|吆|吖|吟|听|吲|吾|呀|呓|员|呦|咏|咦|咬|咽|咿|哑|哕|哟|哩|哽|唁|唷|喁|喑|喝|喻|嗌"); 180 | } 181 | 182 | BOOST_AUTO_TEST_SUITE_END() 183 | 184 | 185 | BOOST_AUTO_TEST_SUITE(Pinyin) 186 | 187 | BOOST_AUTO_TEST_CASE(Base_v03) { 188 | test_query(L"regex:[y" DYNAMIC_CHARSET_YY_1 L"][y" DYNAMIC_CHARSET_YY_2 L"]"); 189 | } 190 | 191 | // slower than Base_v02 192 | BOOST_AUTO_TEST_CASE(LetterBranch) { 193 | // regex:(y|[英])(y|[语]) 194 | test_query(L"regex:(y|[" DYNAMIC_CHARSET_YY_1 L"])(y|[" DYNAMIC_CHARSET_YY_2 L"])"); 195 | } 196 | 197 | BOOST_AUTO_TEST_CASE(LetterBranch_1) { 198 | // regex:(?:y|[英])(?:y|[语]) 199 | test_query(L"regex:(?:y|[" DYNAMIC_CHARSET_YY_1 L"])(?:y|[" DYNAMIC_CHARSET_YY_2 L"])"); 200 | } 201 | 202 | BOOST_AUTO_TEST_CASE(LetterBranch_2) { 203 | // regex:(?>y|[英])(?>y|[语]) 204 | test_query(L"regex:(?>y|[" DYNAMIC_CHARSET_YY_1 L"])(?>y|[" DYNAMIC_CHARSET_YY_2 L"])"); 205 | } 206 | 207 | BOOST_AUTO_TEST_CASE(Base_v02) { 208 | test_query(L"case:regex:[yY" DYNAMIC_CHARSET_YY_1 L"][yY" DYNAMIC_CHARSET_YY_2 L"]"); 209 | } 210 | 211 | BOOST_AUTO_TEST_CASE(DynamicPair) { 212 | test_query(L"regex:[y" DYNAMIC_CHARSET_YY_1 L"][y" DYNAMIC_CHARSET_YY_2 L"]"); 213 | } 214 | 215 | BOOST_AUTO_TEST_CASE(Dynamic) { 216 | test_query(L"regex:[y" DYNAMIC_CHARSET_Y L"]{2}"); 217 | } 218 | 219 | BOOST_AUTO_TEST_CASE(Base_v01) { 220 | test_query(L"regex:[y" + pinyin_regex + L"]{2}"); 221 | } 222 | 223 | BOOST_AUTO_TEST_CASE(Quantifier) { 224 | test_query(L"regex:[y" + pinyin_regex + L"]{2}"); 225 | } 226 | 227 | BOOST_AUTO_TEST_CASE(Repeat) { 228 | test_query(L"regex:[y" + pinyin_regex + L"][y" + pinyin_regex + L"]"); 229 | } 230 | 231 | BOOST_AUTO_TEST_SUITE_END() 232 | 233 | BOOST_AUTO_TEST_SUITE_END() 234 | 235 | 236 | BOOST_FIXTURE_TEST_SUITE(DynamicCharset, Everythings::Everything) 237 | void test_query(std::wstring_view query) { 238 | using namespace Everythings; 239 | 240 | Everything ev(L"1.5a"); 241 | DWORD t = timeGetTime(); 242 | ev.query_send(query, Search::MatchCase, Request::FileName); 243 | QueryResults results = ev.query_get(); 244 | t = timeGetTime() - t; 245 | 246 | BOOST_TEST_MESSAGE(results.available_num << ", " << t << "ms"); 247 | Sleep(2000); 248 | } 249 | 250 | BOOST_AUTO_TEST_CASE(GenerateQuery) { 251 | test_query(L"regex:[〇-𰻞]"); 252 | } 253 | 254 | BOOST_AUTO_TEST_CASE(UpdateQuery) { 255 | test_query(L"rc:"); 256 | } 257 | 258 | BOOST_AUTO_TEST_CASE(UpdateQueryRegex) { 259 | test_query(L"rc: regex:[〇-𰻞]"); 260 | } 261 | 262 | BOOST_AUTO_TEST_SUITE_END() 263 | 264 | BOOST_AUTO_TEST_SUITE_END() --------------------------------------------------------------------------------