fzf-but-typed


Namefzf-but-typed JSON
Version 0.54.0 PyPI version JSON
download
home_pagehttps://github.com/brunofauth/fzf-but-typed
SummaryStatically typed API to fzf
upload_time2024-07-17 02:46:22
maintainerNone
docs_urlNone
authorBruno Fauth
requires_python<4.0,>=3.11
licenseMIT
keywords cli command-line type hint fzf fuzzy finder
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <!--
    vim: nospell
-->

# Table of Contents

- [Introduction](#introduction)
- [Installation](#installation)
- [API Overview and Examples](#api-overview-and-examples)
  * [Main Content](#main-content)
  * [`fzf` Free Function](#fzf-free-function)
  * [`fzf_iter` Free Function](#fzf_iter-free-function)
  * [`FuzzyFinderBuilder` class](#fuzzyfinderbuilder-class)
  * [Going Nuts with All These Features](#going-nuts-with-all-these-features)
- [`fzf` Version Compatibility](#fzf-version-compatibility)


# Introduction

`fzf_but_typed` is a python wrapper for [fzf](https://github.com/junegunn/fzf/).  
It's different from other existing wrappers because it wraps all of fzf's CLI 
options and their possible values into neat types, so that you can leverage 
your IDE/LSP/type-checker as a means of correctly using fzf, without having to 
lookup usage details in the manpages. Furthermore, being able to use your 
editor's autocompletion features instead of having to manually type CLI 
arguments is much more comfortable.


# Installation

With pip:

    pip install fzf_but_typed

With poetry:
    
    poetry add fzf_but_typed


# API Overview and Examples

## Main Content

The following items are the bread and butter of this package:
-  `fzf` (free function)
-  `fzf_iter` (free function)
-  `fzf_pairs` (free function)
-  `fzf_mapping` (free function)
-  `FuzzyFinder` (class)
-  `FuzzyFinderBuilder` (class)
-  `FuzzyFinderOutput` (class)

Many other classes, parts of `FuzzyFinderBuilder`'s configuration are also 
included, but you're not always going to have to use each of them, so, in this 
guide, I'll only mention them when necessary, in appropriate examples.

## `fzf` Free Function

Basic Usage:

```python
from fzf_but_typed import fzf, SearchOptions, DisplayOptions, Color, 

# Basic usage
chosen_items = fzf(input_text="first\nsecond\nthird")
print("you chose:", chosen_items[0])
```

Through `fzf`, you can pass arguments to `FuzzyFinderBuilder` too, as keyword 
arguments, like this:

```python
from fzf_but_typed import (fzf,
    SearchOptions, DisplayOptions, Color, BaseColorScheme)

chosen_items = fzf(
    input_text="first\nsecond\nthird",
    search=SearchOptions(exact=True, case_sensitive=False),
    display=DisplayOptions(color=Color(base_scheme=BaseColorScheme.LIGHT_256)),
)
print("you chose:", chosen_items[0])
```

## `fzf_iter` Free Function

In the spirit of python's duck typing, this module ships `fzf_iter`, to which 
you can pass a list of anything that can be converted into a `str`, as input.  
See the example below

```python
from fzf_but_typed import fzf_iter, Key as SomeStrEnum

a_heterogenous_collection = [
    123123123,
    "aaaaaa",
    12.32,
    SomeStrEnum.CTRL_A,
]
print("you chose:", fzf_iter(input=a_heterogenous_collection)[0])
```

You can pass keyword arguments to `FuzzyFinderBuilder` through this function 
too, just like you did in `fzf` previously! See the example below

```python
from fzf_but_typed import fzf_iter, InterfaceOptions, ScriptingOptions

a_heterogenous_collection = [123123123, "aaaaaa"]
chosen = fzf_iter(
    input=a_heterogenous_collection,
    interface=InterfaceOptions(multi=True, cycle=True),
    scripting=ScriptingOptions(print0=True),
)

print("you chose:", chosen[0])
```


## `fzf_pairs` and `fzf_mapping` Free Functions

Sometimes you may want your users to be able to select from the values of a 
mapping and get those values' keys back. For that use case, you can employ 
`fzf_mapping`, like this:

```python
from fzf_but_typed import fzf_mapping

some_dict = {
    "aaaaa": 22,
    "bbbbb": 33,
    12345: "option_number_three",
}

# This works with any object that is compatible with:
#     Mapping[SupportsStr, SupportsStr]
# Where 'SupportsStr' is anything that implements '__str__'
key = fzf_mapping(input=some_dict)[0]

assert key in some_dict
print("you chose:", some_dict[key])
```

Similarly, you can use `fzf_pairs` to do the same thing as above, but passing 
in an iterable of tuples of strings:

```python
from fzf_but_typed import fzf_pairs

some_data = [
    ("aaaaa", 22),
    ("bbbbb", 33),
    (12345, "option_number_three"),
]

# This works with any object that is compatible with:
#     Iterable[tuple[SupportsStr, SupportsStr]]
# Where 'SupportsStr' is anything that implements '__str__'
key = fzf_mapping(input=some_dict)[0]

assert key in some_dict
print("you chose:", some_data[key])
```


## `FuzzyFinderBuilder` class

Using `FuzzyFinderBuilder` (instead of `fzf` or `fzf_iter`) allows you to cache 
`FuzzyFinder` objects with predefined settings for later use, being a little 
bit more efficient than building a new `FuzzyFinder` every time. It may receive 
many `*Options` parameters, as well as a `Path` to where your `fzf` binary is 
located (defaults to whatever `shutil.which` returns).

```python
from fzf_but_typed import (
    FuzzyFinderBuilder, SearchOptions, ResultsOptions, DisplayOptions,
    PreviewOptions, FuzzyFinder, FuzzyFinderOutput, ExitStatusCode)

# These keyword arguments are also accepted by the previously mentioned 'fzf'
# and 'fzf_iter' functions
builder: FuzzyFinderBuilder = FuzzyFinderBuilder(
    search=SearchOptions(exact=True, case_sensitive=False),
    results=ResultsOptions(tac=True),
    display=DisplayOptions(ansi=True),
    preview=PreviewOptions(preview_command="echo {} | tr [:lower:] [:upper:]"),
)

# This object can be cached to be used again later (thats more efficient than
# calling 'fzf' or 'fzf_iter' multiple times, because this way, you don't have 
# to implicitly instantiate new builders over and over again
fuzzy_finder: FuzzyFinder = builder.build()

# You can access the 'built' command-line arguments through FuzzyFinder
# instances, as well as query the location of the binary to be used
print(f"{fuzzy_finder.binary_path=}")
print(f"{fuzzy_finder.args=}")

# When you feel like it, you can call 'run()' on 'FuzzyFinder' objects. Upon
# completion, they return 'FuzzyFinderOutput' objects
fzf_output: FuzzyFinderOutput = fuzzy_finder.run(input_lines="\n".join([
    "first line", "second line", "yet another line"])

# 'FuzzyFinderOutput' objects contain an 'exit_status_code' field, which is an
# enum, and a output field, which is a 'list' of 'str'
match fzf_output.exit_status_code:
    case ExitStatusCode.ERROR:
        print("something went wrong")
    case other_status_code:
        print("this is what happened:", other_status_code.name)

print("here's what you've selected:")
for item in fzf_output.output:
    print('\t', item)
```

## Going Nuts with All These Features

```python
from fzf_but_typed import (
    Event, Key, ActionSimple, ActionWithArg, ActionWithArgType,
    ActionArgSeparator, FuzzyFinderBuilder, SearchOptions, ResultsOptions,
    InterfaceOptions, LayoutOptions, LayoutType, BorderType, DisplayOptions,
    Color, BaseColorScheme, HistoryOptions, PreviewOptions, ScriptingOptions
)

binds = [
    Binding(Event.ONE, [ActionSimple.ACCEPT]),
    Binding(Key.CTRL_R, [
        ActionWithArg(
            action_type=ActionWithArgType.CHANGE_PREVIEW_WINDOW,
            argument="right,70%|top,60%",
        ),
        ActionWithArg(
            action_type=ActionWithArgType.EXECUTE,
            argument="notify-send {} -t 3000",
            separator=ActionArgSeparator.PERCENT,
        ),
        ActionSimple.FIRST,
    ])
]

builder: FuzzyFinderBuilder = FuzzyFinderBuilder(
    search=SearchOptions(exact=True, case_sensitive=False),
    results=ResultsOptions(tac=True),
    interface=InterfaceOptions(multi=True, cycle=True, bind=binds),
    layout=LayoutOptions(layout=LayoutType.REVERSE, border=BorderType.SHARP),
    display=DisplayOptions(color=Color(base_scheme=BaseColorScheme.LIGHT_256)),
    history=HistoryOptions(history_size=19),
    preview=PreviewOptions(preview_command="echo {} | tr [:lower:] [:upper:]"),
    scripting=ScriptingOptions(read0=True, print0=True),
)

result = builder.build().run(input_lines="\0".join([
    "aaa a a a aaa a a a a a",
    "bb bw b f b bw b b bf db db  ",
    "cc case_sensitive c c       c c c ccccc",
    "asdasdasdas",
    "johnny",
    "",
    "asdasnkdaks",
]))

print("fzf returned code:", result.exit_status_code)
print("you picked:")
for item in result.output:
    print('\t', item)
```


# `fzf` Version Compatibility

Starting from version `0.45.0`, this library's major and minor version numbers 
match those of fzf; that is: `fzf` version `0.45.X` is compatible with 
`fzf_but_typed` version `0.45.Y`.

The contents of this package are based on the informations avaliable on my 
system's man pages for fzf. If your version of fzf is older than mine, some of 
the features exposed on this API may not work. Conversely, if it's newer than 
mine, some features you may want to use may be absent here. Regardless, your 
use case is probably supported by this lib.


# Missing Features and Contributing

If any features you want to use are missing and that's sufficiently important 
to you, you can clone this repo, add that functionality and submit a pull 
request. I'll be glad to take in contributions!


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/brunofauth/fzf-but-typed",
    "name": "fzf-but-typed",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.11",
    "maintainer_email": null,
    "keywords": "cli, command-line, type, hint, fzf, fuzzy, finder",
    "author": "Bruno Fauth",
    "author_email": "149593@upf.br",
    "download_url": "https://files.pythonhosted.org/packages/82/c9/f4b430c1235d0ab3946df7e682ee54270cdd6a9049712c0799216e80d7ab/fzf_but_typed-0.54.0.tar.gz",
    "platform": null,
    "description": "<!--\n    vim: nospell\n-->\n\n# Table of Contents\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n- [API Overview and Examples](#api-overview-and-examples)\n  * [Main Content](#main-content)\n  * [`fzf` Free Function](#fzf-free-function)\n  * [`fzf_iter` Free Function](#fzf_iter-free-function)\n  * [`FuzzyFinderBuilder` class](#fuzzyfinderbuilder-class)\n  * [Going Nuts with All These Features](#going-nuts-with-all-these-features)\n- [`fzf` Version Compatibility](#fzf-version-compatibility)\n\n\n# Introduction\n\n`fzf_but_typed` is a python wrapper for [fzf](https://github.com/junegunn/fzf/).  \nIt's different from other existing wrappers because it wraps all of fzf's CLI \noptions and their possible values into neat types, so that you can leverage \nyour IDE/LSP/type-checker as a means of correctly using fzf, without having to \nlookup usage details in the manpages. Furthermore, being able to use your \neditor's autocompletion features instead of having to manually type CLI \narguments is much more comfortable.\n\n\n# Installation\n\nWith pip:\n\n    pip install fzf_but_typed\n\nWith poetry:\n    \n    poetry add fzf_but_typed\n\n\n# API Overview and Examples\n\n## Main Content\n\nThe following items are the bread and butter of this package:\n-  `fzf` (free function)\n-  `fzf_iter` (free function)\n-  `fzf_pairs` (free function)\n-  `fzf_mapping` (free function)\n-  `FuzzyFinder` (class)\n-  `FuzzyFinderBuilder` (class)\n-  `FuzzyFinderOutput` (class)\n\nMany other classes, parts of `FuzzyFinderBuilder`'s configuration are also \nincluded, but you're not always going to have to use each of them, so, in this \nguide, I'll only mention them when necessary, in appropriate examples.\n\n## `fzf` Free Function\n\nBasic Usage:\n\n```python\nfrom fzf_but_typed import fzf, SearchOptions, DisplayOptions, Color, \n\n# Basic usage\nchosen_items = fzf(input_text=\"first\\nsecond\\nthird\")\nprint(\"you chose:\", chosen_items[0])\n```\n\nThrough `fzf`, you can pass arguments to `FuzzyFinderBuilder` too, as keyword \narguments, like this:\n\n```python\nfrom fzf_but_typed import (fzf,\n    SearchOptions, DisplayOptions, Color, BaseColorScheme)\n\nchosen_items = fzf(\n    input_text=\"first\\nsecond\\nthird\",\n    search=SearchOptions(exact=True, case_sensitive=False),\n    display=DisplayOptions(color=Color(base_scheme=BaseColorScheme.LIGHT_256)),\n)\nprint(\"you chose:\", chosen_items[0])\n```\n\n## `fzf_iter` Free Function\n\nIn the spirit of python's duck typing, this module ships `fzf_iter`, to which \nyou can pass a list of anything that can be converted into a `str`, as input.  \nSee the example below\n\n```python\nfrom fzf_but_typed import fzf_iter, Key as SomeStrEnum\n\na_heterogenous_collection = [\n    123123123,\n    \"aaaaaa\",\n    12.32,\n    SomeStrEnum.CTRL_A,\n]\nprint(\"you chose:\", fzf_iter(input=a_heterogenous_collection)[0])\n```\n\nYou can pass keyword arguments to `FuzzyFinderBuilder` through this function \ntoo, just like you did in `fzf` previously! See the example below\n\n```python\nfrom fzf_but_typed import fzf_iter, InterfaceOptions, ScriptingOptions\n\na_heterogenous_collection = [123123123, \"aaaaaa\"]\nchosen = fzf_iter(\n    input=a_heterogenous_collection,\n    interface=InterfaceOptions(multi=True, cycle=True),\n    scripting=ScriptingOptions(print0=True),\n)\n\nprint(\"you chose:\", chosen[0])\n```\n\n\n## `fzf_pairs` and `fzf_mapping` Free Functions\n\nSometimes you may want your users to be able to select from the values of a \nmapping and get those values' keys back. For that use case, you can employ \n`fzf_mapping`, like this:\n\n```python\nfrom fzf_but_typed import fzf_mapping\n\nsome_dict = {\n    \"aaaaa\": 22,\n    \"bbbbb\": 33,\n    12345: \"option_number_three\",\n}\n\n# This works with any object that is compatible with:\n#     Mapping[SupportsStr, SupportsStr]\n# Where 'SupportsStr' is anything that implements '__str__'\nkey = fzf_mapping(input=some_dict)[0]\n\nassert key in some_dict\nprint(\"you chose:\", some_dict[key])\n```\n\nSimilarly, you can use `fzf_pairs` to do the same thing as above, but passing \nin an iterable of tuples of strings:\n\n```python\nfrom fzf_but_typed import fzf_pairs\n\nsome_data = [\n    (\"aaaaa\", 22),\n    (\"bbbbb\", 33),\n    (12345, \"option_number_three\"),\n]\n\n# This works with any object that is compatible with:\n#     Iterable[tuple[SupportsStr, SupportsStr]]\n# Where 'SupportsStr' is anything that implements '__str__'\nkey = fzf_mapping(input=some_dict)[0]\n\nassert key in some_dict\nprint(\"you chose:\", some_data[key])\n```\n\n\n## `FuzzyFinderBuilder` class\n\nUsing `FuzzyFinderBuilder` (instead of `fzf` or `fzf_iter`) allows you to cache \n`FuzzyFinder` objects with predefined settings for later use, being a little \nbit more efficient than building a new `FuzzyFinder` every time. It may receive \nmany `*Options` parameters, as well as a `Path` to where your `fzf` binary is \nlocated (defaults to whatever `shutil.which` returns).\n\n```python\nfrom fzf_but_typed import (\n    FuzzyFinderBuilder, SearchOptions, ResultsOptions, DisplayOptions,\n    PreviewOptions, FuzzyFinder, FuzzyFinderOutput, ExitStatusCode)\n\n# These keyword arguments are also accepted by the previously mentioned 'fzf'\n# and 'fzf_iter' functions\nbuilder: FuzzyFinderBuilder = FuzzyFinderBuilder(\n    search=SearchOptions(exact=True, case_sensitive=False),\n    results=ResultsOptions(tac=True),\n    display=DisplayOptions(ansi=True),\n    preview=PreviewOptions(preview_command=\"echo {} | tr [:lower:] [:upper:]\"),\n)\n\n# This object can be cached to be used again later (thats more efficient than\n# calling 'fzf' or 'fzf_iter' multiple times, because this way, you don't have \n# to implicitly instantiate new builders over and over again\nfuzzy_finder: FuzzyFinder = builder.build()\n\n# You can access the 'built' command-line arguments through FuzzyFinder\n# instances, as well as query the location of the binary to be used\nprint(f\"{fuzzy_finder.binary_path=}\")\nprint(f\"{fuzzy_finder.args=}\")\n\n# When you feel like it, you can call 'run()' on 'FuzzyFinder' objects. Upon\n# completion, they return 'FuzzyFinderOutput' objects\nfzf_output: FuzzyFinderOutput = fuzzy_finder.run(input_lines=\"\\n\".join([\n    \"first line\", \"second line\", \"yet another line\"])\n\n# 'FuzzyFinderOutput' objects contain an 'exit_status_code' field, which is an\n# enum, and a output field, which is a 'list' of 'str'\nmatch fzf_output.exit_status_code:\n    case ExitStatusCode.ERROR:\n        print(\"something went wrong\")\n    case other_status_code:\n        print(\"this is what happened:\", other_status_code.name)\n\nprint(\"here's what you've selected:\")\nfor item in fzf_output.output:\n    print('\\t', item)\n```\n\n## Going Nuts with All These Features\n\n```python\nfrom fzf_but_typed import (\n    Event, Key, ActionSimple, ActionWithArg, ActionWithArgType,\n    ActionArgSeparator, FuzzyFinderBuilder, SearchOptions, ResultsOptions,\n    InterfaceOptions, LayoutOptions, LayoutType, BorderType, DisplayOptions,\n    Color, BaseColorScheme, HistoryOptions, PreviewOptions, ScriptingOptions\n)\n\nbinds = [\n    Binding(Event.ONE, [ActionSimple.ACCEPT]),\n    Binding(Key.CTRL_R, [\n        ActionWithArg(\n            action_type=ActionWithArgType.CHANGE_PREVIEW_WINDOW,\n            argument=\"right,70%|top,60%\",\n        ),\n        ActionWithArg(\n            action_type=ActionWithArgType.EXECUTE,\n            argument=\"notify-send {} -t 3000\",\n            separator=ActionArgSeparator.PERCENT,\n        ),\n        ActionSimple.FIRST,\n    ])\n]\n\nbuilder: FuzzyFinderBuilder = FuzzyFinderBuilder(\n    search=SearchOptions(exact=True, case_sensitive=False),\n    results=ResultsOptions(tac=True),\n    interface=InterfaceOptions(multi=True, cycle=True, bind=binds),\n    layout=LayoutOptions(layout=LayoutType.REVERSE, border=BorderType.SHARP),\n    display=DisplayOptions(color=Color(base_scheme=BaseColorScheme.LIGHT_256)),\n    history=HistoryOptions(history_size=19),\n    preview=PreviewOptions(preview_command=\"echo {} | tr [:lower:] [:upper:]\"),\n    scripting=ScriptingOptions(read0=True, print0=True),\n)\n\nresult = builder.build().run(input_lines=\"\\0\".join([\n    \"aaa a a a aaa a a a a a\",\n    \"bb bw b f b bw b b bf db db  \",\n    \"cc case_sensitive c c       c c c ccccc\",\n    \"asdasdasdas\",\n    \"johnny\",\n    \"\",\n    \"asdasnkdaks\",\n]))\n\nprint(\"fzf returned code:\", result.exit_status_code)\nprint(\"you picked:\")\nfor item in result.output:\n    print('\\t', item)\n```\n\n\n# `fzf` Version Compatibility\n\nStarting from version `0.45.0`, this library's major and minor version numbers \nmatch those of fzf; that is: `fzf` version `0.45.X` is compatible with \n`fzf_but_typed` version `0.45.Y`.\n\nThe contents of this package are based on the informations avaliable on my \nsystem's man pages for fzf. If your version of fzf is older than mine, some of \nthe features exposed on this API may not work. Conversely, if it's newer than \nmine, some features you may want to use may be absent here. Regardless, your \nuse case is probably supported by this lib.\n\n\n# Missing Features and Contributing\n\nIf any features you want to use are missing and that's sufficiently important \nto you, you can clone this repo, add that functionality and submit a pull \nrequest. I'll be glad to take in contributions!\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Statically typed API to fzf",
    "version": "0.54.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/brunofauth/fzf-but-typed/issues",
        "Homepage": "https://github.com/brunofauth/fzf-but-typed",
        "Repository": "https://github.com/brunofauth/fzf-but-typed"
    },
    "split_keywords": [
        "cli",
        " command-line",
        " type",
        " hint",
        " fzf",
        " fuzzy",
        " finder"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "82c9f4b430c1235d0ab3946df7e682ee54270cdd6a9049712c0799216e80d7ab",
                "md5": "f51a64565e76f1503c0660427c882c88",
                "sha256": "0d7f2b3c2063e4c270509707e5ed27178773109a12fa2910cf55cd61bb45f6da"
            },
            "downloads": -1,
            "filename": "fzf_but_typed-0.54.0.tar.gz",
            "has_sig": false,
            "md5_digest": "f51a64565e76f1503c0660427c882c88",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.11",
            "size": 18078,
            "upload_time": "2024-07-17T02:46:22",
            "upload_time_iso_8601": "2024-07-17T02:46:22.780526Z",
            "url": "https://files.pythonhosted.org/packages/82/c9/f4b430c1235d0ab3946df7e682ee54270cdd6a9049712c0799216e80d7ab/fzf_but_typed-0.54.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-07-17 02:46:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "brunofauth",
    "github_project": "fzf-but-typed",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "fzf-but-typed"
}
        
Elapsed time: 0.31556s