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,73 @@
1
+ .pragma library
2
+
3
+ .import "Search.js" as Search
4
+
5
+ // The mark follows the pane's own clipboard, so spending a cut clears every mark at once.
6
+
7
+ // Sample input: { paths: ["/home/gm/Pictures/phone/IMG_4121.jpg"], moving: true }
8
+ var _cached = null
9
+ var _marks = {}
10
+ // Counts rows reaching the library; production ignores it, tests/listcost.qml asserts on it.
11
+ var markCalls = 0
12
+
13
+ // One keyed lookup per clipboard, rebuilt when the clipboard object changes; every row after that is a single key read.
14
+ function setFor(clipboard) {
15
+ if (clipboard === _cached)
16
+ return _marks
17
+ _cached = clipboard
18
+ _marks = {}
19
+ var paths = (clipboard && clipboard.paths) || []
20
+ for (var i = 0; i < paths.length; i++)
21
+ _marks[paths[i]] = true
22
+ return _marks
23
+ }
24
+
25
+ // An emptied clipboard drops its lookup once, so a cut of a large directory frees it and later rows allocate nothing.
26
+ function release() {
27
+ if (_cached === null) return
28
+ _cached = null
29
+ _marks = {}
30
+ }
31
+
32
+ // Sample input: { paths: [], moving: false } is empty, null is empty.
33
+ function isEmpty(clipboard) {
34
+ return !clipboard || !clipboard.paths || clipboard.paths.length === 0
35
+ }
36
+
37
+ function markFor(path, clipboard) {
38
+ if (isEmpty(clipboard)) {
39
+ release()
40
+ return ""
41
+ }
42
+ return setFor(clipboard)[path] === true ? (clipboard.moving ? "scissors" : "copy") : ""
43
+ }
44
+
45
+ // An empty clipboard costs nothing: its paths are never joined or searched.
46
+ function markForRow(pane, name, clipboard) {
47
+ markCalls += 1
48
+ if (isEmpty(clipboard)) {
49
+ release()
50
+ return ""
51
+ }
52
+ if (!name) {
53
+ return ""
54
+ }
55
+ return markFor(rowPath(pane, name), clipboard)
56
+ }
57
+
58
+ // The pane's own join under the listing's base, so a search result resolves against the scope its search walked.
59
+ // Sample input: pane { path: "/home/gm/Pictures/phone" }, name "IMG_4121.jpg".
60
+ function rowPath(pane, name) {
61
+ if (!name) {
62
+ return ""
63
+ }
64
+ return pane.join(Search.baseOf(pane), name)
65
+ }
66
+
67
+ // A sent cut empties a cut clipboard, so the marks go with it; anything else keeps it. ui/CollideHost.qml decides through this.
68
+ function spent(clipboard, spendsCut) {
69
+ if (spendsCut === true && clipboard && clipboard.moving === true) {
70
+ return { paths: [], moving: false }
71
+ }
72
+ return clipboard
73
+ }
@@ -0,0 +1,67 @@
1
+ .pragma library
2
+
3
+ .import "Clipboard.js" as Clipboard
4
+
5
+ function publish(pane, request, copied) {
6
+ if (request.sequence !== pane.clipSequence) return
7
+ Clipboard.set(pane, request.paths, request.moving)
8
+ pane.message(copied(request.paths.length, request.moving), false)
9
+ }
10
+
11
+ // Untagged paths replies resolve one queued request at a time; only the newest choice publishes.
12
+ function drain(pane) {
13
+ if (pane.clipPending !== null) return
14
+ var queue = (pane.clipQueue || []).slice()
15
+ while (queue.length) {
16
+ var request = queue[0]
17
+ if (request.paths !== null || request.sequence !== pane.clipSequence) {
18
+ queue.shift()
19
+ continue
20
+ }
21
+ if (request.path !== pane.path || request.listing !== pane.backend.heldListing || pane.listInFlight) {
22
+ queue.shift()
23
+ pane.message("Selected items changed; copy or cut again.", false)
24
+ continue
25
+ }
26
+ pane.clipQueue = queue
27
+ pane.clipPending = request
28
+ pane.backend.askPaths(request.rows)
29
+ return
30
+ }
31
+ pane.clipQueue = queue
32
+ }
33
+
34
+ function take(pane, moving, paths, indices, copied) {
35
+ pane.clipSequence = (pane.clipSequence || 0) + 1
36
+ var request = { sequence: pane.clipSequence, moving: moving, paths: paths ? paths.slice() : null,
37
+ rows: paths ? null : indices.slice(), path: pane.path, listing: pane.backend.heldListing }
38
+ pane.clipQueue = (pane.clipQueue || []).concat([request])
39
+ if (request.paths !== null) publish(pane, request, copied)
40
+ drain(pane)
41
+ }
42
+
43
+ function resolved(pane, list, copied) {
44
+ if (pane.clipPending === null) return
45
+ var sequence = pane.clipPending.sequence
46
+ var queue = (pane.clipQueue || []).slice()
47
+ for (var i = 0; i < queue.length; i++) {
48
+ if (queue[i].sequence !== sequence) continue
49
+ var request = Object.assign({}, queue[i], { paths: list.slice() })
50
+ queue[i] = request
51
+ publish(pane, request, copied)
52
+ break
53
+ }
54
+ pane.clipQueue = queue
55
+ pane.clipPending = null
56
+ drain(pane)
57
+ }
58
+
59
+ function failed(pane) {
60
+ if (pane.clipPending === null) return
61
+ var sequence = pane.clipPending.sequence
62
+ pane.clipQueue = (pane.clipQueue || []).filter(function (request) {
63
+ return request.sequence !== sequence
64
+ })
65
+ pane.clipPending = null
66
+ drain(pane)
67
+ }
@@ -0,0 +1,179 @@
1
+ .pragma library
2
+
3
+ .import "ClipMarks.js" as ClipMarks
4
+ .import "Menu.js" as Menu
5
+ .import "Format.js" as Format
6
+
7
+ // Whole sentences with "%1" for a value, filled by fill so each translates as one.
8
+ var WORDS = {
9
+ setFailed: "Copied in this window only: %1",
10
+ clearFailed: "Could not clear the system clipboard: %1"
11
+ }
12
+
13
+ function empty() { return { paths: [], moving: false, token: "" } }
14
+ function state() {
15
+ return { sets: [], ownTokens: Object.create(null), generation: 0, failed: [], gets: [], deferred: null,
16
+ getSequence: 0, acceptedGetSequence: 0 }
17
+ }
18
+ function session(pane) {
19
+ if (!pane.clipboardState) pane.clipboardState = state()
20
+ return pane.clipboardState
21
+ }
22
+
23
+ function set(pane, paths, moving) {
24
+ var s = session(pane)
25
+ s.generation += 1
26
+ s.deferred = null
27
+ var clip = { paths: paths, moving: moving, token: "" }
28
+ pane.clipboard = clip
29
+ s.sets.push({ pane: pane, backend: pane.backend, clip: clip })
30
+ pane.backend.send({ c: "clipSet", op: moving ? "cut" : "copy", paths: paths })
31
+ }
32
+
33
+ function take(queue, backend) {
34
+ for (var i = 0; i < queue.length; i++) {
35
+ if (queue[i].backend === backend) return queue.splice(i, 1)[0]
36
+ }
37
+ return null
38
+ }
39
+
40
+ function replace(pane, message) {
41
+ pane.clipboard = message.clip === "copy" || message.clip === "cut"
42
+ ? { paths: message.paths || [], moving: message.clip === "cut", token: message.token || "" }
43
+ : empty()
44
+ }
45
+
46
+ function pendingEcho(s, message) {
47
+ if (!message.token) return false
48
+ var paths = message.paths || []
49
+ for (var i = 0; i < s.sets.length; i++) {
50
+ var clip = s.sets[i].clip
51
+ if (clip.moving !== (message.clip === "cut") || clip.paths.length !== paths.length) continue
52
+ var equal = true
53
+ for (var j = 0; j < clip.paths.length; j++) {
54
+ if (clip.paths[j] !== paths[j]) {
55
+ equal = false
56
+ break
57
+ }
58
+ }
59
+ if (equal) return true
60
+ }
61
+ return false
62
+ }
63
+
64
+ function selection(pane, message, s) {
65
+ s.deferred = null
66
+ if (message.token && s.ownTokens[message.token]) return
67
+ // A watcher can see our owner before set answers with its token.
68
+ if (pendingEcho(s, message)) { s.deferred = {pane: pane, message: message}; return }
69
+ s.generation += 1
70
+ replace(pane, message)
71
+ }
72
+
73
+ function receive(pane, message) {
74
+ var s = session(pane)
75
+ if (message.op === "set") {
76
+ var entry = take(s.sets, pane.backend)
77
+ if (!entry) return
78
+ if (!message.ok) {
79
+ // The copy itself worked, inside this window: a notice, so the paste's own result line is not held under it.
80
+ entry.pane.message(Format.fill(WORDS.setFailed, message.error), false)
81
+ } else {
82
+ // Both panes can echo any earlier owner after a later set has answered.
83
+ if (message.token) s.ownTokens[message.token] = true
84
+ // The collision card may already hold this cut, so its snapshot keeps the token too.
85
+ entry.clip.token = message.token
86
+ if (pane.clipboard === entry.clip)
87
+ pane.clipboard = { paths: entry.clip.paths, moving: entry.clip.moving, token: message.token }
88
+ }
89
+ var deferred = s.deferred
90
+ if (deferred) {
91
+ s.deferred = null
92
+ selection(deferred.pane, deferred.message, s)
93
+ }
94
+ } else if (message.op === "changed") {
95
+ var index = s.failed.indexOf(pane.backend)
96
+ pane.clipboardWatchFailed = !!message.error
97
+ if (message.error) {
98
+ if (index < 0) s.failed.push(pane.backend)
99
+ return
100
+ }
101
+ if (index >= 0) s.failed.splice(index, 1)
102
+ selection(pane, message, s)
103
+ } else if (message.op === "get") {
104
+ var waiting = take(s.gets, pane.backend)
105
+ if (!waiting) return
106
+ // A local set, newer watcher selection or later accepted read outranks this reply.
107
+ if (message.ok && s.sets.length === 0 && waiting.generation === s.generation
108
+ && waiting.sequence > s.acceptedGetSequence) {
109
+ s.acceptedGetSequence = waiting.sequence
110
+ replace(pane, message)
111
+ }
112
+ waiting.ready()
113
+ } else if (message.op === "clear" && message.ok === false) {
114
+ pane.message(Format.fill(WORDS.clearFailed, message.error), true)
115
+ }
116
+ }
117
+
118
+ function read(pane, ready) {
119
+ var s = session(pane)
120
+ if (s.sets.length > 0 || s.failed.indexOf(pane.backend) < 0) {
121
+ ready()
122
+ return
123
+ }
124
+ for (var i = 0; i < s.gets.length; i++) {
125
+ if (s.gets[i].backend === pane.backend) {
126
+ pane.message("Still reading the clipboard; try again.", false)
127
+ return
128
+ }
129
+ }
130
+ s.getSequence += 1
131
+ s.gets.push({ backend: pane.backend, ready: ready, generation: s.generation, sequence: s.getSequence })
132
+ pane.backend.send({ c: "clipGet" })
133
+ }
134
+
135
+ var IMAGE_NAME = "Pasted image %1 at %2.png"
136
+ function two(n) {
137
+ return (n < 10 ? "0" : "") + n
138
+ }
139
+ // Sample input: new Date(2026, 8, 23, 10, 14, 32) -> "Pasted image 2026-09-23 at 10.14.32.png".
140
+ function imageName(at) {
141
+ var date = at.getFullYear() + "-" + two(at.getMonth() + 1) + "-" + two(at.getDate())
142
+ var time = two(at.getHours()) + "." + two(at.getMinutes()) + "." + two(at.getSeconds())
143
+ return IMAGE_NAME.replace("%1", date).replace("%2", time)
144
+ }
145
+
146
+ // All paste verbs read the same file selection, including the no-watcher fallback.
147
+ function paste(pane, linkKind, forceMove) {
148
+ var dest = pane.path
149
+ function ready() {
150
+ if (pane.path !== dest || pane.listInFlight || pane.recentMode) {
151
+ pane.message("The paste destination changed; try again.", false)
152
+ return
153
+ }
154
+ var clip = pane.clipboard
155
+ var sources = clip.paths
156
+ if (sources.length === 0 && !linkKind) {
157
+ // No paths: the backend pastes an image as a stamped file, or answers its own sentence.
158
+ pane.backend.send({ c: "pasteimage", dest: dest, name: imageName(new Date()) })
159
+ return
160
+ }
161
+ if (sources.length === 0) {
162
+ pane.message(Menu.EMPTY_CLIPBOARD, false)
163
+ return
164
+ }
165
+ pane.asks().ask({ c: linkKind ? "link" : "transfer",
166
+ op: linkKind || (forceMove || clip.moving ? "move" : "copy"), paths: sources, dest: dest },
167
+ null, !linkKind && clip.moving)
168
+ }
169
+ read(pane, ready)
170
+ }
171
+
172
+ // Clear only the cut captured by this transfer, never a newer selection on the card.
173
+ function spent(pane, clip, spendsCut) {
174
+ if (ClipMarks.spent(clip, spendsCut) === clip) return
175
+ pane.backend.send(clip.token ? { c: "clipClear", token: clip.token }
176
+ : { c: "clipClear", cut: clip.paths })
177
+ if (pane.clipboard === clip || (pane.clipboard.paths === clip.paths && pane.clipboard.token === clip.token))
178
+ pane.clipboard = empty()
179
+ }
package/ui/js/Cloud.js ADDED
@@ -0,0 +1,97 @@
1
+ .pragma library
2
+
3
+ .import "NetFs.js" as NetFs
4
+
5
+ // Cloud rows: non-network FUSE mounts inside home, read off the rail's own poll; nothing new runs.
6
+
7
+ // Sample input, /proc/self/mountinfo lines (id parent maj:min root mountpoint options,
8
+ // then fstype source superoptions):
9
+ // 23 1 8:1 / /home/u/gdrive rw,nosuid,nodev - fuse.rclone remote: rw,user_id=1000,group_id=1000
10
+ // 24 1 8:1 / /home/u/My\040Drive rw,nosuid,nodev - fuse.mergerfs merge: rw,user_id=1000,group_id=1000
11
+ // 31 1 0:27 / /home/u/ProtonDrive rw,nosuid,nodev - fuse.protondrive proton: rw,user_id=1000
12
+ // 18 1 8:1 / /home/u rw,nosuid,nodev - btrfs /dev/sda1 rw
13
+ // 40 1 0:40 / /run/user/1000/gvfs rw,nosuid,nodev - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000
14
+ // Only the mergerfs line is a cloud row (network fstypes are share rows; home and gvfs are not); a stacked mountpoint keeps the later line.
15
+ function parseCloudMounts(body, home) {
16
+ var root = String(home || "")
17
+ if (root.length === 0)
18
+ return []
19
+ var prefix = root.charAt(root.length - 1) === "/" ? root : root + "/"
20
+ var out = []
21
+ var at = {}
22
+ var lines = String(body || "").split("\n")
23
+ for (var i = 0; i < lines.length; i++) {
24
+ var parsed = parseMountinfoLine(lines[i])
25
+ if (!parsed || !isCloudFstype(parsed.fstype))
26
+ continue
27
+ if (NetFs.isNetworkFstype(parsed.fstype))
28
+ continue // A network fstype is a share row wherever it is mounted.
29
+ // Strictly inside: the home directory itself mounts whatever the box is made of.
30
+ if (parsed.path.length <= root.length || parsed.path.indexOf(prefix) !== 0)
31
+ continue
32
+ if (at[parsed.path] === undefined)
33
+ at[parsed.path] = out.length
34
+ out[at[parsed.path]] = parsed
35
+ }
36
+ return out
37
+ }
38
+
39
+ // Any FUSE mount is a cloud candidate; the home-folder containment above is what keeps
40
+ // gvfs, portals and the box's own mounts out, because none of them lives under it.
41
+ function isCloudFstype(fstype) {
42
+ var lower = String(fstype || "").toLowerCase()
43
+ return lower === "fuse" || lower.indexOf("fuse.") === 0
44
+ }
45
+
46
+ // Every network-fstype mountinfo line outside the box's plumbing is a NETWORK row, home or not.
47
+ // Sample input: "31 1 0:45 / /mnt/nas rw - nfs nas:/share rw" becomes one row.
48
+ function parseNetworkMounts(body) {
49
+ var out = []
50
+ var at = {}
51
+ var lines = String(body || "").split("\n")
52
+ for (var i = 0; i < lines.length; i++) {
53
+ var parsed = parseMountinfoLine(lines[i])
54
+ if (!parsed || !NetFs.isNetworkFstype(parsed.fstype))
55
+ continue
56
+ if (parsed.path === "/" || isSystemMountPath(parsed.path))
57
+ continue // The box's own plumbing is never a network row.
58
+ if (at[parsed.path] === undefined)
59
+ at[parsed.path] = out.length
60
+ out[at[parsed.path]] = parsed
61
+ }
62
+ return out
63
+ }
64
+
65
+ // Sample input: "/run/user/1000/gvfs" trues, "/mnt/nas" falses; read without a per-row stat.
66
+ function isSystemMountPath(p) {
67
+ if (p.indexOf("/proc/") === 0 || p === "/proc")
68
+ return true
69
+ if (p.indexOf("/sys/") === 0 || p === "/sys")
70
+ return true
71
+ if (p.indexOf("/dev/") === 0 || p === "/dev")
72
+ return true
73
+ if (p.indexOf("/run/") === 0)
74
+ return true
75
+ return false
76
+ }
77
+
78
+ // One mountinfo line into its mountpoint and fstype, or null: the mountpoint is field five
79
+ // of the left half and the fstype is the first field of the right half, split on " - ".
80
+ function parseMountinfoLine(line) {
81
+ var halves = String(line || "").split(" - ")
82
+ if (halves.length < 2)
83
+ return null
84
+ var left = halves[0].split(/\s+/)
85
+ var right = halves[1].split(/\s+/)
86
+ if (left.length < 5 || right.length < 1 || left[4].length === 0 || right[0].length === 0)
87
+ return null
88
+ return { path: unescapeOctal(left[4]), fstype: right[0] }
89
+ }
90
+
91
+ // Sample input: "/home/u/My\040Drive" answers "/home/u/My Drive". A mountinfo escape is a
92
+ // backslash and three octal digits, and anything else is kept literally.
93
+ function unescapeOctal(field) {
94
+ return String(field).replace(/\\([0-7]{3})/g, function (match, digits) {
95
+ return String.fromCharCode(parseInt(digits, 8))
96
+ })
97
+ }
@@ -0,0 +1,72 @@
1
+ .pragma library
2
+
3
+ .import "Contrast.js" as Contrast
4
+ .import "Palette.js" as Palette
5
+
6
+ // The ink names after the foreground, in the order the code reply numbers its roles: 1 to 6 are bat's SGR 31 to 36.
7
+ var INKS = ["red", "green", "yellow", "blue", "magenta", "cyan"]
8
+ // The inks a theme without that colour draws in.
9
+ var FALLBACK = { red: "#f38ba8", green: "#a6e3a1", yellow: "#f9e2af", blue: "#89b4fa", magenta: "#cba6f7", cyan: "#94e2d5" }
10
+ // A tab fills to the next multiple of this many columns.
11
+ var TAB = 8
12
+
13
+ // The foreground, then bat's six colours, each the palette's own (its ANSI slot when unnamed) lifted to 4.5:1 on the background or surface it contrasts less with.
14
+ function inks(found, fallback, foreground) {
15
+ var bg = Palette.pick(found, ["background"], fallback.background)
16
+ var surface = Palette.pick(found, Palette.SURFACE_KEYS, fallback.surface)
17
+ var out = [foreground]
18
+ for (var i = 0; i < INKS.length; i++) {
19
+ var ink = Palette.pick(found, [INKS[i], "color" + (i + 1)], FALLBACK[INKS[i]])
20
+ out.push(Contrast.ensureRatio(ink, Contrast.ratio(ink, bg) < Contrast.ratio(ink, surface) ? bg : surface, 4.5))
21
+ }
22
+ return out
23
+ }
24
+
25
+ function roleName(role) {
26
+ return role >= 1 && role <= INKS.length ? INKS[role - 1] : "foreground"
27
+ }
28
+
29
+ function escape(text) {
30
+ return String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;")
31
+ }
32
+
33
+ // The reply's flat [role, text, role, text, ...] as [role, text] pairs with every tab filled to its stop, since a rich text folds a tab into one space.
34
+ // Sample input: [5, "ab", 0, "\tx"] answers [[5, "ab"], [0, " x"]].
35
+ function pairs(runs) {
36
+ var out = []
37
+ var column = 0
38
+ for (var i = 0; i + 1 < runs.length; i += 2) {
39
+ var text = ""
40
+ var raw = String(runs[i + 1])
41
+ for (var j = 0; j < raw.length; j++) {
42
+ var fill = raw.charAt(j) === "\t" ? TAB - column % TAB : 1
43
+ text += raw.charAt(j) === "\t" ? " ".repeat(fill) : raw.charAt(j)
44
+ column += fill
45
+ }
46
+ out.push([runs[i], text])
47
+ }
48
+ return out
49
+ }
50
+
51
+ function plain(runs) {
52
+ return pairs(runs).map(function (pair) { return pair[1] }).join("")
53
+ }
54
+
55
+ // One line as StyledText: every run escaped, a coloured run in one font tag, and each space kept as a non-breaking space unless it is a single space between two characters, which a rich text keeps and may wrap at.
56
+ // Sample input: [5, "fn", 0, " x <b>"] answers <font color="#cba6f7">fn</font>&nbsp;&nbsp;x &lt;b&gt; with the magenta ink.
57
+ function styled(runs, colors) {
58
+ var parts = pairs(runs)
59
+ var line = parts.map(function (pair) { return pair[1] }).join("")
60
+ var out = ""
61
+ var at = 0
62
+ for (var i = 0; i < parts.length; i++) {
63
+ var body = ""
64
+ for (var j = 0; j < parts[i][1].length; j++, at++) {
65
+ var c = parts[i][1].charAt(j)
66
+ var kept = c === " " && at > 0 && at < line.length - 1 && line.charAt(at - 1) !== " " && line.charAt(at + 1) !== " "
67
+ body += c === " " ? (kept ? " " : "&nbsp;") : escape(c)
68
+ }
69
+ out += parts[i][0] > 0 ? "<font color=\"" + colors[parts[i][0]] + "\">" + body + "</font>" : body
70
+ }
71
+ return out
72
+ }