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
package/ui/RowDrag.qml ADDED
@@ -0,0 +1,213 @@
1
+ import QtQuick
2
+ import "js/Drag.js" as DragOps
3
+ import "js/DragOut.js" as DragOut
4
+ import "js/DropDev.js" as DropDev
5
+ import "js/Tabs.js" as Tabs
6
+ import "js/Search.js" as Search
7
+
8
+ // Delegate input and drop eligibility share a view-owned FileDrag; no platform object lives in this row.
9
+ Item {
10
+ id: root
11
+
12
+ required property var session
13
+ required property int listingIndex
14
+ required property var row
15
+ readonly property var pane: root.session.pane
16
+ // A peek column's session names the directory it shows and the pane whose collide sends its drops; null is the pane's own listing.
17
+ readonly property var dropScope: root.pane === null && root.session.peekSource ? root.session.peekSource : null
18
+ readonly property var targetPane: root.dropScope ? root.dropScope.pane : root.pane
19
+ readonly property string targetDir: root.dropScope ? root.dropScope.dir : (root.pane ? Search.baseOf(root.pane) : "")
20
+
21
+ // A listing row names its own device; a peek or carried column row names none, so the backend's answer for its path stands in, and an unanswered path is 0, which copies.
22
+ readonly property int destDev: !root.row ? 0 : root.row.v ? root.row.v
23
+ : (root.row.d === true && root.targetPane && root.targetPane.backend
24
+ ? DropDev.devFor(root.targetPane.backend.pathDevs, root.targetPane.join(root.targetDir, root.row.n)) : 0)
25
+ // The answer landing while this folder is hovered re-says its line once, in the right verb.
26
+ onDestDevChanged: if (root.lit()) {
27
+ root.session.dropDestDev = root.destDev
28
+ root.session.showTarget(root.row.n, root.destDev)
29
+ }
30
+
31
+ // The drop destination this delegate last recorded on the session, kept so leaving clears only its own record.
32
+ property string recorded: ""
33
+ // False where the view answers drops from one shared area, so the row's own area stays disabled.
34
+ property bool dropsLocal: true
35
+
36
+ anchors.fill: parent
37
+ // A peek column's row lifts through the session's peekSource; which drops it takes is the DropArea's call alone.
38
+ enabled: !!root.row && (root.pane !== null ? !root.pane.listInFlight && root.listingIndex >= 0
39
+ : root.session.peekSource !== null)
40
+
41
+ DragHandler {
42
+ id: lift
43
+ enabled: root.pane === null || (!root.pane.renamePending && root.pane.renamingIndex !== root.listingIndex)
44
+ target: null
45
+ // Preserve List's grab contract: the Flickable must not take the row drag after its threshold.
46
+ grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByHandlersOfSameType
47
+ onActiveChanged: {
48
+ if (active && root.pane !== null) root.session.liftBegan(root.listingIndex, lift.centroid)
49
+ else if (active) root.session.liftPeek(root.row, lift.centroid)
50
+ else root.session.liftReleased()
51
+ }
52
+ onCentroidChanged: if (active) root.session.liftMoved(lift.centroid)
53
+ }
54
+
55
+ // The row's own area answers where dropsLocal holds; a view with one shared area leaves this one inert. No Loader stands in front of it: a Loader would add an object to every list row for a grid tile's saving.
56
+ DropArea {
57
+ anchors.fill: parent
58
+ // A peek row takes drops only as a folder, through its dropScope; without one it would aim the drop at the pane's own folder.
59
+ enabled: root.dropsLocal && (root.pane !== null || (root.dropScope !== null && !!root.row && root.row.d === true && root.targetPane !== null && !root.targetPane.listInFlight))
60
+ keys: [DragOps.ROWS_MIME, "text/uri-list", "text/plain"]
61
+ onEntered: function (drag) { root.enterAt(drag, drag) }
62
+ onPositionChanged: function (drag) { root.moveAt(drag) }
63
+ onExited: root.leaveRow()
64
+ onDropped: function (drop) { root.dropAt(drop) }
65
+ }
66
+
67
+ // A drop area's entrance, at a point in this row's own coordinates: the per-row area passes its drag, a shared one the mapped point.
68
+ function enterAt(drag, at) {
69
+ // xw6: a tab drag carries only the private tab type and is never a file drop.
70
+ if (drag.getDataAsString(Tabs.TAB_MIME) !== "") {
71
+ drag.accepted = false
72
+ return
73
+ }
74
+ drag.accepted = root.enter(drag.getDataAsString(DragOps.ROWS_MIME), drag.urls,
75
+ drag.getDataAsString(DragOps.SHELF_MIME),
76
+ drag.getDataAsString("text/plain"), drag.proposedAction,
77
+ drag.getDataAsString(DragOut.keys.liftMime))
78
+ root.hoverAt(at)
79
+ }
80
+
81
+ function moveAt(at) {
82
+ if (root.lit()) {
83
+ root.session.showTarget(root.row.n, root.destDev)
84
+ root.hoverAt(at)
85
+ }
86
+ }
87
+
88
+ function leaveAt() { root.leaveRow() }
89
+
90
+ function dropAt(drop) {
91
+ if (drop.getDataAsString(Tabs.TAB_MIME) !== "")
92
+ return
93
+ var marker = drop.getDataAsString(DragOps.ROWS_MIME)
94
+ var shelf = drop.getDataAsString(DragOps.SHELF_MIME)
95
+ var plain = drop.getDataAsString("text/plain")
96
+ if (root.refuseDrop(marker, drop.urls, shelf, plain)) return
97
+ if (root.dropped(marker, drop.urls, shelf, plain, drop.proposedAction)) {
98
+ drop.accept(Qt.CopyAction)
99
+ }
100
+ root.session.hoverEnded()
101
+ }
102
+
103
+ // The pointer leaves this delegate: the destination it recorded goes, even when a swap reused the delegate on another row, and a destination another row recorded since stays.
104
+ function leaveRow() {
105
+ if (root.recorded.length > 0 && root.session.dropDest === root.recorded) {
106
+ root.session.dropIndex = -1
107
+ root.session.dropDest = ""
108
+ root.session.dropDestDev = 0
109
+ root.session.leaveTarget()
110
+ }
111
+ root.recorded = ""
112
+ if (root.session.dragRows.length === 0) {
113
+ root.session.dragCopy = false
114
+ root.session.dragLink = false
115
+ }
116
+ root.session.hoverEnded()
117
+ DragOut.keys.leave()
118
+ }
119
+
120
+ // One reset for every finished gesture, refused or dropped: the drag's keys end and the row goes dark again.
121
+ function clearTarget() {
122
+ DragOut.keys.clear()
123
+ root.session.dropIndex = -1
124
+ root.session.dropDest = ""
125
+ root.session.dropDestDev = 0
126
+ root.session.dragCopy = false
127
+ root.session.dragLink = false
128
+ root.session.leaveTarget()
129
+ }
130
+
131
+ // Testable entrance: a refused folder row stays dark and names its refusal, never lighting "move here" for a drop that cannot land.
132
+ function enter(marker, urls, shelf, plain, proposed, lift) {
133
+ if (!(root.row && root.row.d === true)) return false
134
+ var dest = root.targetPane.join(root.targetDir, root.row.n)
135
+ var line = ""
136
+ var ok = false
137
+ if (DragOps.hasPaths(urls) || (plain && !marker)) {
138
+ line = DragOut.refusal(DragOut.sources(urls, plain, marker, ""), dest, marker, "")
139
+ ok = line === "" && DragOps.canDropInto(marker, urls, dest, plain)
140
+ } else if (root.dropScope === null) {
141
+ ok = DragOps.canDropByIndex(marker, root.targetDir, root.session.dragRows, root.listingIndex)
142
+ }
143
+ if (!ok) {
144
+ if (line) root.targetPane.message(line, false)
145
+ return false
146
+ }
147
+ root.session.dropIndex = root.listingIndex
148
+ // The drop's own address: the swap may rebuild this delegate on another row before the release.
149
+ root.session.dropDest = dest
150
+ root.session.dropDestDev = root.destDev
151
+ root.recorded = dest
152
+ if (root.targetPane.columnsArea) root.targetPane.columnsArea.askDropDevs(lift)
153
+ DragOut.keys.enter(marker, lift)
154
+ root.session.enterTarget(marker, urls, root.row.n, root.destDev, shelf, proposed)
155
+ return true
156
+ }
157
+
158
+ // Lit means this delegate still shows the hovered folder: after a swap the index may name another row.
159
+ function lit() {
160
+ return root.session.dropIndex === root.listingIndex && !!root.row
161
+ && root.session.dropDest === root.targetPane.join(root.targetDir, root.row.n)
162
+ }
163
+
164
+ // Where a drop lands: the recorded hovered folder, else this row's own folder, since a swap may have reused the delegate.
165
+ function landing() {
166
+ if (root.session.dropDest.length > 0) return { dest: root.session.dropDest, dev: root.session.dropDestDev }
167
+ var folder = root.row && root.row.d === true
168
+ return { dest: folder ? root.targetPane.join(root.targetDir, root.row.n) : "", dev: folder ? root.destDev : 0 }
169
+ }
170
+
171
+ // Testable refusal: says the sentence and darkens exactly like dropped(), so a refused
172
+ // drop never leaves the row lit (Qt sends dropped, not exited, after the drop).
173
+ function refuseDrop(marker, urls, shelf, plain) {
174
+ var dest = root.landing().dest
175
+ if (!dest) return ""
176
+ var line = DragOut.refusal(DragOut.sources(urls, plain, marker, shelf), dest, marker, shelf)
177
+ if (!line) return ""
178
+ root.targetPane.message(line, false)
179
+ root.clearTarget()
180
+ return line
181
+ }
182
+
183
+ // The drop apart from its platform event, which tests/js/collide.js cannot build: answers whether it was taken.
184
+ function dropped(marker, urls, shelf, plain, proposed) {
185
+ var accepted = false
186
+ var at = root.landing()
187
+ if (at.dest.length > 0) {
188
+ if (DragOps.hasPaths(urls) || (plain && !marker && !shelf))
189
+ accepted = DragOps.dropInto(root.targetPane, marker, urls, at.dest, at.dev, shelf, plain, proposed, DragOut.keys.ctrl, DragOut.keys.shift)
190
+ else if (root.dropScope === null
191
+ && DragOps.canDropByIndex(marker, root.targetDir, root.session.dragRows, root.listingIndex))
192
+ accepted = DragOps.dropByIndex(root.targetPane, root.session.dragRows, root.listingIndex,
193
+ root.session.verbAt(marker, root.row, DragOut.keys.ctrl, DragOut.keys.shift), root.session.dragListing)
194
+ }
195
+ root.clearTarget()
196
+ return accepted
197
+ }
198
+
199
+ // In the view's own coordinates, so the band reads the listing, not the row.
200
+ function hoverAt(at) {
201
+ if (root.dropScope !== null || !at)
202
+ return
203
+ var viewer = root.session.pane
204
+ var list = viewer ? viewer.listArea : null
205
+ if (!list || !viewer || root.targetDir !== Search.baseOf(viewer))
206
+ return
207
+ var pt = root.mapToItem(list, at.x, at.y)
208
+ if (root.lit())
209
+ root.session.hoverBegan(root.listingIndex, root.targetPane.join(root.targetDir, root.row.n), pt.y, list.height)
210
+ else
211
+ root.session.hoverMoved(pt.y, list.height)
212
+ }
213
+ }
@@ -0,0 +1,27 @@
1
+ import QtQuick
2
+ import "js/Drag.js" as DragOps
3
+
4
+ // The file row's shared drop cue and clipboard mark, compiled only when either is drawn.
5
+ DropTarget {
6
+ id: root
7
+
8
+ required property var row
9
+ property alias mark: clipGlyph
10
+ anchors.fill: parent
11
+ shown: root.row.dropTarget
12
+ paintWidth: root.row.paintWidth
13
+ text: DragOps.label(root.row.dropCopying, root.row.dropLinking)
14
+
15
+ // A clipboard row under a drag keeps its mark beside the label, one pixel above the text centre line.
16
+ Glyph {
17
+ id: clipGlyph
18
+ visible: root.row.clipMark.length > 0 && !root.row.renaming && !root.row.searching
19
+ width: root.row.clipPx
20
+ height: root.row.clipPx
21
+ x: root.row.clipMark.length > 0 ? root.row.nameItem().x + Math.min(root.row.nameItem().implicitWidth, root.row.nameItem().width) + Theme.spacing.gap : 0
22
+ anchors.verticalCenter: parent.verticalCenter
23
+ anchors.verticalCenterOffset: -1
24
+ name: root.row.clipMark
25
+ color: Theme.color.mutedFrame
26
+ }
27
+ }
package/ui/RunCard.qml ADDED
@@ -0,0 +1,286 @@
1
+ import Quickshell
2
+ import Quickshell.Io
3
+ import QtQuick
4
+ import qs.Commons
5
+ import "." as Flea
6
+ import "js/RunFile.js" as RunFile
7
+
8
+ // Opening an executable file asks once, in this one card: Cancel, Open as text, Run and Run in terminal, with the ring on the default. An AppImage the desktop names a handler for offers that application first, by its own name, and focuses it instead.
9
+ FocusScope {
10
+ id: root
11
+ anchors.fill: parent
12
+ visible: opened || opacity > 0
13
+ // Closed means no input, even while the fade-out is still drawn.
14
+ enabled: opened
15
+ opacity: 0
16
+ property bool opened: false
17
+ property string path: ""
18
+ property string kind: "script"
19
+ property double size: 0
20
+ // The listed path the ask was opened from, which names the row; path names the resolved target it runs.
21
+ property string listedPath: ""
22
+ property bool hasHandler: false
23
+ property string handlerId: ""
24
+ property string handlerName: ""
25
+ // The mark the listing draws for the asked row, read once at open.
26
+ property string listedGlyph: ""
27
+ // dev and ino stay strings end to end: a double cannot hold every 64-bit value exactly.
28
+ property string dev: ""
29
+ property string ino: ""
30
+ property double mtimeS: 0
31
+ property double mtimeNs: 0
32
+ property string tweak: ""
33
+ property var pane: null
34
+ readonly property string fileName: RunFile.leafOf(root.path)
35
+ readonly property var buttons: RunFile.buttonsFor(root.kind, root.hasHandler)
36
+ // The board's own default: the handler where one is named, Run in terminal elsewhere.
37
+ readonly property string defaultName: RunFile.defaultButton(root.kind, root.hasHandler)
38
+ property string focusName: RunFile.START
39
+ // The card's own single-flight run lane, one per window: a second press while one runs is refused out loud, never queued.
40
+ property string runCurrent: ""
41
+ property string runAction: ""
42
+ readonly property int isDirectoryStatus: 3
43
+ // The run card's own failures, the same numbers src/runfile.rs answers with.
44
+ readonly property int runChangedStatus: 6
45
+ readonly property int runNoExecStatus: 7
46
+ readonly property int runSpawnStatus: 8
47
+ readonly property int runHandlerGoneStatus: 9
48
+ readonly property var cardItem: card
49
+ readonly property string titleText: title.text
50
+ readonly property bool buttonsFit: buttons.width <= body.holderWidth
51
+ function buttonItem(name) {
52
+ var at = root.buttons.indexOf(name)
53
+ return at >= 0 ? buttonRow.itemAt(at) : null
54
+ }
55
+ // One shot: the ask's raw text is parsed here so the card names the resolved target, and the next open re-derives the ring.
56
+ function open(info, pane) {
57
+ var ask = RunFile.parseAsk(info.raw || "")
58
+ if (ask === null) {
59
+ if (pane) pane.message("Flea could not check that file, so it was not run.", true)
60
+ return
61
+ }
62
+ root.pane = pane
63
+ root.path = ask.target
64
+ root.listedPath = info.path || ask.target
65
+ root.kind = ask.kind
66
+ root.size = ask.size
67
+ root.hasHandler = ask.hasHandler
68
+ root.handlerId = ask.handlerId
69
+ root.handlerName = ask.handlerName
70
+ root.listedGlyph = RunFile.listedGlyph(pane, root.listedPath)
71
+ root.dev = ask.dev
72
+ root.ino = ask.ino
73
+ root.mtimeS = ask.mtimeS
74
+ root.mtimeNs = ask.mtimeNs
75
+ root.tweak = info.tweak || ""
76
+ root.focusName = RunFile.startFocus(root.buttons, root.tweak)
77
+ body.contentY = 0
78
+ root.opened = true
79
+ root.forceActiveFocus()
80
+ }
81
+ // Closing hands the keyboard back to the asking pane, whatever closed it.
82
+ function close() {
83
+ root.opened = false
84
+ if (root.pane) root.pane.forceActiveFocus()
85
+ }
86
+ // A press lands on its own button first, so the accent never shows one choice while another is taken.
87
+ function press(choice) {
88
+ root.focusName = choice
89
+ root.choose(choice)
90
+ }
91
+ function launch(action, command, path) {
92
+ if (runChild.running) {
93
+ root.pane.message("Still running the last file; try again in a moment.", false)
94
+ return
95
+ }
96
+ root.runAction = action
97
+ root.runCurrent = path
98
+ runChild.command = command
99
+ runChild.running = true
100
+ }
101
+ // Sample argv: flea --run /home/gm/tool.sh <the card's identity>, never a shell string.
102
+ function run(path, dev, ino, size, mtimeS, mtimeNs) {
103
+ root.launch("run", [Quickshell.env("FLEA_BIN") || "flea", "--run", path, dev, ino, size, mtimeS, mtimeNs], path)
104
+ }
105
+ function runTerminal(path, dev, ino, size, mtimeS, mtimeNs) {
106
+ root.launch("terminal", [Quickshell.env("FLEA_BIN") || "flea", "--run-terminal", path, dev, ino, size, mtimeS, mtimeNs], path)
107
+ }
108
+ function openText(path, pane) {
109
+ if (pane) root.pane = pane
110
+ root.launch("text", [Quickshell.env("FLEA_BIN") || "flea", "--open-text", path], path)
111
+ }
112
+ // Sample argv: flea --open-handler /home/gm/app.AppImage appimagelauncher.desktop <the card's identity>.
113
+ function openHandler(path, id, dev, ino, size, mtimeS, mtimeNs) {
114
+ root.launch("handler", [Quickshell.env("FLEA_BIN") || "flea", "--open-handler", path, id, dev, ino, size, mtimeS, mtimeNs], path)
115
+ }
116
+ // The choice lands on the pane that asked, through ui/js/RunFile.js.
117
+ function choose(choice) {
118
+ root.close()
119
+ RunFile.choose(root.pane, root, choice)
120
+ }
121
+ // A held key never presses the default: repeats move nothing and run nothing.
122
+ function keyPressed(key, autoRepeat, modifiers) {
123
+ if (key === Qt.Key_Escape) { root.choose("cancel"); return }
124
+ if (modifiers & (Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier)) return
125
+ if (autoRepeat === true) return
126
+ if (RunFile.activates(key)) root.choose(root.focusName)
127
+ else root.focusName = RunFile.moved(root.buttons, root.focusName, key, modifiers)
128
+ if (root.opened) body.reveal(root.buttonItem(root.focusName))
129
+ }
130
+ Keys.onPressed: function (event) {
131
+ root.keyPressed(event.key, event.isAutoRepeat, event.modifiers)
132
+ event.accepted = true
133
+ }
134
+ Flea.Reveal { target: root; shown: root.opened; lift: card }
135
+ Process {
136
+ id: runChild
137
+
138
+ onExited: function (exitCode, exitStatus) {
139
+ var action = root.runAction
140
+ var path = root.runCurrent
141
+ root.runAction = ""
142
+ root.runCurrent = ""
143
+ if (exitCode === 0)
144
+ return
145
+ if (exitCode === root.isDirectoryStatus) {
146
+ root.pane.open(path)
147
+ return
148
+ }
149
+ if (exitCode === root.runChangedStatus) {
150
+ root.pane.message(action === "handler" ? "That file changed after Flea checked it, so it was not opened."
151
+ : "That file changed after Flea checked it, so it was not run.", true)
152
+ return
153
+ }
154
+ if (exitCode === root.runNoExecStatus) {
155
+ root.pane.message("That program is on a volume that does not allow running files.", true)
156
+ return
157
+ }
158
+ if (exitCode === root.runHandlerGoneStatus) {
159
+ root.pane.message("That application is no longer installed.", true)
160
+ return
161
+ }
162
+ if (exitCode === root.runSpawnStatus) {
163
+ if (action === "run")
164
+ root.pane.message("Nothing on this system could run that file.", true)
165
+ else if (action === "terminal")
166
+ root.pane.message("Nothing on this system could run that file in a terminal.", true)
167
+ else if (action === "handler")
168
+ root.pane.message("Nothing on this system could be asked to open that file.", true)
169
+ else
170
+ root.pane.message("Nothing on this system could open that file as text.", true)
171
+ return
172
+ }
173
+ if (action === "run")
174
+ root.pane.message("That program could not be run.", true)
175
+ else if (action === "terminal")
176
+ root.pane.message("That program could not be run in a terminal.", true)
177
+ else if (action === "handler")
178
+ root.pane.message("That application did not open the file.", true)
179
+ else
180
+ root.pane.message("No text editor opened that file.", true)
181
+ }
182
+ }
183
+ Flea.DialogScrim {
184
+ onDismissed: root.choose("cancel")
185
+ }
186
+ Rectangle {
187
+ id: card
188
+ x: Theme.cardOrigin(root.width, width)
189
+ y: Theme.cardOrigin(root.height, height)
190
+ // The board's own 448, grown by the text size the way the collision card is.
191
+ width: Theme.cardSpan(card.contentWidth + 2 * card.cardPadding + 2 * Theme.spacing.hairline, root.width - 2 * Theme.spacing.gap)
192
+ height: Theme.cardSpan(body.wanted + card.cardPadding + card.cardBottomPadding + 2 * Theme.spacing.hairline, root.height - 2 * Theme.spacing.gap)
193
+ color: Theme.color.surface
194
+ border.color: Theme.color.mutedFrame
195
+ border.width: Theme.spacing.hairline
196
+ radius: Style.cornerRadius
197
+ readonly property real referenceScale: Theme.font.bodySmall / referenceBody
198
+ readonly property real cardPadding: Math.round(cardPad * referenceScale)
199
+ readonly property real cardBottomPadding: Math.round(cardBottomPad * referenceScale)
200
+ // RunFile's buttons keep 6 px of air over the gap.
201
+ readonly property real buttonsAir: Math.round(buttonsPad * referenceScale)
202
+ // The board's 414 content, since four buttons at DialogButton's pad and gap need 409.
203
+ readonly property real contentWidth: Math.max(card.boardContent, buttons.implicitWidth)
204
+ // The board's own reference size, pad and content width, so no bare number sits in an expression.
205
+ readonly property real referenceBody: 13
206
+ readonly property real cardPad: 16
207
+ readonly property real cardBottomPad: 12
208
+ readonly property real buttonsPad: 6
209
+ readonly property real contentBase: 414
210
+ readonly property real boardContent: Math.round(contentBase * referenceScale * Theme.dialogWidthRatio)
211
+ // The handler's name elides inside what the board's content leaves beside the other buttons, so a long name never widens the card.
212
+ readonly property real handlerRoom: {
213
+ var used = 0
214
+ for (var i = 0; i < buttonRow.count; i++) {
215
+ var item = buttonRow.itemAt(i)
216
+ if (item && item.modelData !== "handler") used += item.implicitWidth + buttons.spacing
217
+ }
218
+ return Math.max(Theme.hitMin, card.boardContent - used - 2 * Theme.spacing.gap - 2 * Theme.spacing.hairline)
219
+ }
220
+ TextMetrics {
221
+ id: handlerLabel
222
+ font.family: Theme.font.family
223
+ font.pixelSize: Theme.font.body
224
+ elide: Text.ElideRight
225
+ elideWidth: card.handlerRoom
226
+ text: root.handlerName
227
+ }
228
+ MouseArea {
229
+ anchors.fill: parent
230
+ hoverEnabled: true
231
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
232
+ onWheel: function (wheel) { wheel.accepted = true }
233
+ }
234
+ Flea.CardFrame {
235
+ id: body
236
+ bleed: Theme.focusClearance
237
+ anchors.fill: parent
238
+ anchors.leftMargin: card.cardPadding + Theme.spacing.hairline - Theme.focusClearance
239
+ anchors.rightMargin: card.cardPadding + Theme.spacing.hairline - Theme.focusClearance
240
+ anchors.topMargin: card.cardPadding + Theme.spacing.hairline - Theme.focusClearance
241
+ anchors.bottomMargin: card.cardBottomPadding + Theme.spacing.hairline - Theme.focusClearance
242
+ title: Flea.DialogHeader {
243
+ id: title
244
+ width: parent.width
245
+ text: RunFile.titleFor(root.fileName)
246
+ }
247
+ buttons: Row {
248
+ id: buttons
249
+ anchors.right: parent.right
250
+ topPadding: card.buttonsAir
251
+ spacing: Theme.spacing.gap
252
+ Repeater {
253
+ id: buttonRow
254
+ model: root.buttons
255
+ Flea.DialogButton {
256
+ required property string modelData
257
+ label: RunFile.labelFor(modelData, handlerLabel.elidedText) || modelData
258
+ primary: modelData === root.defaultName
259
+ focused: root.focusName === modelData
260
+ onActivated: root.press(modelData)
261
+ }
262
+ }
263
+ }
264
+ Row {
265
+ width: parent.width
266
+ height: Theme.fileRowHeight
267
+ spacing: Theme.spacing.gap
268
+ Flea.Glyph {
269
+ width: Theme.markSize
270
+ height: parent.height
271
+ name: RunFile.glyphFor(root.kind, root.listedGlyph)
272
+ color: Theme.color.foreground
273
+ }
274
+ Text {
275
+ width: Math.max(0, parent.width - Theme.markSize - parent.spacing)
276
+ anchors.verticalCenter: parent.verticalCenter
277
+ text: RunFile.subtitleFor(root.kind, root.size)
278
+ textFormat: Text.PlainText
279
+ elide: Text.ElideRight
280
+ color: Theme.color.foreground
281
+ font { family: Theme.font.family; pixelSize: Theme.font.body }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
package/ui/Scripts.qml ADDED
@@ -0,0 +1,65 @@
1
+ pragma Singleton
2
+ import QtQuick
3
+ import Quickshell
4
+ import Quickshell.Io
5
+ import "js/Scripts.js" as Model
6
+
7
+ // MenuAdditions rule 2: the scripts a menu can run, read out of ~/.config/flea/scripts when a menu
8
+ // opens rather than watched, and run with the selected paths as arguments in the first one's folder.
9
+ // The one thing here that touches the outside world, the way ui/NetworkMounts.qml is for gio.
10
+ Item {
11
+ id: root
12
+
13
+ // [{ id, label, path }], sorted by name, the label the file name without its extension.
14
+ property var entries: []
15
+ property bool loaded: false
16
+ readonly property string directory: (Quickshell.env("XDG_CONFIG_HOME") && Quickshell.env("XDG_CONFIG_HOME").length > 0
17
+ ? Quickshell.env("XDG_CONFIG_HOME") : Quickshell.env("HOME") + "/.config") + "/flea/scripts"
18
+
19
+ signal said(string text, bool isError)
20
+
21
+ function refresh() {
22
+ if (!lister.running)
23
+ lister.running = true
24
+ }
25
+
26
+ function run(id, paths) {
27
+ var script = ""
28
+ for (var i = 0; i < root.entries.length; i++)
29
+ if (root.entries[i].id === id) script = root.entries[i].path
30
+ if (script.length === 0 || paths.length === 0) {
31
+ root.said("That script is no longer there.", true)
32
+ return
33
+ }
34
+ runner.script = script
35
+ runner.workingDirectory = paths[0].substring(0, paths[0].lastIndexOf("/")) || "/"
36
+ runner.command = [script].concat(paths)
37
+ runner.running = true
38
+ }
39
+
40
+ // An executable regular file, one level down and nothing else: a directory of scripts is a flat
41
+ // one, and -perm -u+x is the owner bit the board names.
42
+ Process {
43
+ id: lister
44
+ command: ["find", root.directory, "-maxdepth", "1", "-type", "f", "-perm", "-u+x", "-printf", "%f\\n"]
45
+ stdout: StdioCollector {
46
+ waitForEnd: true
47
+ onStreamFinished: {
48
+ root.entries = Model.parse(text, root.directory)
49
+ root.loaded = true
50
+ }
51
+ }
52
+ }
53
+
54
+ // A script's own last stderr line is the report, elided to one sentence by the status centre.
55
+ Process {
56
+ id: runner
57
+ property string script: ""
58
+ stderr: StdioCollector { waitForEnd: true }
59
+ onExited: function (code, status) {
60
+ if (code === 0)
61
+ return
62
+ root.said(Model.failure(runner.script.substring(runner.script.lastIndexOf("/") + 1), runner.stderr.text, code), true)
63
+ }
64
+ }
65
+ }