flea-qml 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +402 -0
  51. package/src/archiveops.js +697 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +129 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,153 @@
1
+ .pragma library
2
+ .import "Format.js" as Format
3
+ .import "Match.js" as Match
4
+
5
+ // Grid-only captions; GridTile loads this, Row and ColumnRow never do.
6
+ // Sample input: gridCaption("screenshot-2026-08-30-final-review-for-gm-after-the-bench-v3.png", 16, 2) answers "screenshot-2026-\n…he-bench-v3.png".
7
+
8
+ // A caption break stays behind a separator, so a word is never split when a break fits.
9
+ var CAPTION_BREAKS = " -_."
10
+
11
+ function isBreakAfter(ch) {
12
+ return CAPTION_BREAKS.indexOf(ch) >= 0
13
+ }
14
+
15
+ // Cells of the caption's last line, so a mark sits past the glyphs it follows.
16
+ // Sample input: lastLineCells("ab\nc🎉") is 3.
17
+ function lastLineCells(text) {
18
+ var s = String(text)
19
+ if (Format.isFastText(s)) return s.length - s.lastIndexOf("\n") - 1
20
+ return cellsOf(Format.charsOf(s.split("\n").pop()))
21
+ }
22
+
23
+ // The extension is the last dot's tail, so the last line can keep it whole; a leading dot names a dotfile, not an extension.
24
+ function extensionLength(chars) {
25
+ var dot = -1
26
+ for (var i = chars.length - 1; i > 0; i--) {
27
+ if (chars[i] === ".") {
28
+ dot = i
29
+ break
30
+ }
31
+ }
32
+ if (dot < 0 || dot === chars.length - 1)
33
+ return 0
34
+ return chars.length - dot
35
+ }
36
+
37
+ // Elides a char array down to this many cells, keeping a one-line extension whole on the tail.
38
+ function elideChars(chars, capacity, perLine) {
39
+ return elideCore(Format.storeOf(chars), capacity, perLine)
40
+ }
41
+
42
+ // The head and tail an elide keeps: the head takes the odd cell, the tail keeps a one-line extension.
43
+ function elideSplit(capacity, ext, extCells, perLine) {
44
+ var head = Math.ceil((capacity - 1) / 2), tail = Math.floor((capacity - 1) / 2)
45
+ // An extension longer than one line, or with no room for the mark beside it, cannot stay whole.
46
+ if (ext > 0 && extCells <= perLine && extCells + 1 <= capacity) {
47
+ tail = Math.max(extCells, tail)
48
+ head = capacity - 1 - tail
49
+ }
50
+ return [head, tail]
51
+ }
52
+
53
+ // One elide for both stores: elements for the wrap behind an array, pieces for the join behind a string.
54
+ function elideCore(st, capacity, perLine) {
55
+ if (capacity <= 1) return ["…"]
56
+ if (Format.rangeCells(st, 0, st.n) <= capacity) return st.widths === null ? [st.seq] : st.seq.slice(0)
57
+ var ext = extensionLength(st.seq)
58
+ var split = elideSplit(capacity, ext, ext > 0 ? Format.rangeCells(st, st.n - ext, st.n) : 0, perLine)
59
+ var h = Format.spanFrom(st, 0, split[0]), t = Format.tailSpan(st, split[1])
60
+ if (st.widths === null) return [Format.pieceOf(st, 0, h), "…", Format.pieceOf(st, st.n - t, st.n)]
61
+ return st.seq.slice(0, h).concat(["…"], st.seq.slice(st.n - t))
62
+ }
63
+
64
+ // Wraps a char array into at most count lines of perLine cells, breaking after the last separator that still leaves the rest fitting.
65
+ function wrapChars(chars, perLine, count) {
66
+ return wrapCore(Format.storeOf(chars), perLine, count)
67
+ }
68
+
69
+ // The break a line takes: the last separator whose rest still fits, the extension dot losing to any earlier one.
70
+ function breakCut(st, far, pos, left, perLine, extDot) {
71
+ var cut = -1, extCut = -1
72
+ for (var i = far - 1; i > pos; i--) {
73
+ if (!isBreakAfter(st.seq[i]) || Format.rangeCells(st, i + 1, st.n) > (left - 1) * perLine) continue
74
+ if (i === extDot) { extCut = i + 1; continue }
75
+ cut = i + 1; break
76
+ }
77
+ return cut >= 0 ? cut : (extCut >= 0 ? extCut : far)
78
+ }
79
+
80
+ // One wrap for both stores: lines of pieces, every range counted once off the layout.
81
+ function wrapCore(st, perLine, count) {
82
+ var out = [], pos = 0
83
+ // The extension's own dot, so a break there never wins while an earlier separator fits.
84
+ var extDot = st.n - extensionLength(st.seq)
85
+ for (var ln = 0; ln < count && pos < st.n; ln++) {
86
+ var left = count - ln
87
+ if (Format.rangeCells(st, pos, st.n) <= perLine) { out.push(Format.pieceOf(st, pos, st.n)); break }
88
+ if (ln === count - 1) { out.push(Format.pieceOf(st, pos, pos + Format.spanFrom(st, pos, perLine))); break }
89
+ var far = pos + Format.spanFrom(st, pos, perLine)
90
+ if (far <= pos) far = pos + 1
91
+ var cut = breakCut(st, far, pos, left, perLine, extDot)
92
+ out.push(Format.pieceOf(st, pos, cut))
93
+ pos = cut
94
+ }
95
+ return out
96
+ }
97
+
98
+ // The caption Flea hands to Text already holds its line breaks, so Qt never wraps.
99
+ // Sample input: gridCaption("screenshot-2026-08-30-final-review-for-gm-after-the-bench-v3.png", 16, 2) answers "screenshot-2026-\n…he-bench-v3.png".
100
+ function gridCaption(name, perLine, lines) {
101
+ var text = String(name), per = Math.floor(perLine), count = Math.floor(lines)
102
+ // A dead or non-finite width budgets nothing: hand Qt the whole name and let ElideRight say so.
103
+ if (!isFinite(per) || !isFinite(count) || !(per >= 1) || !(count >= 1)) return text
104
+ // One scan serves the fit check and the store below, so a fitting fast name builds nothing.
105
+ var isFast = Format.isFastText(text)
106
+ var capacity = per * count
107
+ // A fast name counts one cell a char, so one fitting line needs no elide and no wrap.
108
+ // A one-cell caption still elides below, so the early return keeps that mark.
109
+ if (isFast && capacity > 1 && text.length <= per) return text
110
+ var st = isFast ? Format.fastStoreOf(text) : Format.storeOf(Format.charsOf(text))
111
+ if (st.n === 0) return text
112
+ // A wide glyph never straddles a line and wastes a cell, so elide until Flea's own wrap holds every char.
113
+ if (st.widths === null) {
114
+ var fast = elideCore(st, capacity, per).join("")
115
+ while (capacity > 1 && wrapCore(Format.fastStoreOf(fast), per, count).join("") !== fast)
116
+ fast = elideCore(st, --capacity, per).join("")
117
+ return wrapCore(Format.fastStoreOf(fast), per, count).join("\n")
118
+ }
119
+ var shown = elideCore(st, capacity, per)
120
+ while (capacity > 1 && wrapCore(Format.storeOf(shown), per, count).join("") !== shown.join(""))
121
+ shown = elideCore(st, --capacity, per)
122
+ return wrapCore(Format.storeOf(shown), per, count).join("\n")
123
+ }
124
+
125
+ // The match run per drawn caption line, picked by Match.run in the caption without its breaks; trailing blanks lie past the width Qt centres a line by, so they take no mark.
126
+ // Sample input: captionMarks("appl\nication.log", "PLIC") answers [{line: 0, before: "ap", run: "pl", centred: "appl"}, {line: 1, before: "", run: "ic", centred: "ication.log"}].
127
+ function captionMarks(caption, query) {
128
+ var lines = String(caption).split("\n"), out = []
129
+ var run = Match.run(lines.join(""), query)
130
+ for (var i = 0, pos = 0; run.start >= 0 && i < lines.length; pos += lines[i].length, i++) {
131
+ var centred = lines[i].replace(/\s+$/, "")
132
+ var from = Math.max(run.start, pos) - pos, to = Math.min(run.start + run.length, pos + centred.length) - pos
133
+ if (from < to)
134
+ out.push({ line: i, before: centred.substring(0, from), run: centred.substring(from, to), centred: centred })
135
+ }
136
+ return out
137
+ }
138
+
139
+ // Array-cell helpers over the common store, kept beside the Grid fits that read them.
140
+ // Cells a char array paints.
141
+ function cellsOf(chars) {
142
+ return Format.rangeCells(Format.storeOf(chars), 0, chars.length)
143
+ }
144
+
145
+ // A head that fits in this many cells, never splitting a code point.
146
+ function headByCells(chars, budget) {
147
+ return chars.slice(0, Format.spanFrom(Format.storeOf(chars), 0, budget))
148
+ }
149
+
150
+ // A tail that fits in this many cells, never splitting a code point.
151
+ function tailByCells(chars, budget) {
152
+ return chars.slice(chars.length - Format.tailSpan(Format.storeOf(chars), budget))
153
+ }
@@ -0,0 +1,200 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+
5
+ // Phones and shares open through the GVFS FUSE bridge, and Flea starts it the way gvfsd
6
+ // does when the folder is not serving yet. The QML service owns the processes and the three
7
+ // timers; this module owns every decision, so tests/js/gvfsbridge.js pins each one with no
8
+ // process and no clock. An action is what the service executes next: check (test -d the
9
+ // folder), checkFile (test -e it), start (run gvfsd-fuse once, detached), classify (test -d
10
+ // it once it is served), ready (open the folder, or hand a file to the opener), show (the
11
+ // Starting line), fail (the board's error line) or refuse (busy).
12
+ //
13
+ // The start is detached: closing the rail or the chooser never takes gvfsd-fuse down with it,
14
+ // so no exit status ever reaches the board and the folder poll's own deadline is the failure
15
+ // signal. The check stays a helper process rather than a backend peek, an order of magnitude
16
+ // slower per check in one headless sample (sub-millisecond both) but bounded: a wedged FUSE
17
+ // path hangs a helper the deadline kills and nothing else. A served path is classified by
18
+ // the kernel too, so a file under a live bridge is ready without any start (I-3) and a
19
+ // directory costs the one check it always did.
20
+
21
+ // Whole sentences with "%1" for the device or share and "%2" for the reason; the Starting mark follows ui/Pane.qml's stickyStarting signal, never this text.
22
+ var WORDS = {
23
+ starting: "Opening %1",
24
+ failed: "%1 could not be opened because a system service did not start · %2"
25
+ }
26
+
27
+ // The Starting line stands until the service's own 250 ms timer fires, so a bridge that is
28
+ // already coming up never flashes it.
29
+ var STARTING_MS = 250
30
+ // A test costs about half a millisecond, so this bounds the open behind a starting bridge.
31
+ var POLL_MS = 150
32
+ // One deadline for the whole ensure, checking, file-checking, waiting and classifying: a hung
33
+ // helper and a bridge that never serves are the same wait to the watcher, and both end in the
34
+ // board's failure line through onTimeout, once.
35
+ var ENSURE_MS = 15000
36
+
37
+ function create() {
38
+ return { phase: "idle", waiter: null, starts: 0 }
39
+ }
40
+
41
+ // Sample input: "/run/user/1000" answers "/run/user/1000/gvfs", and "" answers the board's
42
+ // own "/run/user/1000/gvfs", because XDG_RUNTIME_DIR is always set in a systemd session.
43
+ function bridgeDir(runtimeDir) {
44
+ var dir = String(runtimeDir || "")
45
+ return dir.length > 0 ? dir + "/gvfs" : "/run/user/1000/gvfs"
46
+ }
47
+
48
+ // Sample input: "/run/user/1000/gvfs/mtp:host=X" needs it, "/home/gm" and the portal's
49
+ // "/run/user/1000/doc/1/file.pdf" do not. The bridge root itself counts, because with the
50
+ // bridge down even it is unserved.
51
+ function needsBridge(path, dir) {
52
+ var text = String(path || "")
53
+ var root = String(dir || "")
54
+ return root.length > 0 && (text === root || text.indexOf(root + "/") === 0)
55
+ }
56
+
57
+ // Sample input: "Pixel 8" answers "Opening Pixel 8".
58
+ function startingLine(name) {
59
+ return Format.fill(WORDS.starting, name)
60
+ }
61
+
62
+ // Sample input: ("Pixel 8", "waiting for the folder timed out") answers the board's
63
+ // failure line word for word.
64
+ function failedLine(name, reason) {
65
+ return Format.fill(WORDS.failed, name, reason)
66
+ }
67
+
68
+ // Sample input: ("Pixel 8") answers the reason a wait that outlived ENSURE_MS carries.
69
+ function timeoutReason() {
70
+ return "waiting for the folder timed out"
71
+ }
72
+
73
+ // The openShare guard's own refusal, reused so two waiters never start two bridges.
74
+ function busyReason() {
75
+ return "Another network location is still opening. Try again when it opens"
76
+ }
77
+
78
+ // Sample input: "" with "/run/user/1000/gvfs/mtp:host=X" answers that leaf.
79
+ function displayName(label, path) {
80
+ var name = String(label || "")
81
+ if (name.length > 0)
82
+ return name
83
+ var text = String(path || "")
84
+ var cut = text.lastIndexOf("/")
85
+ return cut < 0 ? text : text.substring(cut + 1)
86
+ }
87
+
88
+ // Sample input: "" answers "/usr/lib/gvfsd-fuse", the binary gvfsd spawns on Arch.
89
+ function fuseBin(env) {
90
+ var bin = String(env || "")
91
+ return bin.length > 0 ? bin : "/usr/lib/gvfsd-fuse"
92
+ }
93
+
94
+ // Sample input: ("/usr/lib/gvfsd-fuse", "/run/user/1000/gvfs") answers gvfsd's own spawn,
95
+ // "/usr/lib/gvfsd-fuse /run/user/1000/gvfs -f", measured on minipc.
96
+ function fuseArgv(bin, dir) {
97
+ return [bin, dir, "-f"]
98
+ }
99
+
100
+ // Sample input: a ready waiter with isDir true opens the folder, with false hands the
101
+ // file to the opener, so a typed network URL naming a file is never listed as a folder.
102
+ function readyFor(waiter, isDir) {
103
+ return [{ op: "ready", path: waiter.path, origin: waiter.origin, isDir: isDir !== false }]
104
+ }
105
+
106
+ function reset(st) {
107
+ st.phase = "idle"
108
+ st.waiter = null
109
+ }
110
+
111
+ // A local folder opens at once and starts nothing; a gvfs folder is checked first.
112
+ function ensure(st, req) {
113
+ if (!needsBridge(req.path, req.bridgeDir))
114
+ return readyFor({ path: req.path, origin: req.origin }, true)
115
+ if (st.phase !== "idle") {
116
+ if (st.waiter && st.waiter.path === req.path)
117
+ return []
118
+ return [{ op: "refuse", text: busyReason(), origin: req.origin }]
119
+ }
120
+ st.phase = "checking"
121
+ st.waiter = { path: req.path, label: displayName(req.label, req.path), origin: req.origin,
122
+ bridgeDir: req.bridgeDir, fuseBin: fuseBin(req.fuseBin), shown: false }
123
+ return [{ op: "check", path: req.path }]
124
+ }
125
+
126
+ // The check answered for a directory: a served one opens, anything else is file-checked
127
+ // before anything starts, because test -d fails for a file under a live bridge too.
128
+ function onChecked(st, dirServed) {
129
+ if (st.phase !== "checking" || !st.waiter)
130
+ return []
131
+ if (dirServed) {
132
+ var done = readyFor(st.waiter, true)
133
+ reset(st)
134
+ return done
135
+ }
136
+ st.phase = "checkingFile"
137
+ return [{ op: "checkFile", path: st.waiter.path }]
138
+ }
139
+
140
+ // The file check answered: a served file is ready without any start, and only a path that is
141
+ // neither a directory nor anything at all starts the bridge, exactly once per wait.
142
+ function onCheckedFile(st, exists) {
143
+ if (st.phase !== "checkingFile" || !st.waiter)
144
+ return []
145
+ if (exists) {
146
+ var done = readyFor(st.waiter, false)
147
+ reset(st)
148
+ return done
149
+ }
150
+ st.phase = "waiting"
151
+ st.starts += 1
152
+ return [{ op: "start", argv: fuseArgv(st.waiter.fuseBin, st.waiter.bridgeDir) }]
153
+ }
154
+
155
+ // The 250 ms timer fired: the Starting line appears only now, and only while waiting.
156
+ function onElapsed(st) {
157
+ if (st.phase !== "waiting" || !st.waiter || st.waiter.shown)
158
+ return []
159
+ st.waiter.shown = true
160
+ return [{ op: "show", text: startingLine(st.waiter.label), origin: st.waiter.origin }]
161
+ }
162
+
163
+ // A poll answered: the folder landing is classified before it opens, anything else waits
164
+ // on. The classify is one test -d, so a file the wait started for still lands as a file.
165
+ function onPolled(st, served) {
166
+ if (st.phase !== "waiting" || !st.waiter)
167
+ return []
168
+ if (!served)
169
+ return []
170
+ st.phase = "classifying"
171
+ return [{ op: "classify", path: st.waiter.path }]
172
+ }
173
+
174
+ // The classify answered for a served path: directories open, files go to the opener.
175
+ function onClassified(st, isDir) {
176
+ if (st.phase !== "classifying" || !st.waiter)
177
+ return []
178
+ var done = readyFor(st.waiter, isDir)
179
+ reset(st)
180
+ return done
181
+ }
182
+
183
+ // The whole-ensure deadline fired: whatever leg was still running ends here, in the board's
184
+ // failure line. The service kills its helper beside this and swallows that helper's own exit,
185
+ // so the line answers once however the race landed.
186
+ function onTimeout(st) {
187
+ if ((st.phase !== "checking" && st.phase !== "checkingFile" && st.phase !== "waiting"
188
+ && st.phase !== "classifying") || !st.waiter)
189
+ return []
190
+ var failed = [{ op: "fail", text: failedLine(st.waiter.label, timeoutReason()),
191
+ origin: st.waiter.origin }]
192
+ reset(st)
193
+ return failed
194
+ }
195
+
196
+ // A cancelled wait answers nothing and starts nothing; the caller clears its own line.
197
+ function cancel(st) {
198
+ reset(st)
199
+ return []
200
+ }
@@ -0,0 +1,29 @@
1
+ .pragma library
2
+
3
+ // All panes share this queue. Clipboard payloads are opaque POSIX-quoted text,
4
+ // including the pair of empty double quotes at each end of a cut, on every OS.
5
+ var queue = Promise.resolve()
6
+ function handle(root, qs, message) {
7
+ function read() {
8
+ return qs.readClipboardText ? qs.readClipboardText({ strict: true }) : qs.clipboardText
9
+ }
10
+ function write(text) {
11
+ if (qs.writeClipboardText) return qs.writeClipboardText(text)
12
+ qs.clipboardText = text
13
+ }
14
+ queue = queue.then(function() {
15
+ if (message.op === "read") return Promise.resolve(read()).then(function(text) { return { text: text } })
16
+ if (typeof message.text !== "string") throw new Error("Invalid clipboard text")
17
+ if (message.op === "write") return Promise.resolve(write(message.text)).then(function() { return {} })
18
+ if (message.op === "clear") return Promise.resolve(read()).then(function(text) {
19
+ if (text !== message.text) return { cleared: false }
20
+ return Promise.resolve(write("")).then(function() { return { cleared: true } })
21
+ })
22
+ throw new Error("Unknown clipboard operation")
23
+ }).then(function(answer) {
24
+ root.send(Object.assign({ c: "clipHostReply", id: message.id, ok: true }, answer))
25
+ }, function(error) {
26
+ root.send({ c: "clipHostReply", id: message.id, ok: false, error: String(error.message || error) })
27
+ }).catch(function(error) { console.warn("Clipboard reply failed: " + error) })
28
+ return queue
29
+ }
package/ui/js/Icons.js ADDED
@@ -0,0 +1,218 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+
5
+ // The backend sends a freedesktop icon name per row; this is the only place Flea maps one to a mark.
6
+ // Counts re-derived 2026-08-31 from /usr/share/mime/generic-icons on this box, see AGENTS.md "Icons in the row":
7
+ // x-office-document 106, package-x-generic 89, application-x-executable 57, text-x-generic 46,
8
+ // image-x-generic 40, x-office-spreadsheet 38, text-x-script 36, font-x-generic 23, x-office-presentation 21,
9
+ // video-x-generic 15, text-html 11, then a tail of five or fewer each.
10
+ var GLYPHS = {
11
+ "folder": "folder",
12
+ "inode-directory": "folder",
13
+ "text-x-generic": "file-text",
14
+ "text-plain": "file-text",
15
+ // text-x-script, text-html and application-xml are 49 types a generic file mark would hide.
16
+ "text-x-script": "code",
17
+ "text-html": "code",
18
+ "application-xml": "code",
19
+ "image-x-generic": "image",
20
+ "video-x-generic": "film",
21
+ "audio-x-generic": "music",
22
+ "package-x-generic": "archive",
23
+ "font-x-generic": "type",
24
+ "application-x-executable": "terminal",
25
+ "application-x-generic": "file",
26
+ "x-office-document": "file-text",
27
+ "x-office-spreadsheet": "table",
28
+ "x-office-presentation": "presentation"
29
+ }
30
+
31
+ var FALLBACK = "file"
32
+
33
+ // flea-qml's backend sends an emoji as the row's icon instead of a freedesktop name. Every mark name
34
+ // here is ASCII, so a name holding anything else is an emoji, drawn as itself by Glyph.qml. A keycap
35
+ // such as #️⃣ starts with an ASCII "#", so the whole name is checked, not its first character.
36
+ function isEmoji(name) {
37
+ return /[^\x00-\x7f]/.test(String(name))
38
+ }
39
+
40
+ function glyphFor(iconName) {
41
+ if (isEmoji(iconName))
42
+ return String(iconName)
43
+ var g = GLYPHS[String(iconName)]
44
+ return g ? g : FALLBACK
45
+ }
46
+
47
+ // A row's mark. The backend resolves a symlink's icon to its target's, so a link to a directory
48
+ // arrives as "folder"; every board draws such a row with the link mark instead, so the mode decides
49
+ // here and the icon name only answers for what the row really is. An emoji already says link or
50
+ // broken link itself.
51
+ function glyphForRow(iconName, mode) {
52
+ if (isEmoji(iconName))
53
+ return String(iconName)
54
+ if (Format.isSymlink(mode))
55
+ return "symlink"
56
+ return glyphFor(iconName)
57
+ }
58
+
59
+ // The sidebar's own set, keyed on the favourite's label (Places.js leaf() or bookmark label),
60
+ // the operator's overnight ask; any bookmark outside this set draws the plain folder mark.
61
+ var SIDEBAR_GLYPHS = {
62
+ "Home": "house",
63
+ "Downloads": "download",
64
+ "Documents": "file-text",
65
+ "Pictures": "image",
66
+ "Videos": "film",
67
+ "Music": "music",
68
+ "Projects": "folder-git-2"
69
+ }
70
+
71
+ var SIDEBAR_FALLBACK = "folder"
72
+
73
+ function sidebarGlyphFor(label) {
74
+ var g = SIDEBAR_GLYPHS[String(label)]
75
+ return g ? g : SIDEBAR_FALLBACK
76
+ }
77
+
78
+ // Lucide-static 1.38.0 geometry, ISC licence, https://github.com/lucide-icons/lucide, one "d"
79
+ // per mark on its native 24 unit grid, recut to the Omarchy edge: baked rounded corners became
80
+ // hard corners, real curves stayed; see AGENTS.md "Lucide path data", "The Omarchy cut".
81
+ var PATHS = {
82
+ "info": "M12 11v6 M12 7h.01 M22 12a10 10 0 1 1-20 0a10 10 0 1 1 20 0",
83
+ "shelf": "M21 21H3V3h18v14H7V7h10v6h-6",
84
+ "pin": "M9 3h6v6l3 3v2H6v-2l3-3z M12 14v7",
85
+ "star": "M12 2l2.9 6.6 7.1.6-5.4 4.7 1.6 7L12 17.3l-6.2 3.6 1.6-7L2 9.2l7.1-.6z",
86
+ "globe": "M2 12h20 M12 2a15 15 0 0 1 0 20 M12 2a15 15 0 0 0 0 20 M22 12a10 10 0 1 1-20 0a10 10 0 1 1 20 0",
87
+
88
+ "file": "M4 22V2h10l6 6v14H4z M14 2v6h6",
89
+ "folder": "M2 20V3h6l2 3h12v14H2z",
90
+ "folders-first": "M2 12V4h6l2 2h12v6H2z M2 17h20 M2 21h20",
91
+ "file-text": "M4 22V2h10l6 6v14H4z M14 2v6h6 M8 9h2 M8 13h8 M8 17h8",
92
+ // LanguageMarks' Markdown mark, Flea's cut of dcurtis/markdown-mark (CC0): the frame, the M and the down arrow in one stroke.
93
+ "markdown": "M2 5h20v14H2z M5.5 15V9l3 3.5 3-3.5v6 M17 9v6 M14.5 12.5 17 15l2.5-2.5",
94
+ "html": "M4 2h16l-1.5 17L12 22l-6.5-3z M15.5 6.5h-7V11h7v5L12 17.5 8.5 16",
95
+ "code": "M16 18l6-6-6-6 M8 6l-6 6 6 6",
96
+ "image": "M3 3h18v18H3z M7 9A2 2 0 1 0 11 9A2 2 0 1 0 7 9Z M21 15l-3-3L6 21",
97
+ "film": "M3 3h18v18H3z M7 3v18 M3 7.5h4 M3 12h18 M3 16.5h4 M17 3v18 M17 7.5h4 M17 16.5h4",
98
+ // Note heads squared instead of lucide's circles: the set's brand tell.
99
+ "music": "M9 18V5l12-2v13 M3 15h6v6H3z M15 13h6v6h-6z",
100
+ "archive": "M2 3h20v5H2z M4 8v13h16V8 M10 12h4",
101
+ "type": "M12 4v16 M4 7V4h16v3 M9 20h6",
102
+ "terminal": "M12 19h8 M4 17l6-6-6-6",
103
+ "table": "M3 3h18v18H3z M12 3v18 M3 9h18 M3 15h18",
104
+ "presentation": "M2 3h20 M3 3v13h18V3 M7 21l5-5 5 5",
105
+ "house": "M3 21V10l9-7 9 7v11h-6v-8H9v8H3z",
106
+ "download": "M12 15V3 M7 10l5 5 5-5 M3 15v6h18v-6",
107
+ "folder-git-2": "M18 19a5 5 0 0 1-5-5v8 M9 20H2V3h6l2 2h12v5 M11 12A2 2 0 1 0 15 12A2 2 0 1 0 11 12Z M18 19A2 2 0 1 0 22 19A2 2 0 1 0 18 19Z",
108
+ // The two near-zero-length lines are lucide's own technique for the rack unit's LED dots; SquareCap draws them as square dots, matching the cut.
109
+ "server": "M2 2h20v8H2z M2 14h20v8H2z M6 6L6.01 6 M6 18L6.01 18",
110
+ // The Network group's add mark, replacing a Text "+" the operator read as a Christian cross.
111
+ "plus": "M5 12h14 M12 5v14",
112
+ // The picker rail's Recent mark, lucide rotate-ccw, the one SendPicker.html itself draws; the
113
+ // circle is a real curve and stays, and the arrow head is already square on lucide's own grid.
114
+ "history": "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8 M3 3v5h5",
115
+ // Lucide's hard-drive with its four baked 2 unit corner arcs cut square, which lands the body on
116
+ // (6,4) (18,4) (22,12) (22,20) (2,20) (2,12); the divider and the two LED dots are lucide's own.
117
+ "drive": "M6 4h12l4 8v8H2v-8z M2 12h20 M6 16L6.01 16 M10 16L10.01 16",
118
+ // The DEVICES rail's phone mark, lucide's smartphone with its rx=2 body rect cut square the way
119
+ // drive's arcs were; the home-button dot is lucide's own near-zero line, drawn as server's are.
120
+ "smartphone": "M5 2h14v20H5z M12 18L12.01 18",
121
+ // Its GPhoto2 sibling, per the PhoneMark board: lucide's camera with the four a2 2 body arcs cut
122
+ // to (2,7) (22,7) (22,20) (2,20), the pentaprism kept, and the lens a genuine circle, cut rule 4.
123
+ "camera": "M14.5 4h-5L7 7H2v13h20V7h-5z M15 13a3 3 0 1 1-6 0a3 3 0 1 1 6 0",
124
+ // The rail menu's release mark, the shelf's "for: unmount": lucide's triangle corner arcs
125
+ // extend to (12, 2.09) (22.32, 13) (1.68, 13) and snap to grid, its rx=1 bar rect squares off.
126
+ "eject": "M12 2 22 13H2z M3 17h18v4H3z",
127
+ // Task 22's transport strip, recut sharp like the rest of the set.
128
+ "play": "M6 4l14 8-14 8z",
129
+ "pause": "M14 3h5v18h-5z M5 3h5v18H5z",
130
+ // The search strip's mark; the lens is a real curve, so it stays a circle under the cut.
131
+ "search": "M16.7 16.7 21 21 M3 11A8 8 0 1 0 19 11A8 8 0 1 0 3 11Z",
132
+ // The filter strip's mark, the funnel the icon spec already shelves and the Main board draws.
133
+ "filter": "M3 4h18l-7 8v7l-4 2v-9z",
134
+ // The context menu's own seven marks, added with the operations surface that draws them.
135
+ // The canvas's own open folder, which keeps the closed folder's back panel byte for byte.
136
+ "folder-open": "M2 20V3h6l2 3h12v3 M22 11l-2.5 9H2l2.5-9z",
137
+ // OpenWith.html draws this window for the Open with row, its tail row and an app the theme cannot name.
138
+ "app-window": "M3 4h18v16H3z M3 9h18 M6 6.5h.01 M9 6.5h.01",
139
+ "undo": "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8 M3 3v5h5",
140
+ "rename": "M3 21l1-4L17 4l3 3L7 20l-4 1z M14 7l3 3",
141
+ "file-plus": "M6 22V2h8l4 4v16H6z M14 2v4h4 M12 11v6 M9 14h6",
142
+ // lucide's own folder-plus is the folder body byte for byte plus these two strokes, so the recut
143
+ // body is reused verbatim and only the plus is new; the specimen sheet's 5 unit plus is not it.
144
+ "folder-plus": "M2 20V3h6l2 3h12v14H2z M12 10v6 M9 13h6",
145
+ "trash": "M3 6h18 M8 6V3h8v3 M6 6l1.2 15h9.6L18 6 M10 10v7 M14 10v7",
146
+ // A diamond eye with a square pupil: lucide's own eye is two arcs meeting at points, which the cut squares off.
147
+ "eye": "M12 5 22 12 12 19 2 12z M10 10h4v4h-4z",
148
+ "eye-off": "M12 5 22 12 12 19 2 12z M10 10h4v4h-4z M4 4l16 16",
149
+ // Replaces the "▸" Text the menu used to draw, so it stops mixing a font dingbat into a path language.
150
+ "chevron-right": "M9 18l6-6-6-6",
151
+ "chevron-down": "M6 9l6 6 6-6",
152
+ "chevron-left": "M15 18l-6-6 6-6",
153
+ // The window chrome's own five marks, added with the bar that draws them.
154
+ "arrow-left": "M19 12H5 M12 19l-7-7 7-7",
155
+ "arrow-up": "M12 19V5 M5 12l7-7 7 7",
156
+ // The bullets are lucide's own zero-length-line technique, which SquareCap draws as square dots.
157
+ "list": "M8 6h13 M8 12h13 M8 18h13 M3 6L3.01 6 M3 12L3.01 12 M3 18L3.01 18",
158
+ "columns": "M3 3h18v18H3z M9 3v18 M15 3v18",
159
+ "preview": "M3 3h18v18H3z M15 3v18",
160
+ "dual": "M3 4h8v16H3z M13 4h8v16h-8z",
161
+ "grid": "M3 3h8v8H3z M13 3h8v8h-8z M3 13h8v8H3z M13 13h8v8h-8z",
162
+ // The preview column's own two, taken from the canvas's icon table rather than recut from lucide.
163
+ "symlink": "M7 17L17 7 M8 7h9v9",
164
+ // The dot is the zero-length-line technique again, which SquareCap draws square.
165
+ "alert": "M12 2 23 21H1z M12 10v4 M12 18L12.01 18",
166
+ // The Locked pane state draws this beside it: the shackle is a real curve so it stays an arc, and the keyhole is the same dot technique.
167
+ "lock": "M4 11h16v10H4z M8 11V7a4 4 0 0 1 8 0v4 M12 15h.01",
168
+ // The compress submenu's With-password row: a bow ring, a shaft and two teeth; the bow is a true circle under the cut.
169
+ "key": "M3 7a4 4 0 1 0 8 0a4 4 0 1 0-8 0 M10.5 10.5l8 8 M16 16l2.5-2.5 M18.5 18.5l1.5-1.5",
170
+ // The operations rows the archive and convert subsystems draw, from the spec's own glyph shelf.
171
+ "archive-out": "M2 3h20v5H2z M4 8v13h16V8 M12 18v-6 M9 15l3-3 3 3",
172
+ // The Move to Dropbox row, which the canvas draws with the network mark.
173
+ "network": "M9 2h6v6H9z M2 16h6v6H2z M16 16h6v6h-6z M12 8v4 M5 16v-4h14v4",
174
+ // The convert popup's checkbox mark.
175
+ "check": "M4 12l6 6L20 6",
176
+ // The Tags row's mark: a square-cornered price tag with its hole as a SquareCap dot.
177
+ "tag": "M3 3h7l11 11-7 7L3 10z M7.5 7.5L7.51 7.5",
178
+ // The PDF viewer's own three, recut sharp like the rest of the set; "maximize" is lucide's
179
+ // name for the mark the canvas calls expand.
180
+ "minus": "M5 12h14",
181
+ "maximize": "M8 3H3v5 M16 3h5v5 M8 21H3v-5 M16 21h5v-5",
182
+ "x": "M6 6l12 12 M18 6 6 18",
183
+ "sliders": "M4 21v-7 M4 10V3 M12 21v-9 M12 8V3 M20 21v-5 M20 12V3 M2 14h4 M10 8h4 M18 16h4",
184
+ // Grid zoom's own mark, the SettingsGrammar board's arrows, lucide's move-horizontal recut sharp.
185
+ "move-horizontal": "M4 12h16 M8 8l-4 4 4 4 M16 8l4 4-4 4",
186
+ // The background menu's Sort by row, Menus.html's own geometry: three rules shortening to the
187
+ // right of a bare down arrow. IconSets.html names this mark when it caps the corner radius.
188
+ "sort": "M11 5h10 M11 9h7 M11 13h4 M7 5v14 M7 19l-3-3 M7 19l3-3",
189
+ // MediaMute rule 2: lucide's speaker polygon is already hard-cornered, and the two waves are
190
+ // genuine arcs that stay arcs under cut rule 4; the cross is two lines.
191
+ "volume": "M11 5L6 9H2v6h4l5 4z M15.5 8.5a5 5 0 0 1 0 7 M19 5a10 10 0 0 1 0 14",
192
+ "volume-x": "M11 5L6 9H2v6h4l5 4z M22 9l-6 6 M16 9l6 6",
193
+ // The three basic clipboard rows the context menu grew with its visibility settings. Lucide's
194
+ // scissors and clipboard both carry arcs; these are the cut's own square handles and square tray.
195
+ "scissors": "M5 3l14 14 M19 3L5 17 M2 17h5v5H2z M17 17h5v5h-5z",
196
+ "copy": "M9 8h12v13H9z M4 16V3h13",
197
+ "clipboard": "M9 2h6v4H9z M6 4H3v18h18V4h-3 M8 12h8 M8 16h5",
198
+ // The Keys section's rail mark: the key caps are the same zero-length-line dots the list mark uses.
199
+ "keyboard": "M2 6h20v12H2z M6 10L6.01 10 M10 10L10.01 10 M14 10L14.01 10 M18 10L18.01 10 M8 14h8",
200
+ // Invert selection's mark, lucide's contrast, its outer ring kept a true curve.
201
+ "contrast": "M12 2a10 10 0 1 0 0 20a10 10 0 1 0 0-20 M12 18a6 6 0 0 0 0-12v12z",
202
+ // Settings > Click and refresh's Open items with mark: the arrow head and its tail, as Icons040 cuts it.
203
+ "pointer": "M4 4l16 6.5-7 2-2 7z M13 13l6 6"
204
+ }
205
+
206
+ // The sub-paths a mark fills as well as strokes, by name; ui/Glyph.qml draws them in the mark's own ink.
207
+ var FILLED = {
208
+ // MenuAdditions040: Invert selection's right half disc is solid, lucide's contrast.
209
+ "contrast": "M12 18a6 6 0 0 0 0-12v12z"
210
+ }
211
+
212
+ function filledPathFor(name) {
213
+ return FILLED[name] || ""
214
+ }
215
+
216
+ function pathFor(name) {
217
+ return PATHS[name] || PATHS[FALLBACK]
218
+ }
package/ui/js/Input.js ADDED
@@ -0,0 +1,50 @@
1
+ .pragma library
2
+
3
+ // Delete carries DEL through libxkbcommon; retain SheetQuery's single-character semantics.
4
+ function isPrintable(text) {
5
+ var s = String(text || "")
6
+ return s.length === 1 && s >= " " && s !== "\u007f"
7
+ }
8
+
9
+ // Issue 287's paste chords, matched on the four real modifiers the way ui/js/Keymap.js matches keys.
10
+ function isPasteKey(event) {
11
+ var mods = event.modifiers & (Qt.ControlModifier | Qt.ShiftModifier | Qt.AltModifier | Qt.MetaModifier)
12
+ return (event.key === Qt.Key_V && mods === Qt.ControlModifier)
13
+ || (event.key === Qt.Key_Insert && mods === Qt.ShiftModifier)
14
+ }
15
+
16
+ // The clipboard's first line, keeping printable characters and whole surrogate pairs only.
17
+ function cleanPaste(text) {
18
+ var line = String(text || "").split(/\r\n|[\r\n]/)[0]
19
+ var out = ""
20
+ for (var i = 0; i < line.length; i++) {
21
+ var code = line.charCodeAt(i)
22
+ var low = i + 1 < line.length ? line.charCodeAt(i + 1) : 0
23
+ if (code >= 0xd800 && code <= 0xdbff && low >= 0xdc00 && low <= 0xdfff) {
24
+ out += line.substr(i, 2)
25
+ i++
26
+ } else if ((code < 0xd800 || code > 0xdfff) && isPrintable(line.charAt(i))) {
27
+ out += line.charAt(i)
28
+ }
29
+ }
30
+ return out
31
+ }
32
+
33
+ // Hands a query line's paste to its own typing route; the chord is consumed even when nothing is left to type.
34
+ function pasteInto(host, typeText) {
35
+ var type = function (value) {
36
+ var pasted = cleanPaste(value)
37
+ if (pasted.length > 0)
38
+ typeText(pasted)
39
+ }
40
+ // flea-qml: a Promise where the runtime reads its clipboard asynchronously (buninu-browser).
41
+ var failed = function (error) { console.warn("Clipboard read failed: " + String(error)) }
42
+ try {
43
+ var text = host.clipboardText()
44
+ if (text && typeof text.then === "function")
45
+ Promise.resolve(text).then(type).catch(failed)
46
+ else
47
+ type(text)
48
+ } catch (error) { failed(error) }
49
+ return true
50
+ }