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.
- package/LICENSE +22 -0
- package/README.md +511 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/demos/App.java +5 -0
- package/demos/Dockerfile +4 -0
- package/demos/Main.kt +3 -0
- package/demos/Program.cs +1 -0
- package/demos/README.md +12 -0
- package/demos/app.dart +3 -0
- package/demos/app.deb +0 -0
- package/demos/app.js +1 -0
- package/demos/backup.tar +0 -0
- package/demos/budget.xlsx +0 -0
- package/demos/build.sh +2 -0
- package/demos/bundle.zip +0 -0
- package/demos/clip.mp4 +0 -0
- package/demos/data.sqlite +0 -0
- package/demos/disk.iso +0 -0
- package/demos/engine.cpp +5 -0
- package/demos/firmware.bin +0 -0
- package/demos/flake.nix +4 -0
- package/demos/folder/inside.txt +1 -0
- package/demos/font.ttf +0 -0
- package/demos/index.html +5 -0
- package/demos/index.php +2 -0
- package/demos/init.lua +1 -0
- package/demos/letter.docx +0 -0
- package/demos/lib.rs +3 -0
- package/demos/main.c +6 -0
- package/demos/main.h +3 -0
- package/demos/math-and-diagrams.md +200 -0
- package/demos/notes.tar.gz +0 -0
- package/demos/notes.txt +3 -0
- package/demos/photo.png +0 -0
- package/demos/program +2 -0
- package/demos/report.pdf +32 -0
- package/demos/script.py +1 -0
- package/demos/server.go +7 -0
- package/demos/settings.json +4 -0
- package/demos/slides.pptx +0 -0
- package/demos/song.mp3 +0 -0
- package/demos/style.css +4 -0
- package/demos/tool.rb +1 -0
- package/demos/types.ts +2 -0
- package/docs/pele.md +23 -0
- package/docs/protocol.md +3420 -0
- package/docs/temml.md +63 -0
- package/index.js +107 -0
- package/package.json +34 -4
- package/src/archive.js +407 -0
- package/src/archiveops.js +728 -0
- package/src/backend.js +369 -0
- package/src/bulkrename.js +95 -0
- package/src/clip-host.js +76 -0
- package/src/clip.js +462 -0
- package/src/code.js +168 -0
- package/src/compare.js +74 -0
- package/src/create.js +128 -0
- package/src/dirsize.js +147 -0
- package/src/figure-svg.js +530 -0
- package/src/figure-thread.js +23 -0
- package/src/figure.js +132 -0
- package/src/find.js +55 -0
- package/src/flea.js +39 -0
- package/src/fsinfo.js +39 -0
- package/src/highlight.js +141 -0
- package/src/html.js +52 -0
- package/src/kinds.js +89 -0
- package/src/listing.js +130 -0
- package/src/markdown-html.js +317 -0
- package/src/mathml.js +186 -0
- package/src/menu.js +180 -0
- package/src/meta.js +135 -0
- package/src/office.js +810 -0
- package/src/order.js +100 -0
- package/src/peek.js +49 -0
- package/src/pele-wrapper.js +695 -0
- package/src/permissions.js +180 -0
- package/src/places.js +313 -0
- package/src/preview-language.js +10 -0
- package/src/terminal-server.js +95 -0
- package/src/terminal-shell.js +26 -0
- package/src/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +327 -0
- package/src/uistate.js +393 -0
- package/src/uistore.js +168 -0
- package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
- package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
- package/src/vendor/LICENSES/MIT-katex.txt +21 -0
- package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
- package/src/vendor/LICENSES/MIT-pele.txt +40 -0
- package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
- package/src/vendor/LICENSES/MIT-temml.txt +21 -0
- package/src/vendor/pele.js +145 -0
- package/src/vendor/temml.mjs +14708 -0
- package/src/watch.js +98 -0
- package/src/wayland/client.js +109 -0
- package/src/wayland/protocol.js +55 -0
- package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
- package/src/wayland/protocols/wayland.xml +3248 -0
- package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
- package/src/wayland/resource-io.js +6 -0
- package/src/wayland/socket-discovery.js +26 -0
- package/src/wayland/transport-posix.js +120 -0
- package/src/wayland/transport-win32.js +11 -0
- package/src/wayland/transport.js +3 -0
- package/src/wayland/win32-resources.js +80 -0
- package/src/wayland/win32-wire.js +62 -0
- package/test/archive.test.js +80 -0
- package/test/bench-markdown-scroll.mjs +190 -0
- package/test/clip-host.test.js +113 -0
- package/test/code-preview.test.js +35 -0
- package/test/compare-ui-paths.test.js +24 -0
- package/test/compare.test.js +54 -0
- package/test/delete-trash.test.js +67 -0
- package/test/dirsize.test.js +138 -0
- package/test/file-ops.test.js +307 -0
- package/test/file-url.test.js +24 -0
- package/test/find-contents.test.js +161 -0
- package/test/find-input.test.js +66 -0
- package/test/fixtures/pele-parity.json +1006 -0
- package/test/highlight-launcher.test.js +35 -0
- package/test/html-preview.test.js +22 -0
- package/test/input.test.js +15 -0
- package/test/keymap.test.js +26 -0
- package/test/language-icons.test.js +36 -0
- package/test/launcher.test.js +51 -0
- package/test/manual-archive-here-ui.mjs +47 -0
- package/test/manual-code-scroll.mjs +28 -0
- package/test/manual-column-scroll.mjs +24 -0
- package/test/manual-compare-ui.mjs +20 -0
- package/test/manual-find-status.mjs +37 -0
- package/test/manual-folder-focus.mjs +63 -0
- package/test/manual-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -0
- package/test/manual-terminal-lifecycle.mjs +42 -0
- package/test/manual-terminal-navigation.mjs +48 -0
- package/test/manual-terminal-ui.mjs +47 -0
- package/test/manual-trash-ui.mjs +86 -0
- package/test/markdown-diagrams.test.js +93 -0
- package/test/markdown-html.test.js +105 -0
- package/test/mathml.test.js +92 -0
- package/test/menu-transfer.test.js +57 -0
- package/test/office-preview.test.js +154 -0
- package/test/pele-parity.test.js +28 -0
- package/test/places.test.js +134 -0
- package/test/preview-keys.test.js +60 -0
- package/test/preview-language.test.js +22 -0
- package/test/status-filename.test.js +20 -0
- package/test/transfer-replace-merge.test.js +187 -0
- package/test/trash-address.test.js +23 -0
- package/test/trash-view.test.js +37 -0
- package/test/trashbrowse.test.js +135 -0
- package/ui/AboutFacts.qml +78 -0
- package/ui/ArchiveCards.qml +95 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchiveHereConfirm.qml +127 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +775 -0
- package/ui/BulkOldNames.qml +47 -0
- package/ui/BulkRenameDialog.qml +380 -0
- package/ui/CardFrame.qml +67 -0
- package/ui/CardScroll.qml +79 -0
- package/ui/CheckBox.qml +73 -0
- package/ui/ChromeBar.qml +360 -0
- package/ui/ChromeButton.qml +131 -0
- package/ui/ChromeModes.qml +43 -0
- package/ui/CodeLines.qml +256 -0
- package/ui/CodeRefusal.qml +52 -0
- package/ui/CollideConfirm.qml +147 -0
- package/ui/CollideHost.qml +167 -0
- package/ui/ColumnPane.qml +525 -0
- package/ui/ColumnRow.qml +380 -0
- package/ui/ColumnsArea.qml +594 -0
- package/ui/ColumnsLanding.qml +147 -0
- package/ui/CompareView.qml +321 -0
- package/ui/ContextMenu.qml +743 -0
- package/ui/ConvertDialog.qml +456 -0
- package/ui/CountedWorker.qml +7 -0
- package/ui/Crumb.qml +64 -0
- package/ui/CrumbDrop.qml +25 -0
- package/ui/CsvTable.qml +394 -0
- package/ui/CursorMark.qml +41 -0
- package/ui/DefaultClaim.qml +130 -0
- package/ui/DeviceLock.qml +47 -0
- package/ui/DeviceMounts.qml +540 -0
- package/ui/DialogButton.qml +150 -0
- package/ui/DialogField.qml +147 -0
- package/ui/DialogHeader.qml +31 -0
- package/ui/DialogScrim.qml +20 -0
- package/ui/DialogTitle.qml +37 -0
- package/ui/Divider.qml +9 -0
- package/ui/DropInto.qml +126 -0
- package/ui/DropTarget.qml +35 -0
- package/ui/DropboxMark.qml +60 -0
- package/ui/EmptyState.qml +150 -0
- package/ui/EscapeHint.qml +11 -0
- package/ui/FactsTable.qml +54 -0
- package/ui/FastScrollHandler.qml +476 -0
- package/ui/FatNamesConfirm.qml +157 -0
- package/ui/Favourites.qml +143 -0
- package/ui/FigureService.qml +120 -0
- package/ui/FileDrag.qml +267 -0
- package/ui/FilterStrip.qml +133 -0
- package/ui/FitMetrics.qml +22 -0
- package/ui/FlashDriveRows.qml +137 -0
- package/ui/FlashHost.qml +72 -0
- package/ui/FlashImageRow.qml +104 -0
- package/ui/FlashRunner.qml +119 -0
- package/ui/FlashStepRow.qml +172 -0
- package/ui/FlashStrip.qml +38 -0
- package/ui/FlashView.qml +397 -0
- package/ui/FleaMark.qml +88 -0
- package/ui/FlyoutFade.qml +23 -0
- package/ui/FontPane.qml +170 -0
- package/ui/Glass.qml +114 -0
- package/ui/GlassTagger.qml +59 -0
- package/ui/Glyph.qml +64 -0
- package/ui/GlyphSolid.qml +22 -0
- package/ui/GridArea.qml +664 -0
- package/ui/GridTile.qml +325 -0
- package/ui/GvfsBridge.qml +164 -0
- package/ui/Header.qml +433 -0
- package/ui/HoverTimers.qml +39 -0
- package/ui/HtmlClip.qml +30 -0
- package/ui/HtmlPane.qml +63 -0
- package/ui/HyprlandMark.qml +45 -0
- package/ui/Ipc.qml +1005 -0
- package/ui/IpcControls.qml +7 -0
- package/ui/IpcMenuState.qml +48 -0
- package/ui/IpcPreviewState.qml +185 -0
- package/ui/JumpPath.qml +51 -0
- package/ui/KeymapSheet.qml +561 -0
- package/ui/KeymapSheetResult.qml +89 -0
- package/ui/KindStack.qml +40 -0
- package/ui/LangMark.qml +51 -0
- package/ui/LangMarkLoader.qml +26 -0
- package/ui/List.qml +480 -0
- package/ui/LoadingState.qml +54 -0
- package/ui/LocalSend.qml +56 -0
- package/ui/LocalSendMark.qml +73 -0
- package/ui/MarkdownBlockView.qml +311 -0
- package/ui/MarkdownBlocks.qml +35 -0
- package/ui/MarkdownFigure.qml +254 -0
- package/ui/MarkdownImages.qml +72 -0
- package/ui/MarkdownList.qml +81 -0
- package/ui/MarkdownMathsText.qml +97 -0
- package/ui/MarkdownPane.qml +83 -0
- package/ui/MarkdownPictures.qml +41 -0
- package/ui/MarkdownQuote.qml +52 -0
- package/ui/MarkdownRemote.qml +82 -0
- package/ui/MarkdownSource.qml +155 -0
- package/ui/MarkdownTable.qml +222 -0
- package/ui/MarkdownTableScroll.qml +64 -0
- package/ui/MarkdownTableWheel.qml +126 -0
- package/ui/MarkdownText.qml +87 -0
- package/ui/MarkdownWorker.js +132 -0
- package/ui/MatchText.qml +99 -0
- package/ui/MediaSession.qml +38 -0
- package/ui/MediaSound.qml +26 -0
- package/ui/MediaStrip.qml +191 -0
- package/ui/MediaTrack.qml +36 -0
- package/ui/MediaVolume.qml +54 -0
- package/ui/MenuActionDialog.qml +396 -0
- package/ui/MenuEdgeFade.qml +24 -0
- package/ui/MenuHost.qml +227 -0
- package/ui/MenuRow.qml +351 -0
- package/ui/MountListing.qml +100 -0
- package/ui/NetworkDialog.qml +435 -0
- package/ui/NetworkForm.qml +426 -0
- package/ui/NetworkMounts.qml +913 -0
- package/ui/NetworkPlaces.qml +127 -0
- package/ui/OpenWithDialog.qml +613 -0
- package/ui/Opener.qml +95 -0
- package/ui/Pane.qml +1320 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +268 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +601 -0
- package/ui/ParkedWait.qml +9 -0
- package/ui/PathEntry.qml +186 -0
- package/ui/PathJump.qml +400 -0
- package/ui/PdfViewer.qml +297 -0
- package/ui/PermissionsDialog.qml +658 -0
- package/ui/PermissionsHeadings.qml +31 -0
- package/ui/PhoneMounts.qml +67 -0
- package/ui/PickerAnswers.qml +75 -0
- package/ui/PickerBox.qml +26 -0
- package/ui/PickerChrome.qml +295 -0
- package/ui/PickerFilter.qml +97 -0
- package/ui/PickerGrid.qml +308 -0
- package/ui/PickerHeader.qml +28 -0
- package/ui/PickerLifecycle.qml +27 -0
- package/ui/PickerList.qml +218 -0
- package/ui/PickerListing.qml +149 -0
- package/ui/PickerPathBar.qml +127 -0
- package/ui/PickerPlaces.qml +189 -0
- package/ui/PickerRecent.qml +92 -0
- package/ui/PickerSave.qml +101 -0
- package/ui/PickerSelection.qml +155 -0
- package/ui/PickerWindow.qml +846 -0
- package/ui/PowerSectorsReader.qml +10 -0
- package/ui/PrebuildDriver.qml +146 -0
- package/ui/Preview.qml +1005 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +91 -0
- package/ui/PreviewColumn.qml +553 -0
- package/ui/PreviewEdge.qml +63 -0
- package/ui/PreviewFacts.qml +30 -0
- package/ui/PreviewFactsLine.qml +34 -0
- package/ui/PreviewHtml.qml +233 -0
- package/ui/PreviewImage.qml +253 -0
- package/ui/PreviewImagePan.qml +13 -0
- package/ui/PreviewImageSharp.qml +32 -0
- package/ui/PreviewLines.qml +106 -0
- package/ui/PreviewMarkdown.qml +706 -0
- package/ui/PreviewMedia.qml +250 -0
- package/ui/PreviewPdf.qml +482 -0
- package/ui/PreviewScroll.qml +201 -0
- package/ui/PreviewSwap.qml +335 -0
- package/ui/PreviewText.qml +149 -0
- package/ui/ProtocolChip.qml +18 -0
- package/ui/QuickLookArchive.qml +41 -0
- package/ui/QuickLookBar.qml +103 -0
- package/ui/QuickLookPrepare.qml +355 -0
- package/ui/QuickLookSwap.qml +10 -0
- package/ui/QuickLookWarm.qml +65 -0
- package/ui/RailDrop.qml +155 -0
- package/ui/RailHeading.qml +19 -0
- package/ui/RailPlaces.qml +38 -0
- package/ui/RailTrashRow.qml +67 -0
- package/ui/RenameField.qml +353 -0
- package/ui/RendererRetry.qml +11 -0
- package/ui/ResizeHandle.qml +52 -0
- package/ui/Reveal.qml +54 -0
- package/ui/Row.qml +476 -0
- package/ui/RowDrag.qml +213 -0
- package/ui/RowDropTarget.qml +27 -0
- package/ui/RunCard.qml +286 -0
- package/ui/Scripts.qml +65 -0
- package/ui/SearchStrip.qml +232 -0
- package/ui/SelectionBand.qml +140 -0
- package/ui/SelectionPreview.qml +370 -0
- package/ui/SettingsFavourite.qml +122 -0
- package/ui/SettingsGroup.qml +96 -0
- package/ui/SettingsHint.qml +12 -0
- package/ui/SettingsMetrics.qml +29 -0
- package/ui/SettingsPane.qml +178 -0
- package/ui/SettingsPanel.qml +547 -0
- package/ui/SettingsRail.qml +128 -0
- package/ui/SettingsRow.qml +409 -0
- package/ui/SettingsRuler.qml +85 -0
- package/ui/SettingsSegment.qml +85 -0
- package/ui/ShareBrowser.qml +113 -0
- package/ui/ShareLink.qml +67 -0
- package/ui/ShelfPins.qml +101 -0
- package/ui/Sidebar.qml +728 -0
- package/ui/SidebarRow.qml +358 -0
- package/ui/Spinner.qml +60 -0
- package/ui/StableModel.qml +89 -0
- package/ui/StateMessage.qml +84 -0
- package/ui/StatusBar.qml +512 -0
- package/ui/StatusFileName.qml +27 -0
- package/ui/TabBar.qml +673 -0
- package/ui/TabDragGeometry.qml +60 -0
- package/ui/TagMenuMark.qml +52 -0
- package/ui/TagRailSection.qml +53 -0
- package/ui/TagSlot.qml +40 -0
- package/ui/TagState.qml +150 -0
- package/ui/TagSwatch.qml +28 -0
- package/ui/Taildrop.qml +86 -0
- package/ui/TailscaleMark.qml +50 -0
- package/ui/TerminalService.qml +69 -0
- package/ui/TerminalTab.qml +48 -0
- package/ui/TerminalTabs.qml +27 -0
- package/ui/Theme.qml +460 -0
- package/ui/ThemeColors.qml +43 -0
- package/ui/TransferCard.qml +239 -0
- package/ui/TrashConfirm.qml +129 -0
- package/ui/TrashDropHandler.qml +11 -0
- package/ui/TrashHost.qml +202 -0
- package/ui/TrashMonitor.qml +30 -0
- package/ui/TrashToolbar.qml +19 -0
- package/ui/TrashView.qml +492 -0
- package/ui/UnlockDialog.qml +450 -0
- package/ui/UnlockHost.qml +206 -0
- package/ui/UpdateCheck.qml +97 -0
- package/ui/UserDirs.qml +25 -0
- package/ui/ViewState.qml +565 -0
- package/ui/ViewportScrollBar.qml +195 -0
- package/ui/ViewportScrollBars.qml +25 -0
- package/ui/WebPreview.qml +33 -0
- package/ui/WebPreviewView.qml +26 -0
- package/ui/WindowBody.qml +829 -0
- package/ui/WindowDrag.qml +35 -0
- package/ui/boot/Commons/AudioNodes.qml +50 -0
- package/ui/boot/Commons/AudioNodesModel.js +96 -0
- package/ui/boot/Commons/Border.qml +243 -0
- package/ui/boot/Commons/BorderGeometry.js +373 -0
- package/ui/boot/Commons/Color.qml +258 -0
- package/ui/boot/Commons/I18n.qml +118 -0
- package/ui/boot/Commons/InputDevices.qml +112 -0
- package/ui/boot/Commons/InputMethodState.qml +38 -0
- package/ui/boot/Commons/IpcRegistry.qml +77 -0
- package/ui/boot/Commons/Numbers.js +19 -0
- package/ui/boot/Commons/Plural.js +91 -0
- package/ui/boot/Commons/ShellIpc.qml +12 -0
- package/ui/boot/Commons/Style.qml +561 -0
- package/ui/boot/Commons/Translations.qml +100 -0
- package/ui/boot/Commons/UntypedInput.qml +152 -0
- package/ui/boot/Commons/Util.qml +188 -0
- package/ui/boot/Commons/qmldir +13 -0
- package/ui/boot/LICENSE-omarchy +20 -0
- package/ui/boot/Ui/BackgroundMedia.qml +49 -0
- package/ui/boot/Ui/BarIconButton.qml +106 -0
- package/ui/boot/Ui/BarIconContent.qml +38 -0
- package/ui/boot/Ui/BarIndicator.qml +53 -0
- package/ui/boot/Ui/BarWidget.qml +50 -0
- package/ui/boot/Ui/BorderOverlay.qml +54 -0
- package/ui/boot/Ui/BorderSurface.qml +40 -0
- package/ui/boot/Ui/Button.qml +224 -0
- package/ui/boot/Ui/ButtonGroup.qml +131 -0
- package/ui/boot/Ui/ConfirmDialog.qml +134 -0
- package/ui/boot/Ui/CursorSurface.qml +42 -0
- package/ui/boot/Ui/Dropdown.qml +245 -0
- package/ui/boot/Ui/FilterInput.qml +26 -0
- package/ui/boot/Ui/IconContentBounds.qml +141 -0
- package/ui/boot/Ui/KeyboardPanel.qml +453 -0
- package/ui/boot/Ui/MultiSelect.qml +624 -0
- package/ui/boot/Ui/NumberField.qml +86 -0
- package/ui/boot/Ui/OpticalGlyph.qml +68 -0
- package/ui/boot/Ui/OverlayWindow.qml +102 -0
- package/ui/boot/Ui/Panel.qml +60 -0
- package/ui/boot/Ui/PanelActionButton.qml +105 -0
- package/ui/boot/Ui/PanelController.qml +16 -0
- package/ui/boot/Ui/PanelHero.qml +112 -0
- package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
- package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
- package/ui/boot/Ui/PanelSeparator.qml +19 -0
- package/ui/boot/Ui/PanelSlider.qml +156 -0
- package/ui/boot/Ui/PanelToolTip.qml +50 -0
- package/ui/boot/Ui/PluginBarApi.qml +89 -0
- package/ui/boot/Ui/PointerMoveGate.qml +54 -0
- package/ui/boot/Ui/PopupCard.qml +181 -0
- package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
- package/ui/boot/Ui/SearchableDropdown.qml +354 -0
- package/ui/boot/Ui/SizedImage.qml +125 -0
- package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
- package/ui/boot/Ui/TextField.qml +58 -0
- package/ui/boot/Ui/Toggle.qml +118 -0
- package/ui/boot/Ui/ToggleSwitch.qml +115 -0
- package/ui/boot/Ui/WidgetButton.qml +172 -0
- package/ui/boot/Ui/qmldir +41 -0
- package/ui/boot/fleatab.qml +50 -0
- package/ui/boot/picker.qml +39 -0
- package/ui/boot/shell.qml +131 -0
- package/ui/boot/tabtearoff.qml +51 -0
- package/ui/js/Anchor.js +379 -0
- package/ui/js/AnchorHold.js +162 -0
- package/ui/js/Archive.js +157 -0
- package/ui/js/ArchiveCard.js +44 -0
- package/ui/js/ArchiveOps.js +44 -0
- package/ui/js/BackReturn.js +118 -0
- package/ui/js/BulkRename.js +100 -0
- package/ui/js/Buttons.js +54 -0
- package/ui/js/ChromeKeys.js +116 -0
- package/ui/js/ClipMarks.js +73 -0
- package/ui/js/ClipSelection.js +67 -0
- package/ui/js/Clipboard.js +179 -0
- package/ui/js/Cloud.js +97 -0
- package/ui/js/CodeRuns.js +72 -0
- package/ui/js/Collide.js +212 -0
- package/ui/js/ColumnFit.js +28 -0
- package/ui/js/ColumnMenu.js +111 -0
- package/ui/js/Columns.js +298 -0
- package/ui/js/ColumnsCarry.js +103 -0
- package/ui/js/Compare.js +74 -0
- package/ui/js/Contrast.js +157 -0
- package/ui/js/ControlReader.js +42 -0
- package/ui/js/Convert.js +52 -0
- package/ui/js/CopyAs.js +52 -0
- package/ui/js/Crumbs.js +178 -0
- package/ui/js/Csv.js +231 -0
- package/ui/js/Density.js +44 -0
- package/ui/js/Devices.js +440 -0
- package/ui/js/DirSizes.js +180 -0
- package/ui/js/Drag.js +360 -0
- package/ui/js/DragOut.js +166 -0
- package/ui/js/DropDev.js +52 -0
- package/ui/js/Dropbox.js +41 -0
- package/ui/js/Eject.js +217 -0
- package/ui/js/Errors.js +188 -0
- package/ui/js/ExtThumbs.js +115 -0
- package/ui/js/Facts.js +402 -0
- package/ui/js/FigureDate.js +14 -0
- package/ui/js/Filter.js +285 -0
- package/ui/js/Find.js +46 -0
- package/ui/js/Flash.js +184 -0
- package/ui/js/FlashCard.js +79 -0
- package/ui/js/FlashEndings.js +125 -0
- package/ui/js/FlashPane.js +116 -0
- package/ui/js/FleaBin.js +12 -0
- package/ui/js/Focus.js +504 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +314 -0
- package/ui/js/Fuzzy.js +141 -0
- package/ui/js/GlassTag.js +72 -0
- package/ui/js/Grid.js +33 -0
- package/ui/js/GridGeometry.js +90 -0
- package/ui/js/GridNames.js +153 -0
- package/ui/js/GvfsBridge.js +200 -0
- package/ui/js/HostClipboard.js +29 -0
- package/ui/js/Icons.js +218 -0
- package/ui/js/Input.js +50 -0
- package/ui/js/Jump.js +200 -0
- package/ui/js/KeyName.js +64 -0
- package/ui/js/Keymap.js +401 -0
- package/ui/js/Kinds.js +164 -0
- package/ui/js/LICENSES/ISC-lucide.txt +43 -0
- package/ui/js/LangMarkPaths.js +47 -0
- package/ui/js/LangMarks.js +120 -0
- package/ui/js/Lists.js +11 -0
- package/ui/js/LocalSend.js +39 -0
- package/ui/js/LockedMenu.js +63 -0
- package/ui/js/MakeDefault.js +186 -0
- package/ui/js/MarkBox.js +7 -0
- package/ui/js/Markdown.js +119 -0
- package/ui/js/MarkdownLists.js +86 -0
- package/ui/js/MarkdownMaths.js +58 -0
- package/ui/js/MarkdownPictures.js +32 -0
- package/ui/js/MarkdownPrepared.js +139 -0
- package/ui/js/MarkdownTableFit.js +34 -0
- package/ui/js/Marks.js +148 -0
- package/ui/js/Marquee.js +96 -0
- package/ui/js/Match.js +93 -0
- package/ui/js/Material.js +109 -0
- package/ui/js/MdBlocks.js +437 -0
- package/ui/js/MdBreak.js +71 -0
- package/ui/js/MdChunks.js +70 -0
- package/ui/js/MdContainer.js +137 -0
- package/ui/js/MdDocument.js +337 -0
- package/ui/js/MdEmph.js +97 -0
- package/ui/js/MdEntity.js +108 -0
- package/ui/js/MdEntityTable.js +223 -0
- package/ui/js/MdEscape.js +59 -0
- package/ui/js/MdFront.js +37 -0
- package/ui/js/MdHold.js +32 -0
- package/ui/js/MdHtml.js +307 -0
- package/ui/js/MdHtmlBlock.js +290 -0
- package/ui/js/MdHtmlHeading.js +53 -0
- package/ui/js/MdHtmlImage.js +179 -0
- package/ui/js/MdInline.js +154 -0
- package/ui/js/MdItems.js +212 -0
- package/ui/js/MdLeaf.js +309 -0
- package/ui/js/MdLink.js +196 -0
- package/ui/js/MdMath.js +67 -0
- package/ui/js/MdParagraphs.js +138 -0
- package/ui/js/MdRefs.js +232 -0
- package/ui/js/MdResolve.js +226 -0
- package/ui/js/MdRun.js +300 -0
- package/ui/js/MdUrl.js +226 -0
- package/ui/js/Menu.js +514 -0
- package/ui/js/MenuContext.js +85 -0
- package/ui/js/MenuFit.js +13 -0
- package/ui/js/MenuRefresh.js +74 -0
- package/ui/js/MenuWheel.js +35 -0
- package/ui/js/Messages.js +186 -0
- package/ui/js/Motion.js +16 -0
- package/ui/js/Mounts.js +320 -0
- package/ui/js/MouseNav.js +13 -0
- package/ui/js/Nav.js +329 -0
- package/ui/js/NetFs.js +26 -0
- package/ui/js/OpenWith.js +83 -0
- package/ui/js/Ops.js +585 -0
- package/ui/js/Palette.js +33 -0
- package/ui/js/PathBar.js +260 -0
- package/ui/js/Permissions.js +179 -0
- package/ui/js/Phones.js +112 -0
- package/ui/js/Picker.js +353 -0
- package/ui/js/PlaceMenu.js +96 -0
- package/ui/js/Places.js +265 -0
- package/ui/js/PreviewAsk.js +21 -0
- package/ui/js/PreviewKeys.js +155 -0
- package/ui/js/PreviewSettle.js +29 -0
- package/ui/js/PreviewSwap.js +101 -0
- package/ui/js/PropertyFacts.js +144 -0
- package/ui/js/Protocols.js +296 -0
- package/ui/js/QuickLookKinds.js +27 -0
- package/ui/js/QuickLookRect.js +24 -0
- package/ui/js/RailDrop.js +51 -0
- package/ui/js/RailKeys.js +87 -0
- package/ui/js/RailMenu.js +133 -0
- package/ui/js/Recent.js +135 -0
- package/ui/js/RecentMode.js +156 -0
- package/ui/js/Reload.js +60 -0
- package/ui/js/Renderer.js +9 -0
- package/ui/js/RunFile.js +143 -0
- package/ui/js/Scripts.js +28 -0
- package/ui/js/Scroll.js +304 -0
- package/ui/js/ScrollOff.js +69 -0
- package/ui/js/Search.js +478 -0
- package/ui/js/Selection.js +97 -0
- package/ui/js/Settings.js +476 -0
- package/ui/js/SettingsAbout.js +97 -0
- package/ui/js/SettingsShelf.js +52 -0
- package/ui/js/SheetKeys.js +42 -0
- package/ui/js/SheetQuery.js +281 -0
- package/ui/js/ShelfPile.js +27 -0
- package/ui/js/SlowClick.js +53 -0
- package/ui/js/SlowOp.js +6 -0
- package/ui/js/Sort.js +134 -0
- package/ui/js/Startup.js +63 -0
- package/ui/js/StateWords.js +17 -0
- package/ui/js/Status.js +238 -0
- package/ui/js/Swap.js +166 -0
- package/ui/js/TabMove.js +39 -0
- package/ui/js/Tabs.js +751 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +180 -0
- package/ui/js/TextSize.js +107 -0
- package/ui/js/Thumbs.js +158 -0
- package/ui/js/Transfer.js +172 -0
- package/ui/js/Trash.js +84 -0
- package/ui/js/TrashDates.js +47 -0
- package/ui/js/TrashDrop.js +64 -0
- package/ui/js/UiState.js +438 -0
- package/ui/js/Unlock.js +152 -0
- package/ui/js/Update.js +130 -0
- package/ui/js/UserDirs.js +56 -0
- 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
|
+
}
|