flea-qml 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,133 @@
1
+ .pragma library
2
+
3
+ .import "Menu.js" as Menu
4
+ .import "Mounts.js" as Mounts
5
+ .import "PlaceMenu.js" as PlaceMenu
6
+
7
+ // The rail's own menu: which one a row opens, what a chosen row does, and the Edit that rewrites a
8
+ // saved place. Split out of ui/js/Mounts.js, which parses and identifies rail rows and nothing more.
9
+
10
+ // Which menu a rail row opens, and with which handle: the trash and a favourite carry their own,
11
+ // every other row is a mount or a share and ui/js/Menu.js never sees it. Split out of ui/Sidebar.qml,
12
+ // which sits at its recorded line count, and this file already decides what a row offers.
13
+ function railMenuFor(sidebar, entry, scenePosition, hidden) {
14
+ if (entry.kind === "trash") {
15
+ sidebar.menu.openForRail("trash", Menu.trashEntries(sidebar.trashCount, false), scenePosition)
16
+ return
17
+ }
18
+ // MenuAdditions rule 3: a Places or Favorites row opens the folder menu for its path while that
19
+ // Extras row is on, and with it off a favourite keeps the one Remove it has offered since 0.2.1.
20
+ if (entry.kind === "favourite" || entry.kind === "home") {
21
+ var index = entry.kind === "favourite" ? entry.favouriteIndex : -1
22
+ var rows = PlaceMenu.entries(entry, index, hidden)
23
+ if (rows.length > 0) {
24
+ sidebar.menu.openForRail(PlaceMenu.key(entry, index), rows, scenePosition)
25
+ return
26
+ }
27
+ if (entry.kind !== "favourite")
28
+ return
29
+ // The Places menu is off: the one row is INVENTORY's own Remove from Favorites, never a bare Remove.
30
+ sidebar.menu.openForRail("favourite:" + entry.favouriteIndex + ":" + JSON.stringify(entry.original),
31
+ Menu.railEntries({ group: "favourite", kind: "favourite" }), scenePosition)
32
+ return
33
+ }
34
+ sidebar.menu.openForRail(Mounts.railKey(entry), Mounts.rowMenu(entry), scenePosition)
35
+ }
36
+
37
+ // Issue 21: Edit opens D11's dialog over the saved place, and the address that finally mounts is
38
+ // written back over that place's own line, so a share gio could not reach is corrected where it sits.
39
+ function editPlace(sidebar, share) {
40
+ var entry = sidebar.networkEntries[share]
41
+ if (!entry)
42
+ return
43
+ sidebar.editingPlace = Mounts.normalize(entry.uri)
44
+ sidebar.editingRequest = ""
45
+ sidebar.editRequested(entry.uri, entry.label, "", "Edit this address, then connect and save.", false, sidebar.navigationPane)
46
+ }
47
+
48
+ // Each attempt this dialog makes, so a mount that was already in flight when the rail armed cannot
49
+ // answer for the edit: a refusal only re-binds, because the next attempt is the one that counts.
50
+ function placeSubmitted(sidebar, requestId) {
51
+ if (sidebar.editingPlace.length > 0)
52
+ sidebar.editingRequest = requestId
53
+ }
54
+
55
+ // The answer to that edit: a refused connect keeps the arm, because correcting an address gio could
56
+ // not reach is what the dialog stays open for; ui/shell.qml disarms it when that dialog closes.
57
+ function placeSaved(sidebar, mounts, requestId, uri, success) {
58
+ if (!success || sidebar.editingPlace.length === 0 || requestId !== sidebar.editingRequest)
59
+ return
60
+ var was = sidebar.editingPlace
61
+ sidebar.editingPlace = ""
62
+ sidebar.editingRequest = ""
63
+ if (Mounts.normalize(uri) !== was)
64
+ mounts.replacePlace(was)
65
+ }
66
+
67
+ // The rail menu's chosen row, handed the row's key rather than its position: the rail rebuilds on
68
+ // a five second poll, so the index the menu opened over can name a different row by now. A key
69
+ // that no longer names a row does nothing, because the row it named has left the rail already.
70
+ // Both Services re-check the kind themselves; this only resolves which row was meant, and the rail
71
+ // itself owns the two rows that need no mount at all.
72
+ function release(action, key, devices, mounts, sidebar) {
73
+ // Flash image hands the pane the volume's whole disk to match against its own drive list.
74
+ if (action === "flashImage") {
75
+ var at = Mounts.rowByKey(sidebar.deviceEntries, key)
76
+ if (at >= 0 && sidebar.navigationPane)
77
+ sidebar.navigationPane.openFlashDrive(sidebar.deviceEntries[at].device)
78
+ return
79
+ }
80
+ if (action === "eject") {
81
+ var volume = Mounts.rowByKey(sidebar.deviceEntries, key)
82
+ if (volume >= 0)
83
+ devices.eject(volume)
84
+ return
85
+ }
86
+ // RailAdditions rule 2: Mount and Open are the row's own activation, which mounts when it has to
87
+ // and opens either way, so the menu row and Enter cannot drift apart.
88
+ if (action === "mountVolume" || action === "unmountVolume" || action === "unlockVolume") {
89
+ var row = Mounts.rowByKey(sidebar.deviceEntries, key)
90
+ if (row < 0)
91
+ return
92
+ if (action === "unmountVolume") devices.unmount(row)
93
+ else devices.activate(row)
94
+ return
95
+ }
96
+ // Open is the row's own click: a volume or phone mounts and opens, a share resolves and opens.
97
+ if (action === "open") {
98
+ var volume = Mounts.rowByKey(sidebar.deviceEntries, key)
99
+ if (volume >= 0) {
100
+ devices.activate(volume)
101
+ return
102
+ }
103
+ var at = Mounts.rowByKey(sidebar.networkEntries, key)
104
+ if (at >= 0) {
105
+ mounts.activate(at, sidebar.navigationPane)
106
+ return
107
+ }
108
+ sidebar.openPhone(key)
109
+ return
110
+ }
111
+ // The phone Service is the sidebar's own child, so the sidebar resolves the key against it; a
112
+ // phone unmounts rather than ejects, because gvfs answers can_eject=0 for the MTP monitor.
113
+ if (action === "unmountPhone") {
114
+ sidebar.releasePhone(key)
115
+ return
116
+ }
117
+ // Mount is the row's own activation, which mounts when it has to and opens either way.
118
+ if (action === "mountPhone") {
119
+ sidebar.openPhone(key)
120
+ return
121
+ }
122
+ var share = Mounts.rowByKey(sidebar.networkEntries, key)
123
+ if (share < 0)
124
+ return
125
+ if (action === "unmount")
126
+ mounts.unmount(share)
127
+ else if (action === "editPlace")
128
+ editPlace(sidebar, share)
129
+ else if (action === "rename")
130
+ sidebar.startRename(sidebar.placesEntries.length + share)
131
+ else if (action === "remove")
132
+ mounts.forget(sidebar.networkEntries[share].uri)
133
+ }
@@ -0,0 +1,135 @@
1
+ .pragma library
2
+ .import "Format.js" as Format
3
+
4
+ // The desktop's own history, read and never written; every bookmark is untrusted input.
5
+
6
+ // The freedesktop recent file, and where XDG_DATA_HOME defaults to when the session did not set it.
7
+ var HISTORY_LEAF = "recently-used.xbel"
8
+ var DEFAULT_DATA_HOME = "/.local/share"
9
+
10
+ // The output loop stops here and hands the rail the newest LIMIT paths.
11
+ var LIMIT = 500
12
+
13
+ // Sample input: ("/home/gm/.local/share", "/home/gm") and ("", "/home/gm"); an XDG_DATA_HOME that
14
+ // is not an absolute path is not a data home, so the default answers for it too.
15
+ function historyPath(dataHome, home) {
16
+ var root = String(dataHome || "")
17
+ if (root.charAt(0) !== "/") {
18
+ root = String(home || "") + DEFAULT_DATA_HOME
19
+ }
20
+ return root.replace(/\/+$/, "") + "/" + HISTORY_LEAF
21
+ }
22
+
23
+ // Sample input: "file:///home/gm/a%20b.png" becomes "/home/gm/a b.png".
24
+ // Refuses non-file schemes, foreign authorities, bad escapes and control characters.
25
+ function pathOf(href) {
26
+ var raw = String(href || "")
27
+ if (raw.substring(0, 7).toLowerCase() !== "file://") {
28
+ return ""
29
+ }
30
+ var rest = raw.substring(7)
31
+ // The authority is everything before the path's own leading slash.
32
+ var cut = rest.indexOf("/")
33
+ if (cut < 0) {
34
+ return ""
35
+ }
36
+ var authority = rest.substring(0, cut).toLowerCase()
37
+ if (authority.length > 0 && authority !== "localhost") {
38
+ return ""
39
+ }
40
+ var decoded = ""
41
+ try {
42
+ decoded = decodeURIComponent(rest.substring(cut))
43
+ } catch (e) {
44
+ return ""
45
+ }
46
+ if (decoded.charAt(0) !== "/" || decoded === "/") {
47
+ return ""
48
+ }
49
+ // A control character cannot appear in a path this window will draw or send back as a URI.
50
+ if (/[\x00-\x1f\x7f]/.test(decoded)) {
51
+ return ""
52
+ }
53
+ return decoded
54
+ }
55
+
56
+ // Sample bookmarks: [{ href: "file:///home/gm/a.txt", stamp: "2026-08-30T11:32:04Z" }].
57
+ // Newest first with the stamps kept, so the Used column draws the visit, not the mtime.
58
+ function entries(bookmarks) {
59
+ var rows = []
60
+ for (var i = 0; i < bookmarks.length; i++) {
61
+ var path = pathOf(bookmarks[i].href)
62
+ if (path.length === 0) {
63
+ continue
64
+ }
65
+ rows.push({ path: path, stamp: String(bookmarks[i].stamp || ""), at: rows.length })
66
+ }
67
+ // The file's own order is the tie-break, so two bookmarks sharing a stamp never swap between reads.
68
+ rows.sort(function (a, b) {
69
+ if (a.stamp === b.stamp) {
70
+ return a.at - b.at
71
+ }
72
+ return a.stamp < b.stamp ? 1 : -1
73
+ })
74
+ var out = []
75
+ var seen = {}
76
+ for (var j = 0; j < rows.length && out.length < LIMIT; j++) {
77
+ if (seen[rows[j].path]) {
78
+ continue
79
+ }
80
+ seen[rows[j].path] = true
81
+ out.push({ path: rows[j].path, stamp: rows[j].stamp })
82
+ }
83
+ return out
84
+ }
85
+
86
+ // Sample input: "/home/gm/a.txt" names "a.txt" in "/home/gm".
87
+ // The leaf draws as the name and its parent as the caption beside it.
88
+ function nameOf(path) {
89
+ var text = String(path || "")
90
+ var cut = text.lastIndexOf("/")
91
+ return cut < 0 ? text : text.substring(cut + 1)
92
+ }
93
+
94
+ // Sample input: "home/gm/a.txt" sits in "/home/gm", and "a.txt" in "/".
95
+ function locationOf(path) {
96
+ var text = String(path || "")
97
+ if (text.length === 0) {
98
+ return ""
99
+ }
100
+ var cut = text.lastIndexOf("/")
101
+ if (cut <= 0) {
102
+ return "/"
103
+ }
104
+ var parent = text.substring(0, cut)
105
+ return parent.charAt(0) === "/" ? parent : "/" + parent
106
+ }
107
+
108
+ // Sample input: "home/gm/Documents/claude/a.md" under "/home/gm" is "Documents/claude", a file in home "~", outside it absolute.
109
+ function locationUnder(path, home) {
110
+ var shown = Format.tilde(locationOf(path), String(home || ""))
111
+ if (shown.indexOf("~/") === 0) {
112
+ return shown.substring(2)
113
+ }
114
+ return shown
115
+ }
116
+
117
+ // One bounded lookup accompanies the entries; no file stat or extra history read.
118
+ function visits(entries) {
119
+ var out = {}
120
+ for (var i = 0; i < entries.length; i++) {
121
+ var seconds = Date.parse(entries[i].stamp) / 1000
122
+ out[entries[i].path] = isFinite(seconds) ? seconds : null
123
+ }
124
+ return out
125
+ }
126
+
127
+ // Each asker waits once, and null, the rail pane itself, joins like any other.
128
+ function joinRequesters(current, requester) {
129
+ var asker = requester || null
130
+ var seen = current || []
131
+ if (seen.indexOf(asker) >= 0) {
132
+ return seen
133
+ }
134
+ return seen.concat([asker])
135
+ }
@@ -0,0 +1,156 @@
1
+ .pragma library
2
+
3
+ .import "BackReturn.js" as BackReturn
4
+ .import "DirSizes.js" as DirSizes
5
+ .import "Nav.js" as Nav
6
+ .import "Search.js" as Search
7
+ .import "Thumbs.js" as Thumbs
8
+
9
+ // Recent lists the history's paths under "/", newest first via mtime desc.
10
+ var OFF = ""
11
+ var RESULTS = "results"
12
+
13
+ // One refusal for both paste routes: the menu reaches past key dispatch, so it shares this.
14
+ function refusePaste(pane) {
15
+ if (pane.recentMode.length > 0) {
16
+ pane.message((pane.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false)
17
+ return true
18
+ }
19
+ return false
20
+ }
21
+
22
+ // Open keeps where the pane stood and asks the history's paths after the bounded jump; spanning mounts leaves fsinfo unknown.
23
+ function run(pane, paths, visits, mode) {
24
+ // The history takes the place of a listing out; its answer is dropped by the folder it names, see ui/js/Swap.js onListed.
25
+ if (pane.listInFlight) {
26
+ pane.swap.stopWaiting()
27
+ BackReturn.dropOwed(pane)
28
+ }
29
+ // The standing order is kept for the way back, not the mtime it replaces.
30
+ if (pane.recentMode.length === 0 && pane.backend) {
31
+ pane.recentSortBy = pane.backend.sortBy
32
+ pane.recentSortDesc = pane.backend.sortDesc === true
33
+ }
34
+ if (pane.recentFrom.length === 0) {
35
+ pane.recentFrom = Nav.place(pane)
36
+ }
37
+ // A history replaces the standing listing, so a live session closes first.
38
+ Search.leaveWalk(pane)
39
+ // The paths this listing stands on, so a refresh with the rail hidden still re-asks them.
40
+ pane.recentPaths = paths || []
41
+ pane.recentVisits = visits || ({})
42
+ pane.listInFlight = true
43
+ pane.listedSeen = false
44
+ pane.path = "/"
45
+ pane.recentMode = mode || RESULTS
46
+ pane.listingPath = "/"
47
+ pane.storageClass = ""
48
+ // Recent rows span filesystems, so the Tags row stays and the backend refuses each filesystem that cannot hold tags by name.
49
+ pane.canTag = true
50
+ pane.fsName = ""
51
+ pane.fsFree = 0
52
+ // Recent asks for no figures, so its empty slot is an answer.
53
+ pane.fsAnswered = true
54
+ var ask = {}
55
+ // A walk closed above keeps its rows and its strip until the history lands.
56
+ if (pane.searchLeaving === true) ask.holdWalk = true
57
+ Nav.holdOrForget(pane, ask)
58
+ pane.appliedListingPreferences = pane.listingPreferences
59
+ if (pane.recentMode === "trash") pane.backend.send({c:"listtrash",first:pane.windowSize})
60
+ else pane.backend.listPaths(pane.recentPaths, pane.windowSize)
61
+ // A deep anchored refresh asks its window only after the history's listpaths request.
62
+ var anchor = pane.wire ? pane.wire.anchor : null
63
+ if (anchor && anchor.path === pane.path && anchor.start > 0)
64
+ pane.backend.window(anchor.start, pane.windowSize)
65
+ pane.backend.sortBy = "mtime"
66
+ pane.backend.sortDesc = true
67
+ }
68
+
69
+ // Leaving Recent re-lists the folder it was opened over, pushing no history entry.
70
+ function close(pane) {
71
+ var back = pane.recentFrom.length > 0 ? pane.recentFrom : "/"
72
+ leave(pane)
73
+ pane.openWithoutHistory(back, { supersede: true })
74
+ }
75
+
76
+ // The order run() replaced, handed back before the folder re-lists.
77
+ function restoreSort(pane) {
78
+ if (pane.backend && typeof pane.recentSortBy === "string" && pane.recentSortBy.length > 0) {
79
+ pane.backend.sortBy = pane.recentSortBy
80
+ pane.backend.sortDesc = pane.recentSortDesc === true
81
+ }
82
+ pane.recentSortBy = ""
83
+ pane.recentSortDesc = false
84
+ }
85
+
86
+ // Every way out of Recent, a plain hop, Escape, a tab switch and reveal, leaves through this one step, so each restores the same order.
87
+ function leave(pane) {
88
+ if (pane.recentMode.length > 0) {
89
+ restoreSort(pane)
90
+ }
91
+ pane.recentMode = OFF
92
+ pane.recentFrom = ""
93
+ pane.recentPaths = []
94
+ pane.recentVisits = ({})
95
+ }
96
+
97
+ // Refresh re-reads history after an operation, never re-listing "/" over it; an unloaded sidebar re-asks the standing paths.
98
+ function refresh(pane, selectPath) {
99
+ // A re-ask of the history is no navigation, so it never takes the place of a listing out.
100
+ if (pane.listInFlight) {
101
+ pane.message("A directory is already loading.", false)
102
+ return
103
+ }
104
+ pane.pendingSelect = selectPath ? selectPath : ""
105
+ pane.pendingMenu = false
106
+ if (pane.recentMode === "trash") { run(pane, [], {}, "trash"); return }
107
+ if (pane.sidebar) {
108
+ pane.sidebar.readRecent(pane)
109
+ return
110
+ }
111
+ run(pane, pane.recentPaths || [], pane.recentVisits)
112
+ }
113
+
114
+ // Only the held viewport rows gain a Used stamp; filesystem metadata remains intact.
115
+ function stampRows(pane, rows) {
116
+ if (pane.recentMode !== RESULTS) return rows
117
+ return rows.map(function (row) {
118
+ var visit = (pane.recentVisits || {})[pane.join(pane.path, row.n)]
119
+ return Object.assign({}, row, { used: visit === undefined ? null : visit })
120
+ })
121
+ }
122
+
123
+ // The folder a tab records on a history, "" elsewhere, so it lands where it stood.
124
+ function restingPath(pane) {
125
+ return pane.recentMode.length > 0 && pane.recentFrom.length > 0 ? pane.recentFrom : ""
126
+ }
127
+
128
+ // A tab switch drops the mode and says whether it dropped one.
129
+ function dropOverlay(pane) {
130
+ if (pane.recentMode.length === 0) {
131
+ return false
132
+ }
133
+ leave(pane)
134
+ return true
135
+ }
136
+
137
+ // o opens the row's own folder; Enter opens the file itself, so the two cannot disagree.
138
+ function reveal(pane) {
139
+ if (pane.listInFlight) {
140
+ pane.message("A directory is already loading.", false)
141
+ return
142
+ }
143
+ var row = pane.rowFor(pane.cursorIndex)
144
+ if (!row) {
145
+ return
146
+ }
147
+ var full = pane.join(pane.path, row.n)
148
+ var cut = full.lastIndexOf("/")
149
+ if (cut < 0) {
150
+ return
151
+ }
152
+ var dir = cut === 0 ? "/" : full.substring(0, cut)
153
+ leave(pane)
154
+ pane.pendingSelect = full
155
+ pane.openWithoutHistory(dir)
156
+ }
@@ -0,0 +1,60 @@
1
+ .pragma library
2
+
3
+ .import "Anchor.js" as Anchor
4
+ .import "Format.js" as Format
5
+ .import "Nav.js" as Nav
6
+ .import "Swap.js" as Swap
7
+
8
+ // The status line a reload answers with, one whole sentence per count, each filled by Format.fill.
9
+ var WORDS = {
10
+ one: "Reloaded · 1 row changed",
11
+ many: "Reloaded · %1 rows changed"
12
+ }
13
+
14
+ // Sample input: 2 is "Reloaded · 2 rows changed", 1 is "Reloaded · 1 row changed".
15
+ function line(changed) {
16
+ return changed === 1 ? WORDS.one : Format.fill(WORDS.many, Format.count(changed))
17
+ }
18
+
19
+ // A listing out refuses itself and a search owns its header, so both go quiet.
20
+ function begin(pane, wire) {
21
+ if (Nav.loading(pane)) {
22
+ pane.message(Swap.LOADING, false)
23
+ return false
24
+ }
25
+ if (pane.searchMode.length > 0)
26
+ return false
27
+ // A reload past the wait retries the folder waited on, which a first listing has not yet made the pane's path.
28
+ var waitedOn = pane.listingState === "waiting" ? Nav.trimSlash(pane.listingPath || "") : ""
29
+ // A reload that lists lets a waiting listing go first, the way ui/Pane.qml openWithoutHistory does.
30
+ Anchor.clearWaiting(pane)
31
+ // Recent re-reads its history rather than re-listing its base, which is the root.
32
+ if (pane.recentMode.length > 0) {
33
+ pane.refresh("")
34
+ } else {
35
+ if (waitedOn.length > 0 && waitedOn !== pane.path) {
36
+ pane.openWithoutHistory(waitedOn)
37
+ return true
38
+ }
39
+ wire.anchor = Anchor.watched(pane, true, pane.anchorRowHeight)
40
+ }
41
+ // Set after the anchored re-read above, because opening the listing clears it first.
42
+ pane.reloadFrom = pane.total
43
+ pane.reloadChanged = -1
44
+ return true
45
+ }
46
+
47
+ // Runs on every rows reply; only a manual reload owes a notice, said whenever rows changed.
48
+ function landed(pane) {
49
+ if (pane.reloadFrom < 0)
50
+ return ""
51
+ // The backend counts added plus removed on a same-path re-list; a missing one falls back to net delta.
52
+ var changed = pane.reloadChanged >= 0 ? pane.reloadChanged : Math.abs(pane.total - pane.reloadFrom)
53
+ pane.reloadFrom = -1
54
+ pane.reloadChanged = -1
55
+ if (changed === 0)
56
+ return ""
57
+ var text = line(changed)
58
+ pane.message(text, false)
59
+ return text
60
+ }
@@ -0,0 +1,9 @@
1
+ .pragma library
2
+
3
+ // Only src/gui.rs's own implicit Vulkan choice may retry, and the argv is what it relaunches Flea with.
4
+ // Sample input: ("vulkan", "1", "/usr/bin/flea"), and ("opengl", "1", "/usr/bin/flea") for a launch that may not.
5
+ function fallbackCommand(backend, automatic, bin) {
6
+ if (backend !== "vulkan" || automatic !== "1")
7
+ return null
8
+ return ["/usr/bin/env", "QSG_RHI_BACKEND=opengl", bin || "flea", "--gui"]
9
+ }
@@ -0,0 +1,143 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+ .import "Anchor.js" as Anchor
5
+ .import "Icons.js" as Icons
6
+
7
+ // The run card's own decisions, the way ui/js/Collide.js holds its card's: which buttons a kind draws, where the ring opens, and how the keys walk them.
8
+
9
+ var LABELS = { cancel: "Cancel", text: "Open as text", run: "Run", terminal: "Run in terminal" }
10
+ // Run in terminal is the default because it shows the output; a desktop handler, where one is named, is offered first and takes it instead.
11
+ var START = "terminal"
12
+ var KINDS = ["script", "elf", "appimage"]
13
+ var KIND_LABELS = { script: "Shell script", elf: "Program", appimage: "AppImage application bundle" }
14
+
15
+ // The board's own default: the handler where the desktop names one for an AppImage, Run in terminal everywhere else, and the primary frame sits there.
16
+ function defaultButton(kind, hasHandler) {
17
+ if (kind === "appimage" && hasHandler === true)
18
+ return "handler"
19
+ return START
20
+ }
21
+
22
+ // Left to right, the board's own order, text a script's alone since a binary is not text; the board's tweak focus = terminal | run | text | cancel names the opening ring.
23
+ function buttonsFor(kind, hasHandler) {
24
+ var out = ["cancel"]
25
+ if (kind === "script")
26
+ out.push("text")
27
+ if (kind === "appimage" && hasHandler === true)
28
+ out.push("handler")
29
+ return out.concat(["run", "terminal"])
30
+ }
31
+
32
+ // A tweak naming a button the card did not draw falls back to the default, never to nothing.
33
+ function startFocus(buttons, tweak) {
34
+ if (buttons.indexOf(tweak) >= 0)
35
+ return tweak
36
+ var fallback = defaultButton(buttons.indexOf("handler") >= 0 ? "appimage" : "script", buttons.indexOf("handler") >= 0)
37
+ return buttons.indexOf(fallback) >= 0 ? fallback : buttons[0]
38
+ }
39
+
40
+ // h and l stop at the ends like TrashConfirm's pair; Tab and Backtab come round.
41
+ function moved(buttons, focus, key, modifiers) {
42
+ var at = buttons.indexOf(focus)
43
+ if (at < 0)
44
+ at = buttons.indexOf(defaultButton(buttons.indexOf("handler") >= 0 ? "appimage" : "script", buttons.indexOf("handler") >= 0))
45
+ if (at < 0)
46
+ at = 0
47
+ var last = buttons.length - 1
48
+ if (key === Qt.Key_H || key === Qt.Key_Left)
49
+ return buttons[Math.max(0, at - 1)]
50
+ if (key === Qt.Key_L || key === Qt.Key_Right)
51
+ return buttons[Math.min(last, at + 1)]
52
+ // Shift+Tab reaches a Keys handler as Backtab or as Tab with Shift held, depending on the input path.
53
+ if (key === Qt.Key_Backtab || key === Qt.Key_Tab && (modifiers & Qt.ShiftModifier))
54
+ return buttons[(at + last) % buttons.length]
55
+ if (key === Qt.Key_Tab)
56
+ return buttons[(at + 1) % buttons.length]
57
+ return buttons[at]
58
+ }
59
+
60
+ // The handler button is the application's own Name= from its desktop entry, one whole string.
61
+ function labelFor(button, handlerName) {
62
+ return button === "handler" ? String(handlerName) : LABELS[button]
63
+ }
64
+
65
+ function activates(key) {
66
+ return key === Qt.Key_Return || key === Qt.Key_Enter || key === Qt.Key_Space
67
+ }
68
+
69
+ // The name row's own mark: the board draws the code glyph beside a script, and a binary takes the mark its listed row draws.
70
+ var KIND_GLYPHS = { script: "code", elf: "terminal", appimage: "app-window" }
71
+
72
+ function glyphFor(kind, listed) {
73
+ if (kind !== "script" && listed)
74
+ return listed
75
+ return KIND_GLYPHS[kind] || KIND_GLYPHS.elf
76
+ }
77
+
78
+ // The mark the listing draws for the row the ask was opened from, or "" when no listed row names that path.
79
+ function listedGlyph(pane, path) {
80
+ if (!pane || !pane.rows || typeof pane.rowFor !== "function")
81
+ return ""
82
+ var at = Anchor.matchListed(pane, path)
83
+ var row = at >= 0 ? pane.rowFor(at) : null
84
+ return row ? Icons.glyphForRow(row.i, row.p) : ""
85
+ }
86
+
87
+ // Every user-facing string is one whole template filled by Format.fill, never fragments joined with +.
88
+
89
+ // The card's title names the program; the name row carries its kind and its size.
90
+ var TITLE_PROGRAM = "%1 is a program"
91
+ function titleFor(name) {
92
+ return Format.fill(TITLE_PROGRAM, escapeName(name))
93
+ }
94
+
95
+ // R4: control and bidi characters are shown escaped, never raw, and a clean name passes through byte for byte.
96
+ var SPOOFED = /[\0-\x1F\x7F-\x9F\u061C\u200E\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069\uFEFF]/g
97
+ function escapeName(name) {
98
+ return String(name).replace(SPOOFED, function (ch) {
99
+ var point = ch.codePointAt(0).toString(16).toUpperCase()
100
+ return "<U+" + ("0000" + point).slice(-4) + ">"
101
+ })
102
+ }
103
+
104
+ var SUBTITLE_PROGRAM = "%1 · %2"
105
+ function subtitleFor(kind, bytes) {
106
+ return Format.fill(SUBTITLE_PROGRAM, KIND_LABELS[kind] || KIND_LABELS.elf, Format.size(bytes))
107
+ }
108
+
109
+ function leafOf(path) {
110
+ var text = String(path)
111
+ var cut = text.lastIndexOf("/")
112
+ return cut < 0 ? text : text.substring(cut + 1)
113
+ }
114
+
115
+ // Sample input: {"ask":"run","kind":"script","size":9420,"handlerId":"","handlerName":"","dev":"8","ino":"9","mtimeS":11,"mtimeNs":12,"target":"/real/tool.sh"}.
116
+ function parseAsk(text) {
117
+ var message = null
118
+ try {
119
+ message = JSON.parse(String(text))
120
+ } catch (e) {
121
+ return null
122
+ }
123
+ if (!message || message.ask !== "run" || KINDS.indexOf(message.kind) < 0)
124
+ return null
125
+ if (typeof message.dev !== "string" || typeof message.ino !== "string" || typeof message.target !== "string")
126
+ return null
127
+ var handlerId = typeof message.handlerId === "string" ? message.handlerId : ""
128
+ var handlerName = typeof message.handlerName === "string" ? message.handlerName : ""
129
+ return { kind: message.kind, size: Number(message.size) || 0,
130
+ handlerId: handlerId, handlerName: handlerName,
131
+ hasHandler: handlerId.length > 0 && handlerName.trim().length > 0,
132
+ dev: message.dev, ino: message.ino,
133
+ mtimeS: Number(message.mtimeS) || 0, mtimeNs: Number(message.mtimeNs) || 0,
134
+ target: message.target }
135
+ }
136
+
137
+ // The card's choice on the path it asked about, carrying the R3 identity the ask named, and the handler the id the card drew.
138
+ function choose(pane, card, choice) {
139
+ if (choice === "run") card.run(card.path, card.dev, card.ino, card.size, card.mtimeS, card.mtimeNs)
140
+ else if (choice === "terminal") card.runTerminal(card.path, card.dev, card.ino, card.size, card.mtimeS, card.mtimeNs)
141
+ else if (choice === "text") card.openText(card.path, pane)
142
+ else if (choice === "handler") card.openHandler(card.path, card.handlerId, card.dev, card.ino, card.size, card.mtimeS, card.mtimeNs)
143
+ }
@@ -0,0 +1,28 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+
5
+ // Whole sentences with "%1" for a value, filled by fill so each translates as one.
6
+ var WORDS = {
7
+ exited: "%1 exited with status %2"
8
+ }
9
+
10
+ // MenuAdditions rule 2's own reading: what find printed becomes the submenu's rows, sorted by name,
11
+ // each label the file name without its extension. Sample input, one name a line:
12
+ // convert-to-webp
13
+ // ocr.sh
14
+ function parse(text, directory) {
15
+ var names = String(text || "").split("\n").filter(function (name) { return name.trim().length > 0 })
16
+ names.sort()
17
+ return names.map(function (name) {
18
+ var trimmed = name.trim()
19
+ var dot = trimmed.lastIndexOf(".")
20
+ return { id: trimmed, label: dot > 0 ? trimmed.substring(0, dot) : trimmed, path: directory + "/" + trimmed }
21
+ })
22
+ }
23
+
24
+ // The script's own report: its last stderr line, or the status it exited with when it said nothing.
25
+ function failure(name, stderr, code) {
26
+ var lines = String(stderr || "").split("\n").filter(function (line) { return line.trim().length > 0 })
27
+ return lines.length > 0 ? name + " · " + lines[lines.length - 1].trim() : Format.fill(WORDS.exited, name, code)
28
+ }