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,265 @@
1
+ .pragma library
2
+
3
+ .import "Mounts.js" as Mounts
4
+ .import "UserDirs.js" as UserDirs
5
+
6
+ // Sample input: XDG_DOWNLOAD_DIR="$HOME/Downloads"
7
+ function userDirs(body, home) {
8
+ return UserDirs.userDirs(body, home)
9
+ }
10
+
11
+ // Sample input: file:///home/gm/Downloads Downloads
12
+ function bookmarks(body) {
13
+ var out = []
14
+ var lines = String(body || "").split("\n")
15
+ for (var i = 0; i < lines.length; i++) {
16
+ var line = lines[i].trim()
17
+ // corner: a bookmark may be smb:// or sftp://, which is a Location and not a Favorite.
18
+ if (line.indexOf("file://") !== 0)
19
+ continue
20
+ var space = line.indexOf(" ")
21
+ var uri = space < 0 ? line : line.substring(0, space)
22
+ var label = space < 0 ? "" : line.substring(space + 1).trim()
23
+ var path = Mounts.decodePath(uri.substring("file://".length))
24
+ out.push({ path: path, label: label.length > 0 ? label : leaf(path) })
25
+ }
26
+ return out
27
+ }
28
+
29
+ // The FAVORITES rail's rows, Home first and always, then XDG dirs and bookmarked places in file
30
+ // order, a path seen twice keeping its first position. glyphFor resolves each row's mark so the
31
+ // rail's Icons import stays the rail's own business; see ui/Sidebar.qml's rebuild.
32
+ function favorites(home, dirsText, marksText, glyphFor) {
33
+ var favs = [{ path: home, label: "Home", group: "favorite", kind: "favorite", glyph: glyphFor("Home") }]
34
+ var seen = {}
35
+ seen[home] = true
36
+ var groups = [userDirs(dirsText, home), bookmarks(marksText)]
37
+ for (var g = 0; g < groups.length; g++) {
38
+ for (var i = 0; i < groups[g].length; i++) {
39
+ if (seen[groups[g][i].path])
40
+ continue
41
+ var e = groups[g][i]
42
+ seen[e.path] = true
43
+ favs.push({ path: e.path, label: e.label, group: "favorite", kind: "favorite", glyph: glyphFor(e.label) })
44
+ }
45
+ }
46
+ return favs
47
+ }
48
+
49
+ function leaf(path) {
50
+ var cut = path.lastIndexOf("/")
51
+ return cut < 0 ? path : path.substring(cut + 1)
52
+ }
53
+
54
+ // Sample input: "smb://192.168.1.10/data NAS"; see AGENTS.md "Places.relabel" for the matching, duplicate and control-character rules.
55
+ function relabel(body, path, name) {
56
+ // A trust boundary: an embedded newline could otherwise split one bookmark into two lines.
57
+ var trimmed = String(name || "").replace(/[\r\n]/g, "").trim()
58
+ if (trimmed.length === 0)
59
+ return String(body || "")
60
+ var target = Mounts.normalize(path)
61
+ var lines = String(body || "").split("\n")
62
+ var found = false
63
+ for (var i = 0; i < lines.length; i++) {
64
+ // Read off the trimmed line the way Mounts.removeBookmark reads it, or an indented bookmark
65
+ // is one Remove can drop and this could only ever duplicate.
66
+ var line = lines[i].trim()
67
+ if (line.length === 0)
68
+ continue
69
+ var space = line.indexOf(" ")
70
+ var uri = space < 0 ? line : line.substring(0, space)
71
+ if (Mounts.normalize(uri) === target) {
72
+ lines[i] = uri + " " + trimmed
73
+ found = true
74
+ }
75
+ }
76
+ if (found)
77
+ return lines.join("\n")
78
+ var out = String(body || "")
79
+ if (out.length > 0 && out.charAt(out.length - 1) !== "\n")
80
+ out += "\n"
81
+ return out + target + " " + trimmed + "\n"
82
+ }
83
+
84
+ // Sample input: body as relabel's, oldUri the saved line being rewritten, newUri the address the
85
+ // form's Mounts-as line showed. Matched the way relabel matches, so a live mount's trailing slash
86
+ // still finds the saved line, and an empty oldUri matches nothing and appends instead. PR 21.
87
+ function replace(body, oldUri, newUri, label) {
88
+ var next = Mounts.normalize(newUri)
89
+ if (next.length === 0)
90
+ return String(body || "")
91
+ // The same trust boundary relabel names: an embedded newline would split one bookmark into two.
92
+ var name = String(label || "").replace(/[\r\n]/g, "").trim()
93
+ if (name.length === 0)
94
+ name = leaf(next)
95
+ var target = Mounts.normalize(oldUri)
96
+ var lines = String(body || "").split("\n")
97
+ var found = false
98
+ for (var i = 0; i < lines.length; i++) {
99
+ var line = lines[i].trim()
100
+ if (line.length === 0)
101
+ continue
102
+ var space = line.indexOf(" ")
103
+ var uri = space < 0 ? line : line.substring(0, space)
104
+ if (target.length > 0 && Mounts.normalize(uri) === target) {
105
+ lines[i] = next + " " + name
106
+ found = true
107
+ }
108
+ }
109
+ if (found)
110
+ return lines.join("\n")
111
+ var out = String(body || "")
112
+ if (out.length > 0 && out.charAt(out.length - 1) !== "\n")
113
+ out += "\n"
114
+ return out + next + " " + name + "\n"
115
+ }
116
+
117
+ var WIDTH_STOPS = [160, 192, 224, 256]
118
+ function sidebarWidth(value) {
119
+ if (typeof value !== "number" || !isFinite(value)) return 192
120
+ var nearest = WIDTH_STOPS[0]
121
+ for (var i = 1; i < WIDTH_STOPS.length; i++) {
122
+ if (Math.abs(WIDTH_STOPS[i] - value) < Math.abs(nearest - value)) nearest = WIDTH_STOPS[i]
123
+ }
124
+ return nearest
125
+ }
126
+
127
+ function recordError(record) {
128
+ if (!record || typeof record !== "object" || Array.isArray(record)) return "invalid favorite record"
129
+ if (typeof record.label !== "string" || record.label.trim().length === 0) return "label needs visible text"
130
+ if (typeof record.path !== "string" || /[\u0000-\u001f\u007f]/.test(record.path)) return "invalid path"
131
+ if (record.path.charAt(0) === "/" || record.path === "~" || record.path.indexOf("~/") === 0) return ""
132
+ var schemes = ["smb://", "sftp://", "ftp://", "dav://", "davs://", "afp://", "nfs://", "file://"]
133
+ for (var i = 0; i < schemes.length; i++) {
134
+ if (record.path.indexOf(schemes[i]) === 0 && record.path.length > schemes[i].length) return ""
135
+ }
136
+ return "use a full path, a path that starts with ~/, or a network address"
137
+ }
138
+
139
+ function storedEntries(records, home) {
140
+ var out = []
141
+ for (var i = 0; Array.isArray(records) && i < records.length; i++) {
142
+ var record = records[i]
143
+ var error = recordError(record)
144
+ var label = record && typeof record.label === "string" ? record.label : JSON.stringify(record)
145
+ var path = record && typeof record.path === "string" ? record.path : ""
146
+ var resolved = path === "~" ? home : path.indexOf("~/") === 0 ? home + path.substring(1) : path
147
+ out.push({ label: label || "Invalid favorite", path: resolved, storedPath: path,
148
+ error: error, original: record, favouriteIndex: i, group: "favourite", kind: "favourite",
149
+ glyph: path.indexOf("://") >= 0 ? "network" : "folder" })
150
+ }
151
+ return out
152
+ }
153
+
154
+ // flea-qml: Home, then the folders the backend found by looking (src/places.js), each
155
+ // { path, label, glyph }. Upstream drew the folders user-dirs.dirs names, there or not; here a
156
+ // row is a folder that answered, and until the backend's first line the list is Home alone.
157
+ function homeEntries(home, probed, glyphFor) {
158
+ var entries = [{ label: "Home", path: home, group: "home", kind: "home", glyph: glyphFor("Home") }]
159
+ var rows = Array.isArray(probed) ? probed : []
160
+ for (var i = 0; i < rows.length; i++) {
161
+ var row = rows[i]
162
+ if (!row || typeof row.path !== "string" || row.path.length === 0 || row.path === home)
163
+ continue
164
+ entries.push({ label: String(row.label || row.path), path: row.path, group: "home", kind: "home", glyph: String(row.glyph || "folder") })
165
+ }
166
+ return entries
167
+ }
168
+
169
+ // flea-qml: the drives the backend found by looking, drawn under DEVICES as plain folders: a row
170
+ // opens its path and offers a place's menu, and nothing here mounts or ejects. A drive lsblk
171
+ // already lists, by the mount point of one of `listed`'s rows, is that row and not a second one.
172
+ function volumeEntries(volumes, listed) {
173
+ var out = []
174
+ var rows = Array.isArray(volumes) ? volumes : []
175
+ var held = {}
176
+ for (var d = 0; Array.isArray(listed) && d < listed.length; d++) {
177
+ if (listed[d] && typeof listed[d].path === "string" && listed[d].path.length > 0)
178
+ held[listed[d].path] = true
179
+ }
180
+ for (var i = 0; i < rows.length; i++) {
181
+ var row = rows[i]
182
+ if (!row || typeof row.path !== "string" || row.path.length === 0 || held[row.path])
183
+ continue
184
+ out.push({ label: String(row.label || row.path), path: row.path, group: "home", kind: "home", volume: true,
185
+ glyph: String(row.glyph || "drive"), size: typeof row.size === "number" ? row.size : null })
186
+ }
187
+ return out
188
+ }
189
+
190
+ // The rail and query use the same validation, URI decoding and mount-first open.
191
+ function openEntry(entry, ports) {
192
+ if (!entry) return
193
+ if (entry.kind === "trash") { ports.trash(); return }
194
+ var error = entry.kind === "favourite" ? recordError(entry.original) : ""
195
+ if (error) { ports.message("Could not open %1 · %2".replace(/%([12])/g, function (m, n) { return n === "1" ? entry.label : error }), true); return }
196
+ if (entry.path.indexOf("://") >= 0 && entry.path.indexOf("file://") !== 0) {
197
+ var host = ports.networkHost()
198
+ if (host) host.openChildShare(entry.path, entry.label, ports.pane)
199
+ } else {
200
+ ports.opened(entry.path.indexOf("file://") === 0 ? Mounts.decodePath(entry.path.substring(7)) : entry.path)
201
+ }
202
+ }
203
+
204
+ function railIdentity(entry) {
205
+ if (!entry) return ""
206
+ if (entry.kind === "favourite") return JSON.stringify([entry.kind, entry.original])
207
+ return JSON.stringify([entry.group, entry.kind, Mounts.railKey(entry) || entry.device || entry.uri || entry.path])
208
+ }
209
+
210
+ // Duplicate originals have no stored ID; a changed multiplicity cannot safely identify the selected occurrence.
211
+ function railCursorAfter(before, after, index) {
212
+ if (before.length === 0 && index === 0) return 0
213
+ if (index < 0 || index >= before.length) return -1
214
+ var key = railIdentity(before[index]), oldCount = 0, occurrence = 0, matches = []
215
+ for (var i = 0; i < before.length; i++) {
216
+ if (railIdentity(before[i]) !== key) continue
217
+ oldCount++
218
+ if (i < index) occurrence++
219
+ }
220
+ for (var j = 0; j < after.length; j++) {
221
+ if (railIdentity(after[j]) === key) matches.push(j)
222
+ }
223
+ return matches.length === oldCount ? matches[occurrence] : -1
224
+ }
225
+
226
+ // Under gvfs only the mounted row opened under view.shareKey lights, never a folder prefix or the disk.
227
+ function heldBy(entries, dir, view) {
228
+ var list = entries || []
229
+ var at = view || ({ kind: "dir" })
230
+ var path = String(dir || "")
231
+ var gvfs = Mounts.underGvfs(path)
232
+ var best = -1, depth = -1
233
+ for (var i = 0; i < list.length; i++) {
234
+ var e = list[i]
235
+ if (at.kind !== "dir") {
236
+ if (e.kind === at.kind && (at.kind !== "tag" || e.tag === at.tag))
237
+ return i
238
+ continue
239
+ }
240
+ if (e.kind === "recent" || e.kind === "trash" || e.kind === "tag" || e.error || e.mounted === false)
241
+ continue
242
+ if (gvfs) {
243
+ var key = String(at.shareKey || "")
244
+ if (key.length > 0 && !e.path && (Mounts.normalize(e.uri) === key || Mounts.normalize(e.mountUri) === key))
245
+ return i
246
+ continue
247
+ }
248
+ if (typeof e.path !== "string" || e.path.length === 0)
249
+ continue
250
+ if ((e.path === "/" ? path.charAt(0) === "/" : Mounts.inside(path, e.path)) && e.path.length > depth) {
251
+ best = i
252
+ depth = e.path.length
253
+ }
254
+ }
255
+ return best
256
+ }
257
+
258
+ // pathAlias is the pane's remembered gvfs share (or null); its key is the share's normalized address.
259
+ function litView(trashOpened, recentMode, searchMode, answeredQuery, pathAlias) {
260
+ if (trashOpened || recentMode === "trash") return { kind: "trash" }
261
+ if (String(recentMode || "").length > 0) return { kind: "recent" }
262
+ var query = String(answeredQuery || "")
263
+ if (String(searchMode || "").length > 0 && query.indexOf("tag:") === 0) return { kind: "tag", tag: query.substring(4) }
264
+ return { kind: "dir", shareKey: pathAlias ? String(pathAlias.key || "") : "" }
265
+ }
@@ -0,0 +1,21 @@
1
+ .pragma library
2
+
3
+ .import "PreviewSettle.js" as PreviewSettle
4
+ .import "ExtThumbs.js" as ExtThumbs
5
+
6
+ // The cursor row's single thumbnail ask, shared by the early ask and load()'s askThumb, so the second sends nothing twice.
7
+
8
+ // Sample input: canRead, storageKnown, one selection, index 3, rowT, unasked, local storage answers {ask: [3], drop: [], cacheOnly: false}.
9
+ function workFor(o) {
10
+ if (!o.canRead || !o.storageKnown || o.selectionCount > 1) return null
11
+ if (o.index < 0 || o.rowT !== true || o.asked === true) return null
12
+ return { ask: [o.index], drop: [], cacheOnly: ExtThumbs.cacheOnly(o.storageClass, o.preview) }
13
+ }
14
+
15
+ // The idle half of the early ask is the settle's own rule: a walk step trails and asks nothing early.
16
+ function earlyWorkFor(o) {
17
+ if (PreviewSettle.plan(o.now, o.lastMoveAt, o.interval, o.key, o.lastMoveKey, o.armed, o.pending) !== "now")
18
+ return null
19
+ if (ExtThumbs.manualHold(o.storageClass, o.preview)) return null
20
+ return workFor(o)
21
+ }
@@ -0,0 +1,155 @@
1
+ .pragma library
2
+
3
+ .import "Filter.js" as Filter
4
+ .import "Marks.js" as Marks
5
+ .import "Search.js" as Search
6
+ .import "Thumbs.js" as Thumbs
7
+ .import "Scroll.js" as Scroll
8
+
9
+ // What the preview overlay does with a key, split out of Focus.js at its 300-line hard cap the
10
+ // same way ui/js/Trash.js was: Focus.js decides which surface owns a key, and this is the surface.
11
+
12
+ // Left/Right's seek step, Task 22's operator ruling; act is the only reader.
13
+ var SEEK_MS = 5000
14
+ // The zoom ladder Quick Look's PDF strip walks: the bottom rung fits the frame, one step a press, up to four times.
15
+ var PDF_ZOOM_MIN = 1
16
+ var PDF_ZOOM_MAX = 4
17
+ var PDF_ZOOM_STEP = 0.25
18
+
19
+ // A zoom after steps presses (negative steps down), kept on the ladder; the image pane walks the same rungs as the PDF.
20
+ function zoomStep(zoom, steps) {
21
+ return Math.max(PDF_ZOOM_MIN, Math.min(PDF_ZOOM_MAX, zoom + steps * PDF_ZOOM_STEP))
22
+ }
23
+
24
+ // All advertised page keys share one route in Quick Look and the preview column.
25
+ function pageDirection(action) {
26
+ if (action === "pageDown" || action === "previewPageForward") return 1
27
+ if (action === "pageUp" || action === "previewPageBack") return -1
28
+ return 0
29
+ }
30
+
31
+ function pageViewport(view, direction) {
32
+ if (!view || !direction) return
33
+ if (typeof view.cancelFlick === "function") view.cancelFlick()
34
+ Scroll.stopTail(view)
35
+ var bounds = Scroll.limitsY(view)
36
+ view.contentY = Math.max(bounds.min, Math.min(bounds.max, view.contentY + direction * view.height))
37
+ if (typeof view.forceLayout === "function") view.forceLayout()
38
+ }
39
+
40
+ // The column's PDF has no strip: pages scroll, and Space, Return or e opens Quick Look at the page in view.
41
+ function columnPdfAction(action, viewer) {
42
+ if (pageDirection(action)) { viewer.pageBy(pageDirection(action)); return }
43
+ if (action === "open" || action === "preview" || action === "expand") viewer.toggleExpand()
44
+ else if (action === "seekBack" || action === "parent") viewer.turnPage(-1)
45
+ else if (action === "seekForward" || action === "pageForward") viewer.turnPage(1)
46
+ else if (action === "cursorDown" || action === "cursorUp") viewer.scrollPage(action === "cursorDown" ? 1 : -1)
47
+ }
48
+
49
+ function pdfAction(action, viewer) {
50
+ if (pageDirection(action)) { viewer.pageBy(pageDirection(action)); return }
51
+ var controls = viewer.pdfControls
52
+ if (controls === undefined) return columnPdfAction(action, viewer)
53
+ if (action === "focusNext" || action === "focusPrevious") {
54
+ var step = action === "focusPrevious" ? -1 : 1
55
+ var next = viewer.pdfControlIndex
56
+ if (next < 0) next = step > 0 ? -1 : 0
57
+ for (var i = 0; i < controls.length; i++) {
58
+ next = (next + step + controls.length) % controls.length
59
+ if (controls[next].enabled && controls[next].visible) {
60
+ viewer.pdfControlIndex = next
61
+ break
62
+ }
63
+ }
64
+ } else if (action === "open" || action === "preview") {
65
+ var control = controls[viewer.pdfControlIndex]
66
+ if (control && control.enabled && control.visible) control.activated()
67
+ } else if (action === "seekBack" || action === "parent") viewer.turnPage(-1)
68
+ else if (action === "seekForward" || action === "pageForward") viewer.turnPage(1)
69
+ else if (action === "zoomOut") viewer.zoomBy(-1)
70
+ else if (action === "zoomIn") viewer.zoomBy(1)
71
+ else if (action === "expand") viewer.toggleExpand()
72
+ else if (action === "cursorDown" || action === "cursorUp") viewer.scrollPage(action === "cursorDown" ? 1 : -1)
73
+ }
74
+
75
+ // Space on a folder is a silent no-op; a file carries its cached thumbnail so the overlay shows it at once.
76
+ function open(root) {
77
+ if (!Filter.cursorShown(root)) return
78
+ var row = root.rowFor(root.cursorIndex)
79
+ if (row && !row.d)
80
+ root.quickLook().open(root.join(Search.baseOf(root), row.n), row.i, row.s, root.kindNames[row.k] || "",
81
+ root.thumbState && root.thumbState.file ? Thumbs.fileFor(root.thumbState, root.cursorIndex) : "")
82
+ }
83
+
84
+ // Preview open: j/k move the cursor and the preview follows; escape always closes, and so does a
85
+ // second space, on every kind including media (decided 2026-09-11: pressing Space a second time
86
+ // closes the preview, the way Finder does). That reverses Task 22, which had space toggle
87
+ // play/pause on a media preview; the strip's own play control still does that with the pointer.
88
+ // Any key reveals the media strip, even one that does nothing else, matching "move the mouse or
89
+ // press anything" from the same ruling.
90
+ function act(action, root) {
91
+ root.preview.revealStrip()
92
+ if (pageDirection(action)) { root.preview.pageBy(pageDirection(action)); return }
93
+ switch (action) {
94
+ // A Compare overlay names two files, so the cursor moving under it opens no other file in its place.
95
+ case "cursorDown":
96
+ case "cursorUp":
97
+ var direction = action === "cursorDown" ? 1 : -1
98
+ if (!root.preview.isCompare) { Filter.moveCursor(root, direction); Marks.follow(root); follow(root) }
99
+ return
100
+ case "preview": root.preview.close(); return
101
+ // Space closes every kind now, so playback has its own key; it self-guards, because p reaches
102
+ // this only in the media context and a still image has nothing to play.
103
+ case "playPause":
104
+ if (root.preview.isMedia) root.preview.togglePlay()
105
+ return
106
+ case "focusPreview":
107
+ case "escape": root.preview.close(); return
108
+ // Compare's y: the whole patch goes to the clipboard; the overlay guards on its own kind.
109
+ case "copyPatch": root.preview.copyPatch(); return
110
+ case "seekBack":
111
+ if (root.preview.isPdf) root.preview.turnPage(-1)
112
+ else root.preview.seek(-SEEK_MS)
113
+ return
114
+ case "seekForward":
115
+ if (root.preview.isPdf) root.preview.turnPage(1)
116
+ else root.preview.seek(SEEK_MS)
117
+ return
118
+ // h keeps its own "parent" name from keys.toml; turnPage self-guards, so a media preview
119
+ // ignores both of these rather than seeking on a key the strip never advertised.
120
+ case "parent": root.preview.turnPage(-1); return
121
+ case "pageForward": root.preview.turnPage(1); return
122
+ case "zoomOut": root.preview.zoomBy(-1); return
123
+ case "zoomIn": root.preview.zoomBy(1); return
124
+ case "zoomFit": root.preview.zoomFit(); return
125
+ case "expand": root.preview.toggleExpand(); return
126
+ // MediaMute rule 5: the flag is the preview's to flip, and it silences without pausing.
127
+ case "mute": root.preview.toggleMute(); return
128
+ // r flips only the open document Quick Look between rendered and source.
129
+ case "markdownView":
130
+ if (root.preview.isDocument) root.preview.toggleMarkdownView()
131
+ return
132
+ // Focus.js lets w through for a code or text Quick Look only; the choice is remembered in ui.json.
133
+ case "toggleWrap": root.preview.toggleWrap(); return
134
+ // The text bar toggles Close; Compare owns its actual Copy and Close focus walk.
135
+ case "focusNext":
136
+ case "focusPrevious":
137
+ if (root.preview.isCompare) {
138
+ var compare = root.preview.surfaceItem()
139
+ if (compare) compare.stepFocus(action === "focusPrevious")
140
+ } else if (root.preview.hasBar) root.preview.toggleMarkdownClose()
141
+ return
142
+ case "open":
143
+ if (root.preview.hasBar && root.preview.markdownCloseFocused) root.preview.close()
144
+ return
145
+ }
146
+ }
147
+
148
+ // The row under the moved cursor, handed to Preview.follow so a held key settles before it reloads.
149
+ function follow(root) {
150
+ if (!Filter.cursorShown(root)) return
151
+ var row = root.rowFor(root.cursorIndex)
152
+ if (row && !row.d)
153
+ root.preview.follow(root.join(Search.baseOf(root), row.n), row.i, row.s, root.kindNames[row.k] || "",
154
+ root.thumbState && root.thumbState.file ? Thumbs.fileFor(root.thumbState, root.cursorIndex) : "")
155
+ }
@@ -0,0 +1,29 @@
1
+ .pragma library
2
+
3
+ // Cursor preview loads stamp distinct moves: due(200, 0, 120) and due(100, 200, 120) load now; due(50, 0, 120) trails.
4
+ function due(now, last, interval) {
5
+ var elapsed = now - last
6
+ return elapsed >= interval || elapsed < 0
7
+ }
8
+
9
+ // A settle armed for this row before its move reached the clock (ColumnsArea's folder to file step) is left to the clock.
10
+ // plan(50, 0, 120, "b", "b", true) keeps the pending timer; plan(1000, 0, 120, "c", "b", true, false) is "now".
11
+ function plan(now, last, interval, key, lastKey, armedForKey, pending) {
12
+ if (key === lastKey && armedForKey === true)
13
+ return "same"
14
+ if (pending === true)
15
+ return "later"
16
+ return due(now, last, interval) ? "now" : "later"
17
+ }
18
+
19
+ // A PDF opens at once only when the cursor is idle and no page render is in flight.
20
+ function pdfOpenNow(now, lastRequestAt, intervalMs, renderLoading) {
21
+ return renderLoading !== true && due(now, lastRequestAt, intervalMs)
22
+ }
23
+
24
+ // A lone selection never keys on the version Marks.follow bumps on every plain move.
25
+ function selectionKey(count, version) {
26
+ if (count <= 1)
27
+ return ""
28
+ return count + ":" + version
29
+ }
@@ -0,0 +1,101 @@
1
+ .pragma library
2
+
3
+ .import "Swap.js" as Swap
4
+ .import "Facts.js" as Facts
5
+
6
+ // The preview swap's decisions, see AGENTS.md "The preview swap"; ui/PreviewSwap.qml holds the picture and the timer.
7
+
8
+ // ui/PreviewPdf.qml opens a document only this long after its path settles (issue 117).
9
+ var DOCUMENT_SETTLE_MS = 120
10
+
11
+ // A capture draws on the next frame; one not drawn in this long means the window is not drawing at all.
12
+ var CAPTURE_MS = 100
13
+
14
+ // How long the new preview may build under the held picture from its own start; a PDF's document settle runs under it.
15
+ function capMs(isPdf) {
16
+ return Swap.CAP_MS
17
+ }
18
+
19
+ // When a held preview lets go: -1 while the new one is not whole, else the ms a loading state on screen is still owed.
20
+ function releaseIn(ready, started, shownAt, now) {
21
+ if (ready !== true || started !== true)
22
+ return -1
23
+ return Swap.showLeft(shownAt, now)
24
+ }
25
+
26
+ // Past the cap the loading state stands from shownAt or now; sample input: fallBack(true, 0, 1066) is { shownAt: 1066, left: 100, keeps: true }.
27
+ function fallBack(held, shownAt, now) {
28
+ var at = shownAt > 0 ? shownAt : now
29
+ var left = Swap.showLeft(at, now)
30
+ return { shownAt: at, left: left, keeps: held === true && left > 0 }
31
+ }
32
+
33
+ // What a move does to a swap: start a hold, join the one already starting for this key, or, when the
34
+ // host lets a burst end it, give up a picture that no longer names anything near the cursor.
35
+ var HOLD = "hold"
36
+ var JOIN = "join"
37
+ var BURST = "burst"
38
+
39
+ function onMove(state, key, burstEnds) {
40
+ if (!state.capturing && !state.holding)
41
+ return HOLD
42
+ if (state.key === key || burstEnds !== true)
43
+ return JOIN
44
+ return BURST
45
+ }
46
+
47
+ // A frame drawn with the swap in each state: "held" shows the old picture, "mid" is the defect a hold
48
+ // exists to prevent, "loading" is the fallback's own state and allowed, held in the picture or live.
49
+ function frameKind(held, ready, fellBack, showing) {
50
+ if (showing === true)
51
+ return "loading"
52
+ if (held === true)
53
+ return "held"
54
+ if (ready === true)
55
+ return ""
56
+ return fellBack === true ? "loading" : "mid"
57
+ }
58
+
59
+ // Sample input: { state: "image", thumb: true, frame: 1, noThumbComing: false, pdfDrawn: false,
60
+ // pdfFailed: false, linesLoading: false, meta: true } for the preview column's cursor row, where frame is the
61
+ // thumbnail Image's status (Image.Null 0, Ready 1, Loading 2, Error 3).
62
+ function columnReady(p) {
63
+ switch (p.state) {
64
+ case Facts.LOADING:
65
+ return false
66
+ case Facts.IMAGE:
67
+ // The cache file, or with none coming the original the frame decodes itself, drawn or refused.
68
+ return (p.thumb === true || p.noThumbComing === true) && (p.frame === 1 || p.frame === 3)
69
+ case Facts.VIDEO:
70
+ // The poster drawn or refused, or none coming at all and the kind's mark standing in.
71
+ return p.thumb === true ? p.frame === 1 || p.frame === 3 : p.noThumbComing === true
72
+ case Facts.PDF:
73
+ return p.pdfDrawn === true || p.pdfFailed === true
74
+ case Facts.TEXT:
75
+ case Facts.CODE:
76
+ return p.linesLoading !== true
77
+ case Facts.ARCHIVE:
78
+ return p.meta === true
79
+ }
80
+ return true
81
+ }
82
+
83
+ // Quick Look is ready when nothing loads, a PDF shows a page or is refused, or the interim or a Markdown head shows whole.
84
+ function lookReady(status, isPdf, pdfShown, pdfFailed, interimShown, headShown) {
85
+ if (interimShown === true || headShown === true)
86
+ return true
87
+ if (status === "loading")
88
+ return false
89
+ return isPdf !== true || pdfShown === true || pdfFailed === true
90
+ }
91
+
92
+ // Sample input: interimRect(754, 471, 6000, 4000, 1) is 706.5x471 at 24,0; upright aspect-fit, never enlarged, unknown is null.
93
+ function interimRect(surfaceW, surfaceH, imageW, imageH, orient) {
94
+ if (!(imageW > 0) || !(imageH > 0))
95
+ return null
96
+ var ow = orient >= 5 ? imageH : imageW
97
+ var oh = orient >= 5 ? imageW : imageH
98
+ var s = Math.min(1, surfaceW / ow, surfaceH / oh)
99
+ var w = ow * s, h = oh * s
100
+ return { x: Math.round((surfaceW - w) / 2), y: Math.round((surfaceH - h) / 2), w: w, h: h }
101
+ }