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
package/ui/js/Focus.js ADDED
@@ -0,0 +1,504 @@
1
+ .pragma library
2
+ .import "Input.js" as Input
3
+ .import "ChromeKeys.js" as ChromeKeys
4
+ .import "Eject.js" as Eject
5
+ .import "Filter.js" as Filter
6
+ .import "Grid.js" as Grid
7
+ .import "Format.js" as Format
8
+ .import "Keymap.js" as Keymap
9
+ .import "KeyName.js" as KeyName
10
+ .import "Marks.js" as Marks
11
+ .import "Mounts.js" as Mounts
12
+ .import "Ops.js" as Ops
13
+ .import "PreviewKeys.js" as PreviewKeys
14
+ .import "RailKeys.js" as RailKeys
15
+ .import "Reload.js" as Reload
16
+ .import "Nav.js" as Nav
17
+ .import "RecentMode.js" as RecentMode
18
+ .import "Status.js" as Status
19
+ .import "Search.js" as Search
20
+ .import "Sort.js" as Sort
21
+ .import "Swap.js" as Swap
22
+ .import "TextSize.js" as TextSize
23
+ .import "Trash.js" as Trash
24
+ .import "Tabs.js" as Tabs
25
+
26
+ // Whole sentences with "%1" for the key the running preset binds, filled by KeyName.hinted.
27
+ var WORDS = {
28
+ filterTip: "Press %1 to filter this folder by name"
29
+ }
30
+
31
+ var LIST = "list"
32
+ var RAIL = "rail"
33
+ var CHROME = "chrome"
34
+ var STRIP = "strip"
35
+ // The stops Tab walks, in order; the list is always one and the others only while drawn.
36
+ var RING = [LIST, RAIL, CHROME, STRIP]
37
+
38
+ // Refusal where gio has no Trash, from ui/js/Status.js, which recognises it to drop it when the pane leaves that place; a preset with no key reads bare.
39
+ var NO_TRASH = Status.NO_TRASH
40
+ function noTrashHint() { return Status.trashHint().replace(" · ", "") }
41
+ function noTrashLine() { return Status.noTrashLine() }
42
+
43
+ // Tab is the only thing that moves focus between views, so the rule lives in one function; drawn names the optional stops that are there, as ChromeKeys.drawn says.
44
+ function next(current, drawn, forward) {
45
+ // RailAdditions rule 4: a hidden rail is not a place the keyboard can go, so Tab skips it. Directive 77: one that auto-hide withdrew is, because arriving there is what reveals it.
46
+ var stops = RING.filter(function (view) { return view === LIST || drawn[view] === true })
47
+ var at = stops.indexOf(current)
48
+ return at < 0 ? LIST : stops[(at + (forward ? 1 : stops.length - 1)) % stops.length]
49
+ }
50
+
51
+ // Tab and Shift+Tab. In the dual view the two lists are consecutive stops and the pane switch is the step between them; the rail is the left pane's, so any pane's step onto it hands the keyboard to that one.
52
+ function tabStep(root, sidebar, forward) {
53
+ if (root.dualMode && root.focusView === LIST && forward !== (root.listOnly === true)) { root.switchPane(); return }
54
+ var to = next(root.focusView, ChromeKeys.drawn(root, sidebar || root.sidebar || root.railAvailable), forward)
55
+ if (to === LIST) {
56
+ root.focusView = LIST
57
+ // Forward lands on the left list and backward on the right one, wherever the keyboard stood.
58
+ if (root.dualMode && (root.listOnly === true) === forward) root.switchPane()
59
+ return
60
+ }
61
+ if (to === RAIL && root.dualMode) {
62
+ root.focusView = LIST
63
+ root.switchToRail()
64
+ return
65
+ }
66
+ ChromeKeys.enter(root, to, forward)
67
+ root.focusView = to
68
+ }
69
+
70
+ // Hiding the rail while it holds the keyboard strands focusView, so the listing takes the logical view and the actual focus together.
71
+ function railHidden(root) {
72
+ // Both panes share the hidden state, so only the active one answers it; undefined stays compatible with fixtures that predate the flag.
73
+ if (root.paneFocused === false || root.focusView !== RAIL) return
74
+ root.focusView = LIST
75
+ if (root.listArea) root.listArea.forceActiveFocus()
76
+ }
77
+
78
+ function shareBrowserHere(root) {
79
+ return !!(root.shareBrowser && root.shareBrowser.active && (!root.shareBrowser.owner || root.shareBrowser.owner === root))
80
+ }
81
+
82
+ // The one gate the z key and the "z undoes" click share: no undo under a listing, rename, overlay or query line.
83
+ function canUndo(pane, sidebar) {
84
+ if (!pane || Swap.swallows(pane.listInFlight, "undo"))
85
+ return false
86
+ if (pane.selectionBand !== null || pane.renameEditor() !== null)
87
+ return false
88
+ if (sidebar && sidebar.renameEditor() !== null)
89
+ return false
90
+ if (pane.searchMode === Search.TYPING || pane.filterTyping)
91
+ return false
92
+ if ((pane.preview && pane.preview.active) || shareBrowserHere(pane))
93
+ return false
94
+ if (pane.menuVisible || (pane.menuActions && pane.menuActions.opened))
95
+ return false
96
+ if ((pane.collide && (pane.collide.opened || pane.collide.pending !== null))
97
+ || (pane.keymapSheet && pane.keymapSheet.opened)
98
+ || (pane.settingsPanel && pane.settingsPanel.opened))
99
+ return false
100
+ return true
101
+ }
102
+
103
+ // Pane.qml's one key lookup: the keys.toml action for the focused context, narrowed below per view and overlay.
104
+ function lookup(event, root) {
105
+ var context = (root.preview && root.preview.active) ? (root.preview.isPdf ? "pdf" : root.preview.isMedia ? "media" : "preview")
106
+ : shareBrowserHere(root) ? "menu" : root.focusView === RAIL ? "rail" : "listing"
107
+ // Grid arrows address visual neighbours even when the preset uses them to open folders in List.
108
+ // Issue 114, muellan: h and l are the arrows spelled as letters, so in the grid they mean what
109
+ // the arrows mean and not the tree's own pair, which is what the eye reads off a row of tiles.
110
+ if (context === "listing" && root.viewMode === "grid" && event.modifiers === Qt.NoModifier) {
111
+ if (Grid.sideways(event) < 0) return "cursorLeft"
112
+ if (Grid.sideways(event) > 0) return "cursorRight"
113
+ }
114
+ var action = Keymap.lookup(event.key, event.text, event.modifiers, context)
115
+ // The share listing borrows the menu context for j/k/enter, but it has no submenu to step into.
116
+ if (action === "menuRight" && shareBrowserHere(root)) return "open"
117
+ // flea-qml: every view filters the held rows it draws, Find's results included; the two are
118
+ // independent, so a standing Find never takes the key away.
119
+ // Left and Right seek inside a media preview and turn the page in a PDF one, which is the only
120
+ // place the map binds either action now that the browsing pair is parent and browse-in; the grid
121
+ // takes the bare arrows above, before the map is consulted.
122
+ if (action === "seekBack" || action === "seekForward")
123
+ return root.preview && root.preview.active && (root.preview.isMedia || root.preview.isPdf) ? action : ""
124
+ // The zoom keys reach a PDF or an image, 0 reaches an image only (keys.toml binds it in that context), and e expands a PDF only. l is h's forward: page, else enter or preview.
125
+ if (action === "zoomOut" || action === "zoomIn" || action === "zoomFit" || action === "expand")
126
+ return (root.preview && root.preview.active && (root.preview.isPdf || ((root.preview.isImage || root.preview.isHtml) && action !== "expand"))) ? action : ""
127
+ // w wraps code, text and Markdown Source; other preview kinds keep no wrap action.
128
+ if (action === "toggleWrap")
129
+ return (root.preview && root.preview.active && (root.preview.isCodeText
130
+ || (root.preview.isDocument && root.preview.markdownShown
131
+ && root.preview.markdownShown.shownView === "source"))) ? action : ""
132
+ if (action === "pageForward") {
133
+ if (root.preview && root.preview.active)
134
+ return root.preview.isPdf ? action : ""
135
+ if (shareBrowserHere(root) || root.focusView === RAIL)
136
+ return "open"
137
+ var row = root.rowFor(root.cursorIndex)
138
+ return row && (row.d || (Format.isSymlink(row.p) && row.i === "folder")) ? "open" : (row ? "preview" : "")
139
+ }
140
+ // The key follows the row: where gio has no Trash the refusal names trashRefused, never arming a d that can only fail.
141
+ if ((action === "trashArm" || action === "trash") && root.recentMode !== "trash" && !Mounts.trashable(root.path, !root.backend || root.backend.dirWritable !== false))
142
+ return "trashRefused"
143
+ // reveal only means something on a search result or a recent row, so o is discarded everywhere else.
144
+ if (action === "reveal" && root.searchMode !== Search.RESULTS && root.recentMode.length === 0)
145
+ return ""
146
+ // A sort ends the running walk in the backend and the search strip hides the mark that would
147
+ // show it happening, so both sort keys go quiet for as long as a search owns the header.
148
+ if (action === "sortNext" || action === "sortReverse")
149
+ return root.searchMode.length === 0 ? action : ""
150
+ // A reload re-lists the folder it is on, so it goes quiet where a walk owns the header.
151
+ if (action === "reload" && root.searchMode.length > 0)
152
+ return ""
153
+ return action
154
+ }
155
+
156
+ // Lifted from Pane.qml's Keys.onPressed: the map holds the keys, this holds the behaviour.
157
+ // Takes the Pane root because every case is a method call or a property read on it.
158
+ function act(action, root, menuId, paths) {
159
+ switch (action) {
160
+ // List steps follow item order; in the grid ui/js/Grid.js takes j/k and the arrows as visual cells.
161
+ case "cursorDown": step(root, 1); Marks.follow(root); return
162
+ case "cursorUp": step(root, -1); Marks.follow(root); return
163
+ case "cursorLeft": step(root, -1); Marks.follow(root); return
164
+ case "cursorRight": step(root, 1); Marks.follow(root); return
165
+ case "cursorFirst": Filter.setCursorView(root, 0); Marks.follow(root); return
166
+ case "cursorLast": Filter.setCursorView(root, root.shownTotal - 1); Marks.follow(root); return
167
+ case "pageDown": step(root, Math.max(1, Math.floor(root.visibleRows / 2))); Marks.follow(root); return
168
+ case "pageUp": step(root, -Math.max(1, Math.floor(root.visibleRows / 2))); Marks.follow(root); return
169
+ case "open": root.openCursor(); return
170
+ case "openTab": Tabs.openCursorTab(root); return
171
+ case "parent": root.openParent(); return
172
+ case "historyBack": root.goBack(); return
173
+ case "historyForward": root.goForward(); return
174
+ case "togglePreview": root.togglePreviewColumn(); return
175
+ case "previewPageForward":
176
+ case "previewPageBack": if (root.previewColumnItem) root.previewColumnItem.pageBy(action === "previewPageForward" ? 1 : -1); return
177
+ case "factsToggle": if (root.previewColumnItem && root.previewColumnItem.visible) root.previewColumnItem.toggleFacts(); return
178
+ case "loadPreview": root.loadSelectionPreview(); return
179
+ case "focusPreview": root.focusPreviewColumn(); return
180
+ case "windowNew": root.newWindow(); return
181
+ case "toggleHidden": root.toggleHidden(); return
182
+ // ExtThumbs: the background menu's class row and any future chord land here.
183
+ case "extThumbs": root.toggleExtThumbs(); return
184
+ case "sidebar": root.toggleRail(); return
185
+ // Popups handle Escape first; the focused listing then unwinds filter, search, status and marks.
186
+ case "escape":
187
+ if (root.filterTyping || root.filterQuery.length > 0) Filter.close(root)
188
+ else if (root.searchMode.length > 0 && root.focusView === LIST) Search.abort(root)
189
+ else if (root.recentMode.length > 0 && root.focusView === LIST) RecentMode.close(root)
190
+ else if (root.statusBar && root.statusBar.escapePressed()) return
191
+ else if (escapeUp(root)) root.openParent()
192
+ else root.escapePressed()
193
+ return
194
+ case "reload": Reload.begin(root, root.wire); return
195
+ case "preview": PreviewKeys.open(root); return
196
+ case "toggleSelect": root.toggleSelect(); return
197
+ case "extendDown": root.extendSelection(1); return
198
+ case "extendUp": root.extendSelection(-1); return
199
+ case "selectAll": root.selectAll(); return
200
+ // flea-qml: Find and Filter are independent; a filter left up narrows the results by name too.
201
+ case "search": Search.start(root); return
202
+ case "searchContents": Search.contents(root); return
203
+ // flea-qml: = measures the selected folders, or the cursor's; Alt+= every folder (src/dirsize.js).
204
+ case "measureDirs": root.measureDirs(root.selectionCount() > 0 ? root.selectedIndices() : [root.cursorIndex]); return
205
+ case "measureAllDirs": root.measureAllDirs(); return
206
+ case "filter": Filter.start(root); return
207
+ case "reveal": if (root.recentMode.length > 0) { if (root.listInFlight) root.message("A directory is already loading.", false); else RecentMode.reveal(root) } else Search.reveal(root); return
208
+ // The write operations; every one of them is reversible with undo, so none of them confirms.
209
+ case "duplicate": Ops.duplicate(root, menuId); return
210
+ case "trash": Ops.trash(root, menuId); return
211
+ case "trashArm": Trash.arm(root); return
212
+ // A trash key where there is no Trash refuses in the error role, hinting the key that still works.
213
+ case "trashRefused": root.message(noTrashLine(), true); return
214
+ case "copy": Ops.clip(root, false, paths); return
215
+ case "copydirpath": root.copyDirPath(); return
216
+ // MenuAdditions040: c copies as, P pastes as, V flips the selection.
217
+ case "copyAs": root.openCopyAs(); return
218
+ case "pasteAs":
219
+ if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false); return }
220
+ root.openPasteAs(); return
221
+ case "invertSelection": root.invertSelection(); return
222
+ case "showOriginal": root.showOriginal(); return
223
+ case "makeExecutable": root.makeExecutable(paths); return
224
+ case "compare": Ops.open(root, paths); return
225
+ case "copyPath": Ops.copyAs(root, "path", paths); return
226
+ case "copyName": Ops.copyAs(root, "name", paths); return
227
+ case "copyStem": Ops.copyAs(root, "stem", paths); return
228
+ case "copyUri": Ops.copyAs(root, "uri", paths); return
229
+ case "copyQuoted": Ops.copyAs(root, "quoted", paths); return
230
+ case "pasteLink":
231
+ case "pasteAbsoluteLink":
232
+ case "pasteHardLink":
233
+ if (RecentMode.refusePaste(root)) return
234
+ root.pasteLink(action === "pasteAbsoluteLink" ? "absolute" : action === "pasteHardLink" ? "hard" : "relative"); return
235
+ case "cut": Ops.clip(root, true, paths); return
236
+ // Recent is a history, not a directory: pasting or creating there would land in the root it stands on.
237
+ case "paste": if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false); return } Ops.paste(root); return
238
+ case "movePaste":
239
+ if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false); return }
240
+ Ops.paste(root, true)
241
+ return
242
+ case "undo": Ops.undo(root); return
243
+ case "redo": root.backend.send({c: "redo"}); return
244
+ // m opens the row menu, or says why no row was under the cursor.
245
+ case "menu":
246
+ if (!root.openCursorMenu())
247
+ root.message("No item under the cursor to open a menu on", false)
248
+ return
249
+ // The run card's own entrances; see ui/js/Nav.js runCursor.
250
+ case "run": Nav.runCursor(root, root.opener, "open"); return
251
+ case "openAsText": Nav.runCursor(root, root.opener, "openText"); return
252
+ case "tags": root.tags().openMenu(); return
253
+ case "extract": Ops.extract(root, menuId); return
254
+ case "dropbox": root.moveToDropbox(menuId); return
255
+ case "sharelink": root.copyShareLink(); return
256
+ // Convert opens the one popup this whole design has; every other operation answers without one.
257
+ case "convert": root.openConvert(menuId); return
258
+ // The header answers the same two through ui/Pane.qml, so the key and the click share one route.
259
+ case "sortNext": Sort.next(root); return
260
+ case "sortReverse": Sort.reverse(root); return
261
+ // F4 fits every drawn list column; anywhere but the list view it says where that lives.
262
+ case "autofitColumns":
263
+ if (root.viewMode === "list") root.header.autofitAll()
264
+ else root.message("Autofit needs the list view.", false)
265
+ return
266
+ case "addNetwork": if (root.sidebar) root.sidebar.addRequested(); return
267
+ case "eject": Eject.release(root, root.sidebar, false); return
268
+ // Finder's Cmd+1/2/3/4; the chrome's four buttons write the same property, so they follow.
269
+ case "viewList": root.chooseView("list"); return
270
+ case "viewColumns": root.chooseView("columns"); return
271
+ case "viewGrid": root.chooseView("grid"); return
272
+ case "viewDual": root.chooseView("dual"); return
273
+ case "newFolder": if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder first", false); return } Ops.newFolder(root); return
274
+ // The directory being shown, not the row: the menu row and the chord both land here.
275
+ case "openTerminal": root.openTerminal(); return
276
+ // The background menu's Update Flea row, drawn only while an update is known, opens Omarchy's updater through the pane's opener.
277
+ case "updateFlea": root.opener.updateFlea(root); return
278
+ }
279
+ // A submenu row fires "<action>:<id>", which is how one signal covers Taildrop and Compress both.
280
+ if (action.indexOf("tags:") === 0) { root.tags().choose(action.substring(5)); return }
281
+ if (action.indexOf("compress:") === 0) {
282
+ var picked = action.substring("compress:".length)
283
+ // The submenu's last row opens the password dialog, routed by the pane: this file takes no new first-frame import.
284
+ if (picked === "compressPassword") { root.compressPasswordRequested(paths || null, menuId || 0); return }
285
+ if (paths) Ops.compressResolved(root, paths, picked, menuId)
286
+ else Ops.compress(root, picked)
287
+ return
288
+ }
289
+ // The background menu's Sort by flyout, routed to the header click's own function so an aimed
290
+ // click and an aimed menu row cannot come to mean different things.
291
+ if (action.indexOf("sort:") === 0) {
292
+ Sort.column(root, action.substring("sort:".length))
293
+ return
294
+ }
295
+ // Tabs run here and handleKey opens the path bar, so neither answers unbuilt any more.
296
+ if (action.indexOf("tab") === 0) { Tabs.act(action, root); return }
297
+ root.message("That action is not available yet", false)
298
+ }
299
+
300
+ // Issue 29: Escape climbs only when nothing else owns it, so each unwound state keeps the key.
301
+ function escapeUp(root) {
302
+ return root.escapeUp === true && root.searchMode.length === 0
303
+ && root.filterQuery.length === 0 && !root.filterTyping && !root.menuVisible
304
+ && !(root.collide && root.collide.opened) && !hasDeliberateMarks(root) && !root.listInFlight
305
+ }
306
+
307
+ // Only the row a navigation landed on never counts as a selection, so Escape keeps climbing.
308
+ function hasDeliberateMarks(root) {
309
+ if (root.selectionCount() === 0)
310
+ return false
311
+ if (root.selection && root.selection.isLanded && root.selection.isLanded())
312
+ return false
313
+ return true
314
+ }
315
+ // Only a step from an end wraps; page overshoots and selection extensions retain their clamps.
316
+ function step(root, delta) {
317
+ var last = root.shownTotal - 1
318
+ if (root.wrapAtEnds !== true || last < 0) {
319
+ Filter.moveCursor(root, delta)
320
+ return
321
+ }
322
+ var from = Filter.viewOf(root.shown, root.cursorIndex)
323
+ var to = from + delta
324
+ if (to < 0)
325
+ to = from === 0 ? last : 0
326
+ if (to > last)
327
+ to = from === last ? 0 : last
328
+ Filter.setCursorView(root, to)
329
+ }
330
+
331
+ // ui/ShareBrowser.qml's own overlay, the same j/k/open/escape shape PreviewKeys.act uses.
332
+ function shareBrowserAct(action, root) {
333
+ switch (action) {
334
+ case "cursorDown": root.shareBrowser.moveCursor(1); return
335
+ case "cursorUp": root.shareBrowser.moveCursor(-1); return
336
+ case "open": root.shareBrowser.activateCursor(); return
337
+ case "escape": root.shareBrowser.close(); return
338
+ }
339
+ }
340
+
341
+ // The cursor keys and only those, resolved through the generated table rather than through a second
342
+ // list of key codes, which is how issue 28's Home, End and page keys came with issue 12 for free. A
343
+ // printable character is excluded before the lookup, or j and k would leave the line instead of
344
+ // being typed into it.
345
+ var LEAVES_LINE = ["cursorDown", "cursorUp", "cursorFirst", "cursorLast", "pageDown", "pageUp"]
346
+
347
+ function leavesLine(event) {
348
+ if (Input.isPrintable(event.text))
349
+ return false
350
+ return LEAVES_LINE.indexOf(Keymap.lookup(event.key, event.text, event.modifiers)) >= 0
351
+ }
352
+
353
+ // One stamp for a vim pair's seat, so Escape and the pair read the same identity.
354
+ function stampOf(root) {
355
+ return JSON.stringify([root.path, root.cursorIndex, root.selectionVersion, root.viewMode])
356
+ }
357
+ // Only the second press of the same pair on the same selection fires.
358
+ var ARMED_PAIRS = { copyArm: true, cutArm: true, pasteArm: true, cursorFirstArm: true }
359
+ // Vim pairs are consecutive inputs on the same selection; pointer or navigation changes disarm them.
360
+ function sequenceAction(action, root) {
361
+ var pairs = { copyArm: "copy", cutArm: "cut", pasteArm: "paste", cursorFirstArm: "cursorFirst" }
362
+ var stamp = stampOf(root)
363
+ var paired = pairs[action] && root.keySequence === action && root.keySequenceIdentity === stamp
364
+ root.keySequence = paired || !pairs[action] ? "" : action
365
+ root.keySequenceIdentity = paired || !pairs[action] ? "" : stamp
366
+ return paired ? pairs[action] : pairs[action] ? "" : action
367
+ }
368
+
369
+ // Lifted whole from Pane.qml's Keys.onPressed, which had grown past its file's 400-line cap; returns whether the key was consumed.
370
+ function handleKey(event, root, sidebar, field) {
371
+ // Embedded terminals own ordinary keys; never turn shell typing into file operations.
372
+ if (root.terminalId && !field && !(sidebar && sidebar.activeFocus)) return false
373
+ if (root.selectionBand) {
374
+ if (event.key === Qt.Key_Escape)
375
+ root.selectionBand.cancel()
376
+ return true
377
+ }
378
+ // A live rename editor owns keys; an index left behind by a hidden or recycled editor does not.
379
+ if ((sidebar && sidebar.renameEditor() !== null) || root.renameEditor() !== null) {
380
+ return true
381
+ }
382
+ // A focused query owns Escape. Outside the inputs, unwind Filter first.
383
+ if (event.key === Qt.Key_Escape) {
384
+ if (field === "find") { Search.abort(root); return true }
385
+ if (field === "filter" || root.filterTyping || root.filterQuery.length > 0) {
386
+ Filter.close(root)
387
+ return true
388
+ }
389
+ }
390
+ root.inputAt = Date.now()
391
+ root.rowsAt = 0
392
+ // The query line owns every key unless Quick Look or the share listing is over it; cursor motions act on the results through the one route.
393
+ if (field !== "filter" && root.searchMode === Search.TYPING && !(root.preview && root.preview.active) && !shareBrowserHere(root)) {
394
+ if (leavesLine(event)) {
395
+ var action = Keymap.lookup(event.key, event.text, event.modifiers)
396
+ // No key off the line moves rows a listing or the search's exit is about to replace, as below and in Search.typeKey.
397
+ if (root.searchLeaving === true) return true
398
+ if (Swap.swallows(root.listInFlight, action)) { root.message(Swap.LOADING, false); return true }
399
+ if (Grid.arrow(event, action, root)) {
400
+ return true
401
+ }
402
+ act(action, root)
403
+ return true
404
+ }
405
+ return Search.typeKey(event, root)
406
+ }
407
+ if (root.filterTyping && leavesLine(event)) {
408
+ Filter.commit(root)
409
+ }
410
+ // The filter's query line owns every key while it has the caret, the same as the search's above.
411
+ if (root.filterTyping) {
412
+ return Filter.typeKey(event, root)
413
+ }
414
+ var action = lookup(event, root)
415
+ // A key that means an action ends a pending slow click, so its rename never lands after that key's result; a bare modifier means none.
416
+ if (action.length > 0 && root.cancelSlowClick) root.cancelSlowClick()
417
+ // With escape-up on Escape cancels an armed trash or a live vim pair and stops, with it off Escape disarms through the sequence and runs its own action.
418
+ var escapeCancelsArm = action === "escape" && root.escapeUp === true
419
+ && (root.trashArmedAt > 0 || (ARMED_PAIRS[root.keySequence] === true && root.keySequenceIdentity === stampOf(root)))
420
+ action = sequenceAction(action, root)
421
+ // Anything that is not the second d of the pair disarms it, so an arm never outlives the key
422
+ // after it; ui/js/Trash.js re-stamps on its own, which is why it reads the stamp before writing.
423
+ if (action !== "trashArm") {
424
+ root.trashArmedAt = 0
425
+ }
426
+ if (root.preview && root.preview.active) {
427
+ PreviewKeys.act(action, root)
428
+ return true
429
+ }
430
+ if (shareBrowserHere(root)) {
431
+ shareBrowserAct(action, root)
432
+ return true
433
+ }
434
+ if (windowAction(action, root, sidebar)) return true
435
+ if ((root.focusView === CHROME || root.focusView === STRIP) && ChromeKeys.act(event, root)) return true
436
+ if (root.focusView === RAIL && sidebar) {
437
+ RailKeys.act(action, root, sidebar, event)
438
+ return true
439
+ }
440
+ // An armed pair keeps Escape to cancel the arm instead of climbing.
441
+ if (action === "escape" && escapeCancelsArm) {
442
+ root.trashArmedAt = 0
443
+ root.keySequence = ""
444
+ root.keySequenceIdentity = ""
445
+ root.message("", false)
446
+ return true
447
+ }
448
+ // No row action runs against a listing still in flight.
449
+ if (Swap.swallows(root.listInFlight, action)) { root.message(Swap.LOADING, false); return true }
450
+ if (action === "undo" && !canUndo(root, sidebar)) return true
451
+ if (Grid.arrow(event, action, root)) return true
452
+ if (action.length > 0 || Keymap.lookup(event.key, event.text, event.modifiers).length > 0) {
453
+ if (action.length > 0) dispatchAction(action, root)
454
+ return true
455
+ }
456
+ // Unbound printable keys name the filter instead of jumping into destructive bindings.
457
+ if (root.shown === null && Input.isPrintable(event.text)) {
458
+ var tip = KeyName.hinted(WORDS.filterTip, "filter")
459
+ if (tip.length > 0) root.message(tip, false)
460
+ return true
461
+ }
462
+ return false
463
+ }
464
+
465
+ // Keys and query actions share the window's dispatcher before reaching pane actions.
466
+ function dispatchAction(action, root) {
467
+ if (!windowAction(action, root)) root.act(action)
468
+ }
469
+
470
+ function windowAction(action, root, sidebar) {
471
+ if (action === "focusNext" || action === "focusPrevious") {
472
+ tabStep(root, sidebar, action === "focusNext")
473
+ return true
474
+ }
475
+ if (action === "focusPreview") {
476
+ if (!root.dualMode) root.focusPreviewColumn()
477
+ return true
478
+ }
479
+ if (action === "keymapSheet") {
480
+ root.keymapSheet.open(root)
481
+ return true
482
+ }
483
+ // Tabs answer from either view.
484
+ if (action.indexOf("tab") === 0) {
485
+ root.act(action)
486
+ return true
487
+ }
488
+ // Issue 9: the text size belongs to the window, so it answers from either view.
489
+ if (action.indexOf("textSize") === 0) {
490
+ root.textSizeRequested(TextSize.direction(action))
491
+ return true
492
+ }
493
+ // The chrome owns the path field.
494
+ if (action === "pathBar") {
495
+ root.pathBarRequested()
496
+ return true
497
+ }
498
+ // These answer from the rail as well as the list, so they are taken before the rail's own keys.
499
+ if (action === "windowNew" || action === "reload" || action === "sidebar" || action === "openTerminal" || action === "settings" || action === "copydirpath") {
500
+ root.act(action)
501
+ return true
502
+ }
503
+ return false
504
+ }
@@ -0,0 +1,108 @@
1
+ .pragma library
2
+ .import "UserDirs.js" as UserDirs
3
+
4
+ // Owned here so Backend.qml loads no sort closure at startup.
5
+ var ORDERS = ["name", "size", "mtime", "kind"]
6
+
7
+ // Written only on a user sort in that folder, read once per listing, oldest first.
8
+
9
+ // The cap ui.json holds, oldest first; setting past it drops the folders sorted longest ago.
10
+ var MAX = 500
11
+
12
+ // Sample input: XDG_DOWNLOAD_DIR="$HOME/Inbox"; absent PICTURES and VIDEOS use their conventional names.
13
+ function newestPaths(body, home) {
14
+ var roles = ["DOWNLOAD", "PICTURES", "VIDEOS"]
15
+ var names = ["Downloads", "Pictures", "Videos"]
16
+ var paths = []
17
+ if (!home) return paths
18
+ var configured = {}
19
+ var entries = UserDirs.readRoles(body, home)
20
+ for (var e = 0; e < entries.length; e++)
21
+ configured[entries[e].role] = entries[e].path
22
+ for (var i = 0; i < roles.length; i++) {
23
+ var path = configured[roles[i]] === undefined ? home + "/" + names[i] : configured[roles[i]]
24
+ if (path && path !== home && paths.indexOf(path) < 0)
25
+ paths.push(path)
26
+ }
27
+ return paths
28
+ }
29
+
30
+ function defaultOrder(path, newest) {
31
+ var folder = String(path || "").replace(/\/+$/, "")
32
+ return newest && newest.indexOf(folder) >= 0 ? { key: "mtime", reverse: true } : null
33
+ }
34
+
35
+ // Settings stores Modified as "date" while ORDERS and the backend spell it "mtime".
36
+ function liveKey(key) {
37
+ return key === "date" ? "mtime" : key
38
+ }
39
+
40
+ // Sample input: {"/home/gm/Work": {"key": "size", "reverse": true}}.
41
+ function get(sorts, path) {
42
+ var entry = sorts ? sorts[path] : null
43
+ if (!entry || ORDERS.indexOf(liveKey(entry.key)) < 0)
44
+ return null
45
+ return { key: liveKey(entry.key), reverse: entry.reverse === true }
46
+ }
47
+
48
+ function has(sorts, path) {
49
+ return get(sorts, path) !== null
50
+ }
51
+
52
+ function count(sorts) {
53
+ return sorts ? Object.keys(sorts).length : 0
54
+ }
55
+
56
+ // A re-sort moves its folder to the most recent end; past the cap the oldest entries go.
57
+ function set(sorts, path, key, reverse) {
58
+ var next = {}
59
+ if (sorts) {
60
+ for (var k in sorts) {
61
+ if (k !== path)
62
+ next[k] = sorts[k]
63
+ }
64
+ }
65
+ next[path] = { key: key, reverse: reverse === true }
66
+ var keys = Object.keys(next)
67
+ while (keys.length > MAX)
68
+ delete next[keys.shift()]
69
+ return next
70
+ }
71
+
72
+ function forget(sorts, path) {
73
+ var next = {}
74
+ if (sorts) {
75
+ for (var k in sorts) {
76
+ if (k !== path)
77
+ next[k] = sorts[k]
78
+ }
79
+ }
80
+ return next
81
+ }
82
+
83
+ // A user sort writes its folder only while remembering is on.
84
+ function shouldRemember(remember, path) {
85
+ return remember !== false && !!path
86
+ }
87
+
88
+ // Columns pass keep: a saved order wins over XDG defaults; remembering off uses the global order, except kind, unsupported by peeks.
89
+ function peekOrder(sorts, path, remember, keep, newest, fallback) {
90
+ if (!Array.isArray(keep)) return {}
91
+ var own = remember !== false ? get(sorts, path) || defaultOrder(path, newest)
92
+ : fallback ? orderFor(null, path, fallback, false) : null
93
+ if (remember === false && own && own.key === "name" && !own.reverse) return {}
94
+ return own && own.key !== "kind" ? { by: own.key, desc: own.reverse } : {}
95
+ }
96
+
97
+ // An unknown stored key reads as the default, so a newer Flea never wedges this one.
98
+ function orderFor(sorts, path, fallback, remember, newest) {
99
+ if (remember !== false) {
100
+ var own = get(sorts, path) || defaultOrder(path, newest)
101
+ if (own)
102
+ return own
103
+ }
104
+ fallback = fallback || {}
105
+ var key = liveKey(fallback.key)
106
+ return { key: ORDERS.indexOf(key) >= 0 ? key : "name",
107
+ reverse: fallback.reverse === true }
108
+ }
@@ -0,0 +1,44 @@
1
+ .pragma library
2
+
3
+ // The three layouts a directory can own. Dual pane is a window shape, not a folder view.
4
+ var MODES = ["list", "columns", "grid"]
5
+ var MAX = 500
6
+
7
+ function get(views, path) {
8
+ var mode = views ? views[path] : ""
9
+ return MODES.indexOf(mode) >= 0 ? mode : ""
10
+ }
11
+
12
+ function has(views, path) {
13
+ return get(views, path).length > 0
14
+ }
15
+
16
+ // A re-selection moves its folder to the most recent end; past the cap the oldest goes.
17
+ function set(views, path, mode) {
18
+ var next = {}
19
+ if (views) {
20
+ for (var key in views) {
21
+ if (key !== path)
22
+ next[key] = views[key]
23
+ }
24
+ }
25
+ next[path] = mode
26
+ var keys = Object.keys(next)
27
+ while (keys.length > MAX)
28
+ delete next[keys.shift()]
29
+ return next
30
+ }
31
+
32
+ // A stored folder preference is opt-in. With it off, the existing global view remains the fallback.
33
+ function viewFor(views, path, fallback, remember) {
34
+ if (remember === true) {
35
+ var own = get(views, path)
36
+ if (own)
37
+ return own
38
+ }
39
+ return MODES.indexOf(fallback) >= 0 ? fallback : "list"
40
+ }
41
+
42
+ function shouldRemember(remember, path) {
43
+ return remember === true && !!path
44
+ }