{"id":26022245,"url":"https://github.com/stinos/PsFzfLite","last_synced_at":"2025-03-06T09:54:52.462Z","repository":{"id":80479790,"uuid":"425540108","full_name":"stinos/PsFzfLite","owner":"stinos","description":"Powershell utilities for working with fzf","archived":false,"fork":false,"pushed_at":"2024-04-04T15:33:18.000Z","size":31,"stargazers_count":9,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-01T19:02:24.092Z","etag":null,"topics":["fzf","powershell","powershell-module"],"latest_commit_sha":null,"homepage":"","language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stinos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-07T15:24:54.000Z","updated_at":"2025-02-04T03:04:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"e3ba912d-2d03-4d15-8856-e4ab7d000b75","html_url":"https://github.com/stinos/PsFzfLite","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2FPsFzfLite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2FPsFzfLite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2FPsFzfLite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2FPsFzfLite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stinos","download_url":"https://codeload.github.com/stinos/PsFzfLite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242187657,"owners_count":20086218,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fzf","powershell","powershell-module"],"created_at":"2025-03-06T09:54:44.696Z","updated_at":"2025-03-06T09:54:52.430Z","avatar_url":"https://github.com/stinos.png","language":"PowerShell","funding_links":[],"categories":["PowerShell"],"sub_categories":[],"readme":"![AppVeyor tests](https://img.shields.io/appveyor/tests/stinos/PsFzfLite?logo=appveyor)\n\n# PsFzfLite\n\nPsFzfLite is a PowerShell module providing helpers for working with [fzf](https://github.com/junegunn/fzf),\nwhich is a commandline fuzzy finder. The most common day-to-day usage functions are provided as well:\nfuzzy file and directory finding (ctrl-t and alt-c from fzf), fuzzy history (ctrl-r).\n\nIt was inspired by [PSFzf](https://github.com/kelleyma49/PSFzf) but written from scratch taking a different\napproach with the aim of providing a couple of building blocks one can use to make their own custom\nfunctions using fzf, instead of being a complete wrapper; see rationale below.\n\nAs such [PsFzfLiteCore.ps1](PsFzfLite/PsFzfLiteCore.ps1) just has a few functions which are typically used\nto provide input for and handle output from fzf. These can then be used to build higher-level functions\nusing. By means of example and documentation, that's exactly what is done  for the most common functions,\nsee [PsFzfLiteFuzzies.ps1](PsFzfLite/PsFzfLiteFuzzies.ps1).\n\n## Requirements\n\nPowershell Core.\n\nNotes:\n- actually code is compatible with PS 5.1 but that version buffers all output from an upstream command before\npiping it into a downstream external program so without workarounds (which aren't implemented currently),\nfeeding lots of output (like from listing the filesystem) into fzf takes a considerable amount of time\n- all tests pass on Linux and all fuzzies have been tested as well, but not extensively. Not tested on macOS.\n\n## Installation\n\n```powershell\ngit clone https://github.com/stinos/PsFzfLite ./PsFzfLite\nImport-Module ./PsFzfLite/PsFzfLite/PsFzfLite.psm1\n```\n\nThe import statement normally goes into `$PROFILE`.\n\nNote that on the first import, or when the .cs files change after pulling updates, this will build 2\nassemblies into the temp directory. Done mainly so to avoid having to go through building and\ndeploying binary releases.\n\nThe module supports arguments to control what gets imported, see [PsFzfLite.psm1](PsFzfLite/PsFzfLite.psm1).\n\n## Functions for everyday usage\n\n- `Invoke-FuzzyGetCommand` launch fzf with list of all .exe files in $env:PATH and insert selection at cursor,\ncovenient for quickly finding commands\n- `Invoke-FuzzyGetCmdlet` like above, but for Powershell commands\n- `Invoke-FuzzyHistory` feed PsReadLine history into fzf (no duplicates, MRU order) and insert selection\n- `Invoke-FuzzyKillProcess` launch fzf with Get-Process list and kill selected processes\n- `Invoke-FuzzyBrowse` select from list of paths  and insert selection; uses current token before cursor\nas start path and automatically selects directory finding if there's a `cd` or similar on the commandline\n- `Invoke-FuzzyZLocation` launch fzf with [ZLocation](https://github.com/vors/ZLocation) entries and\ncd to the selected directory, use for fast navigation between directories used often\n\nThe easiest way to use these is binding them to keyboard shortcuts so they can be invoked quickly, plus\nfirst 3 will automatically pre-fill fzf input with the current commandline content. See samples below.\n\nMost of the functions have an argument for passing arguments to fzf in turn; these arguments are\npassed like one would type them on the commandline. Some examples:\n\n```powershell\n# All the usual fzf arguments can be passed.\n$fzfArgs = @(\n  '--multi',\n  '--preview', 'type {}',\n  '--preview-window=\"right:60%\"',\n  '--bind', 'backward-eof:abort,ctrl-s:clear-selection'\n)\nInvoke-FuzzyBrowse -FzfFileArgs $fzfArgs\n\n# Preview with command info, requires recent fzf version which adheres to $env:SHELL='pwsh'\n# or similar, so it can run preview/execute via PS.\nInvoke-FuzzyGetCmdlet -FzfArgs @('--preview', 'Get-Command {} -ShowCommandInfo')\n\n# Fuzzy history with option to delete selected entries.\nInvoke-FuzzyGetCmdlet -FzfArgs @(\n  '--multi', # Not useful when selecting history, but very useful for deleting multiple entries.\n  '--bind',\n  'ctrl-d:execute($i=@(Get-Content {+f}); $h=(Get-PSReadLineOption).HistorySavePath; (Get-Content $h) | ?{$_ -notin $i} | Out-File $h -Encoding utf8NoBom)'\n)\n```\n\n## Sample key bindings and aliases\n\nKey bindings like the ones fzf installs by default in other shells like bash, put in `$PROFILE`:\n\n```powershell\nSet-PSReadLineKeyHandler -Key 'ctrl-r' -BriefDescription 'Fuzzy history' -ScriptBlock {Invoke-FuzzyHistory}\nSet-PSReadLineKeyHandler -Key 'ctrl-t' -BriefDescription 'Fuzzy browse' -ScriptBlock {Invoke-FuzzyBrowse}\nSet-PSReadLineKeyHandler -Key 'alt-c' -BriefDescription 'Fuzzy browse dirs' -ScriptBlock {Invoke-FuzzyBrowse -Directory}\n```\n\nAliases like this can also be useful:\n```powershell\nSet-Alias fz Invoke-FuzzZLocation\nSet-Alias fkill Invoke-FuzzyKillProcess\n```\n\nAn alternative approach to aliasing is using `Invoke-FuzzyGetCmdlet` bound to a keyboard shortcut then use\nthat for fuzzy command finding instead of typing aliases: it is usually about the same number of keystrokes to\nreach a command but doesn't require remembering the exact name and is generic. For example starting\n`Invoke-FuzzyGetCmdlet` and typing `fz` or `fk` (or the other way around, i.e. typing `fz` or `fk` and then\nusing the keyboard shortcut) fuzzy matches the functions shown above.\n\n## Rationale and helper functions\n\nFor a lot of things fzf works fine as-is in Powershell. For example one can use\n\n```powershell\n$selectedLines = Get-Content foo.txt | fzf --multi --no-sort\n```\n\nwithout needing any extra functions (so even no PsFzfLite :]), let alone wrapping. Especially when knowing\nfzf already and/or using it in other shells it's convenient to be able to just use the same in Powershell\n(as opposed to having to figure out the corresponding arguments for PSFzf for instance).\n\nMoreover there are a lot of different usecases for fzf and it has a lot of options, so the wrapping/do-it-all\napproach is on one hand never enough in that people can continue to ask new features to satisfy their own\ncustomizations while on the other hand it's always overkill in that the majority of the code is not used by\nother people because they do things in a different way. So an approach where one uses fzf directly to write\na couple of often-used functions has its merits in that it is fast and does exactly what's needed\nbut nothing more.\n\nUsing fzf like that in Powershell however does run into few issues, and solutions for these are\nwhat PsFzfLite is about:\n- when binding functions using fzf to a keyboard shortcut, the selected result usually needs to be\n  inserted at the current cursor position. That's fairly easy using PsReadLine and PsFzfLite has\n  the basics to do that in a pipe: `fzf | Add-TextAtCursor`.\n- likewise the output of fzf might need to be quoted or wrapped in an array, for example if fzf returns 2\n  lines 'foo' and 'bar' that should become `@('foo', 'bar')`: `fzf | ConvertTo-ReplInput | Add-TextAtCursor`.\n- fuzzy file finding using `Get-ChildItem | fzf` or `cmd /c dir | fzf` is so slow it's hardly usable for\n  more than a couple of directories deep. PsFzfLite implements its own filesystem walking in C# which performs\n  similar to what fzf uses internally (see [FileSystemWalker.cs](PsFzfLite/FileSystemWalker.cs).\n  There is still some overhead for using it in Powershell and piping into fzf and as such it's not as fast as\n  using bare fzf, but still like 10 times faster than PSFzf and also more consistent with standard fzf: it uses\n  no full paths but paths relative to the directory and filters out dot directories.\n  Ballpark performance numbers as seen from within PS Measure-Command {...} for a directory\n  with roughly 0.7 million files, no filtering, after some warmup, numbers in seconds:\n\n  - Get-ChildPathNames (Windows version): 3.9\n  - Get-ChildPathNames (portable version): 4.8\n  - fd -H -I: 8.1\n  - go executable using most basic sample from github.com/saracen/walker (which is what fzf uses internally): 8.6\n  - cmd /c dir /b /s /a-d: 31.5\n  - Get-ChildItem -Path -File -Recurse: 36.5\n\n  Same principle but on PS Core in WSL on a directory with about 200000 files:\n  - fd -H -I: 10\n  - Get-ChildPathNames (portable version): 15\n  - find -type f: 50\n  - Get-ChildItem -Path -File -Recurse: 95\n- at the time of writing there is no builtin way to stop a pipeline, nor do upstream elements detect when a\n  downstream element stopped, so piping a lot of input into fzf is problematic since the pipe will continue even\n  after making a selection in fzf rendering it useless. None of the workarounds are super pretty.\n  PsFzfLite has 2 of them:\n  - Windows-only: `TonsOfInput | cmd /c (New-PipeOrTerminateArgs 'fzf') | Read-PipeOrTerminate`\n  - portable: `TonsOfInput | New-InterruptibleCommand fzf`\n\n  Currently these are used only in `Invoke-FuzzyBrowse`, none of the other examples produce enough input that\n  waiting for the input to enter fzf takes much longer than deciding + typing the fuzzy string.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstinos%2FPsFzfLite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstinos%2FPsFzfLite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstinos%2FPsFzfLite/lists"}