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/Tabs.js ADDED
@@ -0,0 +1,751 @@
1
+ .pragma library
2
+
3
+ .import "Filter.js" as Filter
4
+ .import "Format.js" as Format
5
+ .import "Nav.js" as Nav
6
+ .import "RecentMode.js" as RecentMode
7
+ .import "Search.js" as Search
8
+ .import "Sort.js" as Sort
9
+ .import "Startup.js" as Startup
10
+ .import "TabMove.js" as TabMove
11
+
12
+ // The sentence a digit key answers with when no tab sits there, filled by Format.fill.
13
+ var WORDS = {
14
+ noTab: "No tab %1",
15
+ lastTab: "The last tab cannot be closed"
16
+ }
17
+
18
+ // Hidden tabs are snapshots, so the pane and backend still own only one listing.
19
+ // The nine-tab cap matches TUI's direct digit selection; GUI shortcuts cycle through the same state.
20
+
21
+ var MAX = 9
22
+
23
+ // Where a snapshotted tab reopens: the folder a search or a history was opened over, else the path.
24
+ function restingPath(pane) {
25
+ if (pane.searchMode === "results" && (pane.searchFrom || "").length > 0)
26
+ return pane.searchFrom
27
+ return RecentMode.restingPath(pane) || Nav.place(pane)
28
+ }
29
+
30
+ var nextTabIdentity = 0
31
+
32
+ // Only the held cursor row can name a file; a search's row never belongs to its resting folder.
33
+ function cursorFile(pane) {
34
+ var row = pane.rowFor && pane.cursorIndex >= 0 ? pane.rowFor(pane.cursorIndex) : null
35
+ return row && typeof row.n === "string" ? row.n : ""
36
+ }
37
+
38
+ function snapshot(pane, path, identity, dropped) {
39
+ var where = path === undefined ? restingPath(pane) : path
40
+ // A cursor and a selection read off a search's own listing name nothing in the directory the
41
+ // tab records, so a tab stepping back out of a search starts at its first row with none.
42
+ var elsewhere = where !== pane.path || Search.live(pane) || dropped === true
43
+ return {
44
+ tabIdentity: identity || ++nextTabIdentity,
45
+ terminalId: pane.terminalId || "",
46
+ path: where,
47
+ history: pane.history.slice(),
48
+ forwardHistory: (pane.forwardHistory || []).slice(),
49
+ cursorIndex: elsewhere ? 0 : pane.cursorIndex,
50
+ cursorName: elsewhere ? "" : cursorFile(pane),
51
+ viewMode: pane.viewMode,
52
+ showHidden: pane.showHidden,
53
+ selected: elsewhere ? [] : pane.selectedIndices().slice(),
54
+ // A lone row restores with only(), so a tab switch never re-arms the row a tap left behind.
55
+ follows: elsewhere ? false : pane.selection.follows(),
56
+ sortBy: pane.backend.sortBy,
57
+ sortDesc: pane.backend.sortDesc,
58
+ // Issue 94, nixfred: the counter every list bumps, so a selection only returns to its own rows.
59
+ listRequests: pane.backend.listRequests,
60
+ // The directory's filesystem, so a drop on this tab while another shows decides move against copy.
61
+ dev: elsewhere ? 0 : pane.backend.dirDev
62
+ }
63
+ }
64
+
65
+ // keep is the tabs object whose landing the current tab still owes, for a pack that leaves the current tab's listing out.
66
+ function pack(items, index, keep) {
67
+ var tabs = {
68
+ items: items,
69
+ index: index,
70
+ pendingCursor: -1,
71
+ pendingCursorName: null,
72
+ pendingLocatePath: "",
73
+ pendingSortBy: "",
74
+ pendingSortDesc: false
75
+ }
76
+ if (keep) {
77
+ tabs.pendingCursor = keep.pendingCursor
78
+ tabs.pendingCursorName = keep.pendingCursorName
79
+ tabs.pendingLocatePath = keep.pendingLocatePath
80
+ tabs.pendingSortBy = keep.pendingSortBy
81
+ tabs.pendingSortDesc = keep.pendingSortDesc
82
+ }
83
+ return tabs
84
+ }
85
+
86
+ function label(path, home) {
87
+ if (!path || path === "/")
88
+ return "/"
89
+ if (home && path === home)
90
+ return "Home"
91
+ var leaf = Format.leafPart(Format.tilde(path, home || ""))
92
+ return leaf.length > 0 ? leaf : path
93
+ }
94
+
95
+ // The current tab's path lives on the pane, not in the snapshot, so a navigate does not wait for a switch.
96
+ function labelAt(pane, i) {
97
+ return label(pathAt(pane.tabs, currentIndex(pane), i, pane.path), pane.home)
98
+ }
99
+
100
+ // The path tab i draws: the live pane path for the current tab, the snapshot's for a hidden one.
101
+ // Takes the values rather than the pane so ui/TabBar.qml's binding can read each one by name.
102
+ function pathAt(tabs, index, i, currentPath) {
103
+ if (i === index)
104
+ return currentPath
105
+ return tabs && tabs.items && tabs.items[i] ? tabs.items[i].path : ""
106
+ }
107
+
108
+ // The tab's filesystem the same way, 0 when unknown, which ui/js/Drag.js verbFor reads as copy.
109
+ function devAt(tabs, index, i, currentDev) {
110
+ if (i === index)
111
+ return currentDev
112
+ return tabs && tabs.items && tabs.items[i] ? Number(tabs.items[i].dev) || 0 : 0
113
+ }
114
+
115
+ function labels(pane) {
116
+ var n = count(pane)
117
+ var out = []
118
+ for (var i = 0; i < n; i++)
119
+ out.push(labelAt(pane, i))
120
+ return out
121
+ }
122
+
123
+ function count(pane) {
124
+ return pane.tabs && pane.tabs.items && pane.tabs.items.length > 0 ? pane.tabs.items.length : 1
125
+ }
126
+
127
+ function currentIndex(pane) {
128
+ return pane.tabs ? pane.tabs.index : 0
129
+ }
130
+
131
+ // Search and Recent replace the listing; Trash only covers it, so closing Trash alone needs no re-list.
132
+ function dropOverlay(pane) {
133
+ var dropped = Search.live(pane) || Search.owesRelist(pane) || RecentMode.dropOverlay(pane)
134
+ if (pane.trash) pane.trash.close()
135
+ Search.leaveWalk(pane)
136
+ Filter.close(pane)
137
+ return dropped
138
+ }
139
+
140
+ function closePreview(pane) {
141
+ if (pane.preview && pane.preview.active)
142
+ pane.preview.close()
143
+ }
144
+
145
+ // The mark names a standing notice's serial, never its sentence; a count change withdraws it.
146
+ function sayCount(pane, text) {
147
+ pane.message(text, false)
148
+ pane.tabCountNotice = pane.statusBar ? pane.statusBar.noticeSerial : -1
149
+ }
150
+ // Any other verdict from here replaces a standing count one, so no later change withdraws it.
151
+ function sayPlain(pane, text) {
152
+ pane.tabCountNotice = -1
153
+ pane.message(text, false)
154
+ }
155
+ // The count changed under a standing count verdict, so it is withdrawn; anything else stands.
156
+ function dropCount(pane) {
157
+ if (pane.tabCountNotice !== -1 && pane.statusBar) pane.statusBar.withdraw(pane.tabCountNotice)
158
+ pane.tabCountNotice = -1
159
+ }
160
+
161
+ // Only ever called for a switch that re-listed nothing; the clamp is the belt on top of that, since
162
+ // an index past the end would select a row that is not there at all.
163
+ function restoreSelection(pane, selected, follows) {
164
+ pane.clearSelection()
165
+ if (!selected || selected.length === 0)
166
+ return
167
+ if (follows === true && selected.length === 1 && selected[0] < pane.total) {
168
+ pane.selection.only(selected[0])
169
+ pane.selectionVersion++
170
+ return
171
+ }
172
+ var kept = 0
173
+ for (var i = 0; i < selected.length; i++) {
174
+ if (selected[i] < pane.total) {
175
+ pane.selection.toggle(selected[i])
176
+ kept++
177
+ }
178
+ }
179
+ if (kept > 0)
180
+ pane.selectionVersion++
181
+ }
182
+
183
+ function apply(pane, item, dropped, cursor) {
184
+ pane.terminalId = item.terminalId || ""
185
+ // Issue 93: rows from a search dropped onto its scope, or a listing still out, are not the rows this tab left.
186
+ var same = pane.path === item.path && pane.showHidden === item.showHidden && dropped !== true && cursor === undefined && !pane.listInFlight
187
+ if (pane.tabs) pane.tabs.pendingCursorName = cursor === undefined ? null : cursor
188
+ var shown = pane.viewMode
189
+ pane.history = item.history.slice()
190
+ pane.forwardHistory = (item.forwardHistory || []).slice()
191
+ pane.viewMode = item.viewMode
192
+ // A tab's view becomes the standing one unless its folder keeps its own; ui/Pane.qml adoptView decides.
193
+ if (pane.adoptView)
194
+ pane.adoptView(item.path, item.viewMode)
195
+ pane.showHidden = item.showHidden
196
+ if (same) {
197
+ if (pane.backend && (pane.backend.sortBy !== item.sortBy || pane.backend.sortDesc !== item.sortDesc)) {
198
+ // Issue 94: the one reset a reorder takes, ui/js/Sort.js's, which this branch half repeated.
199
+ Sort.resort(pane, item.sortBy, item.sortDesc)
200
+ pane.tabs.pendingCursor = item.cursorIndex
201
+ return
202
+ }
203
+ // The switch that re-reads nothing, unless something else did: the watch and a write both list.
204
+ pane.setCursor(item.cursorIndex)
205
+ if (pane.backend && item.listRequests === pane.backend.listRequests) {
206
+ restoreSelection(pane, item.selected, item.follows)
207
+ return
208
+ }
209
+ pane.clearSelection()
210
+ return
211
+ }
212
+ // The listing keeps the tab's own dotfile answer restored above; a tab in another view clears at once, as its rows were never listed there.
213
+ pane.openWithoutHistory(item.path, { keepHidden: true, clearAtOnce: pane.viewMode !== shown, supersede: true })
214
+ // After the request: letting a listing go clears what an earlier switch owed, and this one is owed to the listing just asked for.
215
+ pane.tabs.pendingCursorName = cursor === undefined ? null : cursor
216
+ pane.tabs.pendingCursor = cursor === undefined ? item.cursorIndex : 0
217
+ pane.tabs.pendingSortBy = item.sortBy
218
+ pane.tabs.pendingSortDesc = item.sortDesc
219
+ }
220
+
221
+ function applyPending(pane) {
222
+ if (!pane.tabs)
223
+ return
224
+ var t = pane.tabs
225
+ // Issue 91, nixfred: spent on the first reply either way, or an order already in force never was.
226
+ if (t.pendingSortBy && t.pendingSortBy.length > 0 && pane.backend) {
227
+ var by = t.pendingSortBy
228
+ var desc = t.pendingSortDesc
229
+ t.pendingSortBy = ""
230
+ if (pane.backend.sortBy !== by || pane.backend.sortDesc !== desc) {
231
+ pane.backend.sort(by, desc)
232
+ pane.backend.sortBy = by
233
+ pane.backend.sortDesc = desc
234
+ pane.backend.window(0, pane.windowSize)
235
+ return
236
+ }
237
+ }
238
+ if (t.pendingCursorName) {
239
+ var name = t.pendingCursorName
240
+ t.pendingCursorName = null
241
+ var first = pane.held || 0
242
+ var end = Math.min(pane.total, first + (pane.rows ? pane.rows.length : pane.windowSize))
243
+ var found = false
244
+ for (var i = first; i < end; i++) {
245
+ var row = pane.rowFor(i)
246
+ if (row && row.n === name) {
247
+ t.pendingCursor = i
248
+ found = true
249
+ break
250
+ }
251
+ }
252
+ if (!found && pane.total > 0 && pane.backend && pane.backend.send) {
253
+ t.pendingLocatePath = (pane.path === "/" ? "/" : pane.path + "/") + name
254
+ t.pendingCursor = -1
255
+ pane.backend.send({ c: "locate", path: t.pendingLocatePath })
256
+ return
257
+ }
258
+ }
259
+ if (t.pendingCursor >= 0) {
260
+ var last = pane.total > 0 ? pane.total - 1 : 0
261
+ pane.setCursor(Math.min(t.pendingCursor, last))
262
+ t.pendingCursor = -1
263
+ }
264
+ }
265
+
266
+ // A fresh receiver index comes from its own name-only listing, never from the source window.
267
+ function locatedCursor(pane, message) {
268
+ var t = pane.tabs
269
+ if (!t || !t.pendingLocatePath || message.path !== t.pendingLocatePath || message.directory !== pane.path)
270
+ return
271
+ t.pendingLocatePath = ""
272
+ if (pane.listInFlight) return
273
+ var index = message.index >= 0 && message.index < pane.total ? message.index : 0
274
+ pane.setCursor(index)
275
+ if (pane.total > 0 && !pane.rowFor(index)) pane.backend.window(index, pane.windowSize)
276
+ }
277
+
278
+ // The desktop launch carries the same filename through the existing environment seam.
279
+ function prepareCursor(pane, cursor) {
280
+ if (!cursor) return
281
+ if (!pane.tabs) pane.tabs = pack([snapshot(pane)], 0)
282
+ pane.tabs.pendingCursor = 0
283
+ pane.tabs.pendingCursorName = cursor
284
+ pane.tabs.pendingLocatePath = ""
285
+ }
286
+
287
+ function currentItems(pane, here) {
288
+ if (pane.tabs && pane.tabs.items && pane.tabs.items.length > 0)
289
+ return pane.tabs.items.slice()
290
+ return [snapshot(pane, here)]
291
+ }
292
+
293
+ // A caller may name where the new tab lands, which is what the Places row menu's own row does;
294
+ // without one it is Settings, View, Opening that decides, and that still defaults to this folder.
295
+ function openNew(pane, where) {
296
+ // Before the preview and the search go: a refused tenth tab must cost the user nothing.
297
+ if (count(pane) >= MAX) {
298
+ sayCount(pane, "Nine tabs is the most.")
299
+ return
300
+ }
301
+ var here = restingPath(pane)
302
+ closePreview(pane)
303
+ var dropped = dropOverlay(pane)
304
+ // Settings > View > Opening decides where the new tab lands; it cloned the current folder before
305
+ // 0.2.1 and that is still the default. The tab the operator leaves keeps the path it was on.
306
+ var target = where || Startup.newTabPath(pane.uiState, here, pane.home)
307
+ var items = currentItems(pane, here)
308
+ var index = currentIndex(pane)
309
+ items[index] = snapshot(pane, here, items[index].tabIdentity, dropped)
310
+ pane.terminalId = ""
311
+ items.push(snapshot(pane, target, undefined, dropped))
312
+ pane.tabs = pack(items, items.length - 1)
313
+ dropCount(pane)
314
+ // dropOverlay clears the search while its rows still stand, and a listing still out belongs to the tab being left, so both list the target again, the one out let go.
315
+ if (pane.path !== target || dropped || pane.listInFlight)
316
+ pane.openWithoutHistory(target, { supersede: true })
317
+ }
318
+
319
+ // Ctrl+Return on the cursor row, the keyboard twin of Tap.tappedTab's middle
320
+ // click: that directory in a new tab, leaving the cursor and selection alone.
321
+ function openTerminal(pane, path) {
322
+ if (count(pane) >= MAX) { sayCount(pane, "Nine tabs is the most."); return }
323
+ var id = pane.terminalHost.open(path)
324
+ if (!id) return
325
+ openNew(pane, path)
326
+ pane.terminalId = id
327
+ var items = pane.tabs.items.slice()
328
+ items[pane.tabs.index].terminalId = id
329
+ pane.tabs = pack(items, pane.tabs.index, pane.tabs)
330
+ }
331
+
332
+ function openCursorTab(pane) {
333
+ var row = pane.rowFor ? pane.rowFor(pane.cursorIndex) : null
334
+ if (!row || !row.d || typeof row.n !== "string") {
335
+ sayPlain(pane, "Only a folder opens in a new tab.")
336
+ return
337
+ }
338
+ var base = Search.baseOf(pane)
339
+ openNew(pane, base === "/" ? "/" + row.n : base + "/" + row.n)
340
+ }
341
+
342
+ function selectAt(pane, i) {
343
+ var here = restingPath(pane)
344
+ var items = currentItems(pane, here)
345
+ if (i < 0 || i >= items.length) {
346
+ sayCount(pane, Format.fill(WORDS.noTab, i + 1))
347
+ return
348
+ }
349
+ var index = currentIndex(pane)
350
+ if (i === index)
351
+ return
352
+ closePreview(pane)
353
+ var dropped = dropOverlay(pane)
354
+ items[index] = snapshot(pane, here, items[index].tabIdentity, dropped)
355
+ pane.tabs = pack(items, i)
356
+ apply(pane, items[i], dropped)
357
+ }
358
+
359
+ function closeAt(pane, i) {
360
+ var items = currentItems(pane)
361
+ if (items.length <= 1) {
362
+ sayCount(pane, WORDS.lastTab)
363
+ return
364
+ }
365
+ if (i < 0 || i >= items.length) {
366
+ sayCount(pane, Format.fill(WORDS.noTab, i + 1))
367
+ return
368
+ }
369
+ var index = currentIndex(pane)
370
+ if (items[i].terminalId && pane.terminalHost) pane.terminalHost.close(items[i].terminalId)
371
+ items.splice(i, 1)
372
+ var next = index
373
+ if (i < index)
374
+ next = index - 1
375
+ else if (i === index)
376
+ next = Math.min(i, items.length - 1)
377
+ if (i === index) {
378
+ closePreview(pane)
379
+ var dropped = dropOverlay(pane)
380
+ pane.tabs = pack(items, next)
381
+ apply(pane, items[next], dropped)
382
+ } else {
383
+ pane.tabs = pack(items, next, pane.tabs)
384
+ }
385
+ dropCount(pane)
386
+ }
387
+
388
+ // A move lists nothing, so the listing out lands for the tab it belongs to and that tab keeps what the landing owes.
389
+ function move(pane, from, to) {
390
+ var items = currentItems(pane)
391
+ if (items.length < 2)
392
+ return
393
+ var index = currentIndex(pane)
394
+ items[index] = snapshot(pane, restingPath(pane), items[index].tabIdentity)
395
+ pane.tabs = pack(items, TabMove.reorder(items, from, to, index), pane.tabs)
396
+ }
397
+
398
+ // Tabs040 callout 1: { and } move the current tab with no re-list.
399
+ function moveCurrent(pane, delta) {
400
+ var total = count(pane)
401
+ if (total < 2)
402
+ return
403
+ var from = currentIndex(pane)
404
+ move(pane, from, TabMove.step(from, delta, total))
405
+ }
406
+
407
+ function act(action, pane) {
408
+ if (action === "tabMoveLeft" || action === "tabMoveRight") {
409
+ moveCurrent(pane, action === "tabMoveRight" ? 1 : -1)
410
+ return
411
+ }
412
+ if (action === "tabNext" || action === "tabPrevious") {
413
+ var total = count(pane)
414
+ var direction = action === "tabNext" ? 1 : -1
415
+ selectAt(pane, (currentIndex(pane) + total + direction) % total)
416
+ return
417
+ }
418
+ if (action === "tabNew") {
419
+ openNew(pane)
420
+ return
421
+ }
422
+ if (action === "tabClose") {
423
+ closeAt(pane, currentIndex(pane))
424
+ return
425
+ }
426
+ if (action.length === 4 && action.indexOf("tab") === 0 && action.charAt(3) >= "1" && action.charAt(3) <= "9")
427
+ selectAt(pane, parseInt(action.charAt(3), 10) - 1)
428
+ }
429
+
430
+ // Last folder reopens every tab; a missing folder stays for the listing error to name.
431
+ function remembered(pane) {
432
+ // The write lands before the pane moves, so the current tab reads dropPath.
433
+ var here = restingPath(pane)
434
+ if (here === pane.path && pane.dropPath)
435
+ here = pane.dropPath
436
+ var items = pane.tabs && pane.tabs.items && pane.tabs.items.length > 0 ? pane.tabs.items : null
437
+ if (!items)
438
+ return { paths: [here], index: 0 }
439
+ var index = currentIndex(pane)
440
+ var out = []
441
+ for (var i = 0; i < items.length; i++)
442
+ out.push(i === index ? here : String((items[i] || {}).path || ""))
443
+ return { paths: out, index: index }
444
+ }
445
+
446
+ // Without a Last-folder strip or with a named path there is no plan.
447
+ function restorePlan(state, argvPath) {
448
+ if (argvPath && String(argvPath).length > 0)
449
+ return null
450
+ var data = state || {}
451
+ if ((data.startIn || "home") !== "last")
452
+ return null
453
+ var stored = data.lastTabs || null
454
+ var kept = stored && Array.isArray(stored.paths) ? stored.paths : []
455
+ for (var i = 0; i < kept.length; i++) {
456
+ if (typeof kept[i] !== "string" || kept[i].length === 0)
457
+ return null
458
+ }
459
+ var paths = []
460
+ for (var j = 0; j < kept.length && paths.length < MAX; j++)
461
+ paths.push(kept[j])
462
+ if (paths.length === 0)
463
+ return null
464
+ var index = stored && stored.index === Math.floor(stored.index) ? stored.index : 0
465
+ if (index < 0 || index >= paths.length)
466
+ index = Math.min(Math.max(index, 0), paths.length - 1)
467
+ return { paths: paths, index: index }
468
+ }
469
+
470
+ // A restored tab snapshots like a fresh tab, so view, sort and hidden come from the pane.
471
+ function restoreItems(pane, paths) {
472
+ var out = []
473
+ for (var i = 0; i < paths.length; i++)
474
+ out.push(snapshot(pane, String(paths[i])))
475
+ return out
476
+ }
477
+
478
+ // A lift offers only private tab MIME; JSON preserves folder paths and cursor names verbatim.
479
+ var TAB_MIME = "application/x-flea-tab"
480
+
481
+ var TAB_VIEWS = ["list", "grid", "columns"]
482
+
483
+ // An unset process id never owns a tab drag.
484
+ var ownPid = ""
485
+
486
+ function setOwnPid(pid) {
487
+ ownPid = String(pid || "")
488
+ }
489
+
490
+ // One lift's token: the pid names the window, the token names the lift inside it.
491
+ var TOKEN_RANDOM_RANGE = 1000000000 // Spread simultaneous lifts across a billion random suffixes.
492
+ function newToken() {
493
+ return String(Date.now()) + "-" + String(Math.floor(Math.random() * TOKEN_RANDOM_RANGE))
494
+ }
495
+
496
+ // The hand-off a tear-off gives the one window it starts; src/tearoff.rs drops the same names for Rust launches.
497
+ var TEAR_OFF_ENV = ["FLEA_TAB_SOURCE_PID", "FLEA_TAB_CURSOR", "FLEA_TAB_TOKEN"]
498
+
499
+ // Sample input: ["flea", "/tmp"] gives ["env", "-u", "FLEA_TAB_SOURCE_PID", "-u", "FLEA_TAB_CURSOR", "-u", "FLEA_TAB_TOKEN", "flea", "/tmp"].
500
+ function freshLaunch(argv) {
501
+ var unset = ["env"]
502
+ for (var i = 0; i < TEAR_OFF_ENV.length; i++)
503
+ unset.push("-u", TEAR_OFF_ENV[i])
504
+ return unset.concat(argv)
505
+ }
506
+
507
+ // A lift names the live current tab or stored hidden tab, with the cursor name when available; null if absent.
508
+ function tabInfo(pane, index) {
509
+ if (!pane)
510
+ return null
511
+ var total = count(pane)
512
+ if (index < 0 || index >= total)
513
+ return null
514
+ var here = restingPath(pane)
515
+ var current = currentIndex(pane)
516
+ var path, view, cursor
517
+ cursor = ""
518
+ if (index === current) {
519
+ path = here
520
+ view = pane.viewMode
521
+ if (here === pane.path) cursor = cursorFile(pane)
522
+ } else {
523
+ var items = currentItems(pane, here)
524
+ var item = items[index] || {}
525
+ path = String(item.path || "")
526
+ view = String(item.viewMode || "")
527
+ if (typeof item.cursorName === "string")
528
+ cursor = item.cursorName
529
+ }
530
+ if (!path || path.charAt(0) !== "/")
531
+ return null
532
+ return { path: path, view: view, cursor: cursor }
533
+ }
534
+
535
+ // JSON carries every path byte, including CR and LF.
536
+ function tabPayload(pane, index, pid, token) {
537
+ var info = tabInfo(pane, index)
538
+ if (!info)
539
+ return ""
540
+ var who = pid === undefined ? ownPid : pid
541
+ var lift = token === undefined ? "" : token
542
+ return JSON.stringify([String(who), String(lift), String(info.path), String(info.view), String(info.cursor)])
543
+ }
544
+
545
+ // A tab drag offers only the private tab MIME.
546
+ function tabDragMime(pane, index, pid, token) {
547
+ var payload = tabPayload(pane, index, pid, token)
548
+ if (!payload)
549
+ return {}
550
+ var mime = {}
551
+ mime[TAB_MIME] = payload
552
+ return mime
553
+ }
554
+
555
+ // Sample input: ["111","lift-1","/tmp/folder","list","note.txt"].
556
+ function parseTabMime(payload) {
557
+ var fields = null
558
+ try {
559
+ fields = JSON.parse(String(payload))
560
+ } catch (error) {
561
+ return null
562
+ }
563
+ if (!Array.isArray(fields) || fields.length !== 5)
564
+ return null
565
+ var pid = String(fields[0] || "")
566
+ var token = String(fields[1] || "")
567
+ var path = String(fields[2] || "")
568
+ if (!/^[0-9]+$/.test(pid))
569
+ return null
570
+ if (token.length === 0 || /[\x00-\x1f\x7f]/.test(token))
571
+ return null
572
+ if (path.length === 0 || path.charAt(0) !== "/" || path.indexOf("\u0000") >= 0)
573
+ return null
574
+ return { pid: pid, token: token, path: path,
575
+ view: String(fields[3] || ""), cursor: String(fields[4] || "") }
576
+ }
577
+
578
+ // An own-window drag belongs to reorder and must not duplicate its tab.
579
+ function isOwnTab(info, pid) {
580
+ var self = pid === undefined ? ownPid : String(pid)
581
+ return !!info && self.length > 0 && info.pid === self
582
+ }
583
+
584
+ function hasTabFormat(formats) {
585
+ return !!formats && formats.indexOf(TAB_MIME) >= 0
586
+ }
587
+
588
+ function enterAccepts(formats, payload, selfPid, canRecv, outActive) {
589
+ var text = String(payload || "")
590
+ if (text.length === 0)
591
+ return hasTabFormat(formats) && canRecv === true
592
+ var info = parseTabMime(text)
593
+ if (!info)
594
+ return false
595
+ var self = selfPid === undefined ? ownPid : String(selfPid)
596
+ if (self.length > 0 && info.pid === self)
597
+ return outActive === true
598
+ return canRecv === true
599
+ }
600
+
601
+ // Return the on-strip slot under x; off-strip drops never reach this helper, and the caller passes -1.
602
+ function dropIndexAt(x, tabWidth, tabCount) {
603
+ return TabMove.insertionAt(x, tabWidth, tabCount)
604
+ }
605
+
606
+ // A catcher must compare the drop's global coordinates with the source window before tearing off.
607
+ function catcherOutcome(rect, strip, x, y, tabWidth, tabCount) {
608
+ if (!rect || !(rect.width > 0) || !(rect.height > 0) || !isFinite(x) || !isFinite(y))
609
+ return { outcome: "cancel", at: -1 }
610
+ var localX = x - rect.x, localY = y - rect.y
611
+ if (localX < 0 || localY < 0 || localX >= rect.width || localY >= rect.height)
612
+ return { outcome: "tearoff", at: -1 }
613
+ if (strip && localX >= strip.x && localX < strip.x + strip.width
614
+ && localY >= strip.y && localY < strip.y + strip.height)
615
+ return { outcome: "return", at: dropIndexAt(localX - strip.x, tabWidth, tabCount) }
616
+ return { outcome: "cancel", at: -1 }
617
+ }
618
+
619
+ // A full strip refuses incoming tabs; a listing out is let go by the tab received.
620
+ function canReceive(pane) {
621
+ if (!pane)
622
+ return false
623
+ return count(pane) < MAX
624
+ }
625
+
626
+ // A received foreign tab opens at the requested drop position.
627
+ function receiveTab(pane, payload, at) {
628
+ if (!pane)
629
+ return false
630
+ var info = parseTabMime(payload)
631
+ if (!info || isOwnTab(info))
632
+ return false
633
+ if (count(pane) >= MAX) {
634
+ sayCount(pane, "Nine tabs is the most.")
635
+ return false
636
+ }
637
+ closePreview(pane)
638
+ var dropped = dropOverlay(pane)
639
+ var here = restingPath(pane)
640
+ var items = currentItems(pane, here)
641
+ var index = currentIndex(pane)
642
+ items[index] = snapshot(pane, here, items[index].tabIdentity, dropped)
643
+ var snap = snapshot(pane, info.path, undefined, dropped)
644
+ if (TAB_VIEWS.indexOf(info.view) >= 0)
645
+ snap.viewMode = info.view
646
+ if (info.cursor.length > 0)
647
+ snap.cursorName = info.cursor
648
+ var place = at >= 0 && at <= items.length ? at : items.length
649
+ items.splice(place, 0, snap)
650
+ pane.tabs = pack(items, place)
651
+ dropCount(pane)
652
+ apply(pane, snap, dropped, info.cursor)
653
+ return true
654
+ }
655
+
656
+ // A window's lone tab cannot be lifted out of its hidden strip.
657
+ function canLift(pane) {
658
+ return count(pane) >= 2
659
+ }
660
+
661
+ // Only the outstanding lift's token may acknowledge that lift.
662
+ function takeToken(stored, token) {
663
+ return !!stored && stored.length > 0 && stored === String(token || "")
664
+ }
665
+
666
+ // An unacknowledged lift expires after one network leg's 15 s bound (ui/NetworkMounts.qml mountTimeout).
667
+ var ACK_WAIT_MS = 15000
668
+
669
+ function ackCloses(stored, token, liftedAt, now) {
670
+ if (!takeToken(stored, token))
671
+ return false
672
+ if (liftedAt > 0 && now - liftedAt > ACK_WAIT_MS)
673
+ return false
674
+ return true
675
+ }
676
+
677
+ // B's synchronous take decision at drop time; the async peek may still refuse, and then no ack goes out.
678
+ var DROP_TAKE = "move"
679
+ var DROP_IGNORE = "ignore"
680
+ function dropDecision(info, selfPid, outActive, canRecv) {
681
+ if (!info)
682
+ return DROP_IGNORE
683
+ if (isOwnTab(info, selfPid))
684
+ return outActive === true ? DROP_TAKE : DROP_IGNORE
685
+ return canRecv === true ? DROP_TAKE : DROP_IGNORE
686
+ }
687
+
688
+ // Moving a tab must never close the window's only remaining tab.
689
+ function closeTabAfterMove(pane, index) {
690
+ if (!pane)
691
+ return "kept"
692
+ var total = count(pane)
693
+ if (index < 0 || index >= total)
694
+ return "kept"
695
+ if (total <= 1)
696
+ return "kept"
697
+ closeAt(pane, index)
698
+ return "closed"
699
+ }
700
+
701
+ // A rename editor prevents its tab from leaving the window.
702
+ function tearRefusal(pane) {
703
+ if (!pane)
704
+ return ""
705
+ if (pane.listInFlight)
706
+ return "A directory is already loading."
707
+ if (pane.renamePending === true)
708
+ return "Finish the rename before dragging a tab out."
709
+ if (typeof pane.renameEditor === "function" && pane.renameEditor())
710
+ return "Finish the rename before dragging a tab out."
711
+ return ""
712
+ }
713
+
714
+ // Tab lookup uses the live path for the current tab and stored paths for hidden tabs.
715
+ function indexOfPath(pane, path) {
716
+ if (!pane || !path)
717
+ return -1
718
+ var here = restingPath(pane)
719
+ var items = currentItems(pane, here)
720
+ var current = currentIndex(pane)
721
+ for (var i = 0; i < items.length; i++) {
722
+ var named = i === current ? here : String((items[i] || {}).path || "")
723
+ if (named === path)
724
+ return i
725
+ }
726
+ return -1
727
+ }
728
+
729
+ // A lift captures pane and identity; indices and paths may change while its ack travels.
730
+ function captureLift(pane, index, token, now) {
731
+ var items = currentItems(pane)
732
+ if (index < 0 || index >= items.length) return null
733
+ for (var i = 0; i < items.length; i++)
734
+ if (!items[i].tabIdentity) items[i].tabIdentity = ++nextTabIdentity
735
+ if (!pane.tabs) pane.tabs = pack(items, 0)
736
+ return { token: token, pane: pane, identity: items[index].tabIdentity, liftedAt: now, taken: false }
737
+ }
738
+
739
+ function resolveMovedTab(pane, identity) {
740
+ if (!pane || !pane.tabs || !identity) return -1
741
+ var items = pane.tabs.items
742
+ for (var i = 0; i < items.length; i++)
743
+ if (items[i].tabIdentity === identity) return i
744
+ return -1
745
+ }
746
+
747
+ function liftFor(lifts, token) {
748
+ for (var i = 0; i < lifts.length; i++)
749
+ if (takeToken(lifts[i].token, token)) return lifts[i]
750
+ return null
751
+ }