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/Devices.js
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
.import "Mounts.js" as Mounts
|
|
5
|
+
|
|
6
|
+
// The DEVICES half of the rail: one lsblk listing turned into the rows ui/DeviceMounts.qml draws.
|
|
7
|
+
// Split out of ui/js/Mounts.js, which keeps the rail's shared vocabulary and the NETWORK half; a
|
|
8
|
+
// block device and a gvfs share have nothing in common but the rail they land in.
|
|
9
|
+
|
|
10
|
+
// Sample lsblk --bytes --json row, with the columns ui/DeviceMounts.qml asks for:
|
|
11
|
+
// {"name":"sda1","path":"/dev/sda1","label":"128GB","mountpoints":["/run/media/gm/128GB"],"rm":true,"ro":false,
|
|
12
|
+
// "tran":null,"size":124656812032,"type":"part","model":null,"fstype":"vfat","parttype":"0xb",
|
|
13
|
+
// "pttype":"dos","partn":1,"uuid":"A1B2-C3D4"}.
|
|
14
|
+
// Two row kinds come out: one "disk" row for the disk that carries /, then one "volume" row for each
|
|
15
|
+
// volume on every disk. ui/DeviceMounts.qml turns these into rail entries.
|
|
16
|
+
function parseDevices(body, unmounted) {
|
|
17
|
+
var tree
|
|
18
|
+
try {
|
|
19
|
+
tree = JSON.parse(String(body || ""))
|
|
20
|
+
} catch (e) {
|
|
21
|
+
// A parse failure returns the empty shape rather than throwing, so the rail self-hides.
|
|
22
|
+
return []
|
|
23
|
+
}
|
|
24
|
+
var nodes = (tree && tree.blockdevices) || []
|
|
25
|
+
var out = []
|
|
26
|
+
var system = systemDisk(nodes)
|
|
27
|
+
if (system)
|
|
28
|
+
out.push({ kind: "disk", label: String(system.name), device: devicePath(system), path: "/",
|
|
29
|
+
mounted: true, removable: false, size: deviceBytes(system.size) })
|
|
30
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
31
|
+
// Every disk walks the same way; hidden() hides the system disk's plumbing, and its disk row stands for the leaf holding /.
|
|
32
|
+
if (!nodes[i].name || isPseudo(nodes[i]))
|
|
33
|
+
continue
|
|
34
|
+
// No transport to inherit at the top: the disk answers for itself inside the walk.
|
|
35
|
+
collectVolumes([nodes[i]], "", false, out, unmounted === true, unpluggable(nodes[i]))
|
|
36
|
+
}
|
|
37
|
+
return dedupeVolumes(out)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// zram stays out; a loop device is browsable only while it or a child is mounted, despite rm=false.
|
|
41
|
+
function isPseudo(node) {
|
|
42
|
+
var name = String(node.name || "")
|
|
43
|
+
if (/^zram/.test(name))
|
|
44
|
+
return true
|
|
45
|
+
return /^loop/.test(name) && !holdsMount(node)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Like holdsRoot, but a mount on the loop itself or any child keeps the image browsable.
|
|
49
|
+
function holdsMount(node) {
|
|
50
|
+
if (mountOf(node).length > 0)
|
|
51
|
+
return true
|
|
52
|
+
var kids = node.children || []
|
|
53
|
+
for (var k = 0; k < kids.length; k++) {
|
|
54
|
+
if (holdsMount(kids[k]))
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// The disk that actually carries /, found through the mountpoints of its own subtree. It used to be
|
|
61
|
+
// guessed as the first non-removable disk, and with a second internal drive present that guess names
|
|
62
|
+
// whichever disk lsblk lists first: the wrong drive was then labelled with the hostname and pointed
|
|
63
|
+
// at /, while the real system disk had no row at all.
|
|
64
|
+
function systemDisk(nodes) {
|
|
65
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
66
|
+
if (nodes[i].name && holdsRoot(nodes[i]))
|
|
67
|
+
return nodes[i]
|
|
68
|
+
}
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function holdsRoot(node) {
|
|
73
|
+
var points = node.mountpoints || []
|
|
74
|
+
for (var i = 0; i < points.length; i++) {
|
|
75
|
+
if (points[i] === "/")
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
var kids = node.children || []
|
|
79
|
+
for (var k = 0; k < kids.length; k++) {
|
|
80
|
+
if (holdsRoot(kids[k]))
|
|
81
|
+
return true
|
|
82
|
+
}
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// A volume earns a rail row when it can be unplugged, which is a stick whether or not anything
|
|
87
|
+
// mounted it, or when it is mounted, which is every internal drive the operator actually uses.
|
|
88
|
+
// RailAdditions rule 1 adds the third case behind its own switch: a volume nothing has mounted, with
|
|
89
|
+
// a filesystem to browse. With the switch off this is the 0.2.1 rule exactly, which kept a spare EFI
|
|
90
|
+
// or recovery partition out of the rail.
|
|
91
|
+
function collectVolumes(nodes, model, unplugs, out, unmounted, removableDisk, holder, underLoop) {
|
|
92
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
93
|
+
var n = nodes[i]
|
|
94
|
+
var kids = n.children || []
|
|
95
|
+
// Only the disk carries a product name, so it is passed down to its own partitions.
|
|
96
|
+
var own = n.model ? String(n.model) : model
|
|
97
|
+
// Only the disk carries the transport, so its partitions take its answer: measured by
|
|
98
|
+
// mariobgsp (PR 74), whose USB drive reports tran=usb on sdb and null on sdb1. It stops
|
|
99
|
+
// there: what a crypt leaf under it reads as is what it read as before that PR.
|
|
100
|
+
var pulls = unpluggable(n) || (unplugs && String(n.type || "") === "part")
|
|
101
|
+
// Loop ancestry routes eject through unmount and detach, and skips the optional unmounted-volume rule.
|
|
102
|
+
var loopHere = underLoop || /^loop/.test(String(n.name || ""))
|
|
103
|
+
// No row on any setting for a hidden leaf (ESP, swap, member) or for the leaf holding /, which its disk row stands for.
|
|
104
|
+
if (n.name && (kids.length === 0 || mountOf(n).length > 0) && !hidden(n) && !holdsRoot(n)
|
|
105
|
+
&& (pulls || mountOf(n).length > 0 || (unmounted && browsable(n) && !loopHere) || isLockedNode(n)))
|
|
106
|
+
out.push(volumeRow(n, own, pulls, removableDisk === true, holder, loopHere))
|
|
107
|
+
collectVolumes(kids, own, pulls, out, unmounted, removableDisk === true || unpluggable(n), containerName(n), loopHere)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// A leaf udisks hides is no row in any branch.
|
|
112
|
+
function hidden(n) {
|
|
113
|
+
if (mountOf(n).length === 0 && String(n.fstype || "").length === 0)
|
|
114
|
+
return true // H1: a partition with no filesystem and nothing mounted.
|
|
115
|
+
var fs = String(n.fstype || "").toLowerCase()
|
|
116
|
+
if (fs === "swap" || fs.slice(-7) === "_member" || fs === "bcache" || fs === "ceph" || fs === "drbd")
|
|
117
|
+
return true // H2: swap, LVM and RAID members, and other non-filesystem types.
|
|
118
|
+
if (fs.indexOf("crypto_") === 0)
|
|
119
|
+
return false // The Unlock board keeps a locked LUKS container as a row.
|
|
120
|
+
if (isFirmwarePart(n) && !isIsohybridKeep(n))
|
|
121
|
+
return true // H3: ESP, MSR, BIOS boot, WinRE GUID or MBR type, except an installer ISO part.
|
|
122
|
+
if (isRecoveryLabel(n))
|
|
123
|
+
return true // H4: System Reserved and vendor recovery labels on ntfs or vfat.
|
|
124
|
+
if (isSystemMountOnly(n))
|
|
125
|
+
return true // H5: mounted only where the system itself lives, never a user folder.
|
|
126
|
+
return false
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// GPT GUIDs and MBR numbers udisks hides; MBR compared numerically, lsblk drops the leading zero.
|
|
130
|
+
function isFirmwarePart(n) {
|
|
131
|
+
var raw = String(n.parttype || "")
|
|
132
|
+
if (raw.length === 0)
|
|
133
|
+
return false
|
|
134
|
+
var lower = raw.toLowerCase()
|
|
135
|
+
if (lower.indexOf("-") >= 0)
|
|
136
|
+
return gptHidden(lower)
|
|
137
|
+
var num = parseInt(lower, 16)
|
|
138
|
+
if (isNaN(num))
|
|
139
|
+
return false // An unparsable type hides nothing rather than everything.
|
|
140
|
+
return mbrHidden(num)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Sample input: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" trues, "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" falses.
|
|
144
|
+
function gptHidden(lower) {
|
|
145
|
+
var hide = ["c12a7328-f81f-11d2-ba4b-00a0c93ec93b", "21686148-6449-6e6f-744e-656564454649",
|
|
146
|
+
"e3c9e316-0b5c-4db8-817d-f92df00215ae", "de94bba4-06d1-4d40-a16a-bfd50179d6ac",
|
|
147
|
+
"bc13c2ff-59e6-4262-a352-b275fd6f7172", "426f6f74-0000-11aa-aa11-00306543ecac",
|
|
148
|
+
"a19d880f-05fc-4d3b-a006-743f0f84911e", "e6d6d379-f507-44c2-a23c-238f2a3df928"]
|
|
149
|
+
for (var i = 0; i < hide.length; i++)
|
|
150
|
+
if (lower === hide[i])
|
|
151
|
+
return true
|
|
152
|
+
return false
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Sample input: 0x27 trues, 0x7 falses; 0x0 hides unless the isohybrid keep below answers first.
|
|
156
|
+
function mbrHidden(num) {
|
|
157
|
+
var hide = [0x0, 0x5, 0xf, 0x85, 0x11, 0x12, 0x14, 0x16, 0x17, 0x1b, 0x1c, 0x1e, 0x27, 0x3d,
|
|
158
|
+
0x84, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x97, 0x98, 0x9a, 0x9b, 0xab, 0xbb, 0xc2, 0xc3, 0xdd, 0xef, 0xfd]
|
|
159
|
+
for (var i = 0; i < hide.length; i++)
|
|
160
|
+
if (num === hide[i])
|
|
161
|
+
return true
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Sample input: dos with 0x0 part 1 iso9660 keeps, the same part as vfat hides; udisks isohybrid undo.
|
|
166
|
+
function isIsohybridKeep(n) {
|
|
167
|
+
if (String(n.pttype || "").toLowerCase() !== "dos")
|
|
168
|
+
return false
|
|
169
|
+
var num = parseInt(String(n.parttype || ""), 16)
|
|
170
|
+
if (!(num === 0x0 || num === 0x17))
|
|
171
|
+
return false
|
|
172
|
+
var partn = String(n.partn === null || n.partn === undefined ? "" : n.partn)
|
|
173
|
+
if (!(partn === "1" || partn === "2"))
|
|
174
|
+
return false
|
|
175
|
+
var fs = String(n.fstype || "").toLowerCase()
|
|
176
|
+
return fs === "iso9660" || fs === "udf"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Sample input: ntfs "System Reserved" trues, ext4 "System Reserved" falses; spaces read as udev writes them.
|
|
180
|
+
function isRecoveryLabel(n) {
|
|
181
|
+
var fs = String(n.fstype || "").toLowerCase()
|
|
182
|
+
if (!(fs === "ntfs" || fs === "vfat"))
|
|
183
|
+
return false
|
|
184
|
+
var label = String(n.label || "").replace(/ /g, "_")
|
|
185
|
+
var hide = ["Recovery", "RECOVERY", "Lenovo_Recovery", "HP_RECOVERY", "Recovery_Partition",
|
|
186
|
+
"DellUtility", "DellRestore", "IBM_SERVICE", "SERVICEV001", "SERVICEV002",
|
|
187
|
+
"SYSTEM_RESERVED", "System_Reserved", "WINRE_DRV", "DIAGS", "IntelRST"]
|
|
188
|
+
for (var i = 0; i < hide.length; i++)
|
|
189
|
+
if (label === hide[i])
|
|
190
|
+
return true
|
|
191
|
+
return false
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Sample input: ["/"] trues, ["/mnt/data"] falses; every mountpoint must be system for the row to hide.
|
|
195
|
+
function isSystemMountOnly(n) {
|
|
196
|
+
var points = []
|
|
197
|
+
var raw = n.mountpoints || []
|
|
198
|
+
for (var i = 0; i < raw.length; i++) {
|
|
199
|
+
var p = raw[i] === null ? "" : String(raw[i])
|
|
200
|
+
if (p.length > 0 && p.charAt(0) === "/")
|
|
201
|
+
points.push(p)
|
|
202
|
+
}
|
|
203
|
+
if (points.length === 0)
|
|
204
|
+
return false
|
|
205
|
+
for (var j = 0; j < points.length; j++)
|
|
206
|
+
if (!isSystemPath(points[j]))
|
|
207
|
+
return false
|
|
208
|
+
return true
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Sample input: "/boot" trues, "/run" trues, "/home/gm/Data" falses; exact glib list, prefix only under /dev /proc /sys.
|
|
212
|
+
function isSystemPath(p) {
|
|
213
|
+
if (p === "/" || p.indexOf("/.") >= 0)
|
|
214
|
+
return true
|
|
215
|
+
if (p === "/dev" || p === "/proc" || p === "/sys")
|
|
216
|
+
return true
|
|
217
|
+
if (p.indexOf("/dev/") === 0 || p.indexOf("/proc/") === 0 || p.indexOf("/sys/") === 0)
|
|
218
|
+
return true
|
|
219
|
+
var exact = ["/bin", "/boot", "/compat/linux/proc", "/compat/linux/sys", "/etc", "/home",
|
|
220
|
+
"/lib", "/lib64", "/libexec", "/live/cow", "/live/image", "/media", "/mnt", "/net",
|
|
221
|
+
"/opt", "/rescue", "/root", "/run", "/sbin", "/srv", "/tmp", "/usr", "/usr/X11R6", "/usr/local",
|
|
222
|
+
"/usr/obj", "/usr/ports", "/usr/src", "/usr/xobj", "/var", "/var/crash", "/var/local",
|
|
223
|
+
"/var/log", "/var/log/audit", "/var/mail", "/var/run", "/var/tmp"]
|
|
224
|
+
for (var i = 0; i < exact.length; i++)
|
|
225
|
+
if (p === exact[i])
|
|
226
|
+
return true
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// One row per device path and per btrfs UUID: an md repeat lists one path twice, multi-device btrfs shares one.
|
|
231
|
+
function dedupeVolumes(rows) {
|
|
232
|
+
var head = []
|
|
233
|
+
var byUuid = {}
|
|
234
|
+
var at = {}
|
|
235
|
+
for (var i = 0; i < rows.length; i++) {
|
|
236
|
+
var r = rows[i]
|
|
237
|
+
var dkey = String(r.device || "")
|
|
238
|
+
var ukey = String(r.uuid || "")
|
|
239
|
+
var dup = -1
|
|
240
|
+
if (dkey.length > 0 && at[dkey] !== undefined)
|
|
241
|
+
dup = at[dkey]
|
|
242
|
+
else if (ukey.length > 0 && byUuid[ukey] !== undefined)
|
|
243
|
+
dup = byUuid[ukey]
|
|
244
|
+
if (dup < 0) {
|
|
245
|
+
at[dkey] = head.length
|
|
246
|
+
if (ukey.length > 0)
|
|
247
|
+
byUuid[ukey] = head.length
|
|
248
|
+
head.push(r)
|
|
249
|
+
} else if (r.mounted === true && head[dup].mounted !== true) {
|
|
250
|
+
at[dkey] = dup
|
|
251
|
+
if (ukey.length > 0)
|
|
252
|
+
byUuid[ukey] = dup
|
|
253
|
+
head[dup] = r
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return head
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Sample input: {"name":"sdb1","mountpoints":[null],"type":"part","fstype":"crypto_LUKS","fsver":"2"}, a locked leaf.
|
|
260
|
+
function isLockedNode(n) {
|
|
261
|
+
if (!n || (n.children || []).length > 0)
|
|
262
|
+
return false
|
|
263
|
+
if (mountOf(n).length > 0)
|
|
264
|
+
return false
|
|
265
|
+
return String(n.fstype || "").toLowerCase().indexOf("crypto_") === 0
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// RailAdditions rule 1 gate (old lsblk without PARTTYPE): empty-fs and swap die in hidden() ahead; only crypto and efi decide here.
|
|
269
|
+
function browsable(n) {
|
|
270
|
+
var fs = String(n.fstype || "").toLowerCase()
|
|
271
|
+
if (fs.indexOf("crypto_") === 0)
|
|
272
|
+
return false
|
|
273
|
+
return String(n.parttypename || "").toLowerCase().indexOf("efi") < 0
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// A drive somebody can pull out, which is what Eject is for. RM alone is not the answer: a USB
|
|
277
|
+
// bridge (a WD My Passport, PR 74) reports rm=false and is still a drive you unplug, while a hot-swap
|
|
278
|
+
// SATA bay reports its own hotplug and is not, which is why the transport decides and not that.
|
|
279
|
+
function unpluggable(n) {
|
|
280
|
+
return !!n && (n.rm === true || String(n.tran || "").toLowerCase() === "usb")
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// The mount wait starts when gio exits 0, never at launch: an admin polkit prompt longer than the
|
|
284
|
+
// wait is a slow prompt and not a mount that never reported a folder to open.
|
|
285
|
+
function mountTimerStart(exitCode) {
|
|
286
|
+
return exitCode === 0
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// The disk a partition powers off through, so a USB bridge stops instead of re-announcing.
|
|
290
|
+
// Sample input: "/dev/sda1" answers "/dev/sda", "/dev/nvme0n1p2" answers "/dev/nvme0n1.
|
|
291
|
+
function powerOffDisk(device) {
|
|
292
|
+
var text = String(device || "")
|
|
293
|
+
var m = text.match(/^(\/dev\/(?:sd[a-z]+|hd[a-z]+|vd[a-z]+|nvme\d+n\d+|mmcblk\d+|loop\d+))p?\d+$/)
|
|
294
|
+
if (m)
|
|
295
|
+
return m[1]
|
|
296
|
+
var bare = text.match(/^\/dev\/(?:sd[a-z]+|hd[a-z]+|vd[a-z]+|nvme\d+n\d+|mmcblk\d+|loop\d+)$/)
|
|
297
|
+
return bare ? text : ""
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// With another partition mounted, loop-delete only marks autoclear and that mount keeps reading (measured in 0.3.10).
|
|
301
|
+
// Sample input: {device: "/dev/loop0p1", path: "/run/media/u/ISO", loop: true} answers the sh chain on /dev/loop0.
|
|
302
|
+
var detachFailedExit = 3
|
|
303
|
+
function ejectCommand(e) {
|
|
304
|
+
var path = String(e.path || "")
|
|
305
|
+
if (e.loop !== true)
|
|
306
|
+
return ["gio", "mount", "-e", path]
|
|
307
|
+
var loop = String(e.device || "").match(/^\/dev\/(loop\d+)(?:p\d+)?$/)
|
|
308
|
+
if (!loop)
|
|
309
|
+
return ["gio", "mount", "-u", path]
|
|
310
|
+
var loopDisk = "/dev/" + loop[1]
|
|
311
|
+
return ["sh", "-c", 'autoclear=$(cat -- "$4" 2>/dev/null) || autoclear=; before=$(cat -- "$3" 2>/dev/null); '
|
|
312
|
+
+ 'status=0; gio mount -u "$1" || status=1; if [ "$autoclear" != 0 ]; then exit "$status"; fi; ' // Autoclear 1 detaches at the kernel's last close; unreadable values are left alone.
|
|
313
|
+
+ 'after=$(cat -- "$3" 2>/dev/null); if [ -n "$before" ] && [ "$after" = "$before" ]; then '
|
|
314
|
+
+ 'udisksctl loop-delete --no-user-interaction -b "$2" || exit ' + detachFailedExit + '; fi; exit "$status"',
|
|
315
|
+
"sh", path, loopDisk, "/sys/block/" + loop[1] + "/loop/backing_file", "/sys/block/" + loop[1] + "/loop/autoclear"]
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// The sysfs block name for a disk path, so the eject chain can watch its write counter.
|
|
319
|
+
// Sample input: "/dev/sda" answers "sda", "/dev/nvme0n1" answers "nvme0n1.
|
|
320
|
+
function sysBase(disk) {
|
|
321
|
+
var text = String(disk || "")
|
|
322
|
+
var m = text.match(/^\/dev\/(.+)$/)
|
|
323
|
+
return m ? m[1] : ""
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// The written-sector counter out of one /sys/block/<disk>/stat read, "" when unreadable.
|
|
327
|
+
// Sample input: " 1 0 2 3 0 0 42 0 0 0 0 0 0 0 0" answers "42".
|
|
328
|
+
function writtenSectors(body) {
|
|
329
|
+
var fields = String(body || "").trim().split(/\s+/)
|
|
330
|
+
return fields.length >= 7 ? fields[6] : ""
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Every mounted node under one disk in the last listing, hidden ones too (an ESP has no rail row, yet a power-off must unmount it); system mounts never queue.
|
|
334
|
+
// Sample input: sda1 (ESP) mounted at /run/media/u/EFI answers [{device: "/dev/sda1", path: "/run/media/u/EFI"}] for "/dev/sda".
|
|
335
|
+
function powerOffQueue(listing, disk, entries) {
|
|
336
|
+
var tree
|
|
337
|
+
var out = []
|
|
338
|
+
try {
|
|
339
|
+
tree = JSON.parse(String(listing || ""))
|
|
340
|
+
} catch (e) {
|
|
341
|
+
// An unparsable listing keeps the mounted rail volumes queued, as before the hidden-node walk.
|
|
342
|
+
console.warn("Device listing for " + disk + " could not be parsed (" + e.message + "); mounted rail volumes were queued instead.")
|
|
343
|
+
var rows = entries || []
|
|
344
|
+
for (var r = 0; r < rows.length; r++) {
|
|
345
|
+
var row = rows[r]
|
|
346
|
+
if (row.kind === "volume" && row.mounted && powerOffDisk(row.device) === disk)
|
|
347
|
+
out.push({ device: row.device, path: row.path })
|
|
348
|
+
}
|
|
349
|
+
return dedupeVolumes(out)
|
|
350
|
+
}
|
|
351
|
+
var nodes = (tree && tree.blockdevices) || []
|
|
352
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
353
|
+
if (nodes[i].name && powerOffDisk(devicePath(nodes[i])) === disk)
|
|
354
|
+
collectMounted(nodes[i], out)
|
|
355
|
+
}
|
|
356
|
+
return dedupeVolumes(out)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function collectMounted(node, out) {
|
|
360
|
+
var point = mountOf(node)
|
|
361
|
+
if (point.length > 0 && !holdsRoot(node) && !isSystemMountOnly(node))
|
|
362
|
+
out.push({ device: devicePath(node), path: point })
|
|
363
|
+
var kids = node.children || []
|
|
364
|
+
for (var i = 0; i < kids.length; i++)
|
|
365
|
+
collectMounted(kids[i], out)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Sample gio stderr: "Error 1: target is busy", "Not authorized to perform operation",
|
|
369
|
+
// "No volume for device /dev/sda9", "Location is already mounted", "No medium found".
|
|
370
|
+
// "" opens rather than failing: the volume is already mounted, so there is no failure to say.
|
|
371
|
+
function mountError(op, exitCode, stderr, label) {
|
|
372
|
+
if (exitCode === 0)
|
|
373
|
+
return ""
|
|
374
|
+
var text = String(stderr || "").toLowerCase()
|
|
375
|
+
var name = String(label || "")
|
|
376
|
+
if (/already mounted/.test(text))
|
|
377
|
+
return ""
|
|
378
|
+
if (/busy|in use|in use by/.test(text))
|
|
379
|
+
return Format.fill(Mounts.WORDS.busy, name)
|
|
380
|
+
if (/not authorized|not allowed|refused|dismissed|no authentication|auth/i.test(String(stderr || "")))
|
|
381
|
+
return Format.fill(op === "unmount" ? Mounts.WORDS.unmountRefused : op === "eject" ? Mounts.WORDS.ejectRefused : Mounts.WORDS.mountRefused, name)
|
|
382
|
+
if (/no volume|no medium|no media|empty|no device/.test(text))
|
|
383
|
+
return Format.fill(/medium|media|empty/.test(text) ? Mounts.WORDS.noDisc : Mounts.WORDS.notMountable, name)
|
|
384
|
+
if (op === "mount" && /wrong fs type|bad superblock|unknown filesystem type|can.t read superblock|structure needs cleaning/.test(text))
|
|
385
|
+
return Format.fill(Mounts.WORDS.damaged, name)
|
|
386
|
+
if (op === "unmount")
|
|
387
|
+
return Format.fill(Mounts.WORDS.unmountFailed, name)
|
|
388
|
+
if (op === "eject")
|
|
389
|
+
return Format.fill(Mounts.WORDS.ejectFailed, name)
|
|
390
|
+
return Format.fill(Mounts.WORDS.mountFailed, name)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// gio's own reason as the status bar's detail line; sample "Error mounting /dev/sdb1 at /run/media/u/DATA #2: wrong fs type" and "Error unmounting /dev/sdb1: target is busy" give "wrong fs type" and "target is busy", "gio: file:///x: Error ejecting /dev/sdb: busy" gives "busy" (gio's file-URI lead), "" gives "".
|
|
394
|
+
function mountDetail(stderr) {
|
|
395
|
+
var lines = String(stderr || "").split("\n").map(function (line) { return line.trim() }).filter(function (line) { return line.length > 0 })
|
|
396
|
+
return lines.join(" ").replace(/^gio:\s*/, "").replace(/^[a-z][a-z0-9+.-]*:\/\/\S*:\s+/i, "").replace(/^Error (?:mounting|unmounting|ejecting) \S+(?: at .*?)?:\s+/, "").trim()
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Sample: ["/home", "/var/log", "/"] for one btrfs device with several subvolumes mounted, ["[SWAP]"]
|
|
400
|
+
// for swap, which is no directory, and [null] for a volume nothing has mounted. The first real path
|
|
401
|
+
// wins, which is also what drops swap: only a mountpoint is browsable and only one row is drawn.
|
|
402
|
+
function mountOf(node) {
|
|
403
|
+
var points = node.mountpoints || []
|
|
404
|
+
for (var i = 0; i < points.length; i++) {
|
|
405
|
+
var point = points[i] === null ? "" : String(points[i])
|
|
406
|
+
if (point.length > 0 && point.charAt(0) === "/")
|
|
407
|
+
return point
|
|
408
|
+
}
|
|
409
|
+
return ""
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// lsblk's own PATH column, because a device-mapper leaf lives at /dev/mapper/<name> and "/dev/" plus
|
|
413
|
+
// its kernel name is a path that does not exist. gio is handed this, so it has to be the real one.
|
|
414
|
+
function devicePath(node) {
|
|
415
|
+
return node.path ? String(node.path) : "/dev/" + String(node.name)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Sample input: {"name":"sdb1","label":"Backup","fstype":"crypto_LUKS"}, a container its owner named; "" for any other node.
|
|
419
|
+
function containerName(n) {
|
|
420
|
+
return String(n.fstype || "").toLowerCase().indexOf("crypto_") === 0 && n.label ? String(n.label) : ""
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Labelled by the filesystem label, then the drive's product name, then the kernel name; a crypt keeps its named container's.
|
|
424
|
+
function volumeRow(n, model, unplugs, removableDisk, holder, loop) {
|
|
425
|
+
var path = mountOf(n)
|
|
426
|
+
var named = String(n.type || "") === "crypt" ? String(holder || "") : ""
|
|
427
|
+
var label = named.length > 0 ? named : n.label ? String(n.label) : (model.length > 0 ? model : String(n.name))
|
|
428
|
+
var fs = String(n.fstype || "").toLowerCase()
|
|
429
|
+
// A crypt leaf on a removable drive releases like the stick it sits on; an internal one never does.
|
|
430
|
+
var removable = unplugs === true || (String(n.type || "") === "crypt" && removableDisk === true)
|
|
431
|
+
return { kind: "volume", label: label, device: devicePath(n), path: path, mounted: path.length > 0,
|
|
432
|
+
removable: removable, mediaRemovable: n.rm === true, readOnly: n.ro === true, size: deviceBytes(n.size),
|
|
433
|
+
locked: isLockedNode(n), fstype: String(n.fstype || ""), fsver: String(n.fsver || ""),
|
|
434
|
+
uuid: fs === "btrfs" && n.uuid ? String(n.uuid) : "", loop: !!loop }
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// An unavailable or malformed capacity stays absent; only the delegate formats valid byte counts.
|
|
438
|
+
function deviceBytes(value) {
|
|
439
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : null
|
|
440
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
.import "Format.js" as Format
|
|
3
|
+
|
|
4
|
+
// flea-qml: a folder's size is measured only when the user asks (src/dirsize.js). A folder never
|
|
5
|
+
// measured shows UNMEASURED in its Size cell and the Size header carries it too; both take a click.
|
|
6
|
+
var UNMEASURED = "\u2696\ufe0f"
|
|
7
|
+
var MEASURING = "\u2026"
|
|
8
|
+
|
|
9
|
+
// A row this listing has asked about: null means asked and waiting, an object is the answer.
|
|
10
|
+
var ASKED = null
|
|
11
|
+
|
|
12
|
+
function empty() {
|
|
13
|
+
return { file: {}, order: [] }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Only visible rows, only rows the backend called directories, only rows never asked.
|
|
17
|
+
function plan(state, rows, held, first, last) {
|
|
18
|
+
var ask = []
|
|
19
|
+
for (var i = first; i <= last; i++) {
|
|
20
|
+
if (state.file[i] !== undefined) {
|
|
21
|
+
continue
|
|
22
|
+
}
|
|
23
|
+
var row = rows[i - held]
|
|
24
|
+
if (row && row.d) {
|
|
25
|
+
ask.push(i)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return ask
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// The wrapper is new so a QML binding on it re-evaluates; the map inside is mutated in place.
|
|
32
|
+
function applied(state, ask) {
|
|
33
|
+
for (var i = 0; i < ask.length; i++) {
|
|
34
|
+
state.file[ask[i]] = ASKED
|
|
35
|
+
state.order.push(ask[i])
|
|
36
|
+
}
|
|
37
|
+
return { file: state.file, order: state.order }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Gates the cancel wire message, since a fling fires onContentYChanged on every pixel and a fresh listing has nothing queued to cancel yet.
|
|
41
|
+
function hasPending(state) {
|
|
42
|
+
for (var i = 0; i < state.order.length; i++) {
|
|
43
|
+
if (state.file[state.order[i]] === ASKED) {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// A scroll cancels every row still waiting, not only the ones off-viewport, matching what the backend's own dirsizecancel means.
|
|
51
|
+
function cancelled(state) {
|
|
52
|
+
var file = {}
|
|
53
|
+
var order = []
|
|
54
|
+
for (var i = 0; i < state.order.length; i++) {
|
|
55
|
+
var row = state.order[i]
|
|
56
|
+
if (state.file[row] === ASKED) {
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
file[row] = state.file[row]
|
|
60
|
+
order.push(row)
|
|
61
|
+
}
|
|
62
|
+
return { file: file, order: order }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// A live answer re-lists some folders: each answered size follows its row, by name, to that row's new index. Pending asks do not follow.
|
|
66
|
+
function carried(state, oldRows, oldHeld, newRows, newHeld) {
|
|
67
|
+
var at = Object.create(null)
|
|
68
|
+
for (var j = 0; j < newRows.length; j++) {
|
|
69
|
+
if (newRows[j].d) {
|
|
70
|
+
at[newRows[j].n] = newHeld + j
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
var next = empty()
|
|
74
|
+
for (var k = 0; k < state.order.length; k++) {
|
|
75
|
+
var answer = state.file[state.order[k]]
|
|
76
|
+
var row = oldRows[state.order[k] - oldHeld]
|
|
77
|
+
if (answer && row && at[row.n] !== undefined) {
|
|
78
|
+
next.file[at[row.n]] = answer
|
|
79
|
+
next.order.push(at[row.n])
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return next
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Sizes a live answer carried on its rows land with those rows; with none the state comes back as it was.
|
|
86
|
+
// Sample input: (null, [{n: "x", d: true}, {n: "c", d: true, z: 96}], 20) answers file {21: {bytes: 96, partial: false}}, order [21].
|
|
87
|
+
function inlined(state, rows, held) {
|
|
88
|
+
var next = null
|
|
89
|
+
for (var i = 0; i < rows.length; i++) {
|
|
90
|
+
if (rows[i].z === undefined)
|
|
91
|
+
continue
|
|
92
|
+
next = next || state || empty()
|
|
93
|
+
if (next.file[held + i] === undefined)
|
|
94
|
+
next.order.push(held + i)
|
|
95
|
+
next.file[held + i] = { bytes: rows[i].z, partial: rows[i].zp === true }
|
|
96
|
+
}
|
|
97
|
+
return next || state
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// The cap bounds a policy bug, not normal use, the same reason ui/js/Thumbs.js has one; callers pass Pane's own thumbCap.
|
|
101
|
+
function remember(state, row, bytes, partial, cap) {
|
|
102
|
+
if (state.file[row] === undefined) {
|
|
103
|
+
state.order.push(row)
|
|
104
|
+
}
|
|
105
|
+
state.file[row] = { bytes: bytes, partial: partial }
|
|
106
|
+
while (state.order.length > cap) {
|
|
107
|
+
delete state.file[state.order.shift()]
|
|
108
|
+
}
|
|
109
|
+
return { file: state.file, order: state.order, all: state.all }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Sample input: ("network") trues, ("usb") falses.
|
|
113
|
+
function isRemoteClass(storageClass) {
|
|
114
|
+
return storageClass === "network" || storageClass === "phone"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Sample input: (["size"]) trues, ([]) falses.
|
|
118
|
+
function sizeHidden(hiddenCols) {
|
|
119
|
+
return hiddenCols.indexOf("size") >= 0
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Sample input: ("list", [], "", true) trues, ("grid", [], "", true) falses.
|
|
123
|
+
function wantsSizes(viewMode, hiddenCols, storageClass, storageKnown) {
|
|
124
|
+
if (!storageKnown) return false
|
|
125
|
+
if (isRemoteClass(storageClass)) return false
|
|
126
|
+
if (viewMode === "grid") return false
|
|
127
|
+
if (viewMode === "list" && sizeHidden(hiddenCols)) return false
|
|
128
|
+
return true
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// null covers both "never asked" and "asked and still waiting"; cellFor tells them apart for drawing.
|
|
132
|
+
function sizeFor(state, row) {
|
|
133
|
+
var value = state.file[row]
|
|
134
|
+
return value && typeof value === "object" ? value : null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// What a Size cell draws from: the answer, { waiting: true } while a walk is out for it, or null.
|
|
138
|
+
function cellFor(state, row) {
|
|
139
|
+
var value = state.file[row]
|
|
140
|
+
if (value && typeof value === "object") return value
|
|
141
|
+
if (value === ASKED || (value === undefined && state.all === true)) return { waiting: true }
|
|
142
|
+
return null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// A folder's size from this listing's answers, else the size a row came back carrying (z, zp).
|
|
146
|
+
// Sample input: (null, {d: true, z: 2048}) gives {bytes: 2048, partial: false}; (null, {d: true}) gives null.
|
|
147
|
+
function known(cell, row) {
|
|
148
|
+
if (cell && !cell.waiting) return cell
|
|
149
|
+
if (row && row.z !== undefined) return { bytes: row.z, partial: row.zp === true }
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// The Size cell of a folder: MEASURING while asked, else UNMEASURED, followed by the size once
|
|
154
|
+
// there is one, so a measured folder still shows what a click on it does: measure it again.
|
|
155
|
+
// Sample input: ({bytes: 2048, partial: false}) gives "⚖️ 2 kB"; (null) gives "⚖️".
|
|
156
|
+
function folderText(cell, row) {
|
|
157
|
+
if (cell && cell.waiting) return MEASURING
|
|
158
|
+
var size = known(cell, row)
|
|
159
|
+
return size ? UNMEASURED + " " + (size.partial ? ">" : "") + Format.size(size.bytes) : UNMEASURED
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Rows the user asked to measure wait until their answers, or the run's end, land.
|
|
163
|
+
function asking(state, rows) {
|
|
164
|
+
for (var i = 0; i < rows.length; i++) {
|
|
165
|
+
if (state.file[rows[i]] === undefined) state.order.push(rows[i])
|
|
166
|
+
state.file[rows[i]] = ASKED
|
|
167
|
+
}
|
|
168
|
+
return { file: state.file, order: state.order, all: state.all }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// The header's ⚖️: every folder in the listing waits, held in the window or not, and is measured anew.
|
|
172
|
+
function askingAll(state) {
|
|
173
|
+
return { file: {}, order: [], all: true }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// The run ended (dirsizedone): whatever still waits has no answer coming.
|
|
177
|
+
function settled(state) {
|
|
178
|
+
var next = cancelled(state)
|
|
179
|
+
return { file: next.file, order: next.order }
|
|
180
|
+
}
|