flea-qml 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +402 -0
  51. package/src/archiveops.js +697 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +129 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,394 @@
1
+ pragma ComponentBehavior: Bound
2
+
3
+ import QtQuick
4
+ import qs.Commons
5
+ import "js/Csv.js" as Csv
6
+ import "." as Flea
7
+
8
+ // CSV or TSV as a sticky table, with raw line windows aligned to whole records by the backend.
9
+ Item {
10
+ id: root
11
+
12
+ property var backend: null
13
+ property string slot: "column"
14
+ property string path: ""
15
+ // true sends the bytes in `text` (null until the caller has read them) instead of the path.
16
+ property bool fromText: false
17
+ property var text: null
18
+ property bool active: false
19
+ // Quick Look's grid: row numbers, each column its widest cell plus the row padding, and both axes scroll.
20
+ property bool look: false
21
+ property int limit: 0
22
+ // Screens asked past the view on each side.
23
+ property int margin: 1
24
+ property int pixelSize: Theme.font.caption
25
+ readonly property int lineCap: 400 // The most lines one ask names (docs/protocol.md "code"); a longer window is asked in parts.
26
+
27
+ readonly property string delim: Csv.delimiter(root.path)
28
+ readonly property bool engine: root.backend !== null && typeof root.backend.askCode === "function"
29
+ // The board draws its table at caption 12; its pixel values scale with the caption, as the board sizes in Theme.qml do.
30
+ readonly property real boardScale: root.pixelSize / 12
31
+ // Board: the column's rows sit 12 px in from the frame on each side.
32
+ readonly property int columnEdge: Math.round(12 * root.boardScale)
33
+ // Board: 6 px between the column's cells.
34
+ readonly property int columnGap: Math.round(6 * root.boardScale)
35
+ // Board: Quick Look's row numbers fill a 42 px column.
36
+ readonly property int numberWidth: Math.round(42 * root.boardScale)
37
+ // Board: 3 px above and below each column row and its header.
38
+ readonly property int columnPadY: Math.round(3 * root.boardScale)
39
+ // Board: 6 px above and below each Quick Look row.
40
+ readonly property int gridPadY: Math.round(6 * root.boardScale)
41
+ // Board: 8 px above and below the Quick Look header.
42
+ readonly property int gridHeadPadY: Math.round(8 * root.boardScale)
43
+ readonly property int edge: root.look ? Theme.spacing.rowPaddingX : root.columnEdge
44
+ readonly property int bodyPadY: root.look ? root.gridPadY : root.columnPadY
45
+ readonly property int headPadY: root.look ? root.gridHeadPadY : root.columnPadY
46
+ // The table rule of ui/PreviewMarkdown.qml, drawn under the header.
47
+ readonly property real ruleOpacity: 0.12
48
+ readonly property real rowHeight: bodyMetrics.height + 2 * root.bodyPadY
49
+ readonly property real headHeight: headMetrics.height + 2 * root.headPadY + Theme.spacing.hairline
50
+
51
+ // "" until the first screen is answered, then styled, plain, binary, large or failed.
52
+ property string answer: ""
53
+ property int total: 0
54
+ property int records: 0
55
+ // The held physical lines, each {t: text}, with record: ordinal at every reply start; stamp counts changes to it.
56
+ property var held: ({})
57
+ property int stamp: 0
58
+ // The token of the ask in flight, 0 when none: an answer for any other token is dropped.
59
+ property int token: 0
60
+ property bool retiring: false
61
+ // The last record of the first screen, so the first screen is known whole before the table is drawn.
62
+ property int firstTo: 0
63
+ // The table as held: the header cells, the body rows and the column count.
64
+ property var table: ({ header: null, rows: [], byLine: ({}), byRecord: ({}), cols: 0, open: [] })
65
+ // Widths and alignments are measured on the first screen and only extended after it, so no column moves under the reader.
66
+ property bool frozen: false
67
+ property var heads: []
68
+ property var widths: []
69
+ property var rights: []
70
+
71
+ readonly property bool settled: root.answer === "styled" || root.answer === "plain"
72
+ readonly property int shown: root.limit > 0 ? Math.min(root.records, root.limit) : root.records
73
+ readonly property bool firstReady: root.settled && root.covered(1, Math.min(root.shown, root.firstTo))
74
+ && Csv.ready(root.table, Math.min(root.shown, root.firstTo))
75
+ readonly property bool firstScreen: root.firstReady && (root.look
76
+ || (root.covered(root.needed().from, root.needed().to) && Csv.ready(root.table, root.needed().to)))
77
+ visible: root.firstReady
78
+ // The scroll view the wheel, the bars and the Quick Look reader read.
79
+ readonly property var list: view
80
+ readonly property alias viewport: view
81
+ // One delegate per data record; continuation lines never take a row or a number.
82
+ readonly property int bodyRows: Csv.dataRows(root.shown)
83
+ // The plain text of the lines drawn, for the readers that check what is on screen.
84
+ readonly property var lines: {
85
+ root.stamp
86
+ var out = []
87
+ var tail = root.table.byRecord[root.shown]
88
+ var last = root.limit > 0 && root.shown > 1 ? (tail ? tail.line + tail.span - 1 : 0) : root.total
89
+ for (var i = 1; i <= last; i++)
90
+ out.push(root.held[i] ? root.held[i].t : "")
91
+ return out
92
+ }
93
+ readonly property var layout: root.look ? Csv.grid(root.widths, root.rights, root.numberWidth, Theme.spacing.rowPaddingX)
94
+ : Csv.fit(root.widths, root.heads, root.rights, root.columnGap, view.width - 2 * root.edge)
95
+ readonly property real contentEnd: root.layout.length > 0 ? root.layout[root.layout.length - 1].x + root.layout[root.layout.length - 1].w : 0
96
+ // Quick Look's grid is at least the frame wide and as wide as its boxes; a column keeps the frame's width.
97
+ readonly property real gridWidth: root.look ? Math.max(view.width, root.contentEnd) : view.width
98
+
99
+ FontMetrics {
100
+ id: bodyMetrics
101
+ font.family: Theme.font.family
102
+ font.pixelSize: root.pixelSize
103
+ }
104
+ FontMetrics {
105
+ id: headMetrics
106
+ font.family: Theme.font.family
107
+ font.pixelSize: root.pixelSize
108
+ font.bold: true
109
+ }
110
+ // Digits in a numeric cell draw with tabular figures, so they are measured the same way.
111
+ FontMetrics {
112
+ id: figureMetrics
113
+ font.family: Theme.font.family
114
+ font.pixelSize: root.pixelSize
115
+ font.features: ({ "tnum": 1 })
116
+ }
117
+
118
+ // The width of column c: its widest header or body cell, the header in bold.
119
+ function naturalWidth(grid, c) {
120
+ var px = headMetrics.advanceWidth(String(grid[0][c] || ""))
121
+ for (var r = 1; r < grid.length; r++) {
122
+ var cell = String(grid[r][c] || "")
123
+ px = Math.max(px, (Csv.isNumber(cell) ? figureMetrics : bodyMetrics).advanceWidth(cell))
124
+ }
125
+ return Math.ceil(px)
126
+ }
127
+
128
+ // Re-reads the held table, and measures each column it has not measured yet; nothing is measured again once the first screen is whole.
129
+ function refresh(parsed) {
130
+ var t = parsed || Csv.table(root.held, root.total, root.delim)
131
+ root.table = t
132
+ if (t.header === null || (root.frozen && root.widths.length >= t.cols))
133
+ return
134
+ var measured = root.frozen ? t.rows : t.rows.filter(function (rec) { return rec.record <= root.firstTo })
135
+ var grid = [t.header].concat(measured.map(function (rec) { return rec.cells }))
136
+ var align = Csv.numericColumns(grid, t.cols)
137
+ var heads = root.frozen ? root.heads.slice() : []
138
+ var widths = root.frozen ? root.widths.slice() : []
139
+ var rights = root.frozen ? root.rights.slice() : []
140
+ for (var c = widths.length; c < t.cols; c++) {
141
+ heads.push(Math.ceil(headMetrics.advanceWidth(String(t.header[c] || ""))))
142
+ widths.push(root.naturalWidth(grid, c))
143
+ rights.push(align[c])
144
+ }
145
+ if (!root.frozen && root.covered(1, Math.min(root.shown, root.firstTo)) && Csv.ready(t, Math.min(root.shown, root.firstTo)))
146
+ root.frozen = true
147
+ root.heads = heads
148
+ root.widths = widths
149
+ root.rights = rights
150
+ }
151
+
152
+ // The record ordinals the view needs, with the margin, file and limit bounds; ordinal 1 is the header.
153
+ function needed() {
154
+ var rows = Math.max(1, Math.ceil(view.height / Math.max(1, root.rowHeight)))
155
+ // ListView rounds fractional row heights, so its delegate index names the record even on a far jump.
156
+ var top = view.contentHeight > 0 ? Math.max(0, view.indexAt(0, view.contentY + 1)) + 2 : 2
157
+ var to = top + rows * (1 + root.margin) - 1
158
+ if (root.limit > 0)
159
+ to = Math.min(to, root.limit)
160
+ if (root.settled)
161
+ to = Math.min(to, root.records)
162
+ var from = root.rowAt(1) ? Math.max(2, top - rows * root.margin) : 1
163
+ return { from: from, to: to }
164
+ }
165
+
166
+ function rowAt(n) {
167
+ return root.stamp >= 0 ? (n === 1 ? root.table.header : root.table.byRecord[n]) : undefined
168
+ }
169
+
170
+ function covered(from, to) {
171
+ for (var i = from; i <= to; i++)
172
+ if (!root.rowAt(i))
173
+ return false
174
+ return true
175
+ }
176
+
177
+ function reset() {
178
+ root.held = {}
179
+ root.stamp += 1
180
+ root.total = 0
181
+ root.records = 0
182
+ root.answer = ""
183
+ root.token = 0
184
+ root.firstTo = 0
185
+ root.frozen = false
186
+ root.heads = []
187
+ root.widths = []
188
+ root.rights = []
189
+ root.table = { header: null, rows: [], byLine: ({}), byRecord: ({}), cols: 0, open: [] }
190
+ }
191
+
192
+ // Starts a view of a new file or text; the first ask waits for the end of the turn so one change of several properties asks once.
193
+ function fresh() {
194
+ root.reset()
195
+ if (!root.active)
196
+ return
197
+ if (!root.engine && root.fromText && root.text !== null)
198
+ root.answerPlain()
199
+ else
200
+ Qt.callLater(root.ask)
201
+ }
202
+
203
+ // Lines of the caller's own text, drawn plain when no backend can ask for them.
204
+ function answerPlain() {
205
+ var rows = Csv.plainLines(root.text)
206
+ var held = {}
207
+ for (var i = 0; i < rows.length; i++)
208
+ held[i + 1] = { t: rows[i] }
209
+ root.held = held
210
+ root.total = rows.length
211
+ var parsed = Csv.table(held, root.total, root.delim)
212
+ root.records = parsed.rows.length + (parsed.header !== null ? 1 : 0)
213
+ root.answer = "plain"
214
+ root.firstTo = root.needed().to
215
+ root.refresh(parsed)
216
+ root.stamp += 1
217
+ }
218
+
219
+ function ask() {
220
+ if (root.retiring || !root.active || !root.engine || view.height <= 0)
221
+ return
222
+ if (root.answer === "binary" || root.answer === "large" || root.answer === "failed")
223
+ return
224
+ if (root.fromText && root.text === null)
225
+ return
226
+ if (root.fromText && root.text.length === 0) {
227
+ root.answerPlain()
228
+ return
229
+ }
230
+ if (!root.fromText && root.path.length === 0)
231
+ return
232
+ if (root.token !== 0)
233
+ return
234
+ var want = root.needed()
235
+ if (want.to < want.from || (root.settled && root.covered(want.from, want.to)))
236
+ return
237
+ var from = want.from
238
+ while (from <= want.to && root.rowAt(from))
239
+ from += 1
240
+ if (root.firstTo === 0)
241
+ root.firstTo = want.to
242
+ // raw sends the lines plain: a table is never coloured as code.
243
+ var source = root.fromText ? { text: root.text, name: root.path.split("/").pop(), lang: "", raw: true, csv: root.delim, record: from } : { path: root.path, raw: true, csv: root.delim, record: from }
244
+ root.token = root.backend.askCode(root.slot, source, from, Math.min(root.lineCap, want.to - from + 1))
245
+ }
246
+
247
+ function answered(message) {
248
+ if (root.token === 0 || message.token !== root.token)
249
+ return
250
+ root.token = 0
251
+ if (!root.settled || message.state === "binary" || message.state === "large" || message.state === "failed")
252
+ root.answer = message.state
253
+ root.total = message.total || 0
254
+ root.records = message.records || 0
255
+ var rows = message.lines || []
256
+ for (var i = 0; i < rows.length; i++)
257
+ root.held[message.first + i] = { t: rows[i].length > 0 ? rows[i][1] : "" }
258
+ if (rows.length > 0)
259
+ root.held[message.first].record = message.firstRecord
260
+ root.refresh()
261
+ root.stamp += 1
262
+ // Binary, large and failed are the file's whole answer: nothing more is asked of it until the view starts a new one.
263
+ if (root.settled)
264
+ Qt.callLater(root.ask)
265
+ }
266
+
267
+ onPathChanged: root.fresh()
268
+ onTextChanged: root.fresh()
269
+ onFromTextChanged: root.fresh()
270
+ onActiveChanged: root.fresh()
271
+ Component.onDestruction: root.retiring = true
272
+ onLimitChanged: Qt.callLater(root.ask)
273
+
274
+ Connections {
275
+ target: root.engine ? root.backend : null
276
+ function onCodeResult(message) { root.answered(message) }
277
+ }
278
+
279
+ // The header, sticky above the rows; in Quick Look it moves sideways with the grid and stays at the top.
280
+ Item {
281
+ id: head
282
+ anchors.top: parent.top
283
+ anchors.left: parent.left
284
+ anchors.right: parent.right
285
+ height: root.headHeight
286
+ visible: root.table.header !== null
287
+ clip: true
288
+
289
+ Item {
290
+ x: root.look ? -view.contentX : 0
291
+ width: root.gridWidth
292
+ height: parent.height
293
+
294
+ Repeater {
295
+ model: root.table.header !== null ? root.layout.length : 0
296
+ delegate: Text {
297
+ required property int index
298
+ // A reset clears the layout before old delegates are destroyed.
299
+ readonly property var place: root.layout[index] || { x: 0, w: 0, right: false }
300
+ x: root.look ? place.x + Theme.spacing.rowPaddingX : root.edge + place.x
301
+ width: root.look ? Math.max(0, place.w - 2 * Theme.spacing.rowPaddingX) : place.w
302
+ y: root.headPadY
303
+ text: Csv.oneLine(root.table.header !== null ? root.table.header[index] || "" : "")
304
+ horizontalAlignment: place.right ? Text.AlignRight : Text.AlignLeft
305
+ elide: Text.ElideRight
306
+ color: Theme.color.foregroundBright
307
+ font.family: Theme.font.family
308
+ font.pixelSize: root.pixelSize
309
+ font.bold: true
310
+ textFormat: Text.PlainText
311
+ }
312
+ }
313
+ }
314
+
315
+ Rectangle {
316
+ anchors.bottom: parent.bottom
317
+ anchors.left: parent.left
318
+ anchors.right: parent.right
319
+ height: Theme.spacing.hairline
320
+ color: Theme.color.foreground
321
+ opacity: root.ruleOpacity
322
+ }
323
+ }
324
+
325
+ ListView {
326
+ id: view
327
+ anchors.top: head.bottom
328
+ anchors.left: parent.left
329
+ anchors.right: parent.right
330
+ anchors.bottom: parent.bottom
331
+ clip: true
332
+ interactive: true
333
+ flickableDirection: Flickable.HorizontalAndVerticalFlick
334
+ boundsBehavior: Flickable.StopAtBounds
335
+ model: root.bodyRows
336
+ contentWidth: root.gridWidth
337
+ onContentYChanged: Qt.callLater(root.ask)
338
+ onHeightChanged: Qt.callLater(root.ask)
339
+
340
+ delegate: Item {
341
+ id: row
342
+ required property int index
343
+ // A held record occupies exactly one delegate at its ordinal.
344
+ readonly property var rec: root.table.byRecord[index + 2] || null
345
+ width: root.gridWidth
346
+ height: root.rowHeight
347
+
348
+ Text {
349
+ visible: root.look && row.rec !== null
350
+ x: 0
351
+ width: root.numberWidth - Theme.spacing.rowPaddingX
352
+ y: root.bodyPadY
353
+ text: row.rec !== null ? String(Csv.rowNumber(row.rec.record)) : ""
354
+ horizontalAlignment: Text.AlignRight
355
+ color: Theme.color.muted
356
+ font.family: Theme.font.family
357
+ font.pixelSize: root.pixelSize
358
+ font.features: ({ "tnum": 1 })
359
+ textFormat: Text.PlainText
360
+ }
361
+
362
+ Repeater {
363
+ model: row.rec !== null ? root.layout.length : 0
364
+ delegate: Text {
365
+ required property int index
366
+ // A reset may clear the record before its old cells are destroyed.
367
+ readonly property var place: root.layout[index] || { x: 0, w: 0, right: false }
368
+ readonly property string cell: Csv.oneLine(row.rec !== null ? row.rec.cells[index] || "" : "")
369
+ x: root.look ? place.x + Theme.spacing.rowPaddingX : root.edge + place.x
370
+ width: root.look ? Math.max(0, place.w - 2 * Theme.spacing.rowPaddingX) : place.w
371
+ y: root.bodyPadY
372
+ text: cell
373
+ horizontalAlignment: place.right ? Text.AlignRight : Text.AlignLeft
374
+ elide: Text.ElideRight
375
+ color: Theme.color.foreground
376
+ font.family: Theme.font.family
377
+ font.pixelSize: root.pixelSize
378
+ font.features: Csv.isNumber(cell) ? ({ "tnum": 1 }) : ({})
379
+ textFormat: Text.PlainText
380
+ }
381
+ }
382
+ }
383
+ }
384
+
385
+ Flea.FastScrollHandler {
386
+ visible: root.look
387
+ flickable: view
388
+ }
389
+
390
+ Flea.ViewportScrollBars {
391
+ visible: root.look
392
+ flickable: view
393
+ }
394
+ }
@@ -0,0 +1,41 @@
1
+ import QtQuick
2
+
3
+ // Each delegate files itself here by listing row, so a cursor move relights only the delegate it leaves and the one it reaches.
4
+ QtObject {
5
+ id: root
6
+
7
+ // The listing row the cursor is on; -1 lights none.
8
+ property int row: -1
9
+ // Listing row to the delegate filed under it, changed in place and read only here.
10
+ readonly property var cells: new Map()
11
+ // The delegate drawn as the cursor, null while no delegate holds the cursor row.
12
+ property Item lit: null
13
+
14
+ onRowChanged: {
15
+ var cell = root.row >= 0 ? root.cells.get(root.row) : undefined
16
+ // A delegate destroyed without parking first reads no markRow back, so its stale entry goes here.
17
+ if (cell !== undefined && cell.markRow !== root.row) { root.cells.delete(root.row); cell = undefined }
18
+ root.light(cell === undefined ? null : cell)
19
+ }
20
+
21
+ // A delegate calls this when built and whenever its listing row changes; a parked one reads -1 and files nowhere.
22
+ function place(cell) {
23
+ var from = cell.markRow
24
+ var to = cell.listingIndex
25
+ if (from >= 0 && root.cells.get(from) === cell) root.cells.delete(from)
26
+ cell.markRow = to
27
+ if (to >= 0) root.cells.set(to, cell)
28
+ if (to >= 0 && to === root.row) {
29
+ root.light(cell)
30
+ } else {
31
+ cell.cursor = false
32
+ if (root.lit === cell) root.lit = null
33
+ }
34
+ }
35
+
36
+ function light(cell) {
37
+ if (root.lit !== null && root.lit !== cell) root.lit.cursor = false
38
+ root.lit = cell
39
+ if (cell !== null) cell.cursor = true
40
+ }
41
+ }
@@ -0,0 +1,130 @@
1
+ pragma Singleton
2
+ import QtQuick
3
+ import Quickshell
4
+ import Quickshell.Io
5
+ import "js/MakeDefault.js" as MakeDefault
6
+
7
+ // Settings > About's Make Flea the default, shared by every window: the handler xdg-mime answers, whether this build has a desktop entry, `flea --default [off]` and the portal restart after it; ui/js/MakeDefault.js holds the states and the words.
8
+ QtObject {
9
+ id: root
10
+
11
+ readonly property string binary: Quickshell.env("FLEA_BIN") || "flea"
12
+ // The one answer the File manager row states and the box is ticked by.
13
+ property string handler: ""
14
+ property var claim: MakeDefault.idle()
15
+ // Handler reads are numbered as they start, so a run is settled only by a read begun after it exited.
16
+ property int reads: 0
17
+ // True from a read's start until its exit and its text are both in, which is when the next may start.
18
+ property bool readBusy: false
19
+ // A run that exited during another window's read asks for one more behind it, since a running Process is not restarted.
20
+ property bool readAgain: false
21
+ // Each process's exit code and collector text, filled in whichever order they land.
22
+ property var readAnswer: ({})
23
+ property var runAnswer: ({})
24
+ // What the run asked for, so a flea that never starts is named in the note.
25
+ property var runCommand: []
26
+
27
+ // About opening: the handler, and whether there is an entry for flea --default to point at.
28
+ function read() {
29
+ root.startRead()
30
+ prober.command = MakeDefault.probeCommand(MakeDefault.entryPaths({
31
+ HOME: Quickshell.env("HOME") || "",
32
+ XDG_DATA_HOME: Quickshell.env("XDG_DATA_HOME") || "",
33
+ XDG_DATA_DIRS: Quickshell.env("XDG_DATA_DIRS") || ""
34
+ }))
35
+ prober.running = true
36
+ }
37
+
38
+ // Enter, Space or a click on the row; a press during a run, or on a build with no entry, does nothing.
39
+ function toggle() {
40
+ var args = MakeDefault.press(root.handler, root.claim)
41
+ if (args === null || runner.running)
42
+ return
43
+ root.claim = MakeDefault.started(root.claim, args)
44
+ root.runAnswer = ({})
45
+ root.runCommand = [root.binary].concat(args)
46
+ runner.command = root.runCommand
47
+ runner.running = true
48
+ }
49
+
50
+ // False when a read is already in flight, whose answer may predate whatever the caller is waiting on.
51
+ function startRead() {
52
+ if (root.readBusy)
53
+ return false
54
+ root.readBusy = true
55
+ root.reads += 1
56
+ root.readAnswer = ({})
57
+ reader.running = true
58
+ return true
59
+ }
60
+
61
+ // A half landing after the answer is whole, a stream ending behind a program that never ran, is ignored.
62
+ function readLanded(half) {
63
+ if (MakeDefault.whole(root.readAnswer))
64
+ return
65
+ root.readAnswer = MakeDefault.landed(root.readAnswer, half)
66
+ if (!MakeDefault.whole(root.readAnswer))
67
+ return
68
+ root.readBusy = false
69
+ root.handler = MakeDefault.handlerOf(root.readAnswer)
70
+ root.claim = MakeDefault.settled(root.claim, root.reads)
71
+ if (root.readAgain) {
72
+ root.readAgain = false
73
+ root.startRead()
74
+ }
75
+ }
76
+
77
+ function runLanded(half) {
78
+ if (MakeDefault.whole(root.runAnswer))
79
+ return
80
+ root.runAnswer = MakeDefault.landed(root.runAnswer, half)
81
+ if (!MakeDefault.whole(root.runAnswer))
82
+ return
83
+ // The next read to start is the first that can see what this run wrote.
84
+ root.claim = MakeDefault.finished(root.claim, root.runAnswer.code, root.runAnswer.text, root.reads + 1)
85
+ if (!root.startRead())
86
+ root.readAgain = true
87
+ if (root.claim.restarting)
88
+ restarter.running = true
89
+ }
90
+
91
+ property var readQuery: Process {
92
+ id: reader
93
+ command: ["xdg-mime", "query", "default", "inode/directory"]
94
+ // Sample output: com.thisisgm.flea.desktop
95
+ stdout: StdioCollector { waitForEnd: true; onStreamFinished: root.readLanded({ text: this.text }) }
96
+ onExited: function (code) { root.readLanded({ code: code }) }
97
+ // An xdg-mime that cannot start raises no exited, so the read ends here, stating no handler.
98
+ onRunningChanged: {
99
+ if (MakeDefault.neverRan(root.readAnswer, reader.running))
100
+ root.readLanded(MakeDefault.NEVER_RAN)
101
+ }
102
+ }
103
+
104
+ property var probeQuery: Process {
105
+ id: prober
106
+ onExited: function (code) { root.claim = MakeDefault.probed(root.claim, code === 0) }
107
+ }
108
+
109
+ // Asynchronous like every Process, so the window keeps drawing while flea rewrites the four files.
110
+ property var runQuery: Process {
111
+ id: runner
112
+ stderr: StdioCollector { waitForEnd: true; onStreamFinished: root.runLanded({ text: this.text }) }
113
+ onExited: function (code) { root.runLanded({ code: code }) }
114
+ // A flea that cannot start wrote nothing, so there is nothing to read again and no portal to restart.
115
+ onRunningChanged: {
116
+ if (MakeDefault.neverRan(root.runAnswer, runner.running)) {
117
+ root.runAnswer = MakeDefault.landed(root.runAnswer, MakeDefault.NEVER_RAN)
118
+ root.claim = MakeDefault.unstarted(root.claim, root.runCommand)
119
+ }
120
+ }
121
+ }
122
+
123
+ // Only this switch restarts the portal; flea --default on a command line prints the hint instead.
124
+ property var restartQuery: Process {
125
+ id: restarter
126
+ command: MakeDefault.RESTART
127
+ onExited: function (code) { root.claim = MakeDefault.restarted(root.claim, code === 0) }
128
+ onRunningChanged: root.claim = MakeDefault.restartStopped(root.claim, restarter.running)
129
+ }
130
+ }
@@ -0,0 +1,47 @@
1
+ import QtQuick
2
+ import Quickshell.Io
3
+ import "js/Unlock.js" as Unlock
4
+
5
+ // U039: the udisksctl lock after releasing an unlocked crypt; a refusal names the drive.
6
+ Item {
7
+ id: root
8
+ // The DeviceMounts that posts the refusal and re-polls once the lock has settled.
9
+ property var host: null
10
+ property string _label: ""
11
+ // Locks waiting while one runs, each keeping its own backing container and label.
12
+ property var _queue: []
13
+
14
+ // Answers whether a lock started: only a crypt leaf has a backing container, so no caller checks the kind first.
15
+ function lockCryptAfter(listing, cryptDevice, label) {
16
+ var backing = Unlock.backingFor(String(listing || ""), String(cryptDevice || ""))
17
+ if (backing.length === 0)
18
+ return false
19
+ if (lockProcess.running) {
20
+ root._queue = root._queue.concat([{ backing: backing, label: label }])
21
+ return true
22
+ }
23
+ root._label = label
24
+ lockProcess.command = ["udisksctl", "lock", "--block-device", backing]
25
+ lockProcess.running = true
26
+ return true
27
+ }
28
+
29
+ Process {
30
+ id: lockProcess
31
+ onExited: function (exitCode) {
32
+ var label = root._label
33
+ root._label = ""
34
+ if (exitCode !== 0)
35
+ root.host.message(Unlock.lockNote(label), true)
36
+ if (root._queue.length > 0) {
37
+ var next = root._queue[0]
38
+ root._queue = root._queue.slice(1)
39
+ root._label = next.label
40
+ lockProcess.command = ["udisksctl", "lock", "--block-device", next.backing]
41
+ lockProcess.running = true
42
+ return
43
+ }
44
+ root.host.poll()
45
+ }
46
+ }
47
+ }