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/Filter.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
.import "Input.js" as Input
|
|
3
|
+
|
|
4
|
+
.import "Format.js" as Format
|
|
5
|
+
.import "Match.js" as Match
|
|
6
|
+
.import "Thumbs.js" as Thumbs
|
|
7
|
+
|
|
8
|
+
// The strip's two sentences and the no-match tile's heading, each filled by Format.fill.
|
|
9
|
+
var WORDS = {
|
|
10
|
+
noMatchOne: "No match among 1 item",
|
|
11
|
+
noMatchMany: "No match among %1 items",
|
|
12
|
+
shown: "%1 of %2 shown",
|
|
13
|
+
shownOfFolder: "%1 of %2 shown · of %3 in this folder",
|
|
14
|
+
nothingMatched: "Nothing matched %1"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// The filter narrows the listing already on screen: no walk, no round trip, and every row it keeps
|
|
18
|
+
// is one the backend has already sent. ui/js/Search.js is its bigger sibling, which walks the
|
|
19
|
+
// subtree and replaces the listing; the design canvas draws the two as different things and this
|
|
20
|
+
// file never reaches ui/Backend.qml at all.
|
|
21
|
+
//
|
|
22
|
+
// Two index spaces meet here. A "listing row" is what the backend numbers, what a selection holds
|
|
23
|
+
// and what every write operation sends; a "view position" is where a row is drawn. With no filter
|
|
24
|
+
// up the two are the same number, and at() and viewOf() below are the only places that convert.
|
|
25
|
+
|
|
26
|
+
// The listing rows a query leaves standing, in the order the backend sent them, or null when there
|
|
27
|
+
// is no filter at all. Only the rows the pane holds can be tested, so the answer is a subsequence
|
|
28
|
+
// of the held window; scope() below is what says so when the window is not the whole listing.
|
|
29
|
+
// It is a subsequence and never a re-ranking, which is what keeps directories ahead of files.
|
|
30
|
+
function shown(rows, held, query) {
|
|
31
|
+
if (query.length === 0) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
var out = []
|
|
35
|
+
for (var i = 0; i < rows.length; i++) {
|
|
36
|
+
// The same run ui/js/Match.js paints in the name, so a row can never match without showing why.
|
|
37
|
+
// flea-qml: a Find result's row is a relative path, and the filter reads only its name.
|
|
38
|
+
if (Match.run(Match.rowName(rows[i], true), query).start >= 0) {
|
|
39
|
+
out.push(held + i)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return out
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function at(list, view) {
|
|
46
|
+
if (list === null) {
|
|
47
|
+
return view
|
|
48
|
+
}
|
|
49
|
+
// A delegate can outlive the view position it was built for by a frame when the match list
|
|
50
|
+
// shrinks, so a position past the end answers -1: a listing row nothing holds and nothing draws.
|
|
51
|
+
return view < list.length ? list[view] : -1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// -1 for a row the filter hides, which is what the callers below clamp against.
|
|
55
|
+
function viewOf(list, row) {
|
|
56
|
+
return list === null ? row : list.indexOf(row)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Issue 92, nixfred: a query matching nothing leaves the cursor on a row the filter no longer draws.
|
|
60
|
+
function cursorShown(pane) { return viewOf(pane.shown, pane.cursorIndex) >= 0 }
|
|
61
|
+
|
|
62
|
+
// The strip's own sentence, SearchFilter rules 1 and 2: what the filter kept, out of the rows it
|
|
63
|
+
// could test, and the directory those rows are a window on. The scope is the half that must not be
|
|
64
|
+
// dropped, because zero matches among 350 loaded rows is not zero matches in a 104,812-file
|
|
65
|
+
// directory; the tail goes when the window is the whole listing, which is nothing left to say.
|
|
66
|
+
function summary(list, loaded, total) {
|
|
67
|
+
if (list === null) {
|
|
68
|
+
return ""
|
|
69
|
+
}
|
|
70
|
+
if (total > loaded) {
|
|
71
|
+
return Format.fill(WORDS.shownOfFolder, Format.count(list.length), Format.count(loaded), Format.count(total))
|
|
72
|
+
}
|
|
73
|
+
return Format.fill(WORDS.shown, Format.count(list.length), Format.count(loaded))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// States' no-match tile: the pane names the query back and says how many rows it tested, because
|
|
77
|
+
// the query is up in a strip the reader may have looked away from.
|
|
78
|
+
function noMatch(total) {
|
|
79
|
+
return total === 1 ? WORDS.noMatchOne : Format.fill(WORDS.noMatchMany, Format.count(total))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The rows drawn between two ends, which is not the range between them: a plain index range would
|
|
83
|
+
// sweep up every row the filter hid in the gap, and nothing on screen would say it had.
|
|
84
|
+
function between(list, a, b) {
|
|
85
|
+
var lo = Math.min(a, b)
|
|
86
|
+
var hi = Math.max(a, b)
|
|
87
|
+
var out = []
|
|
88
|
+
for (var i = 0; i < list.length; i++) {
|
|
89
|
+
if (list[i] >= lo && list[i] <= hi) {
|
|
90
|
+
out.push(list[i])
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// A request cut back to the rows still drawn. A filtered viewport covers a set and not a run, so
|
|
97
|
+
// the range-shaped planners hand back rows the filter hides, and asking for those would fetch work
|
|
98
|
+
// nothing draws.
|
|
99
|
+
function keep(asked, list) {
|
|
100
|
+
if (list === null) {
|
|
101
|
+
return asked
|
|
102
|
+
}
|
|
103
|
+
var drawn = {}
|
|
104
|
+
for (var i = 0; i < list.length; i++) {
|
|
105
|
+
drawn[list[i]] = true
|
|
106
|
+
}
|
|
107
|
+
var out = []
|
|
108
|
+
for (var j = 0; j < asked.length; j++) {
|
|
109
|
+
if (drawn[asked[j]] === true) {
|
|
110
|
+
out.push(asked[j])
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return out
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// A pending thumbnail can be hidden inside the planner's span as well as outside its viewport.
|
|
117
|
+
function cut(work, list, state) {
|
|
118
|
+
var drop = work.drop.slice()
|
|
119
|
+
if (list !== null) {
|
|
120
|
+
var drawn = {}
|
|
121
|
+
for (var i = 0; i < list.length; i++) drawn[list[i]] = true
|
|
122
|
+
var dropping = {}
|
|
123
|
+
for (var j = 0; j < drop.length; j++) dropping[drop[j]] = true
|
|
124
|
+
for (var key in state.file) {
|
|
125
|
+
var row = Number(key)
|
|
126
|
+
if (Thumbs.pending(state.file[key]) && drawn[row] !== true && dropping[row] !== true)
|
|
127
|
+
drop.push(row)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return { ask: keep(work.ask, list), drop: drop }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// The listing rows a view range covers, for the two planners that take a first and a last.
|
|
134
|
+
function span(list, first, last) {
|
|
135
|
+
if (list === null) {
|
|
136
|
+
return { first: first, last: last }
|
|
137
|
+
}
|
|
138
|
+
if (list.length === 0) {
|
|
139
|
+
return { first: 0, last: -1 }
|
|
140
|
+
}
|
|
141
|
+
var lo = Math.max(0, Math.min(list.length - 1, first))
|
|
142
|
+
var hi = Math.max(0, Math.min(list.length - 1, last))
|
|
143
|
+
return { first: list[lo], last: list[hi] }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// The transitions, taking ui/Pane.qml's root the way ui/js/Search.js and ui/js/Sort.js do: the pane
|
|
147
|
+
// holds the state, this holds what the state does.
|
|
148
|
+
|
|
149
|
+
// "/" opens the query line. Unlike the search's, nothing is committed to start a walk: the rows are
|
|
150
|
+
// already here, so the listing narrows on the keystroke itself.
|
|
151
|
+
function start(pane) {
|
|
152
|
+
pane.filterTyping = true
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function typed(pane, character) {
|
|
156
|
+
apply(pane, pane.filterQuery + character)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function backspace(pane) {
|
|
160
|
+
apply(pane, pane.filterQuery.substring(0, pane.filterQuery.length - 1))
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Enter hands the keyboard back to the list with the filter standing, which is what makes y, x, d
|
|
164
|
+
// and r work over the narrowed rows; an empty query has nothing to stand, so it closes instead.
|
|
165
|
+
function commit(pane) {
|
|
166
|
+
if (pane.filterQuery.length === 0) {
|
|
167
|
+
close(pane)
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
pane.filterTyping = false
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Esc, and every fresh listing. The selection is deliberately not cleared: prune() below has already
|
|
174
|
+
// cut it to rows the filter was showing, so what is left is exactly what was on screen.
|
|
175
|
+
function close(pane) {
|
|
176
|
+
pane.filterQuery = ""
|
|
177
|
+
pane.filterTyping = false
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// The new query is applied here rather than by writing the property alone, because the selection has
|
|
181
|
+
// to lose the rows that just dropped out before anything can act on rows nobody can see. The next
|
|
182
|
+
// match list is computed rather than read back off the pane's binding, so the order is not a guess.
|
|
183
|
+
function apply(pane, query) {
|
|
184
|
+
var next = shown(pane.rows, pane.held, query)
|
|
185
|
+
prune(pane, next)
|
|
186
|
+
if (query !== pane.filterQuery) pane.filterKeyAt = Date.now()
|
|
187
|
+
pane.filterQuery = query
|
|
188
|
+
if (query.length > 0) pane.filterNarrowedAt = Date.now()
|
|
189
|
+
// A cursor the filter just hid takes the first row still standing, so it is never off screen.
|
|
190
|
+
if (next !== null && next.length > 0 && viewOf(next, pane.cursorIndex) < 0) {
|
|
191
|
+
pane.cursorIndex = next[0]
|
|
192
|
+
pane.cursorSeq += 1
|
|
193
|
+
pane.showRow(0)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// A selection you cannot see is one you can act on by accident, and trash, cut and copy all take the
|
|
198
|
+
// selection with no confirmation at all: what the filter hides, it takes out of the selection too.
|
|
199
|
+
function prune(pane, list) {
|
|
200
|
+
if (list === null) {
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
var drawn = {}
|
|
204
|
+
for (var i = 0; i < list.length; i++) {
|
|
205
|
+
drawn[list[i]] = true
|
|
206
|
+
}
|
|
207
|
+
var was = pane.selectedIndices()
|
|
208
|
+
var dropped = 0
|
|
209
|
+
for (var j = 0; j < was.length; j++) {
|
|
210
|
+
if (drawn[was[j]] !== true) {
|
|
211
|
+
pane.selection.toggle(was[j])
|
|
212
|
+
dropped += 1
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (dropped > 0) {
|
|
216
|
+
pane.selectionVersion += 1
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Cursor is a listing row but moves through drawn rows, so both steps convert.
|
|
221
|
+
function setCursor(pane, index, context) {
|
|
222
|
+
setCursorView(pane, viewOf(pane.shown, index), context)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function setCursorView(pane, view, context) {
|
|
226
|
+
if (pane.shownTotal === 0) {
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
var to = Math.max(0, Math.min(pane.shownTotal - 1, view))
|
|
230
|
+
pane.cursorIndex = at(pane.shown, to)
|
|
231
|
+
// Every cursor setter bumps cursorSeq, so a plain move ends a Shift gesture.
|
|
232
|
+
pane.cursorSeq += 1
|
|
233
|
+
pane.showRow(to, context)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function moveCursor(pane, delta) {
|
|
237
|
+
setCursorView(pane, viewOf(pane.shown, pane.cursorIndex) + delta)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// The wheel moved the viewport and the cursor follows it. Both ends are view positions, because
|
|
241
|
+
// under a filter the listing rows they name are not a run and a numeric clamp would be meaningless.
|
|
242
|
+
function clampCursor(pane, first, last) {
|
|
243
|
+
var was = viewOf(pane.shown, pane.cursorIndex)
|
|
244
|
+
var to = Math.max(first, Math.min(last, was))
|
|
245
|
+
if (to !== was) {
|
|
246
|
+
var held = pulledFrom(pane)
|
|
247
|
+
var from = held >= 0 ? held : pane.cursorIndex
|
|
248
|
+
pane.cursorIndex = at(pane.shown, to)
|
|
249
|
+
pane.cursorSeq = (pane.cursorSeq || 0) + 1
|
|
250
|
+
pane.cursorPulled = { from: from, to: pane.cursorIndex, seq: pane.cursorSeq, version: pane.selectionVersion }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// The row the cursor held before the wheel pulled it, while no move, mark or new listing came since (issue 286); else -1.
|
|
255
|
+
function pulledFrom(pane) {
|
|
256
|
+
var pull = pane.cursorPulled
|
|
257
|
+
var current = pull && pull.seq === (pane.cursorSeq || 0) && pull.to === pane.cursorIndex
|
|
258
|
+
&& pull.version === pane.selectionVersion
|
|
259
|
+
return current ? pull.from : -1
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// The query line's own keys while it has the caret, the shape ui/js/Search.js typeKey uses for the
|
|
263
|
+
// search's. Enter commits, escape abandons, backspace shortens, every printable character narrows.
|
|
264
|
+
function typeKey(event, pane) {
|
|
265
|
+
// Ctrl+V and Shift+Insert type the clipboard's first line as one narrowing (issue 287).
|
|
266
|
+
if (Input.isPasteKey(event))
|
|
267
|
+
return Input.pasteInto(pane, function (text) { typed(pane, text) })
|
|
268
|
+
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
|
269
|
+
commit(pane)
|
|
270
|
+
return true
|
|
271
|
+
}
|
|
272
|
+
if (event.key === Qt.Key_Escape) {
|
|
273
|
+
close(pane)
|
|
274
|
+
return true
|
|
275
|
+
}
|
|
276
|
+
if (event.key === Qt.Key_Backspace) {
|
|
277
|
+
backspace(pane)
|
|
278
|
+
return true
|
|
279
|
+
}
|
|
280
|
+
if (Input.isPrintable(event.text)) {
|
|
281
|
+
typed(pane, event.text)
|
|
282
|
+
return true
|
|
283
|
+
}
|
|
284
|
+
return true
|
|
285
|
+
}
|
package/ui/js/Find.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// Match names by default; a forward slash explicitly asks for a relative path.
|
|
4
|
+
// find emits slash-separated paths on Windows too (bunmsh's builtin), so the
|
|
5
|
+
// query is never rewritten to backslashes, which would become glob escapes.
|
|
6
|
+
function expression(query, hidden) {
|
|
7
|
+
var pattern = /[*?[]/.test(query) ? query : "*" + query + "*"
|
|
8
|
+
var predicate = query.indexOf("/") >= 0 ? "-ipath" : "-iname"
|
|
9
|
+
return hidden ? [predicate, pattern]
|
|
10
|
+
: ["-mindepth", "1", "-name", ".*", "-prune", "-o", predicate, pattern, "-print"]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// flea-qml: Ctrl+G's content search, `grep -r` with the query as literal text. Each file reports
|
|
14
|
+
// its first matching line (-m 1), binary files included (-a), case ignored as -iname ignores it.
|
|
15
|
+
// -o with CONTEXT characters either side bounds every output line, so a match inside a huge line
|
|
16
|
+
// (a minified script, a binary with no line ends) still arrives as a short snippet around the
|
|
17
|
+
// match. -Z ends the file name with NUL, so a name holding ":" parses. With no path operand grep
|
|
18
|
+
// walks "." and names files without "./"; hidden names are skipped as find prunes them, and the
|
|
19
|
+
// bare "." is never excluded by --exclude-dir.
|
|
20
|
+
var CONTEXT = 80
|
|
21
|
+
var SNIPPET_LIMIT = 300
|
|
22
|
+
function escapeRegex(text) {
|
|
23
|
+
return String(text).replace(/[\\^$.*+?()[\]{}|]/g, "\\$&")
|
|
24
|
+
}
|
|
25
|
+
function grepArguments(query, hidden) {
|
|
26
|
+
var args = ["-r", "-n", "-o", "-a", "-i", "-m", "1", "-Z", "--line-buffered", "-E"]
|
|
27
|
+
if (!hidden) args.push("--exclude=.*", "--exclude-dir=.*")
|
|
28
|
+
return args.concat(["-e", ".{0," + CONTEXT + "}" + escapeRegex(query) + ".{0," + CONTEXT + "}"])
|
|
29
|
+
}
|
|
30
|
+
// One output line "name\0line:text" as {path, line, text}, or null for anything else.
|
|
31
|
+
function grepLine(raw) {
|
|
32
|
+
var line = String(raw)
|
|
33
|
+
var cut = line.indexOf("\u0000")
|
|
34
|
+
if (cut <= 0) return null
|
|
35
|
+
var rest = line.substring(cut + 1)
|
|
36
|
+
var number = /^(\d+):/.exec(rest)
|
|
37
|
+
if (!number) return null
|
|
38
|
+
return { path: line.substring(0, cut), line: Number(number[1]), text: snippet(rest.substring(number[0].length)) }
|
|
39
|
+
}
|
|
40
|
+
// Control characters (a binary's NULs among them) and undecodable bytes become a middle dot and tabs a space, so the
|
|
41
|
+
// row's single line of PlainText never breaks or hides; the text is cut at SNIPPET_LIMIT.
|
|
42
|
+
function snippet(text) {
|
|
43
|
+
var cut = text.length > SNIPPET_LIMIT ? text.substring(0, SNIPPET_LIMIT) : text
|
|
44
|
+
// U+FFFD is a byte that was not UTF-8, as a binary holds many; it is shown the same way.
|
|
45
|
+
return cut.replace(/\t/g, " ").replace(/[\u0000-\u001f\u007f\ufffd]/g, "\u00b7").trim()
|
|
46
|
+
}
|
package/ui/js/Flash.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
|
|
5
|
+
// The model behind ui/FlashView.qml, checked headless; every string is a whole template filled by one function.
|
|
6
|
+
|
|
7
|
+
// One pass over the placeholders, so a value that holds a placeholder is never read twice.
|
|
8
|
+
function fill(template, values) {
|
|
9
|
+
return String(template).replace(/\{(\w+)\}/g, function (whole, key) {
|
|
10
|
+
return Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : whole
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function leaf(path) {
|
|
15
|
+
var cut = String(path || "").lastIndexOf("/")
|
|
16
|
+
return cut >= 0 ? String(path).substring(cut + 1) : String(path)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// A drive fits when the backend refused it for no reason.
|
|
20
|
+
function fits(drive) {
|
|
21
|
+
return !drive || drive.refused === ""
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// An SD card reports through mmcblk, so its read-only row names the lock switch.
|
|
25
|
+
function isCard(dev) {
|
|
26
|
+
return String((dev || "")).indexOf("mmcblk") === 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Refusal hints, each one whole sentence.
|
|
30
|
+
var HINT_SMALL = "It is too small for the image."
|
|
31
|
+
var HINT_LOCK = "Its lock switch is on. Slide the switch off and plug the card in again."
|
|
32
|
+
var HINT_READONLY = "It is read-only, so Flea cannot write to it."
|
|
33
|
+
var HINT_HOLDS_IMAGE = "The image is on this drive. Copy it elsewhere first."
|
|
34
|
+
var HINT_MEMBER = "It is part of a RAID or volume group."
|
|
35
|
+
var HINT_NOT_IMAGE = "This file is not a disk image."
|
|
36
|
+
|
|
37
|
+
// The refusal hint under a refused drive row, the boards' own wording.
|
|
38
|
+
function refusedHint(drive) {
|
|
39
|
+
var refused = drive ? drive.refused : ""
|
|
40
|
+
if (refused === "small")
|
|
41
|
+
return HINT_SMALL
|
|
42
|
+
if (refused === "readonly")
|
|
43
|
+
return isCard(drive.dev) ? HINT_LOCK : HINT_READONLY
|
|
44
|
+
if (refused === "holdsimage")
|
|
45
|
+
return HINT_HOLDS_IMAGE
|
|
46
|
+
if (refused === "member")
|
|
47
|
+
return HINT_MEMBER
|
|
48
|
+
return ""
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// The label, or the model where no volume label names it; a repeated label gains the kernel name.
|
|
52
|
+
function driveName(drive, drives) {
|
|
53
|
+
var label = drive.label && drive.label.length > 0 ? drive.label : drive.model
|
|
54
|
+
var twins = 0
|
|
55
|
+
for (var i = 0; i < (drives || []).length; i++) {
|
|
56
|
+
var other = drives[i].label && drives[i].label.length > 0 ? drives[i].label : drives[i].model
|
|
57
|
+
if (other === label)
|
|
58
|
+
twins += 1
|
|
59
|
+
}
|
|
60
|
+
return twins > 1 ? fill("{label} ({dev})", { label: label, dev: drive.dev }) : label
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The detail column, empty when it would repeat the label.
|
|
64
|
+
function driveDetail(drive, drives) {
|
|
65
|
+
var model = drive.model || ""
|
|
66
|
+
return model === driveName(drive, drives) ? "" : model
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The compressed image's unpacked size in the detail column.
|
|
70
|
+
function unpackedLine(bytes) {
|
|
71
|
+
return fill("{size} unpacked", { size: Format.size(bytes) })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// One drive that fits is chosen for you; with two or more none is.
|
|
75
|
+
function preselect(drives) {
|
|
76
|
+
var found = -1
|
|
77
|
+
for (var i = 0; i < (drives || []).length; i++) {
|
|
78
|
+
if (!fits(drives[i]))
|
|
79
|
+
continue
|
|
80
|
+
if (found >= 0)
|
|
81
|
+
return -1
|
|
82
|
+
found = i
|
|
83
|
+
}
|
|
84
|
+
return found
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Cursor positions: 0 is the image, 1 to n the drives, n + 1 the Flash step.
|
|
88
|
+
function flashPos(driveCount) {
|
|
89
|
+
return 1 + (driveCount || 0)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The cursor walk skips refused rows, so a refused drive is never the choice.
|
|
93
|
+
function step(cursor, delta, drives, hasImage, flashLive) {
|
|
94
|
+
var count = flashPos((drives || []).length) + 1
|
|
95
|
+
var at = cursor + delta
|
|
96
|
+
while (at >= 0 && at < count) {
|
|
97
|
+
if (at === 0 && hasImage)
|
|
98
|
+
return at
|
|
99
|
+
if (at > 0 && at <= (drives || []).length && fits(drives[at - 1]))
|
|
100
|
+
return at
|
|
101
|
+
if (at === flashPos((drives || []).length) && flashLive)
|
|
102
|
+
return at
|
|
103
|
+
at += delta
|
|
104
|
+
}
|
|
105
|
+
return cursor
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Flash is live only when an image and a fitting drive are both chosen.
|
|
109
|
+
function flashLive(imageOk, drive) {
|
|
110
|
+
return imageOk === true && !!drive && fits(drive)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The greyed row names the chosen drive, or the drive in general when none is chosen.
|
|
114
|
+
var ERASE_NAMED = "Erases everything on {drive}"
|
|
115
|
+
var ERASE_BARE = "Erases everything on the drive"
|
|
116
|
+
var FLASH_NAMED = "Flash {drive}"
|
|
117
|
+
var FLASH_BARE = "Flash"
|
|
118
|
+
|
|
119
|
+
function flashWords(imageOk, drive, drives) {
|
|
120
|
+
var name = drive ? driveName(drive, drives) : ""
|
|
121
|
+
if (!imageOk || !name)
|
|
122
|
+
return { erase: ERASE_BARE, action: FLASH_BARE }
|
|
123
|
+
return { erase: fill(ERASE_NAMED, { drive: name }), action: fill(FLASH_NAMED, { drive: name }) }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Ending headlines and hints live in ui/js/FlashEndings.js, beside the table they serve.
|
|
127
|
+
|
|
128
|
+
// The card's heads and byte lines: one template each, {f:key} spans ink as figures.
|
|
129
|
+
var FLASH_HEAD_WRITING = "Flashing {drive}"
|
|
130
|
+
var FLASH_HEAD_VERIFYING = "Verifying {drive}"
|
|
131
|
+
var FLASH_WAIT_PASSWORD = "waiting for your password"
|
|
132
|
+
var FLASH_FILE_KNOWN = "{name} · {size}"
|
|
133
|
+
var FLASH_FLUSH_LINE = "{f:bytes} written · waiting for the drive"
|
|
134
|
+
var FLASH_KNOWN_LINE = "{f:moved} of {f:total} · {f:rate}{f:unit} · {f:left} left"
|
|
135
|
+
var FLASH_KNOWN_STALLED = "{f:moved} of {f:total} · {f:rate}{f:unit}"
|
|
136
|
+
var FLASH_UNKNOWN_LINE = "{f:moved} written · {f:rate}{f:unit} · {f:left} left"
|
|
137
|
+
var FLASH_UNKNOWN_STALLED = "{f:moved} written · {f:rate}{f:unit}"
|
|
138
|
+
|
|
139
|
+
// The status bar counts the pane's drives, never the covered folder: whole-sentence variants.
|
|
140
|
+
var DRIVES_LINE = "{count} drives"
|
|
141
|
+
var ONE_DRIVE_LINE = "1 drive"
|
|
142
|
+
|
|
143
|
+
// A second pane cannot take the host while a flash runs.
|
|
144
|
+
var ALREADY_RUNNING = "A flash is already running. Wait for it to finish."
|
|
145
|
+
|
|
146
|
+
function drivesLine(n) {
|
|
147
|
+
return n === 1 ? ONE_DRIVE_LINE : fill(DRIVES_LINE, { count: Format.count(n) })
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function alreadyRunning() {
|
|
151
|
+
return ALREADY_RUNNING
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// A rail volume names its whole disk: sda1 is sda, sdp1 is sdp, nvme0n1p2 is nvme0n1, and mmcblk0 names itself.
|
|
155
|
+
function railDisk(device) {
|
|
156
|
+
var name = leaf(device)
|
|
157
|
+
var numbered = /^(.*[0-9])p[0-9]+$/.exec(name)
|
|
158
|
+
if (numbered)
|
|
159
|
+
return numbered[1]
|
|
160
|
+
var lettered = /^((?:sd|vd|hd|xvd)[a-z]+)[0-9]+$/.exec(name)
|
|
161
|
+
return lettered ? lettered[1] : name
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// The unpacked size shows only for a compressed image whose file records it; a raw image's size is its own.
|
|
165
|
+
function imageDetail(image) {
|
|
166
|
+
var raw = !image || image.kind === "iso" || image.kind === "img"
|
|
167
|
+
return !raw && image.known === true && image.unpacked > 0 ? unpackedLine(image.unpacked) : ""
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// The card's image from a flashimage reply, or null when the reply answers another file's probe, such as the pane's zip check.
|
|
171
|
+
function imageFrom(current, message) {
|
|
172
|
+
if (!current || !message || message.path !== current.path)
|
|
173
|
+
return null
|
|
174
|
+
var kind = message.kind || ""
|
|
175
|
+
return { path: current.path, kind: kind, bytes: message.bytes || 0, unpacked: message.unpacked || 0,
|
|
176
|
+
known: message.known === true, member: message.member || "", refused: kind === "" }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// The Flash row's label ink: the erase line wears the warning's red with its triangle, the running head the foreground.
|
|
180
|
+
function stepRole(running, ending) {
|
|
181
|
+
if (ending)
|
|
182
|
+
return ending.role
|
|
183
|
+
return running ? "foreground" : "error"
|
|
184
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Flash.js" as Flash
|
|
4
|
+
.import "Format.js" as Format
|
|
5
|
+
|
|
6
|
+
// The flash card's rendering, imported only by the lazy flasher so no startup file compiles it.
|
|
7
|
+
|
|
8
|
+
// One template fill into inked parts: {f:key} spans become figures, the rest words.
|
|
9
|
+
function lined(template, values) {
|
|
10
|
+
var parts = [], text = "", at = 0
|
|
11
|
+
while (at < template.length) {
|
|
12
|
+
var open = template.indexOf("{f:", at)
|
|
13
|
+
if (open < 0) {
|
|
14
|
+
text += template.substring(at)
|
|
15
|
+
break
|
|
16
|
+
}
|
|
17
|
+
text += template.substring(at, open)
|
|
18
|
+
var close = template.indexOf("}", open)
|
|
19
|
+
if (text.length > 0) {
|
|
20
|
+
parts.push({ text: text, figure: false })
|
|
21
|
+
text = ""
|
|
22
|
+
}
|
|
23
|
+
parts.push({ text: String(values[template.substring(open + 3, close)]), figure: true })
|
|
24
|
+
at = close + 1
|
|
25
|
+
}
|
|
26
|
+
if (text.length > 0)
|
|
27
|
+
parts.push({ text: text, figure: false })
|
|
28
|
+
return parts
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function head(t) {
|
|
32
|
+
return Flash.fill(t.phase === "verify" ? Flash.FLASH_HEAD_VERIFYING : Flash.FLASH_HEAD_WRITING,
|
|
33
|
+
{ drive: t.drive })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function file(t) {
|
|
37
|
+
return t.total > 0 ? Flash.fill(Flash.FLASH_FILE_KNOWN, { name: t.name, size: Format.size(t.total) }) : t.name
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The total a flash measures against: the known size, else the share the unpacker reports scaled up, else 0.
|
|
41
|
+
function total(t) {
|
|
42
|
+
if (t.known === true && t.total > 0)
|
|
43
|
+
return t.total
|
|
44
|
+
var moved = t.bytes || 0
|
|
45
|
+
return (t.permille || 0) > 0 && moved > 0 ? Math.round(moved * 1000 / t.permille) : 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parts(t, rate) {
|
|
49
|
+
if (t.phase === "prepare" || t.phase === "password")
|
|
50
|
+
return [{ text: Flash.FLASH_WAIT_PASSWORD, figure: false }]
|
|
51
|
+
if (t.phase === "flush")
|
|
52
|
+
return t.bytes > 0 ? lined(Flash.FLASH_FLUSH_LINE, { bytes: Format.size(t.bytes) }) : []
|
|
53
|
+
var moved = t.bytes || 0
|
|
54
|
+
if (moved <= 0)
|
|
55
|
+
return []
|
|
56
|
+
var whole = total(t)
|
|
57
|
+
var values = { moved: Format.size(moved), rate: Format.size(rate), unit: "/s" }
|
|
58
|
+
if (whole > 0)
|
|
59
|
+
values.total = Format.size(whole)
|
|
60
|
+
if (whole > 0 && rate > 0)
|
|
61
|
+
values.left = Format.duration(Math.max(0, whole - moved) / rate * 1000)
|
|
62
|
+
if (t.known === true && t.total > 0)
|
|
63
|
+
return lined(values.left !== undefined ? Flash.FLASH_KNOWN_LINE : Flash.FLASH_KNOWN_STALLED, values)
|
|
64
|
+
return lined(values.left !== undefined ? Flash.FLASH_UNKNOWN_LINE : Flash.FLASH_UNKNOWN_STALLED, values)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function share(t) {
|
|
68
|
+
if (t.known === true && t.total > 0)
|
|
69
|
+
return (t.bytes || 0) / t.total
|
|
70
|
+
return (t.permille || 0) / 1000
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// One render of every line a flash draws, stored on the transfer by the runner.
|
|
74
|
+
function render(t, rate) {
|
|
75
|
+
var lines = parts(t, rate)
|
|
76
|
+
var at = share(t)
|
|
77
|
+
return { headText: head(t), fileText: file(t), byteText: lines,
|
|
78
|
+
share: at < 0 ? 0 : (at > 1 ? 1 : at), noCancel: t.phase === "flush" }
|
|
79
|
+
}
|