flea-qml 0.0.0-stage → 0.1.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 +478 -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 +402 -0
- package/src/archiveops.js +697 -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 +129 -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/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +326 -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 +241 -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-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-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -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 +68 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +771 -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 +523 -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 +115 -0
- package/ui/Pane.qml +1296 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +239 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +605 -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 +1004 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +66 -0
- package/ui/PreviewColumn.qml +551 -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 +38 -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 +732 -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/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 +827 -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 +122 -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 +364 -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 +502 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +305 -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 +736 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +174 -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 +81 -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 +228 -0
package/ui/PathEntry.qml
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import qs.Commons
|
|
3
|
+
import "js/PathBar.js" as PathBar
|
|
4
|
+
|
|
5
|
+
// The path bar's typed half for the main chrome and the picker: field, frame, Jump dropdown and Tab; hosts answer its commits.
|
|
6
|
+
Item {
|
|
7
|
+
id: root
|
|
8
|
+
|
|
9
|
+
property string path: ""
|
|
10
|
+
property string home: ""
|
|
11
|
+
// Read by the path bar alone, so a Tab on a dotted leaf peeks the way the listing is set to look.
|
|
12
|
+
property bool showHidden: false
|
|
13
|
+
|
|
14
|
+
// The commit and the jump's choice, which each host answers for itself.
|
|
15
|
+
signal commitLine(string text)
|
|
16
|
+
signal jumpChosen(string path)
|
|
17
|
+
signal editClosed()
|
|
18
|
+
signal completeRequested(string dir, bool hidden)
|
|
19
|
+
signal said(string text)
|
|
20
|
+
// The folder jump's one read per open, carried to the pane's backend like Tab's peek; see ui/PathJump.qml.
|
|
21
|
+
signal jumpRequested(int id, int ranking, var favourites, var recent)
|
|
22
|
+
|
|
23
|
+
// Built by the first edit and kept for the window's life, so a bar never opened compiles none of it.
|
|
24
|
+
property bool jumpBuilt: false
|
|
25
|
+
readonly property var jump: jumpLoader.item
|
|
26
|
+
readonly property bool jumpShown: jumpLoader.item !== null && jumpLoader.item.shown
|
|
27
|
+
// What the seam reads: the line as it stands.
|
|
28
|
+
readonly property alias editText: field.text
|
|
29
|
+
// The open field and its frame, so a test measures where they lie in the strip.
|
|
30
|
+
readonly property alias pathFrame: editFrame
|
|
31
|
+
readonly property alias pathField: field
|
|
32
|
+
|
|
33
|
+
// The Tab request in flight and the one that came back, keyed by path and hidden flag, so a Tab on ".conf" never answers off rows peeked without dotfiles.
|
|
34
|
+
property string pendingKey: ""
|
|
35
|
+
property string cachedKey: ""
|
|
36
|
+
property var cachedNames: []
|
|
37
|
+
|
|
38
|
+
// The strip typed instead of drawn: keys.toml's pathBar action (":" and Ctrl+L) and a double click on the path open it.
|
|
39
|
+
property bool editing: false
|
|
40
|
+
|
|
41
|
+
function startEdit() {
|
|
42
|
+
if (root.editing) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
// The Loader below is synchronous, so the jump stands before this returns.
|
|
46
|
+
root.jumpBuilt = true
|
|
47
|
+
root.editing = true
|
|
48
|
+
// The trailing slash makes a child the next keystroke, and the line opens selected so a typed name replaces it.
|
|
49
|
+
field.text = PathBar.editLine(root.path)
|
|
50
|
+
field.forceActiveFocus()
|
|
51
|
+
field.selectAll()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function closeEdit() {
|
|
55
|
+
if (!root.editing) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
root.editing = false
|
|
59
|
+
root.pendingKey = ""
|
|
60
|
+
root.cachedKey = ""
|
|
61
|
+
root.cachedNames = []
|
|
62
|
+
// The field is in no focus scope of its own, so the keyboard goes nowhere until the host answers editClosed.
|
|
63
|
+
root.editClosed()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Tab completes from the backend's peek, the read the columns view already makes, so it costs no new request type.
|
|
67
|
+
function completeEdit() {
|
|
68
|
+
// A virtual root has no filesystem completion; never send it to peek.
|
|
69
|
+
if (PathBar.isTrashRoot(field.text)) return
|
|
70
|
+
var dir = PathBar.completionDir(field.text, PathBar.isTrashRoot(root.path) ? "/" : root.path, root.home)
|
|
71
|
+
var hidden = PathBar.wantsHidden(field.text, root.showHidden)
|
|
72
|
+
var key = PathBar.requestKey(dir, hidden)
|
|
73
|
+
if (key === root.cachedKey) {
|
|
74
|
+
root.applyCompletion(dir, root.cachedNames)
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
root.pendingKey = key
|
|
78
|
+
root.completeRequested(dir, hidden)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Column peeks and a Tab's dotfile retry share the wire, so a reply matches on the echoed (dir, hidden) pair; only directories complete.
|
|
82
|
+
function completeWith(dir, hidden, rows) {
|
|
83
|
+
if (PathBar.requestKey(dir, hidden) !== root.pendingKey) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
var names = []
|
|
87
|
+
for (var i = 0; i < rows.length; i++) {
|
|
88
|
+
if (rows[i].d) {
|
|
89
|
+
names.push(rows[i].n)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
root.cachedKey = root.pendingKey
|
|
93
|
+
root.cachedNames = names
|
|
94
|
+
root.pendingKey = ""
|
|
95
|
+
if (root.editing && PathBar.completionDir(field.text, PathBar.isTrashRoot(root.path) ? "/" : root.path, root.home) === dir) {
|
|
96
|
+
root.applyCompletion(dir, names)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function applyCompletion(dir, names) {
|
|
101
|
+
var before = field.text
|
|
102
|
+
var after = PathBar.complete(before, names)
|
|
103
|
+
field.text = after.text
|
|
104
|
+
field.cursorPosition = field.text.length
|
|
105
|
+
var say = PathBar.completionMessage(before, after, dir)
|
|
106
|
+
if (say.length > 0) {
|
|
107
|
+
root.said(say)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// The rename editor's own frame, at chrome scale: the accent marks the strip with the keyboard, and its fill covers the two Texts beneath.
|
|
112
|
+
Rectangle {
|
|
113
|
+
id: editFrame
|
|
114
|
+
visible: root.editing
|
|
115
|
+
anchors.fill: parent
|
|
116
|
+
anchors.topMargin: Theme.spacing.hairline * 2
|
|
117
|
+
// One below against two above centres the field in the strip, which is the flush dropdown the Jump board draws.
|
|
118
|
+
anchors.bottomMargin: Theme.spacing.hairline
|
|
119
|
+
color: Theme.color.background
|
|
120
|
+
radius: Style.cornerRadius
|
|
121
|
+
border.width: Theme.spacing.hairline
|
|
122
|
+
border.color: Theme.color.accent
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// corner: a typed path is arbitrary text, drawn at the size of the path it replaces, the caret on the line.
|
|
126
|
+
TextInput {
|
|
127
|
+
id: field
|
|
128
|
+
visible: root.editing
|
|
129
|
+
enabled: root.editing
|
|
130
|
+
anchors.fill: parent
|
|
131
|
+
anchors.leftMargin: Theme.spacing.gap
|
|
132
|
+
anchors.rightMargin: Theme.spacing.gap
|
|
133
|
+
verticalAlignment: TextInput.AlignVCenter
|
|
134
|
+
color: Theme.color.foreground
|
|
135
|
+
selectionColor: Theme.color.accent
|
|
136
|
+
selectedTextColor: Theme.color.background
|
|
137
|
+
font.family: Theme.font.family
|
|
138
|
+
font.pixelSize: Theme.font.caption
|
|
139
|
+
clip: true
|
|
140
|
+
// The jump's dropdown takes the arrows and Enter first, and only while it is showing rows.
|
|
141
|
+
Keys.forwardTo: root.jump !== null ? [root.jump] : []
|
|
142
|
+
|
|
143
|
+
// Each key here is accepted, as in ui/RenameField.qml: the pane would read an unaccepted Return as "open the row" and Tab as "move to the rail".
|
|
144
|
+
Keys.onPressed: function (event) {
|
|
145
|
+
if (event.key === Qt.Key_Escape) {
|
|
146
|
+
root.closeEdit()
|
|
147
|
+
event.accepted = true
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
|
151
|
+
root.commitLine(field.text)
|
|
152
|
+
event.accepted = true
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) {
|
|
156
|
+
root.completeEdit()
|
|
157
|
+
event.accepted = true
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Losing the keyboard closes the bar, as the rename editor does, so it never commits against a window that has moved on.
|
|
162
|
+
onActiveFocusChanged: if (!activeFocus && root.editing) root.closeEdit()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The Jump board's dropdown, flush under this field at its width from the path slot its Loader fills.
|
|
166
|
+
Loader {
|
|
167
|
+
id: jumpLoader
|
|
168
|
+
anchors.fill: parent
|
|
169
|
+
active: root.jumpBuilt
|
|
170
|
+
asynchronous: false
|
|
171
|
+
source: "PathJump.qml"
|
|
172
|
+
// Live bindings onto the lazy item, kept after the bar closes; set here so a bar never opened adds no Binding objects.
|
|
173
|
+
onLoaded: {
|
|
174
|
+
item.editing = Qt.binding(function () { return root.editing })
|
|
175
|
+
item.query = Qt.binding(function () { return field.text })
|
|
176
|
+
item.home = Qt.binding(function () { return root.home })
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
Connections {
|
|
180
|
+
target: jumpLoader.item
|
|
181
|
+
function onRequested(id, ranking, favourites, recent) { root.jumpRequested(id, ranking, favourites, recent) }
|
|
182
|
+
function onDeclined() { root.commitLine(field.text) }
|
|
183
|
+
function onDismissed() { root.closeEdit() }
|
|
184
|
+
function onChosen(path) { root.jumpChosen(path) }
|
|
185
|
+
}
|
|
186
|
+
}
|
package/ui/PathJump.qml
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import Quickshell
|
|
3
|
+
import Quickshell.Io
|
|
4
|
+
import qs.Commons
|
|
5
|
+
import "." as Flea
|
|
6
|
+
import "js/Jump.js" as Jump
|
|
7
|
+
import "js/Recent.js" as Recent
|
|
8
|
+
|
|
9
|
+
// The path bar's folder jump, the Jump board: a name typed into the bar lists matching folders from
|
|
10
|
+
// Flea's favourites, zoxide's ranking and the desktop's recent history in a dropdown flush under the
|
|
11
|
+
// field, at its width and in the menu recipe. ui/ChromeBar.qml owns the field and forwards its keys
|
|
12
|
+
// here; ui/js/Jump.js decides the rows. Nothing is written anywhere, and zoxide is asked once per open.
|
|
13
|
+
Item {
|
|
14
|
+
id: root
|
|
15
|
+
|
|
16
|
+
property bool editing: false
|
|
17
|
+
// The field's line as typed; ui/js/Jump.js decides whether it is a name to jump by or a path.
|
|
18
|
+
property string query: ""
|
|
19
|
+
property string home: ""
|
|
20
|
+
// The tallest the dropdown may be before it scrolls: the window less the chrome strip above and the
|
|
21
|
+
// status bar below, both a chrome strip tall, and a gap clear of the status bar.
|
|
22
|
+
readonly property real room: (root.Window.window ? root.Window.window.height : 0) - 2 * Theme.chromeHeight - Theme.spacing.gap
|
|
23
|
+
|
|
24
|
+
// The backend's answer for this open, { favourites, zoxide, recent }, empty until it arrives.
|
|
25
|
+
property var sources: ({})
|
|
26
|
+
readonly property bool answered: root.sources.favourites !== undefined
|
|
27
|
+
// The same answer folded once for ranking: every keystroke ranks out of this instead of folding
|
|
28
|
+
// every candidate again, so a keystroke costs the alignment alone. Dropped with sources below,
|
|
29
|
+
// so one open never keeps the next one's folds.
|
|
30
|
+
property var prepared: null
|
|
31
|
+
// Tab is the path bar's own completion, so a line it has touched is a path for the rest of the edit:
|
|
32
|
+
// with two children sharing a prefix it stops short of the slash, and Enter still means ./that.
|
|
33
|
+
property bool pathTyped: false
|
|
34
|
+
readonly property var entries: root.editing && !root.pathTyped && root.prepared !== null
|
|
35
|
+
? Jump.rowsPrepared(root.prepared, root.query) : []
|
|
36
|
+
property int cursor: -1
|
|
37
|
+
readonly property bool shown: root.entries.length > 0
|
|
38
|
+
// The high-water row count of this open: the Repeater holds this many delegates standing and
|
|
39
|
+
// hides the tail past the entries, so a keystroke that narrows the list rebinds rows instead
|
|
40
|
+
// of rebuilding them. Reset with the open below.
|
|
41
|
+
property int rowHighWater: 0
|
|
42
|
+
// Every ask carries a new id and take() keeps only the newest open's answers, so a slow answer to
|
|
43
|
+
// an earlier ask can never land in this one, or move a cursor the user has already moved.
|
|
44
|
+
property int asked: 0
|
|
45
|
+
// An open whose history is stale asks twice: a provisional ask with what is kept, so the
|
|
46
|
+
// dropdown fills from the backend's answer instead of waiting out the history read, and the whole
|
|
47
|
+
// ask under a new id once the read lands. take() shows the provisional rows but only the whole
|
|
48
|
+
// answer spends a held Enter or settles wholeTaken; a provisional answer landing after the whole
|
|
49
|
+
// one is dropped like a stale one. The whole ask waits for the provisional answer as well as the
|
|
50
|
+
// read, so the two backend calls never overlap on the backend's one zoxide slot.
|
|
51
|
+
property int provisionalId: 0
|
|
52
|
+
property bool wholeTaken: false
|
|
53
|
+
// The provisional answer has landed, and the whole ask has been sent; one whole ask per open.
|
|
54
|
+
property bool provTaken: false
|
|
55
|
+
property bool wholeAsked: false
|
|
56
|
+
// Enter on a name before this open's answer is in: held, then taken by the answer, so the same keys
|
|
57
|
+
// open the same folder however fast they were typed.
|
|
58
|
+
property bool enterWaiting: false
|
|
59
|
+
// Where any row last saw the pointer, so rows changing under a resting pointer never move the cursor; see ui/MenuRow.qml.
|
|
60
|
+
property point pointerGlobal: Qt.point(-1, -1)
|
|
61
|
+
// Rows appearing under a resting pointer must not take the cursor either: moves are ignored
|
|
62
|
+
// until the first frame after rows appear, the way ui/ContextMenu.qml settles them.
|
|
63
|
+
property bool pointerSettling: false
|
|
64
|
+
Connections {
|
|
65
|
+
target: root.pointerSettling ? root.Window.window : null
|
|
66
|
+
function onAfterAnimating() { root.pointerSettling = false }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ui/WindowBody.qml carries these to the pane's backend and back, the way it carries the bar's Tab.
|
|
70
|
+
// ranking is the provisional ask this whole ask follows, or 0: the backend answers it from that ask's zoxide run.
|
|
71
|
+
signal requested(int id, int ranking, var favourites, var recent)
|
|
72
|
+
signal chosen(string path)
|
|
73
|
+
// Enter that the dropdown did not take after all: nothing matched, so the bar resolves the line as a path.
|
|
74
|
+
signal declined()
|
|
75
|
+
// A click on the dropdown's own padding: the bar closes with nothing opened, the menu recipe.
|
|
76
|
+
signal dismissed()
|
|
77
|
+
// For tests/jump-ui.sh: whether the dropdown's frame stands, and the frame itself while it does.
|
|
78
|
+
readonly property bool dropBuilt: drop.item !== null
|
|
79
|
+
readonly property var dropItem: drop.item
|
|
80
|
+
|
|
81
|
+
// The keys arrive through the field's Keys.forwardTo, which skips an invisible item, so this stays
|
|
82
|
+
// visible for the whole edit and hands back every key it does not use; only the dropdown unloads.
|
|
83
|
+
visible: root.editing
|
|
84
|
+
// The parent is the bar's path slot, which stops a hairline above the strip's bottom edge.
|
|
85
|
+
y: root.parent ? root.parent.height + Theme.spacing.hairline : 0
|
|
86
|
+
width: root.parent ? root.parent.width : 0
|
|
87
|
+
height: drop.item ? drop.item.height : 0
|
|
88
|
+
|
|
89
|
+
onEntriesChanged: {
|
|
90
|
+
root.rowHighWater = Math.max(root.rowHighWater, root.entries.length)
|
|
91
|
+
root.cursor = Jump.step(root.entries, -1, 1)
|
|
92
|
+
}
|
|
93
|
+
// The rows live behind the Loader below, so a cursor moved while they stand unbuilt asks nothing.
|
|
94
|
+
onCursorChanged: { if (drop.item) drop.item.reveal(root.cursor) }
|
|
95
|
+
onShownChanged: {
|
|
96
|
+
if (!root.shown) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
root.pointerGlobal = Qt.point(-1, -1)
|
|
100
|
+
root.pointerSettling = true
|
|
101
|
+
// An appearance that changes nothing drawn schedules no frame, so it asks for the one
|
|
102
|
+
// that ends the settle, the way ui/ContextMenu.qml's place() does.
|
|
103
|
+
if (root.Window.window) root.Window.window.update()
|
|
104
|
+
}
|
|
105
|
+
onEditingChanged: {
|
|
106
|
+
root.sources = ({})
|
|
107
|
+
root.rowHighWater = 0
|
|
108
|
+
root.prepared = null
|
|
109
|
+
root.enterWaiting = false
|
|
110
|
+
root.pathTyped = false
|
|
111
|
+
root.provisionalId = 0
|
|
112
|
+
root.wholeTaken = false
|
|
113
|
+
root.provTaken = false
|
|
114
|
+
root.wholeAsked = false
|
|
115
|
+
root.pointerGlobal = Qt.point(-1, -1)
|
|
116
|
+
root.pointerSettling = false
|
|
117
|
+
root.asked += 1
|
|
118
|
+
if (!root.editing) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
if (root.historyKept && root.historyReadAt === root.historyChanges) {
|
|
122
|
+
root.wholeAsked = true
|
|
123
|
+
root.ask(0)
|
|
124
|
+
} else {
|
|
125
|
+
root.provisionalId = root.asked
|
|
126
|
+
root.ask(0)
|
|
127
|
+
root.readHistory()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// The recent history, read once and kept until the file changes, so an open with it unchanged asks at
|
|
132
|
+
// once: re-reading 5,000 bookmarks on every open cost the dropdown some 70 ms, measured.
|
|
133
|
+
property var recentPaths: []
|
|
134
|
+
property bool historyKept: false
|
|
135
|
+
property bool historyReading: false
|
|
136
|
+
// Every change the watcher has reported, and the count the kept paths were read at.
|
|
137
|
+
property int historyChanges: 0
|
|
138
|
+
property int historyReadAt: -1
|
|
139
|
+
// How many times the history has been parsed; tests/jump-ui.sh reads it.
|
|
140
|
+
property int historyReads: 0
|
|
141
|
+
|
|
142
|
+
function ask(ranking) {
|
|
143
|
+
root.requested(root.asked, ranking, root.favouritePaths(), root.recentPaths)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function askWhole() {
|
|
147
|
+
// One whole ask per open, only once the provisional answer and the history read are both in,
|
|
148
|
+
// so the two backend calls never overlap on the backend's one zoxide slot. The read's own
|
|
149
|
+
// staleness is the next open's business: this one asks with the newest paths it has.
|
|
150
|
+
if (!root.editing || root.wholeAsked || !root.provTaken) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
if (root.provisionalId !== 0 && !(root.historyKept && !root.historyReading)) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
root.wholeAsked = true
|
|
157
|
+
root.asked += 1
|
|
158
|
+
root.ask(root.provisionalId)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// The watch starts before the read, so a change landing while it runs is counted and read next time.
|
|
162
|
+
function readHistory() {
|
|
163
|
+
root.historyReading = true
|
|
164
|
+
root.historyReadAt = root.historyChanges
|
|
165
|
+
watcher.path = Recent.historyPath(Quickshell.env("XDG_DATA_HOME"), Quickshell.env("HOME"))
|
|
166
|
+
recent.active = true
|
|
167
|
+
recent.item.refresh()
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Watching only: it never loads the file, and it reports a rename over it, a delete and a re-create alike.
|
|
171
|
+
FileView {
|
|
172
|
+
id: watcher
|
|
173
|
+
preload: false
|
|
174
|
+
watchChanges: true
|
|
175
|
+
onFileChanged: root.historyChanges += 1
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The backend's jumped line; one for another open, or landing after the bar closed, is dropped.
|
|
179
|
+
// A provisional answer draws its rows but never spends a held Enter and never settles the open.
|
|
180
|
+
function take(id, favourites, zoxide, recentFolders, frecency) {
|
|
181
|
+
if (!root.editing) {
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
var provisional = id === root.provisionalId && root.provisionalId !== 0 && !root.wholeTaken
|
|
185
|
+
if (id !== root.asked && !provisional) {
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
var answer = { favourites: favourites, zoxide: zoxide, recent: recentFolders, frecency: frecency || ({}) }
|
|
189
|
+
root.sources = answer
|
|
190
|
+
root.prepared = Jump.prepare(answer, root.home)
|
|
191
|
+
if (provisional) {
|
|
192
|
+
root.provTaken = true
|
|
193
|
+
root.askWhole()
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
root.wholeTaken = true
|
|
197
|
+
if (root.enterWaiting) {
|
|
198
|
+
root.enterWaiting = false
|
|
199
|
+
root.enter()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Enter itself: the cursor row when there is one, and otherwise the line as a path, as before the jump.
|
|
204
|
+
function enter() {
|
|
205
|
+
if (root.cursor >= 0) {
|
|
206
|
+
root.chosen(root.entries[root.cursor].path)
|
|
207
|
+
} else {
|
|
208
|
+
root.declined()
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function favouritePaths() {
|
|
213
|
+
var records = Flea.Favourites.records
|
|
214
|
+
var out = []
|
|
215
|
+
for (var i = 0; i < records.length; i++) {
|
|
216
|
+
out.push(String(records[i].path || ""))
|
|
217
|
+
}
|
|
218
|
+
return out
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// The picker's own reader of recently-used.xbel, built for a read and dropped after it, so a window whose
|
|
222
|
+
// bar is never typed into loads no XML module at all.
|
|
223
|
+
Loader {
|
|
224
|
+
id: recent
|
|
225
|
+
active: false
|
|
226
|
+
source: "PickerRecent.qml"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
Connections {
|
|
230
|
+
target: recent.item
|
|
231
|
+
function onRefreshed() {
|
|
232
|
+
root.recentPaths = recent.item.paths
|
|
233
|
+
root.historyKept = true
|
|
234
|
+
root.historyReading = false
|
|
235
|
+
root.historyReads += 1
|
|
236
|
+
// The parsed model goes once its newest paths are kept, which bounds what stays in memory at
|
|
237
|
+
// Recent.LIMIT paths; later, because the reader is the one emitting this signal.
|
|
238
|
+
Qt.callLater(function () { if (!root.historyReading) recent.active = false })
|
|
239
|
+
// The whole ask waits for the provisional answer too, which take() records; either order
|
|
240
|
+
// of the two landings converges on it, and a closed bar asks nothing more.
|
|
241
|
+
root.askWhole()
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// The backend answers inside its own zoxide and stat budgets, docs/protocol.md "jump"; one that never
|
|
246
|
+
// answers at all, a backend gone, must not hold an Enter for good, so past this the line is a path.
|
|
247
|
+
readonly property int answerLimitMs: 4000
|
|
248
|
+
Timer {
|
|
249
|
+
id: enterLimit
|
|
250
|
+
interval: root.answerLimitMs
|
|
251
|
+
running: root.enterWaiting
|
|
252
|
+
onTriggered: {
|
|
253
|
+
root.enterWaiting = false
|
|
254
|
+
root.declined()
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
Keys.onPressed: function (event) {
|
|
259
|
+
// A held Enter stands for the line as it was, so nothing typed after it changes what it opens; esc still closes.
|
|
260
|
+
if (root.enterWaiting && event.key !== Qt.Key_Escape) {
|
|
261
|
+
event.accepted = true
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
if (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) {
|
|
265
|
+
root.pathTyped = true
|
|
266
|
+
event.accepted = false
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
if (root.shown && (event.key === Qt.Key_Down || event.key === Qt.Key_Up)) {
|
|
270
|
+
root.cursor = Jump.step(root.entries, root.cursor, event.key === Qt.Key_Down ? 1 : -1)
|
|
271
|
+
event.accepted = true
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
|
275
|
+
if (root.shown) {
|
|
276
|
+
root.enter()
|
|
277
|
+
event.accepted = true
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
// Held until the whole answer, not the provisional one, so the same keys open the same
|
|
281
|
+
// folder however fast they were typed; a visible row above already took the press itself.
|
|
282
|
+
if ((!root.answered || !root.wholeTaken) && !root.pathTyped && Jump.isQuery(root.query)) {
|
|
283
|
+
root.enterWaiting = true
|
|
284
|
+
event.accepted = true
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
event.accepted = false
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
readonly property int drawnRows: drop.item === null ? 0 : Math.min(root.entries.length, Math.ceil((drop.item.scrollY + drop.item.height - 2 * Theme.spacing.rowPaddingY) / Theme.rowHeight)) - Math.floor(drop.item.scrollY / Theme.rowHeight)
|
|
292
|
+
// The dropdown's frame, built only while rows show: the scroll body, its window listener,
|
|
293
|
+
// both fades and the rows are nothing the first frame shows.
|
|
294
|
+
Loader {
|
|
295
|
+
id: drop
|
|
296
|
+
active: root.shown
|
|
297
|
+
sourceComponent: dropFrame
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
Component {
|
|
301
|
+
id: dropFrame
|
|
302
|
+
Rectangle {
|
|
303
|
+
id: frame
|
|
304
|
+
width: root.width
|
|
305
|
+
height: Math.max(0, Math.min(rows.implicitHeight + 2 * Theme.spacing.rowPaddingY, root.room))
|
|
306
|
+
color: Theme.color.surface
|
|
307
|
+
border.width: Theme.spacing.hairline
|
|
308
|
+
border.color: Theme.color.mutedFrame
|
|
309
|
+
radius: Style.cornerRadius
|
|
310
|
+
|
|
311
|
+
function reveal(index) { scroll.reveal(rowItems.itemAt(index)) }
|
|
312
|
+
// For tests/jump-ui.sh: how many delegates stand, and the one at an index.
|
|
313
|
+
readonly property int liveCount: rowItems.count
|
|
314
|
+
// For the picker's path shots: how far the rows have scrolled.
|
|
315
|
+
readonly property real scrollY: scroll.contentY
|
|
316
|
+
function liveAt(index) { return rowItems.itemAt(index) }
|
|
317
|
+
Component.onCompleted: reveal(root.cursor)
|
|
318
|
+
|
|
319
|
+
// The ground takes every pointer event the rows leave, so nothing reaches the listing beneath.
|
|
320
|
+
MouseArea {
|
|
321
|
+
id: ground
|
|
322
|
+
anchors.fill: parent
|
|
323
|
+
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
324
|
+
hoverEnabled: true
|
|
325
|
+
// The sink records the point, so rows appearing under a resting pointer compare
|
|
326
|
+
// against where it already is, the menu's own recipe.
|
|
327
|
+
onEntered: root.pointerGlobal = ground.mapToItem(null, ground.mouseX, ground.mouseY)
|
|
328
|
+
onPositionChanged: function (mouse) { root.pointerGlobal = ground.mapToItem(null, mouse.x, mouse.y) }
|
|
329
|
+
// The recipe's close: a click that hit no row closes the bar with nothing opened.
|
|
330
|
+
onClicked: root.dismissed()
|
|
331
|
+
onWheel: function (wheel) { wheel.accepted = true }
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
Flea.CardScroll {
|
|
335
|
+
id: scroll
|
|
336
|
+
// The dropdown steps the highlight like a menu: one row a notch, one row per
|
|
337
|
+
// row height of gained touchpad travel. The cursor's reveal() follows.
|
|
338
|
+
highlightSteps: true
|
|
339
|
+
stepBy: function (delta) { root.cursor = Jump.step(root.entries, root.cursor, delta) }
|
|
340
|
+
anchors.fill: parent
|
|
341
|
+
anchors.topMargin: Theme.spacing.rowPaddingY
|
|
342
|
+
anchors.bottomMargin: Theme.spacing.rowPaddingY
|
|
343
|
+
|
|
344
|
+
Column {
|
|
345
|
+
id: rows
|
|
346
|
+
width: parent.width
|
|
347
|
+
|
|
348
|
+
Repeater {
|
|
349
|
+
id: rowItems
|
|
350
|
+
// The high-water count, so a keystroke that narrows the list leaves every
|
|
351
|
+
// delegate standing: rows rebind to entries[index] instead of rebuilding, and
|
|
352
|
+
// the tail past the entries hides. The max against the entries covers a growth
|
|
353
|
+
// the high-water handler has not recorded yet, whichever runs first.
|
|
354
|
+
model: Math.max(root.rowHighWater, root.entries.length)
|
|
355
|
+
// The menu's own row, so the lift, the mark slot and the pointer rules are the context menu's;
|
|
356
|
+
// the label is the path the chrome would draw, laid over its empty one.
|
|
357
|
+
delegate: Flea.MenuRow {
|
|
358
|
+
id: row
|
|
359
|
+
required property int index
|
|
360
|
+
// The row at this slot of the newest answer, undefined mid-swap or past it.
|
|
361
|
+
// A hidden tail keeps its delegate standing at zero height, because an
|
|
362
|
+
// invisible item still holds its Column position.
|
|
363
|
+
readonly property var rowData: root.entries[row.index]
|
|
364
|
+
readonly property bool rowStanding: row.index < root.entries.length
|
|
365
|
+
visible: row.rowStanding
|
|
366
|
+
height: row.rowStanding ? Theme.rowHeight : 0
|
|
367
|
+
width: rows.width
|
|
368
|
+
entry: ({ glyph: "folder", label: "", hint: "" })
|
|
369
|
+
current: root.cursor === row.index
|
|
370
|
+
lastPointerGlobal: root.pointerGlobal
|
|
371
|
+
onPointerSeen: function (at) { root.pointerGlobal = at }
|
|
372
|
+
onPointerMoved: { if (!root.pointerSettling) root.cursor = row.index }
|
|
373
|
+
onActivated: { if (row.rowData !== undefined) root.chosen(row.rowData.path) }
|
|
374
|
+
|
|
375
|
+
Flea.JumpPath {
|
|
376
|
+
entry: row.rowData !== undefined ? row.rowData : ({})
|
|
377
|
+
anchors.left: parent.left
|
|
378
|
+
anchors.leftMargin: Theme.spacing.rowPaddingX + row.slotSize + Theme.spacing.gap
|
|
379
|
+
anchors.right: parent.right
|
|
380
|
+
anchors.rightMargin: Theme.spacing.rowPaddingX
|
|
381
|
+
anchors.verticalCenter: parent.verticalCenter
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
Flea.MenuEdgeFade {
|
|
389
|
+
anchors.top: parent.top
|
|
390
|
+
visible: scroll.contentY > 0
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
Flea.MenuEdgeFade {
|
|
394
|
+
anchors.bottom: parent.bottom
|
|
395
|
+
visible: scroll.contentY + scroll.height < scroll.contentHeight
|
|
396
|
+
rotation: 180
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|