Giter Site home page Giter Site logo

zf's Introduction

zf

shield showing current tests status Packaging status

zf is a fuzzy finder that excels at filtering filepaths:

While it also functions as a general-purpose fuzzy finder, the goal of zf is to be more accurate than other fuzzy finders when filtering filepaths. If you find something that could be improved, please let me know.

zf is also available as an allocation-free library for fuzzy filtering.

Try it online!

Demo

zf-demo.mp4

Features

  • designed for fuzzy matching file paths (but also works as a general purpose fuzzy finder)
  • refine search results with whitespace separated query terms
  • case insensitive unless the query contains uppercase letters (smartcase)
  • multiselect to output multiple selected lines
  • Zig and C libraries for the zf ranking algorithm

zf aims to be simple:

  • no full-window interface
  • minimal config and options
  • sensible defaults

Docs

Why use zf?

zf was designed knowing that a frequent use case for fuzzy finders is filtering filepaths. It also works great for any arbitrary string, but it is especially good at filtering filepaths with precision.

Specifically,

  • Matches on filenames are prioritized over filepath matches
  • Matches on the beginning of a word are prioritized over matches in the middle of a word
  • Non-sequential character matches are penalized
  • Strict path matching offers even more precision

Here are some concrete examples.

Filename priority

The query is matched first on the filename and then on the path if the filename doesn't match. This example comes from Blender's source code, and was my original inspiration for designing zf.

> make
./GNUmakefile
./source/blender/makesdna/DNA_genfile.h
./source/blender/makesdna/intern/dna_genfile.c
./source/blender/makesrna/intern/rna_cachefile.c
./source/blender/makesdna/DNA_curveprofile_types.h

Fzf and fzy both rank source/blender/makesdna/DNA_genfile.h first in the results, with GNUmakefile 10 items down the list.

Space-separated tokens

But not every filename is unique. Sometimes there are codebases where there are many files with the same or similar names, like an __init__.py in Python, or .c and .h file pairs in C. In zf each space separated query term is used to narrow down the results. Imagine searching for an __init__.py file in a Python project.

> init
./__init__.py
./ui/__init__.py
./data/__init__.py
./config/__init__.py

At this point you can either move the selection down with Down or c-n to find ./config/__init__.py, or you can add a new token to the query string.

> init c
./config/__init__.py

Treating the query string as a sequence of tokens makes filtering more efficient.

Strict path matching

This feature is a "do what I mean" feature, more easily used than explained. When the query looks like a path (contains at least one path separator) strict path matching is enabled.

Path segments are the portions of a path delimited by path separators. foo/bar has segments foo and bar. With strict path matching the path segments of the query token must not span across path segments in the candidate. As an example, the query foo/ would match foo/bar/ but not fo/obar/ because the characters "foo" must appear in a single path segment.

This is useful for narrowing down results when you know the exact path structure of your files. With the following paths

./app/models/foo/bar/baz.rb
./app/models/foo/bar-baz.rb
./app/models/foo-bar-baz.rb
./app/monsters/dungeon/foo/bar/baz.rb

Strict path matching ensures that the intended path structure is found.

> a/m/f/b/baz
./app/models/foo/bar/baz.rb

In other fuzzy finders the string app/monsters/dungeon/foo/bar/baz.rb is also included in the results. Strict path matching prevents this because there is a slash between onsters/dungeon and nothing in the query matches the dungeon segment.

To end strict path matching, just add a space to start a new query token.

Installation

Arch Linux

An AUR package is available.

macOS

Install with Homebrew

brew install zf

Nix

nix-env --install zf

Binaries

Each release has binaries attached for macOS and Linux.

Building from source

For compatibility with system package managers, zf targets the latest stable release of Zig. The unstable branch is kept up to date with Zig master.

git clone https://github.com/natecraddock/zf
cd zf
zig build -Doptimize=ReleaseSafe --summary all

The executable will be created in ./zig-out/bin/zf. For debug builds omit -Doptimize=ReleaseSafe.

Integrations

Would you like to use zf in an editor? Try one of the following plugins

Contributing

I am open to contributions of all kinds, but be aware that I want to keep zf small and easy to maintain.

zf's People

Contributors

arrufat avatar ezradiniz avatar gpanders avatar jmbaur avatar natecraddock avatar ratfactor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

zf's Issues

Cursor position is off when ZF_PROMPT has special characters like ansi escape codes

I'm trying to use a character like as the ZF_PROMPT, but it seems like it the cursor is shifted way right of where text is actually inserted:

Screen.Recording.2023-01-05.at.9.53.29.AM.mov

This is even more pronounced when adding ansi color codes, ie ZF_PROMPT="\e[41m  \e[0m\e[31m\e[0m" :

Screen.Recording.2023-01-05.at.10.02.31.AM.mov

Improve path matching ranking

Something I noticed

> mod/baz.rb
./app/models/foo-bar-baz.rb
./app/models/foo/bar-baz.rb
./app/models/foo/bar/baz.rb

In this case I think we should expect mod/baz.rb to rank ./app/models/foo/bar/baz.rb the hightest because baz.rb has the greatest path segment coverage on that string.

Improve zf’s speed

Dear Nathan,

thank you very much for this excellent tool. I would like to switch to zf from fzf.

As fzf feels faster and snappier, I did some very basic benchmark testing. Here’s the results:

  • time find -type f | zf: 2.29 secs (~300,000 files)

  • time find -type f | fzf: 170.00 millis (~300,000 files)

  • time fd -t f | zf: 1.84 secs (~128,000 files)

  • time fd -t f | fzf: 725.22 millis (~128,000 files)

Can/will this be adressed?

Thank you very much.

Background:

Tested with zf 0.8.0 on Void Linux with fish shell. (Experienced some problems building zf from source as I am just slowly digging into zig.)

Also tested with -k -p flags.

I always work from ~/. That’s why I always search many files. This is what I have been using for years within a little POSIX script: fd --type file --max-depth 1 && fd --type file --min-depth 2 | fzf.

Support for fzf syntax

Hi, I've been using zf through telescope for a couple of months now, and I love it for both speed and file name matching priority. I'm just wondering if fzf compatible syntax for pattern matching is planed and or even possible? Full disclosure: I use it rarely, but occasionally, it is helpful to have.

For reference, telescope-fzf-native.nvim has a nice reference table of the syntax:

image

Add multiselect support

It would occasionally be helpful to support multiselect in interactive mode. This would allow selecting multiple results which are written to stdout separated by spaces.

A use case would be a fuzzy finder over git branches that allows selecting multiple for deletion.

Example UI

  >                                                                      4/4 (3 selected) 
  master
* feature-branch-one
* fix-bug-10
* temp-feature-branch

Each row would show an * when selected. The upper right would show the selection status.

zf would behave as normal. When tab is pressed, the currently highlighted row would become selected, tab again would deselect the row.

When enter is pressed all selected rows would be written to stdout. If no rows are selected, only the highlighted row is written (maintaining the current behavior).

Either all rows will be shifted right two columns when selection is active, or all rows will always be shifted.

Prerequisites

Before this is implemented, zf needs support for scrolling the entire list of search candidates. #23

Reduce memory consumption

Zf uses an arena allocator for speed, and does not free memory during the application's runtime.

Each time the filter function is run, a new slice of Candidates is allocated, meaning that memory use grows as zf is run.

Even though zf is intended to be a short-lived program, we should still use as little memory as possible.

alternative algorithm

Hey, read about your project on lobste.rs (I don't have an account there or I'd have commented in the thread). A while ago I made a drawing tool which made software architecture diagrams from text, as you type - for use as a whiteboard in zooms - and it attempted to guess icons for things you drew, picking from eg the aws (https://aws.amazon.com/architecture/icons/) and kubernetes sets. I wanted to avoid an explicit picker which breaks the flow of the diagramming discussion, so it just does a fuzzy find and picks the first result.

This produces results similar to your fuzzy find, you may be interested in the trick (since I see your code works entirely differently; mine was a quick hack in js). What my code did was take the search target you request and rank the results by the shortest occurrence of that sequence of characters. To do this, I just transform the target into a regexp (being lazy, and not writing a bunch of match code). For example, for word, it generates (w[^w]*?o[^o]*?r[^r]*?d); the w[^w]*? avoids captures like wwwword where there is a shorter subsequence containing the target within the match (this falls over a bit for strings with multiple matches; you can easily fix this by grabbing all matches and choosing the shortest). In my case, the input would only be a single token containing alphanumerics, underscores, and dashes; I split on the non-alphanumerics and match each subtoken separately; the score is the total size of all the matches in each string. (I had various other ways of breaking ties, specific to my use-case)

This isn't particularly efficient, and I'm well aware that abusing regexes like this is a hack, but the number of strings I had to match against wasn't very large, and the input alphabet was limited so I knew the generated regexes would be valid. It does, however, rank your 'makefile' example at the top, so I thought it might interest you.

add simple variants of all public module functions

The module functions are becoming a bit complicated (which is fine). This is to maximize the performance of zf. But there may be cases when a simple variant is preferred (small lists to filter, for example).

So each function can offer a simple variant, and then an extended version with more parameters for maximal control

breaks on control sequences in folder/file name

Reproduce with:

git clone https://github.com/matu3ba/chepa/tree/cdbc5cc3574aa38f7604a77d57745f854d8ef783
cd chepa
zig build tfgen
cd test_folders && rm -fr base_perf && rm -fr control_sequences
cd control_sequences
fd -t f | zf

output:

>
./f_
./f_
./f_
./f_
./f_
./f_
./f_
./f_
./f_
./f_

Picture related
breaks_on_control_sequences

Buffer writing to stdout

I previously fixed a lot of flicker in the UI #6 by using a buffered writer. But in a lot of the terminal drawing codepaths I simply bypass the buffer. This is unintentional, I misunderstood the BufferredWriter interface.

So I'm planning on removing the BufferedWriter and doing my own implementation that is more closely tied to the Terminal struct

Grapheme ZWJ clusters in query

When there are grapheme clusters in the query, the query width is incorrectly calculated and is wrapped to the next line. Editing still works however.

> 🐻‍❄️                                             1
/5[garbled unicode here]

Is there a way to prioritize by whole file name?

Hello, I really like this extension by the same reasons you created it :), between the alternative it matches my workflow the best by far.

There is a case where I think zf could improve, I set the following file tree to illustrate it. For example, searching for app.py will sort test_app.py first. Is there a way to prioritize by whole file name in that case?

.
├── myownmod
│   └── custom
│       └── app.py
└── tests
    └── test_app.py

or

./myownmod/custom/app.py
./tests/test_app.py

zf-search

Replace `--lines` with `--height`

Height makes more sense, especially now that there will be a preview window. Support both options until 1.0 which will remove the --lines option.

Can we use `comptime` to de-duplicate the ranking and highlighting code?

Currently the ranking and highlighting code is duplicated in filter.zig (rankToken() and highlightToken()). This makes some things more clear (each function returns a specific type, no unneeded args), and it also should make the function more performant. But it is an occasional burden to remember to update both functions.

A quick brainthought makes me think we could leverage comptime arguments to specify which version of the function to use (return the rank vs return the matched buffers) and not suffer any runtime performance penalty. I'll look into this...

Issue with system and linking libc

When linking libc (needed for pselect), std.os.system no longer contains all necessary symbols. Probably an issue with the Zig stdlib.

I can work around this for the 0.9.0 release. Future versions will only use pselect on macOS so this isn't urgent to resolve.

Escape ANSI codes in ZF_PROMPT

As reported in #13, ANSI codes are not escaped in the ZF_PROMPT env variable which leads to incorrect width calculations when displaying the prompt.

ANSI escapes should be ignored and only the prompt character(s) should be considered

Add a potentially new option `-0` for NUL-separated lines.

Hi Nate - great piece of software!

I'm wondering if it's possible to add a new option -0 that is a shortcut to specifying -d'\0'? I guess there will be some cost for maintaining another option whose functionality already exists, so curious to get your thoughts on it.

Cheers

Use `ReleaseSafe`

I did some basic tests and it seems that ReleaseSafe is only marginally slower than ReleaseFast. I'll do a bit more investigation, but it seems like I should switch to ReleaseSafe just to be safe ;)

Part of 0.8.0 but most (all) of the work takes place after the release tagging

  • update readme build instructions
  • update telescope-zf-native.nvim
  • update makefile for releases
  • update brew package
  • update arch package

Unicode support

After evaluating things, I'm not sure if full unicode support is required. I looked at other fuzzy finders, and none that I checked (fzf, fzy, sk) fully support unicode in the way I was imagining to support for zf. I want to prioritize speed and simplicity first. So I want to simplify the unicode implementation. Here is the plan:

  • normalization of input lines and query
    • this only has a minimal impact on performance, and will make matching unicode mostly perfect
  • fixing all code that uses the length of a string as the display width
  • query editing

This will actually be better than any other I tested (handling graphemes in the query editor line), but also keep zf as optimized as possible.

I am open to changing things in the future, but for now I think this is enough.

Use os-specific path separators

the zf UI only supports unix. But the zf library is cross-platform. There are many hard-coded / path separators. These should be fixed before the 0.8.0 release so the library doesn't break on Windows.

Improve commandline argument parsing

The current parser for commandline arguments isn't perfect. It doesn't allow arguments to follow short options without spaces (-h20 should be equivalent to -h 20). The code is messy, and error handling is not as easy as it could be.

There are many available Zig libraries, and I could use one. I do think it would be best to just improve my current custom parser. Zf is simple and doesn't need much of the complexity that comes from a general-purpose argument parser.

Here are some goals for an improved version:

  • Move code to a new file (ArgParse.zig?)
  • Handle short options with arguments and no spaces between
  • Handle chained boolean short options
  • Improve error handling

macOS brew installation issue

Following the README for installing on macOS, getting the following error:

==> Installing zf from natecraddock/taps
==> Installing dependencies for natecraddock/taps/zf: z3 and zig
==> Installing natecraddock/taps/zf dependency: z3
==> Pouring z3--4.11.2.arm64_ventura.bottle.2.tar.gz
🍺  /opt/homebrew/Cellar/z3/4.11.2: 142 files, 30.3MB
==> Installing natecraddock/taps/zf dependency: zig
==> Pouring zig--0.10.0.arm64_ventura.bottle.tar.gz
🍺  /opt/homebrew/Cellar/zig/0.10.0: 13,837 files, 362.1MB
==> Installing natecraddock/taps/zf
==> zig build -Drelease-fast=true
Last 15 lines from /Users/mxgrn/Library/Logs/Homebrew/zf/01.zig:
2022-12-03 07:39:57 +0000

zig
build
-Drelease-fast=true

/private/tmp/zf-20221203-28656-cl3y6q/zf-0.5/src/main.zig:238:45: error: invalid builtin function: '@minimum'
        var terminal = try ui.Terminal.init(@minimum(candidates.len, config.lines), no_color);
                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: zf...
error: The following command exited with error code 1:
/opt/homebrew/Cellar/zig/0.10.0/bin/zig build-exe /private/tmp/zf-20221203-28656-cl3y6q/zf-0.5/src/main.zig -OReleaseFast --cache-dir /private/tmp/zf-20221203-28656-cl3y6q/zf-0.5/zig-cache
 --global-cache-dir /private/tmp/zf-20221203-28656-cl3y6q/zf-0.5/.brew_home/.cache/zig --name zf --enable-cache
error: the following build command failed with exit code 1:
/private/tmp/zf-20221203-28656-cl3y6q/zf-0.5/zig-cache/o/e6c08c3c962bc14f424bc077b89fec37/build /opt/homebrew/Cellar/zig/0.10.0/bin/zig /private/tmp/zf-20221203-28656-cl3y6q/zf-0.5 /privat
e/tmp/zf-20221203-28656-cl3y6q/zf-0.5/zig-cache /private/tmp/zf-20221203-28656-cl3y6q/zf-0.5/.brew_home/.cache/zig -Drelease-fast=true

Add newlines after usage

When zf prints usage (-h or when there are errors reading arguments) it should print a newline so prompts start on a newline

breaks on prefixed spaces inside file/folder name

git clone https://github.com/matu3ba/chepa/tree/cdbc5cc3574aa38f7604a77d57745f854d8ef783
cd chepa
zig build tfgen
cd test_folders && rm -fr base_perf && rm -fr control_sequences
cd bad_patterns
fd -t d | zf

output:
zf terminates immediately without showing prompt.

Respond to `SIGWINCH`

We should redraw the interface when the terminal window is resized. This requires an event loop

Overlapping highlights are incorrect

❯ fd -t f | zf
> source/b/e outlinerdraw
source/blender/freestyle/intern/scene_graph/DrawingStyle.h

On the second line we would expect the source/b/e and the outlinerdraw highlights to overlap, highlighting source/blender/freestyle/intern/scene_graph/Draw, but only the first token is highlighted.

So filtering works, but range highlighting needs a rework.

The current algorithm is messy and error prone. Because range highlighting occurs for a smaller number of candidates (n < 100 usually), we can do a bit more work.

Ideally, when highlighting the output array of ranges should be sorted and joined. So the ranges are in the correct order, and if needed, any overlaps are joined together.

Which Zig version works?

Attempting to build tag 0.8.0 from source with Zig 0.10.1, which is the "latest stable Zig" as specified in the readme, fails with this error:

Unrecognized argument: -fsummary

Edit: the above is my bad, the option is not present in the readme in 0.8.0, however I'm still running into problems.

If I omit that flag I run into dependency errors, which is reasonable since I don't have ziglyph package on my system, but I don't know how 0.8.0 brought that dependency in. There is no .zon file in that tree.

I would overall like clearer instructions for how to build zf for someone with minimal Zig knowledge.

edit: nevermind, i figured it all out (git submodules) i'm a bit dumb, i'm getting there hehe

Evented IO

zf currently uses a blocking read loop for inputs. This keeps zf very efficient - if there is nothing to read, then zf is waiting on the kernel to wake it up. But the current implementation only waits on reading from the tty file descriptor.

I have two features I want to implement that depend on an event loop:

I'm not yet sure how I want to do this. Using kqueue / epoll directly isn't much work, so perhaps I will just roll my own. There is also a std.io.poll in the next Zig version that could work. Perhaps I will rely on a library like https://github.com/mitchellh/libxev or libuv.

Rework strict path matching

Strict path matching was implemented from a request (#11) and I misunderstood the initial request.

As implemented in version 0.7.0 I do think it is currently useful. But there is room for improvement as suggested in later replies in that issue. Current implementation: when a / is found the path matching is made strict to the right and requires contiguous paths in the query.

There are two good points raised in the issue

  1. Examples that currently fail

Given these files:

app/models/foo/bar/baz.rb
app/models/foo/bar-baz.rb
app/models/foo-bar-baz.rb
app/monsters/dungeon/foo/bar/baz.rb

I would expect that typing model/barbaz would filter down to:

app/models/foo/bar-baz.rb
app/models/foo-bar-baz.rb

Because, for a search input of model/barbaz, I'm expecting that barbaz should match only within one level of depth in the dir tree. foo/bar/baz.rb has "bar/baz" split across two levels.

  1. a model of "locking" and fuzziness

It's like each slash should "lock" a portion of the path to the left, but still leave the portion to the right for fuzzier matching until the next slash and so on...

Search:
> dung/bar/
  | 1 | 2 |  3 (fuzzy)...

Match:
app/monsters/dungeon/foo/bar/baz.rb
|        1          |   2   |  3 (fuzzy)...
                    ^       ^
                 "lock"  "lock"

I've thought about this for a while and I believe I have a good solution

Solution

  • Enable strict path matching when a query token contains a / anywhere.
  • Strict path matching is defined as: each segment of a query must match within a single path segment, but the segments are not required to be contigous
  • the already existing multi-token nature of zf enables the suggested model of "locking" and fuzziness

Here are some examples, all using our lovely test strings

app/models/foo/bar/baz.rb
app/models/foo/bar-baz.rb
app/models/foo-bar-baz.rb
app/monsters/dungeon/foo/bar/baz.rb

Example 1

query: app/mod/fo/ba/baz
       |1 |2  |3 |4 |5  |

app/models/foo/bar/baz.rb
|1 |2     |3  |4  |5     | (pass)

app/monsters/dungeon/foo/bar/baz.rb
|1 |        (fail: 'mod' not found in single segment)

Example 2

query: model/barbaz
       | 1  | 2   |

app/models/foo/bar-baz.rb
   | 1    |   | 2       | (match)

app/models/foo-bar-baz.rb
   | 1    |    |2       | (match)

app/models/foo/bar/baz.rb
   | 1    |       (fail: 'barbaz' not found in single segment)

Example 3

query: mod/ foo
       |1 | |1'|

(matches the first 3 test strings)

app/monsters/dungeon/foo/bar/baz.rb)
            (fail: 'mod' not found in single segment)

With those examples in mind, I think this covers all the possible use cases, and makes things quite useful!

To recap: A query token containing any / will be used for strict path matching. The path segments are not required to be contiguous.

Currently a query of mod/ would match both mo/d/ and /mod/, but with these changes only /mod/ would be selected.

Open questions

It's like each slash should "lock" a portion of the path to the left, but still leave the portion to the right for fuzzier matching until the next slash and so on...

I like this idea, but zf already natively supports this fuzziness by inserting a space and adding a new query token. I'm not against adding this, but I think adding a space keeps things more consistent.

Environment Variables

I've had thoughts about various environment variables that would be nice to support in the future. These would be vars rather than flags because they are typically something you would set once and always be in effect when running zf.

  • ZF_PROMPT
    For overriding the default > prompt. Could be any arbitrary string.
  • ZF_HIGHLIGHT
    ANSI color code for highlights. Not yet sure if it would be the name or the integer.
  • ZF_VI_BINDINGS
    Set to false, ctrl-k will delete from cursor to end of line. Set to true, will move line down. There may be other bindings to change.
  • NO_COLOR https://no-color.org
    Disable coloring.

Maybe some of the flags could also have env vars to set defaults, like the default height.

Limit search by delimiter (e.g. slashes between directories)

junegunn/fzf#1706

My feature request is probably best explained by an example. Given the following lines:

app/models/foo/bar/baz.rb
app/models/foo/bar-baz.rb
app/models/foo-bar-baz.rb
app/monsters/dungeon/foo/bar/baz.rb

if I type app/mod/fo/ba/baz, I want fzf to filter down to app/models/foo/bar/baz.rb, and not include any of the others.

In other words, if I know in my head the dir structure of my project, and I want to get at a file that is under a specific subtree in the repo, I want to be able to use slashes to trim fzf's result set.

As fzf is now, when I type app/mod, it matches both app/models and app/monsters/dungeon because the letters mo are in monsters and d is in dungeon.

Feature request: Custom deliminator

a possible use case could be to filter nested class names or attributes, i.e. strings on the form foo.bar.baz.

Would you consider adding support for configuring the deliminator?

Allow scrolling the list of candidates

Currently zf only shows a fixed number of candidates (the height). The list should ideally be scrollable.

  • when the cursor is at the bottom, there are more candidates, and down is pressed it should scroll
  • also scroll up at the top
  • when the query is updated the scroll offset should be reset
  • maybe add a shortcut for top/bottom? paging?

Highlights and selected row go off screen

If the passed --height is greater than the height of the terminal, then the highlight on the last line is not displayed. I believe was introduced in the latest version when the last line is cleared.

-f, --filter differs from interactive

If I have a project with some zig files (extension .zig), if I just manually type .zig into zf, the results differ from passing -f .zig

 % find . -type f | /home/dev/git/zf/zig-out/bin/zf
> .zig
./src/ui.zig
./src/lib.zig
./src/clib.zig
./src/main.zig
./src/term.zig
./lib/ziglyph/src/category/mark.zig
./lib/ziglyph/src/segmenter/Word.zig
./build.zig
./lib/ziglyph/build.zig
./lib/ziglyph/src/ascii.zig

find . -type f | /home/dev/git/zf/zig-out/bin/zf -f .zig
[...]
./.git/modules/lib/ziglyph/info/exclude
./.git/modules/lib/ziglyph/refs/heads/main
./.git/modules/lib/ziglyph/hooks/update.sample
./.git/modules/lib/ziglyph/logs/refs/heads/main
./.git/modules/lib/ziglyph/hooks/pre-push.sample
./.git/modules/lib/ziglyph/hooks/commit-msg.sample
[...]

So, it looks like the -f option is matching:

  • . with .git
  • z with ziglyph
  • etc.

telescope integration

The roadmap in the readme shows telescope integration slated for release 0.2, but unless I'm crazy I don't see it in the 0.2 tag.

UI blocks until all results are collected

Would there be a way to incrementally display results? Currently if ran with rg --files | zf in home directory, there is a few seconds blocking until the prompt displays. I don't think it would be trivial to make it work but I am curious.

Packaging

Tracking

  • Debian
  • Mac (homebrew)
  • Mac (macports)
  • Arch Linux
  • Nixpkgs
  • Binaries for Linux and macOS (x86 and arm)

some problems that block me adopting zf

hi folks, thanks for making this awesome tool!
i want to use zf in my nvim plugin and here are some problems that stop me from adopting zf.
and i do know zf aims to be simple and can be use as a library, but i still think it's worth to put them here.

a) able to read from a file
nvim does not support ls | zf without using a shell
neovim/neovim#23141

b) able to save output as a file
since zf itself uses stdout or stderr to show its tui, i'd like to get user's
choice from a known file. you may say 'why not use ls | zf > file`, that
invokes a shell, i do want to avoid invoking that.

c) settable keybinds to choose the item, and output the triggered keybind
this is essential to my use, with it, i can know which way that user wants my
plugin to deal with the choice.
for example, <c-o> for editing the chose file in nvim, <c-t> for editing the
file in new tab, <c-v for editing the file in a vertical split.

d) able to set last query and use last query as a placeholder
maybe it's possible to do without changing the implementation: feeding last query in zf's stdin when its tui is ready.
even it's doable by that way, we has no way to support this placeholder feature at now.
this placeholder feature is just like how the HTML tag <input> works:
once user input something new, the placeholder will be erased.

UI Preview

Today I finally came across a use case for a UI preview. I am still not 100% sure if this is needed, but here are my thoughts

A new --preview long option that accepts a string representing a command to be run. The command accepts {} as a substitution for the current selected line. Alternate might be --command (more general)

If --preview is not null/empty, then the UI will look like this

>                                                                                             5/5
main                                               │               command output
missing-return-type                                │
nathan-pilot                                       │
php-8.1-upgrade                                    │
php-8.1-upgrade-whitespace                         │

It might also be nice to have a keybind to show/hide the preview (hidden by default?)

Again, I'm not 100% convinced this is needed. Maybe for scripts that require a preview command like this I'll just use fzf or something else.

Highlights incorrect when a candidate ends in a `/`

> slash
wow/this/slash/
          -----

the highlights are off-by-one. I think this is due to the implementation of basename in Zig.

Also this only happens when the last path component is the first part of the match. Searching for sslash correctly highlights s/slash.

Ranking improvements

I have a local file where I am tracking possible improvements to zf's ranking algorithm, but I figured this would be a better place to keep them.


In this example I expect complete/zf to be ranked above complete/_zf. The leading _ is adding to the score. A simpler way to look at this is an exact match should be prioritized

❯ zf
complete/_zf
doc/zf.1
complete/zf
doc/zf.md
complete/zf.fish
lib/ziglyph/src/autogen/case_folding.zig
lib/ziglyph/src/data/uca/allkeys-diffs.txt
lib/ziglyph/src/data/uca/allkeys-diffs.txt.gz

Usable as C library?

The documentation states this is usable as a C library, but it says TODO in that respective section. Can I use this as a C library (through FFI)?

Reduce flicker in the TUI

Flickering UIs seem to be my recurring battle. The zf ui flickers when rendering. While this doesn't interfere with proper use, it is annoying. This flicker was introduced when highlighting ranges. The candidates are printed character-by-character and highlights are toggled on and off as needed.

If I remove highlights and print each line as a full string there is no flicker. This makes sense, as the writeByte() function internally makes an array and passes that to the write() function, and that's a lot of overhead for drawing a single byte.

Perhaps there is a way to build a display string once per candidate with the range information and SGR codes embedded. Or even better, print the string in slices cut at the highlight points. This would require sorting the ranges, but that seems like less work than allocating a new string.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.