flea-qml 0.0.0-stage → 0.2.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 (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -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 +407 -0
  51. package/src/archiveops.js +728 -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 +135 -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/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,158 @@
1
+ .pragma library
2
+
3
+ // A row this listing has dealt with: null means asked and waiting, a string is the answer.
4
+ // A cache-only ask carries a mark, so its empty answer means "not tried" and a class switch forgets it.
5
+ var ASKED = null
6
+ var CACHE_ASKED = "cache-asked"
7
+ var CACHE_MISS = "cache-missed"
8
+
9
+ // Asked and not answered yet, a plain ask or a cache-only one; only these have a job to cancel.
10
+ function pending(value) {
11
+ return value === ASKED || value === CACHE_ASKED
12
+ }
13
+
14
+ function empty() {
15
+ return { file: {}, order: [] }
16
+ }
17
+
18
+ // The rows a request may name: the viewport in row indices, clamped to the last row of the listing.
19
+ function viewport(contentY, rowHeight, visibleRows, total) {
20
+ var first = Math.floor(contentY / rowHeight)
21
+ // A window that is not row aligned straddles one more row than it holds, so the bottom comes off its pixel extent.
22
+ var bottom = contentY + visibleRows * rowHeight
23
+ return { first: first, last: Math.min(total - 1, Math.ceil(bottom / rowHeight) - 1) }
24
+ }
25
+
26
+ // Only visible rows, only rows the backend called thumbnailable, only rows never asked.
27
+ function plan(state, rows, held, first, last, mode) {
28
+ var ask = []
29
+ for (var i = first; i <= last; i++) {
30
+ if (state.file[i] !== undefined) {
31
+ continue
32
+ }
33
+ var row = rows[i - held]
34
+ if (allowed(row, mode)) {
35
+ ask.push(i)
36
+ }
37
+ }
38
+ var drop = []
39
+ for (var key in state.file) {
40
+ if (!pending(state.file[key])) {
41
+ continue
42
+ }
43
+ var at = Number(key)
44
+ if (at < first || at > last || !allowed(rows[at - held], mode)) {
45
+ drop.push(at)
46
+ }
47
+ }
48
+ return { ask: ask, drop: drop }
49
+ }
50
+
51
+ // A cancelled row is forgotten here too, because the backend forgets it when it drops the job.
52
+ function forget(state, row) {
53
+ delete state.file[row]
54
+ var at = state.order.indexOf(row)
55
+ if (at >= 0) {
56
+ state.order.splice(at, 1)
57
+ }
58
+ }
59
+
60
+ // A miss on a generating class returns to unasked; on a cache-only class it stays a miss.
61
+ function miss(state, row, generating, cap) {
62
+ if (generating === true) {
63
+ forget(state, row)
64
+ return { file: state.file, order: state.order }
65
+ }
66
+ return remember(state, row, "", cap)
67
+ }
68
+
69
+ // The wrapper is new so a QML binding on it re-evaluates; the map inside is mutated in place.
70
+ function applied(state, work) {
71
+ for (var i = 0; i < work.drop.length; i++) {
72
+ forget(state, work.drop[i])
73
+ }
74
+ var mark = work.cacheOnly === true ? CACHE_ASKED : ASKED
75
+ for (var j = 0; j < work.ask.length; j++) {
76
+ state.file[work.ask[j]] = mark
77
+ state.order.push(work.ask[j])
78
+ }
79
+ return { file: state.file, order: state.order }
80
+ }
81
+
82
+ // A live answer re-lists some rows: each finished thumbnail follows its row, by name, to that row's new index. Asked and missed rows do not follow.
83
+ function carried(state, oldRows, oldHeld, newRows, newHeld) {
84
+ var at = Object.create(null)
85
+ for (var j = 0; j < newRows.length; j++) {
86
+ if (newRows[j].t) {
87
+ at[newRows[j].n] = newHeld + j
88
+ }
89
+ }
90
+ var next = empty()
91
+ for (var k = 0; k < state.order.length; k++) {
92
+ var file = state.file[state.order[k]]
93
+ var row = oldRows[state.order[k] - oldHeld]
94
+ if (file && file !== CACHE_ASKED && file !== CACHE_MISS && row && at[row.n] !== undefined) {
95
+ next.file[at[row.n]] = file
96
+ next.order.push(at[row.n])
97
+ }
98
+ }
99
+ return next
100
+ }
101
+
102
+ // The cap bounds a policy bug, not normal use: only the rows a viewport held are ever recorded.
103
+ function remember(state, row, file, cap) {
104
+ if (state.file[row] === undefined) {
105
+ state.order.push(row)
106
+ }
107
+ // An empty answer to a cache-only ask was never a decode, so it keeps its mark.
108
+ state.file[row] = (file === "" && state.file[row] === CACHE_ASKED) ? CACHE_MISS : file
109
+ while (state.order.length > cap) {
110
+ delete state.file[state.order.shift()]
111
+ }
112
+ return { file: state.file, order: state.order }
113
+ }
114
+
115
+ function fileFor(state, row) {
116
+ var value = state.file[row]
117
+ if (value === CACHE_ASKED || value === CACHE_MISS) return ""
118
+ return typeof value === "string" ? value : ""
119
+ }
120
+
121
+ // Answered with nothing, which is not the same as not answered yet. A thumbnailer that could not
122
+ // read the file reports an empty name, and only once that has arrived is it honest to say so.
123
+ function refused(state, row) {
124
+ return state.file[row] === ""
125
+ }
126
+
127
+ // src/backend/thumbs.rs THUMB_SIZE: the longest side of a cache file made from a larger original.
128
+ var CACHE_SIZE = 256
129
+
130
+ // How much a picture may be enlarged to fit its box, and never past limit: 1 for an original, which
131
+ // draws at its own size when it is smaller than the box (decided 2026-09-24). Sample input: (754, 471, 120, 68, 1) is 1.
132
+ function fitScale(boxWidth, boxHeight, width, height, limit) {
133
+ return Math.min(limit, boxWidth / Math.max(1, width), boxHeight / Math.max(1, height))
134
+ }
135
+
136
+ // A cache file stands in for its original, so it is enlarged at most to the original's own size. The
137
+ // longest side is compared because EXIF can turn either one. Unknown dimensions leave a full-size cache
138
+ // file free to fill the box, while a smaller one already is the original. Sample input: (256, 171, 300, 200) is 300/256.
139
+ function thumbLimit(thumbWidth, thumbHeight, originalWidth, originalHeight) {
140
+ var thumbLongest = Math.max(1, thumbWidth, thumbHeight)
141
+ var originalLongest = Math.max(Number(originalWidth) || 0, Number(originalHeight) || 0)
142
+ if (originalLongest > 0)
143
+ return originalLongest / thumbLongest
144
+ return thumbLongest < CACHE_SIZE ? 1 : Infinity
145
+ }
146
+
147
+ // A video poster fills the frame; an image keeps the never-enlarge cap.
148
+ function posterLimit(isVideo, thumbWidth, thumbHeight, originalWidth, originalHeight) {
149
+ if (isVideo)
150
+ return Infinity
151
+ return thumbLimit(thumbWidth, thumbHeight, originalWidth, originalHeight)
152
+ }
153
+
154
+ // Backend icon identity distinguishes image thumbnails from video without opening any extra file; an AppImage's own icon is its identity, so Images draws a row the backend flagged a.
155
+ function allowed(row, mode) {
156
+ if (!row || !row.t || mode === "off") return false
157
+ return mode !== "images" || row.i === "image-x-generic" || row.a === true
158
+ }
@@ -0,0 +1,172 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+
5
+ // The model behind ui/TransferCard.qml, kept out of the QML so every state the card can draw is
6
+ // checked without a window. The object each function takes is ui/js/Ops.js's transfer.
7
+
8
+ // Whole phrases with "%1" for a value, filled by fill so each translates as one; a leading space is the join to the figure drawn before it.
9
+ var WORDS = {
10
+ movedWaiting: " moved · waiting for the drive",
11
+ copiedWaiting: " copied · waiting for the drive",
12
+ moved: " moved",
13
+ copied: " copied",
14
+ writingTo: "Writing to %1",
15
+ moving: "Moving %1 of %2",
16
+ copying: "Copying %1 of %2",
17
+ redoing: "Redoing %3 %1 of %2"
18
+ }
19
+
20
+ // The byte sample for the item in flight. done is the count already finished, so it stays where it
21
+ // was: a sample fills the item in, it does not complete it.
22
+ function sampled(t, index, name, bytes, total, scanned) {
23
+ // A sample carrying none must not unset the total an earlier one already brought.
24
+ var settled = scanned > 0 ? scanned : (t.scanned || 0)
25
+ // A sample for an item itemDone already closed carries the bytes paced lines left out, so they join moved and the card stays put.
26
+ if (index < (t.done || 0))
27
+ return Object.assign({}, t, {moved: (t.moved || 0) + bytes, scanned: settled})
28
+ return Object.assign({}, t, {index: index, name: name, done: index, bytes: bytes, total: total, scanned: settled})
29
+ }
30
+
31
+ // That item's own terminal line: it counts whole from here, and its byte sample is spent. What it
32
+ // moved joins the running sum first, as the size the wire last named for it, or as the bytes it
33
+ // reported when it never had a total, which is what a directory's own running count is. An item
34
+ // that emitted no sample at all adds nothing, which undercounts a small file and never overcounts.
35
+ function itemDone(t, index, name) {
36
+ var sampled = t.index === index ? (t.total > 0 ? t.total : t.bytes) : 0
37
+ return Object.assign({}, t, {index: index, name: name, done: index + 1, bytes: 0, total: 0,
38
+ moved: (t.moved || 0) + sampled})
39
+ }
40
+
41
+ // Sample input: itemsDone(t, [{index: 0, name: "a"}, {index: 1, name: "b"}]) is itemDone(itemDone(t, 0, "a"), 1, "b") in one write.
42
+ function itemsDone(t, held) {
43
+ var next = t
44
+ for (var i = 0; i < held.length; i++)
45
+ next = itemDone(next, held[i].index, held[i].name)
46
+ return next
47
+ }
48
+
49
+ // TransferCard rule 2: what the whole transfer has moved, the finished items plus the one in flight.
50
+ function movedBytes(t) {
51
+ return (t.moved || 0) + (t.bytes || 0)
52
+ }
53
+
54
+ // Durability: the backend's last directory flush. Sample input:
55
+ // {"t":"transferprogress","id":12,"index":0,"name":"","bytes":0,"total":0,"scanned":0,"phase":"writing","drive":"128GB"}
56
+ // Every file is already complete, so the counted bytes stay and the sample is spent.
57
+ function markWriting(t, drive) {
58
+ return Object.assign({}, t, {writing: true, drive: drive || "", name: "", bytes: 0, total: 0})
59
+ }
60
+
61
+ // A surface that pre-renders its own Cancel state carries noCancel; see ui/js/FlashCard.js.
62
+ function cancelEnabled(t) {
63
+ if (t.noCancel === true)
64
+ return false
65
+ // The flush dims Cancel because every file is already complete, so there is nothing left to stop.
66
+ return t.running === true && t.writing !== true
67
+ }
68
+
69
+ // TransferCard rule 1's line under the bar, as the pieces it is drawn from: a figure the card inks
70
+ // in the foreground, or the muted words between them.
71
+ function byteParts(t, rate) {
72
+ // A surface that pre-renders its own line carries byteText; see ui/js/FlashCard.js.
73
+ if (t.byteText !== undefined)
74
+ return t.byteText
75
+ // The flush has no percentage because the kernel reports none: the confirmed bytes and the wait.
76
+ if (t.writing === true) {
77
+ var confirmed = movedBytes(t)
78
+ if (confirmed <= 0) {
79
+ return []
80
+ }
81
+ return [figure(Format.size(confirmed)), word(t.moving ? WORDS.movedWaiting : WORDS.copiedWaiting)]
82
+ }
83
+ var moved = movedBytes(t)
84
+ if (moved <= 0) {
85
+ return []
86
+ }
87
+ var total = transferTotal(t)
88
+ var parts = [figure(Format.size(moved))]
89
+ if (total > 0) {
90
+ parts.push(word(" of "), figure(Format.size(total)))
91
+ } else {
92
+ parts.push(word(t.moving ? WORDS.moved : WORDS.copied))
93
+ }
94
+ parts.push(word(" · "), figure(Format.size(rate) + "/s"))
95
+ // Rule 3b: an estimate needs both a total and a rate, and a stall has neither to divide by.
96
+ if (total > 0 && rate > 0) {
97
+ // Clamped: the sweep and the copy count separately, so a file appended mid-copy can pass it.
98
+ parts.push(word(" · "), figure(Format.duration(Math.max(0, total - moved) / rate * 1000)), word(" left"))
99
+ }
100
+ return parts
101
+ }
102
+
103
+ function figure(text) {
104
+ return { text: text, figure: true }
105
+ }
106
+
107
+ function word(text) {
108
+ return { text: text, figure: false }
109
+ }
110
+
111
+ // The card's headline, the count with no name in it: the card gives the name a row of its own, and
112
+ // ui/js/Ops.js builds the status bar's one-line form from this same string.
113
+ function head(t) {
114
+ // A surface that pre-renders its own headline carries headText; see ui/js/FlashCard.js.
115
+ if (t.headText !== undefined)
116
+ return t.headText
117
+ // The flush headline names the drive being waited on, with no percentage, because the kernel reports none.
118
+ if (t.writing === true)
119
+ return Format.fill(WORDS.writingTo, t.drive && t.drive.length > 0 ? t.drive : "the drive")
120
+ // An extract has no items to count, so it names its verb alone.
121
+ if (t.extract)
122
+ return "Extracting"
123
+ return Format.fill(t.redo ? WORDS.redoing : t.moving ? WORDS.moving : WORDS.copying, Format.count(t.index + 1), Format.count(t.n), t.redo)
124
+ }
125
+
126
+ // The card's second row: the item in flight and how big it is. total is 0 for a directory, whose
127
+ // size is not known in advance without a sweep, so that one names itself and claims nothing more:
128
+ // the running count it does have is the byte line's under the bar, and saying it twice is the thing
129
+ // this canvas exists to stop.
130
+ function fileLine(t) {
131
+ // A surface that pre-renders its own file line carries fileText; see ui/js/FlashCard.js.
132
+ if (t.fileText !== undefined)
133
+ return t.fileText
134
+ // The flush carries no file line: every file is already complete.
135
+ if (t.writing === true) {
136
+ return ""
137
+ }
138
+ if (t.name.length === 0) {
139
+ return ""
140
+ }
141
+ return t.total > 0 ? t.name + " · " + Format.size(t.total) : t.name
142
+ }
143
+
144
+ // The bar is the whole transfer, never the one file: done carries the items already finished and
145
+ // the byte sample only fills in the one in flight. One large file is then its own byte bar, and
146
+ // thirty thousand small ones step it once each instead of restarting it thirty thousand times.
147
+ // t.total is the item in flight's, so it is the transfer's only when the transfer is that one
148
+ // item. One directory is n === 1 with no total of its own, and the sweep is what answers for it.
149
+ function transferTotal(t) {
150
+ return t.n === 1 && t.total > 0 ? t.total : (t.scanned || 0)
151
+ }
152
+
153
+ // A bar figure held to 0 through 1, where a missing or non-numeric one reads as empty.
154
+ function unit(value) {
155
+ if (typeof value !== "number" || !(value > 0))
156
+ return 0
157
+ return value > 1 ? 1 : value
158
+ }
159
+
160
+ // The bar fills against the same total the line under it names, so the two always agree; with no
161
+ // total yet it counts finished items plus the one in flight's share, as it always did.
162
+ function fraction(t) {
163
+ // A surface that pre-renders its own share carries it; see ui/js/FlashCard.js.
164
+ if (t.share !== undefined)
165
+ return unit(t.share)
166
+ if (t.n <= 0) {
167
+ return 0
168
+ }
169
+ var total = transferTotal(t)
170
+ var at = total > 0 ? movedBytes(t) / total : (t.done + (t.total > 0 ? t.bytes / t.total : 0)) / t.n
171
+ return unit(at)
172
+ }
package/ui/js/Trash.js ADDED
@@ -0,0 +1,84 @@
1
+ .pragma library
2
+
3
+ .import "KeyName.js" as KeyName
4
+ .import "Format.js" as Format
5
+ .import "Ops.js" as Ops
6
+
7
+ // Whole sentences with "%1" for the key that arms and "%2" for the key that acts on its own, filled by Format.fill.
8
+ var WORDS = {
9
+ trash: "Press %1 again to move it to Trash, or %2 on its own.",
10
+ review: "Press %1 again to review permanent deletion, or %2 on its own.",
11
+ trashAlone: "Press %1 again to move it to Trash.",
12
+ trashMany: "Press %1 again to move them to Trash, or %2 on its own.",
13
+ trashManyAlone: "Press %1 again to move them to Trash.",
14
+ reviewAlone: "Press %1 again to review permanent deletion.",
15
+ deleteOne: "Delete 1 item permanently?",
16
+ deleteMany: "Delete %1 items permanently?"
17
+ }
18
+
19
+ // The keys come from the running preset: the arming key, and the key that acts at once when the preset binds one; the count of rows the pair would trash picks it or them.
20
+ function trashPrompt(count) {
21
+ var alone = KeyName.keyOf("trash", "none"), many = count > 1
22
+ if (alone.length > 0) return Format.fill(many ? WORDS.trashMany : WORDS.trash, KeyName.keyFor("trash"), alone)
23
+ return Format.fill(many ? WORDS.trashManyAlone : WORDS.trashAlone, KeyName.keyFor("trash"))
24
+ }
25
+ function reviewPrompt() {
26
+ var alone = KeyName.keyOf("trash", "none")
27
+ return alone.length > 0 ? Format.fill(WORDS.review, KeyName.keyFor("trash"), alone) : Format.fill(WORDS.reviewAlone, KeyName.keyFor("trash"))
28
+ }
29
+
30
+ // The dd pair. A single d used to trash, and it sat in the middle of the letters a name is typed
31
+ // with, so the third keystroke of "Vid" trashed the row (issue 7). Delete and Ctrl+Delete are not
32
+ // letters and still go on one press, through Ops.trash directly.
33
+
34
+ // How long the first d stays armed. Long enough to be a deliberate pair, short enough that an arm
35
+ // nobody finished cannot be completed by a d typed minutes later.
36
+ var ARM_MS = 1500
37
+
38
+ // ui/js/Focus.js clears pane.trashArmedAt for every other action, so an arm never survives the key
39
+ // after it; this reads the stamp before it writes one, which is what makes the second press the pair.
40
+ function arm(pane) {
41
+ if (pane.trashArmedAt > 0 && Date.now() - pane.trashArmedAt < ARM_MS) {
42
+ pane.trashArmedAt = 0
43
+ Ops.trash(pane)
44
+ return
45
+ }
46
+ pane.trashArmedAt = Date.now()
47
+ pane.armPrompted(trashPrompt(Ops.targetIndices(pane).length))
48
+ }
49
+
50
+ // Window-level keys the Trash view borrows: "direct" skips pane.act as Focus.handleKey does, "act" goes through it, "trash" stays here.
51
+ function route(action) {
52
+ if (action === "keymapSheet" || action === "pathBar") return "direct"
53
+ if (action.indexOf("textSize") === 0) return "direct"
54
+ if (action === "settings" || action === "sidebar") return "act"
55
+ if (action.indexOf("tab") === 0) return "act"
56
+ return "trash"
57
+ }
58
+
59
+ // The delete card's words come from a filled snapshot only (R0: the whole filled card or nothing), so an unfilled one says no word at all.
60
+ function filled(snapshot) {
61
+ return typeof snapshot.count === "number"
62
+ }
63
+
64
+ // "Empty Trash?", or one whole sentence per count; Format.fill takes the grouped count into the placeholder.
65
+ function confirmTitle(snapshot) {
66
+ if (!filled(snapshot)) return ""
67
+ if (snapshot.all) return "Empty Trash?"
68
+ return snapshot.count === 1 ? WORDS.deleteOne : Format.fill(WORDS.deleteMany, Format.count(snapshot.count))
69
+ }
70
+
71
+ function confirmBody(snapshot, scope) {
72
+ if (!filled(snapshot)) return ""
73
+ var body = snapshot.all ? Ops.deleteAllLine(snapshot.count, Format.size(snapshot.bytes || 0)) : Ops.deleteScopeLine(scope, snapshot.count)
74
+ if (snapshot.count === 1 && typeof snapshot.name === "string" && snapshot.name.length > 0)
75
+ body = "“" + snapshot.name + "”\n\n" + body
76
+ return body
77
+ }
78
+
79
+ // Where m opens: the cursor row's menu when no row is marked or the only mark is the cursor row, the marked rows' menu otherwise, the whole-Trash menu when nothing is listed.
80
+ function menuTarget(total, markedCount, cursorMarked) {
81
+ if (total === 0) return "strip"
82
+ if (markedCount === 0 || (markedCount === 1 && cursorMarked)) return "cursor"
83
+ return "marked"
84
+ }
@@ -0,0 +1,47 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+
5
+ function location(original, home) {
6
+ var cut = String(original).lastIndexOf("/")
7
+ if (cut < 0) return "Unknown"
8
+ var folder = cut === 0 ? "/" : original.slice(0, cut)
9
+ if (home && (folder === home || folder.indexOf(home + "/") === 0))
10
+ return "~" + folder.slice(home.length)
11
+ return folder
12
+ }
13
+
14
+ // Sample input, GIO trash::deletion-date: "2026-09-08T10:00:00" in local time.
15
+ function deleted(text) {
16
+ // The same guard expired() carries below, and for the same reason: new Date(null) is the epoch,
17
+ // so an item with no date would have been labelled with a day in 1970 instead of Unknown.
18
+ if (typeof text !== "string" || text.length === 0) return "Unknown"
19
+ var date = new Date(text)
20
+ if (!isFinite(date.getTime())) return "Unknown"
21
+ // Format.stamp is the product's one date form, so the trash queue sorts against the file list.
22
+ return Format.stamp(date)
23
+ }
24
+
25
+ // The 30 day sweep's own two questions. Decided 2026-09-11: the sweep is off by default and
26
+ // opt in, because permanent deletion is outside the undo journal and nobody opted into it by
27
+ // installing an update.
28
+ var DAY_MS = 24 * 60 * 60 * 1000
29
+
30
+ // Sample input is deleted()'s own: gio's trash::deletion-date, "2026-09-08T10:00:00" in local time.
31
+ // An item whose date cannot be read is NEVER swept: this is the one direction a wrong answer here
32
+ // can be taken in, and "leave it alone" is that direction.
33
+ function expired(text, nowMs, days) {
34
+ // new Date(null) is the EPOCH, not an invalid date, so a missing value reads as 1970 and would
35
+ // be swept by every run. The type is checked before the parse rather than after it.
36
+ if (typeof text !== "string" || text.length === 0) return false
37
+ var date = new Date(text)
38
+ if (!isFinite(date.getTime())) return false
39
+ return nowMs - date.getTime() >= days * DAY_MS
40
+ }
41
+
42
+ // Which day it is, in whole days since the epoch at local midnight, which is what the sweep records
43
+ // so that it runs once a day rather than once per launch.
44
+ function dayNumber(nowMs) {
45
+ var now = new Date(nowMs)
46
+ return Math.floor(new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / DAY_MS)
47
+ }
@@ -0,0 +1,64 @@
1
+ .pragma library
2
+
3
+ .import "Drag.js" as Drag
4
+ .import "DragOut.js" as DragOut
5
+ .import "Ops.js" as Ops
6
+ .import "Swap.js" as Swap
7
+ .import "Mounts.js" as Mounts
8
+
9
+ // Only rows lifted in this window may trash through ui/RailTrashRow.qml, with dd's request and z's undo.
10
+ // Sample marker: "<instance>\n1,3\nmove\n%2Fd\n42\n1\n0\n7".
11
+ function markerRows(marker) {
12
+ var field = String(marker).split("\n")[1] || ""
13
+ if (field.length === 0) return []
14
+ var rows = []
15
+ var parts = field.split(",")
16
+ for (var i = 0; i < parts.length; i++) {
17
+ if (!/^[0-9]+$/.test(parts[i])) return []
18
+ var n = Number(parts[i])
19
+ if (!Number.isInteger(n) || n < 0) return []
20
+ rows.push(n)
21
+ }
22
+ return rows
23
+ }
24
+
25
+ // The request or null: carried paths survive listing changes; rows are only for a selection too wide to carry paths, on its source listing in lift-time numbering, so src/backend/rowguard.rs refuses stale indices.
26
+ function request(marker, urls, path, backend) {
27
+ if (!Drag.isOwnDrag(marker)) return null
28
+ // Issue 133: a GVFS mount has no trash, so the drop is refused up front as d and the menu are.
29
+ if (!Mounts.trashable(Drag.markerSource(marker) || path)) return null
30
+ var paths = DragOut.filePaths(urls)
31
+ if (paths.length > 0) return { c: "trash", paths: paths }
32
+ var rows = markerRows(marker)
33
+ var listing = Drag.markerListing(marker)
34
+ if (rows.length === 0 || listing <= 0 || !Drag.sameListing(marker, path) || !Drag.liftedBy(marker, backend)) return null
35
+ return Swap.named({ c: "trash", rows: rows }, listing)
36
+ }
37
+
38
+ // Whether the drag can trash its carried files here, used by the hover check and status line.
39
+ function accepts(marker, urls, path, backend) {
40
+ return request(marker, urls, path, backend) !== null
41
+ }
42
+
43
+ // Sends trash through the pane's backend and answers whether it sent; the trashed reply clears the selection and re-reads the listing.
44
+ function drop(pane, marker, urls) {
45
+ if (!pane || !pane.backend) return false
46
+ var sent = request(marker, urls, pane.path, pane.backend)
47
+ if (!sent) return false
48
+ // Where the cursor lands once the rows are gone, as dd sets it; only a drag from this listing has one.
49
+ var rows = Drag.sameListing(marker, pane.path) && Drag.liftedBy(marker, pane.backend) ? markerRows(marker) : []
50
+ var first = rows.length > 0 ? rows[0] : -1
51
+ for (var i = 1; i < rows.length; i++)
52
+ if (rows[i] < first) first = rows[i]
53
+ pane.trashedFirst = first
54
+ pane.backend.send(sent)
55
+ return true
56
+ }
57
+
58
+ // The status bar while the drag rests on the Trash row. Sample: "Move 2 items to Trash".
59
+ function line(marker, urls, path, backend) {
60
+ if (!accepts(marker, urls, path, backend)) return ""
61
+ var rows = markerRows(marker)
62
+ var n = rows.length > 0 ? rows.length : DragOut.filePaths(urls).length
63
+ return "Move " + Ops.items(n) + " to Trash"
64
+ }