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,440 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+ .import "Mounts.js" as Mounts
5
+
6
+ // The DEVICES half of the rail: one lsblk listing turned into the rows ui/DeviceMounts.qml draws.
7
+ // Split out of ui/js/Mounts.js, which keeps the rail's shared vocabulary and the NETWORK half; a
8
+ // block device and a gvfs share have nothing in common but the rail they land in.
9
+
10
+ // Sample lsblk --bytes --json row, with the columns ui/DeviceMounts.qml asks for:
11
+ // {"name":"sda1","path":"/dev/sda1","label":"128GB","mountpoints":["/run/media/gm/128GB"],"rm":true,"ro":false,
12
+ // "tran":null,"size":124656812032,"type":"part","model":null,"fstype":"vfat","parttype":"0xb",
13
+ // "pttype":"dos","partn":1,"uuid":"A1B2-C3D4"}.
14
+ // Two row kinds come out: one "disk" row for the disk that carries /, then one "volume" row for each
15
+ // volume on every disk. ui/DeviceMounts.qml turns these into rail entries.
16
+ function parseDevices(body, unmounted) {
17
+ var tree
18
+ try {
19
+ tree = JSON.parse(String(body || ""))
20
+ } catch (e) {
21
+ // A parse failure returns the empty shape rather than throwing, so the rail self-hides.
22
+ return []
23
+ }
24
+ var nodes = (tree && tree.blockdevices) || []
25
+ var out = []
26
+ var system = systemDisk(nodes)
27
+ if (system)
28
+ out.push({ kind: "disk", label: String(system.name), device: devicePath(system), path: "/",
29
+ mounted: true, removable: false, size: deviceBytes(system.size) })
30
+ for (var i = 0; i < nodes.length; i++) {
31
+ // Every disk walks the same way; hidden() hides the system disk's plumbing, and its disk row stands for the leaf holding /.
32
+ if (!nodes[i].name || isPseudo(nodes[i]))
33
+ continue
34
+ // No transport to inherit at the top: the disk answers for itself inside the walk.
35
+ collectVolumes([nodes[i]], "", false, out, unmounted === true, unpluggable(nodes[i]))
36
+ }
37
+ return dedupeVolumes(out)
38
+ }
39
+
40
+ // zram stays out; a loop device is browsable only while it or a child is mounted, despite rm=false.
41
+ function isPseudo(node) {
42
+ var name = String(node.name || "")
43
+ if (/^zram/.test(name))
44
+ return true
45
+ return /^loop/.test(name) && !holdsMount(node)
46
+ }
47
+
48
+ // Like holdsRoot, but a mount on the loop itself or any child keeps the image browsable.
49
+ function holdsMount(node) {
50
+ if (mountOf(node).length > 0)
51
+ return true
52
+ var kids = node.children || []
53
+ for (var k = 0; k < kids.length; k++) {
54
+ if (holdsMount(kids[k]))
55
+ return true
56
+ }
57
+ return false
58
+ }
59
+
60
+ // The disk that actually carries /, found through the mountpoints of its own subtree. It used to be
61
+ // guessed as the first non-removable disk, and with a second internal drive present that guess names
62
+ // whichever disk lsblk lists first: the wrong drive was then labelled with the hostname and pointed
63
+ // at /, while the real system disk had no row at all.
64
+ function systemDisk(nodes) {
65
+ for (var i = 0; i < nodes.length; i++) {
66
+ if (nodes[i].name && holdsRoot(nodes[i]))
67
+ return nodes[i]
68
+ }
69
+ return null
70
+ }
71
+
72
+ function holdsRoot(node) {
73
+ var points = node.mountpoints || []
74
+ for (var i = 0; i < points.length; i++) {
75
+ if (points[i] === "/")
76
+ return true
77
+ }
78
+ var kids = node.children || []
79
+ for (var k = 0; k < kids.length; k++) {
80
+ if (holdsRoot(kids[k]))
81
+ return true
82
+ }
83
+ return false
84
+ }
85
+
86
+ // A volume earns a rail row when it can be unplugged, which is a stick whether or not anything
87
+ // mounted it, or when it is mounted, which is every internal drive the operator actually uses.
88
+ // RailAdditions rule 1 adds the third case behind its own switch: a volume nothing has mounted, with
89
+ // a filesystem to browse. With the switch off this is the 0.2.1 rule exactly, which kept a spare EFI
90
+ // or recovery partition out of the rail.
91
+ function collectVolumes(nodes, model, unplugs, out, unmounted, removableDisk, holder, underLoop) {
92
+ for (var i = 0; i < nodes.length; i++) {
93
+ var n = nodes[i]
94
+ var kids = n.children || []
95
+ // Only the disk carries a product name, so it is passed down to its own partitions.
96
+ var own = n.model ? String(n.model) : model
97
+ // Only the disk carries the transport, so its partitions take its answer: measured by
98
+ // mariobgsp (PR 74), whose USB drive reports tran=usb on sdb and null on sdb1. It stops
99
+ // there: what a crypt leaf under it reads as is what it read as before that PR.
100
+ var pulls = unpluggable(n) || (unplugs && String(n.type || "") === "part")
101
+ // Loop ancestry routes eject through unmount and detach, and skips the optional unmounted-volume rule.
102
+ var loopHere = underLoop || /^loop/.test(String(n.name || ""))
103
+ // No row on any setting for a hidden leaf (ESP, swap, member) or for the leaf holding /, which its disk row stands for.
104
+ if (n.name && (kids.length === 0 || mountOf(n).length > 0) && !hidden(n) && !holdsRoot(n)
105
+ && (pulls || mountOf(n).length > 0 || (unmounted && browsable(n) && !loopHere) || isLockedNode(n)))
106
+ out.push(volumeRow(n, own, pulls, removableDisk === true, holder, loopHere))
107
+ collectVolumes(kids, own, pulls, out, unmounted, removableDisk === true || unpluggable(n), containerName(n), loopHere)
108
+ }
109
+ }
110
+
111
+ // A leaf udisks hides is no row in any branch.
112
+ function hidden(n) {
113
+ if (mountOf(n).length === 0 && String(n.fstype || "").length === 0)
114
+ return true // H1: a partition with no filesystem and nothing mounted.
115
+ var fs = String(n.fstype || "").toLowerCase()
116
+ if (fs === "swap" || fs.slice(-7) === "_member" || fs === "bcache" || fs === "ceph" || fs === "drbd")
117
+ return true // H2: swap, LVM and RAID members, and other non-filesystem types.
118
+ if (fs.indexOf("crypto_") === 0)
119
+ return false // The Unlock board keeps a locked LUKS container as a row.
120
+ if (isFirmwarePart(n) && !isIsohybridKeep(n))
121
+ return true // H3: ESP, MSR, BIOS boot, WinRE GUID or MBR type, except an installer ISO part.
122
+ if (isRecoveryLabel(n))
123
+ return true // H4: System Reserved and vendor recovery labels on ntfs or vfat.
124
+ if (isSystemMountOnly(n))
125
+ return true // H5: mounted only where the system itself lives, never a user folder.
126
+ return false
127
+ }
128
+
129
+ // GPT GUIDs and MBR numbers udisks hides; MBR compared numerically, lsblk drops the leading zero.
130
+ function isFirmwarePart(n) {
131
+ var raw = String(n.parttype || "")
132
+ if (raw.length === 0)
133
+ return false
134
+ var lower = raw.toLowerCase()
135
+ if (lower.indexOf("-") >= 0)
136
+ return gptHidden(lower)
137
+ var num = parseInt(lower, 16)
138
+ if (isNaN(num))
139
+ return false // An unparsable type hides nothing rather than everything.
140
+ return mbrHidden(num)
141
+ }
142
+
143
+ // Sample input: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" trues, "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" falses.
144
+ function gptHidden(lower) {
145
+ var hide = ["c12a7328-f81f-11d2-ba4b-00a0c93ec93b", "21686148-6449-6e6f-744e-656564454649",
146
+ "e3c9e316-0b5c-4db8-817d-f92df00215ae", "de94bba4-06d1-4d40-a16a-bfd50179d6ac",
147
+ "bc13c2ff-59e6-4262-a352-b275fd6f7172", "426f6f74-0000-11aa-aa11-00306543ecac",
148
+ "a19d880f-05fc-4d3b-a006-743f0f84911e", "e6d6d379-f507-44c2-a23c-238f2a3df928"]
149
+ for (var i = 0; i < hide.length; i++)
150
+ if (lower === hide[i])
151
+ return true
152
+ return false
153
+ }
154
+
155
+ // Sample input: 0x27 trues, 0x7 falses; 0x0 hides unless the isohybrid keep below answers first.
156
+ function mbrHidden(num) {
157
+ var hide = [0x0, 0x5, 0xf, 0x85, 0x11, 0x12, 0x14, 0x16, 0x17, 0x1b, 0x1c, 0x1e, 0x27, 0x3d,
158
+ 0x84, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x97, 0x98, 0x9a, 0x9b, 0xab, 0xbb, 0xc2, 0xc3, 0xdd, 0xef, 0xfd]
159
+ for (var i = 0; i < hide.length; i++)
160
+ if (num === hide[i])
161
+ return true
162
+ return false
163
+ }
164
+
165
+ // Sample input: dos with 0x0 part 1 iso9660 keeps, the same part as vfat hides; udisks isohybrid undo.
166
+ function isIsohybridKeep(n) {
167
+ if (String(n.pttype || "").toLowerCase() !== "dos")
168
+ return false
169
+ var num = parseInt(String(n.parttype || ""), 16)
170
+ if (!(num === 0x0 || num === 0x17))
171
+ return false
172
+ var partn = String(n.partn === null || n.partn === undefined ? "" : n.partn)
173
+ if (!(partn === "1" || partn === "2"))
174
+ return false
175
+ var fs = String(n.fstype || "").toLowerCase()
176
+ return fs === "iso9660" || fs === "udf"
177
+ }
178
+
179
+ // Sample input: ntfs "System Reserved" trues, ext4 "System Reserved" falses; spaces read as udev writes them.
180
+ function isRecoveryLabel(n) {
181
+ var fs = String(n.fstype || "").toLowerCase()
182
+ if (!(fs === "ntfs" || fs === "vfat"))
183
+ return false
184
+ var label = String(n.label || "").replace(/ /g, "_")
185
+ var hide = ["Recovery", "RECOVERY", "Lenovo_Recovery", "HP_RECOVERY", "Recovery_Partition",
186
+ "DellUtility", "DellRestore", "IBM_SERVICE", "SERVICEV001", "SERVICEV002",
187
+ "SYSTEM_RESERVED", "System_Reserved", "WINRE_DRV", "DIAGS", "IntelRST"]
188
+ for (var i = 0; i < hide.length; i++)
189
+ if (label === hide[i])
190
+ return true
191
+ return false
192
+ }
193
+
194
+ // Sample input: ["/"] trues, ["/mnt/data"] falses; every mountpoint must be system for the row to hide.
195
+ function isSystemMountOnly(n) {
196
+ var points = []
197
+ var raw = n.mountpoints || []
198
+ for (var i = 0; i < raw.length; i++) {
199
+ var p = raw[i] === null ? "" : String(raw[i])
200
+ if (p.length > 0 && p.charAt(0) === "/")
201
+ points.push(p)
202
+ }
203
+ if (points.length === 0)
204
+ return false
205
+ for (var j = 0; j < points.length; j++)
206
+ if (!isSystemPath(points[j]))
207
+ return false
208
+ return true
209
+ }
210
+
211
+ // Sample input: "/boot" trues, "/run" trues, "/home/gm/Data" falses; exact glib list, prefix only under /dev /proc /sys.
212
+ function isSystemPath(p) {
213
+ if (p === "/" || p.indexOf("/.") >= 0)
214
+ return true
215
+ if (p === "/dev" || p === "/proc" || p === "/sys")
216
+ return true
217
+ if (p.indexOf("/dev/") === 0 || p.indexOf("/proc/") === 0 || p.indexOf("/sys/") === 0)
218
+ return true
219
+ var exact = ["/bin", "/boot", "/compat/linux/proc", "/compat/linux/sys", "/etc", "/home",
220
+ "/lib", "/lib64", "/libexec", "/live/cow", "/live/image", "/media", "/mnt", "/net",
221
+ "/opt", "/rescue", "/root", "/run", "/sbin", "/srv", "/tmp", "/usr", "/usr/X11R6", "/usr/local",
222
+ "/usr/obj", "/usr/ports", "/usr/src", "/usr/xobj", "/var", "/var/crash", "/var/local",
223
+ "/var/log", "/var/log/audit", "/var/mail", "/var/run", "/var/tmp"]
224
+ for (var i = 0; i < exact.length; i++)
225
+ if (p === exact[i])
226
+ return true
227
+ return false
228
+ }
229
+
230
+ // One row per device path and per btrfs UUID: an md repeat lists one path twice, multi-device btrfs shares one.
231
+ function dedupeVolumes(rows) {
232
+ var head = []
233
+ var byUuid = {}
234
+ var at = {}
235
+ for (var i = 0; i < rows.length; i++) {
236
+ var r = rows[i]
237
+ var dkey = String(r.device || "")
238
+ var ukey = String(r.uuid || "")
239
+ var dup = -1
240
+ if (dkey.length > 0 && at[dkey] !== undefined)
241
+ dup = at[dkey]
242
+ else if (ukey.length > 0 && byUuid[ukey] !== undefined)
243
+ dup = byUuid[ukey]
244
+ if (dup < 0) {
245
+ at[dkey] = head.length
246
+ if (ukey.length > 0)
247
+ byUuid[ukey] = head.length
248
+ head.push(r)
249
+ } else if (r.mounted === true && head[dup].mounted !== true) {
250
+ at[dkey] = dup
251
+ if (ukey.length > 0)
252
+ byUuid[ukey] = dup
253
+ head[dup] = r
254
+ }
255
+ }
256
+ return head
257
+ }
258
+
259
+ // Sample input: {"name":"sdb1","mountpoints":[null],"type":"part","fstype":"crypto_LUKS","fsver":"2"}, a locked leaf.
260
+ function isLockedNode(n) {
261
+ if (!n || (n.children || []).length > 0)
262
+ return false
263
+ if (mountOf(n).length > 0)
264
+ return false
265
+ return String(n.fstype || "").toLowerCase().indexOf("crypto_") === 0
266
+ }
267
+
268
+ // RailAdditions rule 1 gate (old lsblk without PARTTYPE): empty-fs and swap die in hidden() ahead; only crypto and efi decide here.
269
+ function browsable(n) {
270
+ var fs = String(n.fstype || "").toLowerCase()
271
+ if (fs.indexOf("crypto_") === 0)
272
+ return false
273
+ return String(n.parttypename || "").toLowerCase().indexOf("efi") < 0
274
+ }
275
+
276
+ // A drive somebody can pull out, which is what Eject is for. RM alone is not the answer: a USB
277
+ // bridge (a WD My Passport, PR 74) reports rm=false and is still a drive you unplug, while a hot-swap
278
+ // SATA bay reports its own hotplug and is not, which is why the transport decides and not that.
279
+ function unpluggable(n) {
280
+ return !!n && (n.rm === true || String(n.tran || "").toLowerCase() === "usb")
281
+ }
282
+
283
+ // The mount wait starts when gio exits 0, never at launch: an admin polkit prompt longer than the
284
+ // wait is a slow prompt and not a mount that never reported a folder to open.
285
+ function mountTimerStart(exitCode) {
286
+ return exitCode === 0
287
+ }
288
+
289
+ // The disk a partition powers off through, so a USB bridge stops instead of re-announcing.
290
+ // Sample input: "/dev/sda1" answers "/dev/sda", "/dev/nvme0n1p2" answers "/dev/nvme0n1.
291
+ function powerOffDisk(device) {
292
+ var text = String(device || "")
293
+ var m = text.match(/^(\/dev\/(?:sd[a-z]+|hd[a-z]+|vd[a-z]+|nvme\d+n\d+|mmcblk\d+|loop\d+))p?\d+$/)
294
+ if (m)
295
+ return m[1]
296
+ var bare = text.match(/^\/dev\/(?:sd[a-z]+|hd[a-z]+|vd[a-z]+|nvme\d+n\d+|mmcblk\d+|loop\d+)$/)
297
+ return bare ? text : ""
298
+ }
299
+
300
+ // With another partition mounted, loop-delete only marks autoclear and that mount keeps reading (measured in 0.3.10).
301
+ // Sample input: {device: "/dev/loop0p1", path: "/run/media/u/ISO", loop: true} answers the sh chain on /dev/loop0.
302
+ var detachFailedExit = 3
303
+ function ejectCommand(e) {
304
+ var path = String(e.path || "")
305
+ if (e.loop !== true)
306
+ return ["gio", "mount", "-e", path]
307
+ var loop = String(e.device || "").match(/^\/dev\/(loop\d+)(?:p\d+)?$/)
308
+ if (!loop)
309
+ return ["gio", "mount", "-u", path]
310
+ var loopDisk = "/dev/" + loop[1]
311
+ return ["sh", "-c", 'autoclear=$(cat -- "$4" 2>/dev/null) || autoclear=; before=$(cat -- "$3" 2>/dev/null); '
312
+ + 'status=0; gio mount -u "$1" || status=1; if [ "$autoclear" != 0 ]; then exit "$status"; fi; ' // Autoclear 1 detaches at the kernel's last close; unreadable values are left alone.
313
+ + 'after=$(cat -- "$3" 2>/dev/null); if [ -n "$before" ] && [ "$after" = "$before" ]; then '
314
+ + 'udisksctl loop-delete --no-user-interaction -b "$2" || exit ' + detachFailedExit + '; fi; exit "$status"',
315
+ "sh", path, loopDisk, "/sys/block/" + loop[1] + "/loop/backing_file", "/sys/block/" + loop[1] + "/loop/autoclear"]
316
+ }
317
+
318
+ // The sysfs block name for a disk path, so the eject chain can watch its write counter.
319
+ // Sample input: "/dev/sda" answers "sda", "/dev/nvme0n1" answers "nvme0n1.
320
+ function sysBase(disk) {
321
+ var text = String(disk || "")
322
+ var m = text.match(/^\/dev\/(.+)$/)
323
+ return m ? m[1] : ""
324
+ }
325
+
326
+ // The written-sector counter out of one /sys/block/<disk>/stat read, "" when unreadable.
327
+ // Sample input: " 1 0 2 3 0 0 42 0 0 0 0 0 0 0 0" answers "42".
328
+ function writtenSectors(body) {
329
+ var fields = String(body || "").trim().split(/\s+/)
330
+ return fields.length >= 7 ? fields[6] : ""
331
+ }
332
+
333
+ // Every mounted node under one disk in the last listing, hidden ones too (an ESP has no rail row, yet a power-off must unmount it); system mounts never queue.
334
+ // Sample input: sda1 (ESP) mounted at /run/media/u/EFI answers [{device: "/dev/sda1", path: "/run/media/u/EFI"}] for "/dev/sda".
335
+ function powerOffQueue(listing, disk, entries) {
336
+ var tree
337
+ var out = []
338
+ try {
339
+ tree = JSON.parse(String(listing || ""))
340
+ } catch (e) {
341
+ // An unparsable listing keeps the mounted rail volumes queued, as before the hidden-node walk.
342
+ console.warn("Device listing for " + disk + " could not be parsed (" + e.message + "); mounted rail volumes were queued instead.")
343
+ var rows = entries || []
344
+ for (var r = 0; r < rows.length; r++) {
345
+ var row = rows[r]
346
+ if (row.kind === "volume" && row.mounted && powerOffDisk(row.device) === disk)
347
+ out.push({ device: row.device, path: row.path })
348
+ }
349
+ return dedupeVolumes(out)
350
+ }
351
+ var nodes = (tree && tree.blockdevices) || []
352
+ for (var i = 0; i < nodes.length; i++) {
353
+ if (nodes[i].name && powerOffDisk(devicePath(nodes[i])) === disk)
354
+ collectMounted(nodes[i], out)
355
+ }
356
+ return dedupeVolumes(out)
357
+ }
358
+
359
+ function collectMounted(node, out) {
360
+ var point = mountOf(node)
361
+ if (point.length > 0 && !holdsRoot(node) && !isSystemMountOnly(node))
362
+ out.push({ device: devicePath(node), path: point })
363
+ var kids = node.children || []
364
+ for (var i = 0; i < kids.length; i++)
365
+ collectMounted(kids[i], out)
366
+ }
367
+
368
+ // Sample gio stderr: "Error 1: target is busy", "Not authorized to perform operation",
369
+ // "No volume for device /dev/sda9", "Location is already mounted", "No medium found".
370
+ // "" opens rather than failing: the volume is already mounted, so there is no failure to say.
371
+ function mountError(op, exitCode, stderr, label) {
372
+ if (exitCode === 0)
373
+ return ""
374
+ var text = String(stderr || "").toLowerCase()
375
+ var name = String(label || "")
376
+ if (/already mounted/.test(text))
377
+ return ""
378
+ if (/busy|in use|in use by/.test(text))
379
+ return Format.fill(Mounts.WORDS.busy, name)
380
+ if (/not authorized|not allowed|refused|dismissed|no authentication|auth/i.test(String(stderr || "")))
381
+ return Format.fill(op === "unmount" ? Mounts.WORDS.unmountRefused : op === "eject" ? Mounts.WORDS.ejectRefused : Mounts.WORDS.mountRefused, name)
382
+ if (/no volume|no medium|no media|empty|no device/.test(text))
383
+ return Format.fill(/medium|media|empty/.test(text) ? Mounts.WORDS.noDisc : Mounts.WORDS.notMountable, name)
384
+ if (op === "mount" && /wrong fs type|bad superblock|unknown filesystem type|can.t read superblock|structure needs cleaning/.test(text))
385
+ return Format.fill(Mounts.WORDS.damaged, name)
386
+ if (op === "unmount")
387
+ return Format.fill(Mounts.WORDS.unmountFailed, name)
388
+ if (op === "eject")
389
+ return Format.fill(Mounts.WORDS.ejectFailed, name)
390
+ return Format.fill(Mounts.WORDS.mountFailed, name)
391
+ }
392
+
393
+ // gio's own reason as the status bar's detail line; sample "Error mounting /dev/sdb1 at /run/media/u/DATA #2: wrong fs type" and "Error unmounting /dev/sdb1: target is busy" give "wrong fs type" and "target is busy", "gio: file:///x: Error ejecting /dev/sdb: busy" gives "busy" (gio's file-URI lead), "" gives "".
394
+ function mountDetail(stderr) {
395
+ var lines = String(stderr || "").split("\n").map(function (line) { return line.trim() }).filter(function (line) { return line.length > 0 })
396
+ return lines.join(" ").replace(/^gio:\s*/, "").replace(/^[a-z][a-z0-9+.-]*:\/\/\S*:\s+/i, "").replace(/^Error (?:mounting|unmounting|ejecting) \S+(?: at .*?)?:\s+/, "").trim()
397
+ }
398
+
399
+ // Sample: ["/home", "/var/log", "/"] for one btrfs device with several subvolumes mounted, ["[SWAP]"]
400
+ // for swap, which is no directory, and [null] for a volume nothing has mounted. The first real path
401
+ // wins, which is also what drops swap: only a mountpoint is browsable and only one row is drawn.
402
+ function mountOf(node) {
403
+ var points = node.mountpoints || []
404
+ for (var i = 0; i < points.length; i++) {
405
+ var point = points[i] === null ? "" : String(points[i])
406
+ if (point.length > 0 && point.charAt(0) === "/")
407
+ return point
408
+ }
409
+ return ""
410
+ }
411
+
412
+ // lsblk's own PATH column, because a device-mapper leaf lives at /dev/mapper/<name> and "/dev/" plus
413
+ // its kernel name is a path that does not exist. gio is handed this, so it has to be the real one.
414
+ function devicePath(node) {
415
+ return node.path ? String(node.path) : "/dev/" + String(node.name)
416
+ }
417
+
418
+ // Sample input: {"name":"sdb1","label":"Backup","fstype":"crypto_LUKS"}, a container its owner named; "" for any other node.
419
+ function containerName(n) {
420
+ return String(n.fstype || "").toLowerCase().indexOf("crypto_") === 0 && n.label ? String(n.label) : ""
421
+ }
422
+
423
+ // Labelled by the filesystem label, then the drive's product name, then the kernel name; a crypt keeps its named container's.
424
+ function volumeRow(n, model, unplugs, removableDisk, holder, loop) {
425
+ var path = mountOf(n)
426
+ var named = String(n.type || "") === "crypt" ? String(holder || "") : ""
427
+ var label = named.length > 0 ? named : n.label ? String(n.label) : (model.length > 0 ? model : String(n.name))
428
+ var fs = String(n.fstype || "").toLowerCase()
429
+ // A crypt leaf on a removable drive releases like the stick it sits on; an internal one never does.
430
+ var removable = unplugs === true || (String(n.type || "") === "crypt" && removableDisk === true)
431
+ return { kind: "volume", label: label, device: devicePath(n), path: path, mounted: path.length > 0,
432
+ removable: removable, mediaRemovable: n.rm === true, readOnly: n.ro === true, size: deviceBytes(n.size),
433
+ locked: isLockedNode(n), fstype: String(n.fstype || ""), fsver: String(n.fsver || ""),
434
+ uuid: fs === "btrfs" && n.uuid ? String(n.uuid) : "", loop: !!loop }
435
+ }
436
+
437
+ // An unavailable or malformed capacity stays absent; only the delegate formats valid byte counts.
438
+ function deviceBytes(value) {
439
+ return Number.isSafeInteger(value) && value >= 0 ? value : null
440
+ }
@@ -0,0 +1,180 @@
1
+ .pragma library
2
+ .import "Format.js" as Format
3
+
4
+ // flea-qml: a folder's size is measured only when the user asks (src/dirsize.js). A folder never
5
+ // measured shows UNMEASURED in its Size cell and the Size header carries it too; both take a click.
6
+ var UNMEASURED = "\u2696\ufe0f"
7
+ var MEASURING = "\u2026"
8
+
9
+ // A row this listing has asked about: null means asked and waiting, an object is the answer.
10
+ var ASKED = null
11
+
12
+ function empty() {
13
+ return { file: {}, order: [] }
14
+ }
15
+
16
+ // Only visible rows, only rows the backend called directories, only rows never asked.
17
+ function plan(state, rows, held, first, last) {
18
+ var ask = []
19
+ for (var i = first; i <= last; i++) {
20
+ if (state.file[i] !== undefined) {
21
+ continue
22
+ }
23
+ var row = rows[i - held]
24
+ if (row && row.d) {
25
+ ask.push(i)
26
+ }
27
+ }
28
+ return ask
29
+ }
30
+
31
+ // The wrapper is new so a QML binding on it re-evaluates; the map inside is mutated in place.
32
+ function applied(state, ask) {
33
+ for (var i = 0; i < ask.length; i++) {
34
+ state.file[ask[i]] = ASKED
35
+ state.order.push(ask[i])
36
+ }
37
+ return { file: state.file, order: state.order }
38
+ }
39
+
40
+ // Gates the cancel wire message, since a fling fires onContentYChanged on every pixel and a fresh listing has nothing queued to cancel yet.
41
+ function hasPending(state) {
42
+ for (var i = 0; i < state.order.length; i++) {
43
+ if (state.file[state.order[i]] === ASKED) {
44
+ return true
45
+ }
46
+ }
47
+ return false
48
+ }
49
+
50
+ // A scroll cancels every row still waiting, not only the ones off-viewport, matching what the backend's own dirsizecancel means.
51
+ function cancelled(state) {
52
+ var file = {}
53
+ var order = []
54
+ for (var i = 0; i < state.order.length; i++) {
55
+ var row = state.order[i]
56
+ if (state.file[row] === ASKED) {
57
+ continue
58
+ }
59
+ file[row] = state.file[row]
60
+ order.push(row)
61
+ }
62
+ return { file: file, order: order }
63
+ }
64
+
65
+ // A live answer re-lists some folders: each answered size follows its row, by name, to that row's new index. Pending asks do not follow.
66
+ function carried(state, oldRows, oldHeld, newRows, newHeld) {
67
+ var at = Object.create(null)
68
+ for (var j = 0; j < newRows.length; j++) {
69
+ if (newRows[j].d) {
70
+ at[newRows[j].n] = newHeld + j
71
+ }
72
+ }
73
+ var next = empty()
74
+ for (var k = 0; k < state.order.length; k++) {
75
+ var answer = state.file[state.order[k]]
76
+ var row = oldRows[state.order[k] - oldHeld]
77
+ if (answer && row && at[row.n] !== undefined) {
78
+ next.file[at[row.n]] = answer
79
+ next.order.push(at[row.n])
80
+ }
81
+ }
82
+ return next
83
+ }
84
+
85
+ // Sizes a live answer carried on its rows land with those rows; with none the state comes back as it was.
86
+ // Sample input: (null, [{n: "x", d: true}, {n: "c", d: true, z: 96}], 20) answers file {21: {bytes: 96, partial: false}}, order [21].
87
+ function inlined(state, rows, held) {
88
+ var next = null
89
+ for (var i = 0; i < rows.length; i++) {
90
+ if (rows[i].z === undefined)
91
+ continue
92
+ next = next || state || empty()
93
+ if (next.file[held + i] === undefined)
94
+ next.order.push(held + i)
95
+ next.file[held + i] = { bytes: rows[i].z, partial: rows[i].zp === true }
96
+ }
97
+ return next || state
98
+ }
99
+
100
+ // The cap bounds a policy bug, not normal use, the same reason ui/js/Thumbs.js has one; callers pass Pane's own thumbCap.
101
+ function remember(state, row, bytes, partial, cap) {
102
+ if (state.file[row] === undefined) {
103
+ state.order.push(row)
104
+ }
105
+ state.file[row] = { bytes: bytes, partial: partial }
106
+ while (state.order.length > cap) {
107
+ delete state.file[state.order.shift()]
108
+ }
109
+ return { file: state.file, order: state.order, all: state.all }
110
+ }
111
+
112
+ // Sample input: ("network") trues, ("usb") falses.
113
+ function isRemoteClass(storageClass) {
114
+ return storageClass === "network" || storageClass === "phone"
115
+ }
116
+
117
+ // Sample input: (["size"]) trues, ([]) falses.
118
+ function sizeHidden(hiddenCols) {
119
+ return hiddenCols.indexOf("size") >= 0
120
+ }
121
+
122
+ // Sample input: ("list", [], "", true) trues, ("grid", [], "", true) falses.
123
+ function wantsSizes(viewMode, hiddenCols, storageClass, storageKnown) {
124
+ if (!storageKnown) return false
125
+ if (isRemoteClass(storageClass)) return false
126
+ if (viewMode === "grid") return false
127
+ if (viewMode === "list" && sizeHidden(hiddenCols)) return false
128
+ return true
129
+ }
130
+
131
+ // null covers both "never asked" and "asked and still waiting"; cellFor tells them apart for drawing.
132
+ function sizeFor(state, row) {
133
+ var value = state.file[row]
134
+ return value && typeof value === "object" ? value : null
135
+ }
136
+
137
+ // What a Size cell draws from: the answer, { waiting: true } while a walk is out for it, or null.
138
+ function cellFor(state, row) {
139
+ var value = state.file[row]
140
+ if (value && typeof value === "object") return value
141
+ if (value === ASKED || (value === undefined && state.all === true)) return { waiting: true }
142
+ return null
143
+ }
144
+
145
+ // A folder's size from this listing's answers, else the size a row came back carrying (z, zp).
146
+ // Sample input: (null, {d: true, z: 2048}) gives {bytes: 2048, partial: false}; (null, {d: true}) gives null.
147
+ function known(cell, row) {
148
+ if (cell && !cell.waiting) return cell
149
+ if (row && row.z !== undefined) return { bytes: row.z, partial: row.zp === true }
150
+ return null
151
+ }
152
+
153
+ // The Size cell of a folder: MEASURING while asked, else UNMEASURED, followed by the size once
154
+ // there is one, so a measured folder still shows what a click on it does: measure it again.
155
+ // Sample input: ({bytes: 2048, partial: false}) gives "⚖️ 2 kB"; (null) gives "⚖️".
156
+ function folderText(cell, row) {
157
+ if (cell && cell.waiting) return MEASURING
158
+ var size = known(cell, row)
159
+ return size ? UNMEASURED + " " + (size.partial ? ">" : "") + Format.size(size.bytes) : UNMEASURED
160
+ }
161
+
162
+ // Rows the user asked to measure wait until their answers, or the run's end, land.
163
+ function asking(state, rows) {
164
+ for (var i = 0; i < rows.length; i++) {
165
+ if (state.file[rows[i]] === undefined) state.order.push(rows[i])
166
+ state.file[rows[i]] = ASKED
167
+ }
168
+ return { file: state.file, order: state.order, all: state.all }
169
+ }
170
+
171
+ // The header's ⚖️: every folder in the listing waits, held in the window or not, and is measured anew.
172
+ function askingAll(state) {
173
+ return { file: {}, order: [], all: true }
174
+ }
175
+
176
+ // The run ended (dirsizedone): whatever still waits has no answer coming.
177
+ function settled(state) {
178
+ var next = cancelled(state)
179
+ return { file: next.file, order: next.order }
180
+ }