flea-qml 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +402 -0
  51. package/src/archiveops.js +697 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +129 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,186 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "js/PathBar.js" as PathBar
4
+
5
+ // The path bar's typed half for the main chrome and the picker: field, frame, Jump dropdown and Tab; hosts answer its commits.
6
+ Item {
7
+ id: root
8
+
9
+ property string path: ""
10
+ property string home: ""
11
+ // Read by the path bar alone, so a Tab on a dotted leaf peeks the way the listing is set to look.
12
+ property bool showHidden: false
13
+
14
+ // The commit and the jump's choice, which each host answers for itself.
15
+ signal commitLine(string text)
16
+ signal jumpChosen(string path)
17
+ signal editClosed()
18
+ signal completeRequested(string dir, bool hidden)
19
+ signal said(string text)
20
+ // The folder jump's one read per open, carried to the pane's backend like Tab's peek; see ui/PathJump.qml.
21
+ signal jumpRequested(int id, int ranking, var favourites, var recent)
22
+
23
+ // Built by the first edit and kept for the window's life, so a bar never opened compiles none of it.
24
+ property bool jumpBuilt: false
25
+ readonly property var jump: jumpLoader.item
26
+ readonly property bool jumpShown: jumpLoader.item !== null && jumpLoader.item.shown
27
+ // What the seam reads: the line as it stands.
28
+ readonly property alias editText: field.text
29
+ // The open field and its frame, so a test measures where they lie in the strip.
30
+ readonly property alias pathFrame: editFrame
31
+ readonly property alias pathField: field
32
+
33
+ // The Tab request in flight and the one that came back, keyed by path and hidden flag, so a Tab on ".conf" never answers off rows peeked without dotfiles.
34
+ property string pendingKey: ""
35
+ property string cachedKey: ""
36
+ property var cachedNames: []
37
+
38
+ // The strip typed instead of drawn: keys.toml's pathBar action (":" and Ctrl+L) and a double click on the path open it.
39
+ property bool editing: false
40
+
41
+ function startEdit() {
42
+ if (root.editing) {
43
+ return
44
+ }
45
+ // The Loader below is synchronous, so the jump stands before this returns.
46
+ root.jumpBuilt = true
47
+ root.editing = true
48
+ // The trailing slash makes a child the next keystroke, and the line opens selected so a typed name replaces it.
49
+ field.text = PathBar.editLine(root.path)
50
+ field.forceActiveFocus()
51
+ field.selectAll()
52
+ }
53
+
54
+ function closeEdit() {
55
+ if (!root.editing) {
56
+ return
57
+ }
58
+ root.editing = false
59
+ root.pendingKey = ""
60
+ root.cachedKey = ""
61
+ root.cachedNames = []
62
+ // The field is in no focus scope of its own, so the keyboard goes nowhere until the host answers editClosed.
63
+ root.editClosed()
64
+ }
65
+
66
+ // Tab completes from the backend's peek, the read the columns view already makes, so it costs no new request type.
67
+ function completeEdit() {
68
+ // A virtual root has no filesystem completion; never send it to peek.
69
+ if (PathBar.isTrashRoot(field.text)) return
70
+ var dir = PathBar.completionDir(field.text, PathBar.isTrashRoot(root.path) ? "/" : root.path, root.home)
71
+ var hidden = PathBar.wantsHidden(field.text, root.showHidden)
72
+ var key = PathBar.requestKey(dir, hidden)
73
+ if (key === root.cachedKey) {
74
+ root.applyCompletion(dir, root.cachedNames)
75
+ return
76
+ }
77
+ root.pendingKey = key
78
+ root.completeRequested(dir, hidden)
79
+ }
80
+
81
+ // Column peeks and a Tab's dotfile retry share the wire, so a reply matches on the echoed (dir, hidden) pair; only directories complete.
82
+ function completeWith(dir, hidden, rows) {
83
+ if (PathBar.requestKey(dir, hidden) !== root.pendingKey) {
84
+ return
85
+ }
86
+ var names = []
87
+ for (var i = 0; i < rows.length; i++) {
88
+ if (rows[i].d) {
89
+ names.push(rows[i].n)
90
+ }
91
+ }
92
+ root.cachedKey = root.pendingKey
93
+ root.cachedNames = names
94
+ root.pendingKey = ""
95
+ if (root.editing && PathBar.completionDir(field.text, PathBar.isTrashRoot(root.path) ? "/" : root.path, root.home) === dir) {
96
+ root.applyCompletion(dir, names)
97
+ }
98
+ }
99
+
100
+ function applyCompletion(dir, names) {
101
+ var before = field.text
102
+ var after = PathBar.complete(before, names)
103
+ field.text = after.text
104
+ field.cursorPosition = field.text.length
105
+ var say = PathBar.completionMessage(before, after, dir)
106
+ if (say.length > 0) {
107
+ root.said(say)
108
+ }
109
+ }
110
+
111
+ // The rename editor's own frame, at chrome scale: the accent marks the strip with the keyboard, and its fill covers the two Texts beneath.
112
+ Rectangle {
113
+ id: editFrame
114
+ visible: root.editing
115
+ anchors.fill: parent
116
+ anchors.topMargin: Theme.spacing.hairline * 2
117
+ // One below against two above centres the field in the strip, which is the flush dropdown the Jump board draws.
118
+ anchors.bottomMargin: Theme.spacing.hairline
119
+ color: Theme.color.background
120
+ radius: Style.cornerRadius
121
+ border.width: Theme.spacing.hairline
122
+ border.color: Theme.color.accent
123
+ }
124
+
125
+ // corner: a typed path is arbitrary text, drawn at the size of the path it replaces, the caret on the line.
126
+ TextInput {
127
+ id: field
128
+ visible: root.editing
129
+ enabled: root.editing
130
+ anchors.fill: parent
131
+ anchors.leftMargin: Theme.spacing.gap
132
+ anchors.rightMargin: Theme.spacing.gap
133
+ verticalAlignment: TextInput.AlignVCenter
134
+ color: Theme.color.foreground
135
+ selectionColor: Theme.color.accent
136
+ selectedTextColor: Theme.color.background
137
+ font.family: Theme.font.family
138
+ font.pixelSize: Theme.font.caption
139
+ clip: true
140
+ // The jump's dropdown takes the arrows and Enter first, and only while it is showing rows.
141
+ Keys.forwardTo: root.jump !== null ? [root.jump] : []
142
+
143
+ // Each key here is accepted, as in ui/RenameField.qml: the pane would read an unaccepted Return as "open the row" and Tab as "move to the rail".
144
+ Keys.onPressed: function (event) {
145
+ if (event.key === Qt.Key_Escape) {
146
+ root.closeEdit()
147
+ event.accepted = true
148
+ return
149
+ }
150
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
151
+ root.commitLine(field.text)
152
+ event.accepted = true
153
+ return
154
+ }
155
+ if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) {
156
+ root.completeEdit()
157
+ event.accepted = true
158
+ }
159
+ }
160
+
161
+ // Losing the keyboard closes the bar, as the rename editor does, so it never commits against a window that has moved on.
162
+ onActiveFocusChanged: if (!activeFocus && root.editing) root.closeEdit()
163
+ }
164
+
165
+ // The Jump board's dropdown, flush under this field at its width from the path slot its Loader fills.
166
+ Loader {
167
+ id: jumpLoader
168
+ anchors.fill: parent
169
+ active: root.jumpBuilt
170
+ asynchronous: false
171
+ source: "PathJump.qml"
172
+ // Live bindings onto the lazy item, kept after the bar closes; set here so a bar never opened adds no Binding objects.
173
+ onLoaded: {
174
+ item.editing = Qt.binding(function () { return root.editing })
175
+ item.query = Qt.binding(function () { return field.text })
176
+ item.home = Qt.binding(function () { return root.home })
177
+ }
178
+ }
179
+ Connections {
180
+ target: jumpLoader.item
181
+ function onRequested(id, ranking, favourites, recent) { root.jumpRequested(id, ranking, favourites, recent) }
182
+ function onDeclined() { root.commitLine(field.text) }
183
+ function onDismissed() { root.closeEdit() }
184
+ function onChosen(path) { root.jumpChosen(path) }
185
+ }
186
+ }
@@ -0,0 +1,400 @@
1
+ import QtQuick
2
+ import Quickshell
3
+ import Quickshell.Io
4
+ import qs.Commons
5
+ import "." as Flea
6
+ import "js/Jump.js" as Jump
7
+ import "js/Recent.js" as Recent
8
+
9
+ // The path bar's folder jump, the Jump board: a name typed into the bar lists matching folders from
10
+ // Flea's favourites, zoxide's ranking and the desktop's recent history in a dropdown flush under the
11
+ // field, at its width and in the menu recipe. ui/ChromeBar.qml owns the field and forwards its keys
12
+ // here; ui/js/Jump.js decides the rows. Nothing is written anywhere, and zoxide is asked once per open.
13
+ Item {
14
+ id: root
15
+
16
+ property bool editing: false
17
+ // The field's line as typed; ui/js/Jump.js decides whether it is a name to jump by or a path.
18
+ property string query: ""
19
+ property string home: ""
20
+ // The tallest the dropdown may be before it scrolls: the window less the chrome strip above and the
21
+ // status bar below, both a chrome strip tall, and a gap clear of the status bar.
22
+ readonly property real room: (root.Window.window ? root.Window.window.height : 0) - 2 * Theme.chromeHeight - Theme.spacing.gap
23
+
24
+ // The backend's answer for this open, { favourites, zoxide, recent }, empty until it arrives.
25
+ property var sources: ({})
26
+ readonly property bool answered: root.sources.favourites !== undefined
27
+ // The same answer folded once for ranking: every keystroke ranks out of this instead of folding
28
+ // every candidate again, so a keystroke costs the alignment alone. Dropped with sources below,
29
+ // so one open never keeps the next one's folds.
30
+ property var prepared: null
31
+ // Tab is the path bar's own completion, so a line it has touched is a path for the rest of the edit:
32
+ // with two children sharing a prefix it stops short of the slash, and Enter still means ./that.
33
+ property bool pathTyped: false
34
+ readonly property var entries: root.editing && !root.pathTyped && root.prepared !== null
35
+ ? Jump.rowsPrepared(root.prepared, root.query) : []
36
+ property int cursor: -1
37
+ readonly property bool shown: root.entries.length > 0
38
+ // The high-water row count of this open: the Repeater holds this many delegates standing and
39
+ // hides the tail past the entries, so a keystroke that narrows the list rebinds rows instead
40
+ // of rebuilding them. Reset with the open below.
41
+ property int rowHighWater: 0
42
+ // Every ask carries a new id and take() keeps only the newest open's answers, so a slow answer to
43
+ // an earlier ask can never land in this one, or move a cursor the user has already moved.
44
+ property int asked: 0
45
+ // An open whose history is stale asks twice: a provisional ask with what is kept, so the
46
+ // dropdown fills from the backend's answer instead of waiting out the history read, and the whole
47
+ // ask under a new id once the read lands. take() shows the provisional rows but only the whole
48
+ // answer spends a held Enter or settles wholeTaken; a provisional answer landing after the whole
49
+ // one is dropped like a stale one. The whole ask waits for the provisional answer as well as the
50
+ // read, so the two backend calls never overlap on the backend's one zoxide slot.
51
+ property int provisionalId: 0
52
+ property bool wholeTaken: false
53
+ // The provisional answer has landed, and the whole ask has been sent; one whole ask per open.
54
+ property bool provTaken: false
55
+ property bool wholeAsked: false
56
+ // Enter on a name before this open's answer is in: held, then taken by the answer, so the same keys
57
+ // open the same folder however fast they were typed.
58
+ property bool enterWaiting: false
59
+ // Where any row last saw the pointer, so rows changing under a resting pointer never move the cursor; see ui/MenuRow.qml.
60
+ property point pointerGlobal: Qt.point(-1, -1)
61
+ // Rows appearing under a resting pointer must not take the cursor either: moves are ignored
62
+ // until the first frame after rows appear, the way ui/ContextMenu.qml settles them.
63
+ property bool pointerSettling: false
64
+ Connections {
65
+ target: root.pointerSettling ? root.Window.window : null
66
+ function onAfterAnimating() { root.pointerSettling = false }
67
+ }
68
+
69
+ // ui/WindowBody.qml carries these to the pane's backend and back, the way it carries the bar's Tab.
70
+ // ranking is the provisional ask this whole ask follows, or 0: the backend answers it from that ask's zoxide run.
71
+ signal requested(int id, int ranking, var favourites, var recent)
72
+ signal chosen(string path)
73
+ // Enter that the dropdown did not take after all: nothing matched, so the bar resolves the line as a path.
74
+ signal declined()
75
+ // A click on the dropdown's own padding: the bar closes with nothing opened, the menu recipe.
76
+ signal dismissed()
77
+ // For tests/jump-ui.sh: whether the dropdown's frame stands, and the frame itself while it does.
78
+ readonly property bool dropBuilt: drop.item !== null
79
+ readonly property var dropItem: drop.item
80
+
81
+ // The keys arrive through the field's Keys.forwardTo, which skips an invisible item, so this stays
82
+ // visible for the whole edit and hands back every key it does not use; only the dropdown unloads.
83
+ visible: root.editing
84
+ // The parent is the bar's path slot, which stops a hairline above the strip's bottom edge.
85
+ y: root.parent ? root.parent.height + Theme.spacing.hairline : 0
86
+ width: root.parent ? root.parent.width : 0
87
+ height: drop.item ? drop.item.height : 0
88
+
89
+ onEntriesChanged: {
90
+ root.rowHighWater = Math.max(root.rowHighWater, root.entries.length)
91
+ root.cursor = Jump.step(root.entries, -1, 1)
92
+ }
93
+ // The rows live behind the Loader below, so a cursor moved while they stand unbuilt asks nothing.
94
+ onCursorChanged: { if (drop.item) drop.item.reveal(root.cursor) }
95
+ onShownChanged: {
96
+ if (!root.shown) {
97
+ return
98
+ }
99
+ root.pointerGlobal = Qt.point(-1, -1)
100
+ root.pointerSettling = true
101
+ // An appearance that changes nothing drawn schedules no frame, so it asks for the one
102
+ // that ends the settle, the way ui/ContextMenu.qml's place() does.
103
+ if (root.Window.window) root.Window.window.update()
104
+ }
105
+ onEditingChanged: {
106
+ root.sources = ({})
107
+ root.rowHighWater = 0
108
+ root.prepared = null
109
+ root.enterWaiting = false
110
+ root.pathTyped = false
111
+ root.provisionalId = 0
112
+ root.wholeTaken = false
113
+ root.provTaken = false
114
+ root.wholeAsked = false
115
+ root.pointerGlobal = Qt.point(-1, -1)
116
+ root.pointerSettling = false
117
+ root.asked += 1
118
+ if (!root.editing) {
119
+ return
120
+ }
121
+ if (root.historyKept && root.historyReadAt === root.historyChanges) {
122
+ root.wholeAsked = true
123
+ root.ask(0)
124
+ } else {
125
+ root.provisionalId = root.asked
126
+ root.ask(0)
127
+ root.readHistory()
128
+ }
129
+ }
130
+
131
+ // The recent history, read once and kept until the file changes, so an open with it unchanged asks at
132
+ // once: re-reading 5,000 bookmarks on every open cost the dropdown some 70 ms, measured.
133
+ property var recentPaths: []
134
+ property bool historyKept: false
135
+ property bool historyReading: false
136
+ // Every change the watcher has reported, and the count the kept paths were read at.
137
+ property int historyChanges: 0
138
+ property int historyReadAt: -1
139
+ // How many times the history has been parsed; tests/jump-ui.sh reads it.
140
+ property int historyReads: 0
141
+
142
+ function ask(ranking) {
143
+ root.requested(root.asked, ranking, root.favouritePaths(), root.recentPaths)
144
+ }
145
+
146
+ function askWhole() {
147
+ // One whole ask per open, only once the provisional answer and the history read are both in,
148
+ // so the two backend calls never overlap on the backend's one zoxide slot. The read's own
149
+ // staleness is the next open's business: this one asks with the newest paths it has.
150
+ if (!root.editing || root.wholeAsked || !root.provTaken) {
151
+ return
152
+ }
153
+ if (root.provisionalId !== 0 && !(root.historyKept && !root.historyReading)) {
154
+ return
155
+ }
156
+ root.wholeAsked = true
157
+ root.asked += 1
158
+ root.ask(root.provisionalId)
159
+ }
160
+
161
+ // The watch starts before the read, so a change landing while it runs is counted and read next time.
162
+ function readHistory() {
163
+ root.historyReading = true
164
+ root.historyReadAt = root.historyChanges
165
+ watcher.path = Recent.historyPath(Quickshell.env("XDG_DATA_HOME"), Quickshell.env("HOME"))
166
+ recent.active = true
167
+ recent.item.refresh()
168
+ }
169
+
170
+ // Watching only: it never loads the file, and it reports a rename over it, a delete and a re-create alike.
171
+ FileView {
172
+ id: watcher
173
+ preload: false
174
+ watchChanges: true
175
+ onFileChanged: root.historyChanges += 1
176
+ }
177
+
178
+ // The backend's jumped line; one for another open, or landing after the bar closed, is dropped.
179
+ // A provisional answer draws its rows but never spends a held Enter and never settles the open.
180
+ function take(id, favourites, zoxide, recentFolders, frecency) {
181
+ if (!root.editing) {
182
+ return
183
+ }
184
+ var provisional = id === root.provisionalId && root.provisionalId !== 0 && !root.wholeTaken
185
+ if (id !== root.asked && !provisional) {
186
+ return
187
+ }
188
+ var answer = { favourites: favourites, zoxide: zoxide, recent: recentFolders, frecency: frecency || ({}) }
189
+ root.sources = answer
190
+ root.prepared = Jump.prepare(answer, root.home)
191
+ if (provisional) {
192
+ root.provTaken = true
193
+ root.askWhole()
194
+ return
195
+ }
196
+ root.wholeTaken = true
197
+ if (root.enterWaiting) {
198
+ root.enterWaiting = false
199
+ root.enter()
200
+ }
201
+ }
202
+
203
+ // Enter itself: the cursor row when there is one, and otherwise the line as a path, as before the jump.
204
+ function enter() {
205
+ if (root.cursor >= 0) {
206
+ root.chosen(root.entries[root.cursor].path)
207
+ } else {
208
+ root.declined()
209
+ }
210
+ }
211
+
212
+ function favouritePaths() {
213
+ var records = Flea.Favourites.records
214
+ var out = []
215
+ for (var i = 0; i < records.length; i++) {
216
+ out.push(String(records[i].path || ""))
217
+ }
218
+ return out
219
+ }
220
+
221
+ // The picker's own reader of recently-used.xbel, built for a read and dropped after it, so a window whose
222
+ // bar is never typed into loads no XML module at all.
223
+ Loader {
224
+ id: recent
225
+ active: false
226
+ source: "PickerRecent.qml"
227
+ }
228
+
229
+ Connections {
230
+ target: recent.item
231
+ function onRefreshed() {
232
+ root.recentPaths = recent.item.paths
233
+ root.historyKept = true
234
+ root.historyReading = false
235
+ root.historyReads += 1
236
+ // The parsed model goes once its newest paths are kept, which bounds what stays in memory at
237
+ // Recent.LIMIT paths; later, because the reader is the one emitting this signal.
238
+ Qt.callLater(function () { if (!root.historyReading) recent.active = false })
239
+ // The whole ask waits for the provisional answer too, which take() records; either order
240
+ // of the two landings converges on it, and a closed bar asks nothing more.
241
+ root.askWhole()
242
+ }
243
+ }
244
+
245
+ // The backend answers inside its own zoxide and stat budgets, docs/protocol.md "jump"; one that never
246
+ // answers at all, a backend gone, must not hold an Enter for good, so past this the line is a path.
247
+ readonly property int answerLimitMs: 4000
248
+ Timer {
249
+ id: enterLimit
250
+ interval: root.answerLimitMs
251
+ running: root.enterWaiting
252
+ onTriggered: {
253
+ root.enterWaiting = false
254
+ root.declined()
255
+ }
256
+ }
257
+
258
+ Keys.onPressed: function (event) {
259
+ // A held Enter stands for the line as it was, so nothing typed after it changes what it opens; esc still closes.
260
+ if (root.enterWaiting && event.key !== Qt.Key_Escape) {
261
+ event.accepted = true
262
+ return
263
+ }
264
+ if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) {
265
+ root.pathTyped = true
266
+ event.accepted = false
267
+ return
268
+ }
269
+ if (root.shown && (event.key === Qt.Key_Down || event.key === Qt.Key_Up)) {
270
+ root.cursor = Jump.step(root.entries, root.cursor, event.key === Qt.Key_Down ? 1 : -1)
271
+ event.accepted = true
272
+ return
273
+ }
274
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
275
+ if (root.shown) {
276
+ root.enter()
277
+ event.accepted = true
278
+ return
279
+ }
280
+ // Held until the whole answer, not the provisional one, so the same keys open the same
281
+ // folder however fast they were typed; a visible row above already took the press itself.
282
+ if ((!root.answered || !root.wholeTaken) && !root.pathTyped && Jump.isQuery(root.query)) {
283
+ root.enterWaiting = true
284
+ event.accepted = true
285
+ return
286
+ }
287
+ }
288
+ event.accepted = false
289
+ }
290
+
291
+ readonly property int drawnRows: drop.item === null ? 0 : Math.min(root.entries.length, Math.ceil((drop.item.scrollY + drop.item.height - 2 * Theme.spacing.rowPaddingY) / Theme.rowHeight)) - Math.floor(drop.item.scrollY / Theme.rowHeight)
292
+ // The dropdown's frame, built only while rows show: the scroll body, its window listener,
293
+ // both fades and the rows are nothing the first frame shows.
294
+ Loader {
295
+ id: drop
296
+ active: root.shown
297
+ sourceComponent: dropFrame
298
+ }
299
+
300
+ Component {
301
+ id: dropFrame
302
+ Rectangle {
303
+ id: frame
304
+ width: root.width
305
+ height: Math.max(0, Math.min(rows.implicitHeight + 2 * Theme.spacing.rowPaddingY, root.room))
306
+ color: Theme.color.surface
307
+ border.width: Theme.spacing.hairline
308
+ border.color: Theme.color.mutedFrame
309
+ radius: Style.cornerRadius
310
+
311
+ function reveal(index) { scroll.reveal(rowItems.itemAt(index)) }
312
+ // For tests/jump-ui.sh: how many delegates stand, and the one at an index.
313
+ readonly property int liveCount: rowItems.count
314
+ // For the picker's path shots: how far the rows have scrolled.
315
+ readonly property real scrollY: scroll.contentY
316
+ function liveAt(index) { return rowItems.itemAt(index) }
317
+ Component.onCompleted: reveal(root.cursor)
318
+
319
+ // The ground takes every pointer event the rows leave, so nothing reaches the listing beneath.
320
+ MouseArea {
321
+ id: ground
322
+ anchors.fill: parent
323
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
324
+ hoverEnabled: true
325
+ // The sink records the point, so rows appearing under a resting pointer compare
326
+ // against where it already is, the menu's own recipe.
327
+ onEntered: root.pointerGlobal = ground.mapToItem(null, ground.mouseX, ground.mouseY)
328
+ onPositionChanged: function (mouse) { root.pointerGlobal = ground.mapToItem(null, mouse.x, mouse.y) }
329
+ // The recipe's close: a click that hit no row closes the bar with nothing opened.
330
+ onClicked: root.dismissed()
331
+ onWheel: function (wheel) { wheel.accepted = true }
332
+ }
333
+
334
+ Flea.CardScroll {
335
+ id: scroll
336
+ // The dropdown steps the highlight like a menu: one row a notch, one row per
337
+ // row height of gained touchpad travel. The cursor's reveal() follows.
338
+ highlightSteps: true
339
+ stepBy: function (delta) { root.cursor = Jump.step(root.entries, root.cursor, delta) }
340
+ anchors.fill: parent
341
+ anchors.topMargin: Theme.spacing.rowPaddingY
342
+ anchors.bottomMargin: Theme.spacing.rowPaddingY
343
+
344
+ Column {
345
+ id: rows
346
+ width: parent.width
347
+
348
+ Repeater {
349
+ id: rowItems
350
+ // The high-water count, so a keystroke that narrows the list leaves every
351
+ // delegate standing: rows rebind to entries[index] instead of rebuilding, and
352
+ // the tail past the entries hides. The max against the entries covers a growth
353
+ // the high-water handler has not recorded yet, whichever runs first.
354
+ model: Math.max(root.rowHighWater, root.entries.length)
355
+ // The menu's own row, so the lift, the mark slot and the pointer rules are the context menu's;
356
+ // the label is the path the chrome would draw, laid over its empty one.
357
+ delegate: Flea.MenuRow {
358
+ id: row
359
+ required property int index
360
+ // The row at this slot of the newest answer, undefined mid-swap or past it.
361
+ // A hidden tail keeps its delegate standing at zero height, because an
362
+ // invisible item still holds its Column position.
363
+ readonly property var rowData: root.entries[row.index]
364
+ readonly property bool rowStanding: row.index < root.entries.length
365
+ visible: row.rowStanding
366
+ height: row.rowStanding ? Theme.rowHeight : 0
367
+ width: rows.width
368
+ entry: ({ glyph: "folder", label: "", hint: "" })
369
+ current: root.cursor === row.index
370
+ lastPointerGlobal: root.pointerGlobal
371
+ onPointerSeen: function (at) { root.pointerGlobal = at }
372
+ onPointerMoved: { if (!root.pointerSettling) root.cursor = row.index }
373
+ onActivated: { if (row.rowData !== undefined) root.chosen(row.rowData.path) }
374
+
375
+ Flea.JumpPath {
376
+ entry: row.rowData !== undefined ? row.rowData : ({})
377
+ anchors.left: parent.left
378
+ anchors.leftMargin: Theme.spacing.rowPaddingX + row.slotSize + Theme.spacing.gap
379
+ anchors.right: parent.right
380
+ anchors.rightMargin: Theme.spacing.rowPaddingX
381
+ anchors.verticalCenter: parent.verticalCenter
382
+ }
383
+ }
384
+ }
385
+ }
386
+ }
387
+
388
+ Flea.MenuEdgeFade {
389
+ anchors.top: parent.top
390
+ visible: scroll.contentY > 0
391
+ }
392
+
393
+ Flea.MenuEdgeFade {
394
+ anchors.bottom: parent.bottom
395
+ visible: scroll.contentY + scroll.height < scroll.contentHeight
396
+ rotation: 180
397
+ }
398
+ }
399
+ }
400
+ }