Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/prompt_toolkit/buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ class Buffer:
:param complete_while_typing: :class:`~prompt_toolkit.filters.Filter`
or `bool`. Decide whether or not to do asynchronous autocompleting while
typing.
:param filter_noop_completions: :class:`~prompt_toolkit.filters.Filter` or
`bool`. Ignore a single completion that would not change the input.
:param validate_while_typing: :class:`~prompt_toolkit.filters.Filter`
or `bool`. Decide whether or not to do asynchronous validation while
typing.
Expand Down Expand Up @@ -235,10 +237,12 @@ def __init__(
on_cursor_position_changed: BufferEventHandler | None = None,
on_completions_changed: BufferEventHandler | None = None,
on_suggestion_set: BufferEventHandler | None = None,
filter_noop_completions: FilterOrBool = True,
) -> None:
# Accept both filters and booleans as input.
enable_history_search = to_filter(enable_history_search)
complete_while_typing = to_filter(complete_while_typing)
filter_noop_completions = to_filter(filter_noop_completions)
validate_while_typing = to_filter(validate_while_typing)
read_only = to_filter(read_only)
multiline = to_filter(multiline)
Expand All @@ -253,6 +257,7 @@ def __init__(

# Filters. (Usually, used by the key bindings to drive the buffer.)
self.complete_while_typing = complete_while_typing
self.filter_noop_completions = filter_noop_completions
self.validate_while_typing = validate_while_typing
self.enable_history_search = enable_history_search
self.read_only = read_only
Expand Down Expand Up @@ -1761,8 +1766,10 @@ async def refresh_while_loading() -> None:
completions = complete_state.completions

# When there is only one completion, which has nothing to add, ignore it.
if len(completions) == 1 and completion_does_nothing(
document, completions[0]
if (
self.filter_noop_completions()
and len(completions) == 1
and completion_does_nothing(document, completions[0])
):
del completions[:]

Expand Down
15 changes: 15 additions & 0 deletions src/prompt_toolkit/shortcuts/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ class PromptSession(Generic[_T]):
:param complete_while_typing: `bool` or
:class:`~prompt_toolkit.filters.Filter`. Enable autocompletion while
typing.
:param filter_noop_completions: `bool` or
:class:`~prompt_toolkit.filters.Filter`. Ignore a single completion
that would not change the input.
:param validate_while_typing: `bool` or
:class:`~prompt_toolkit.filters.Filter`. Enable input validation while
typing.
Expand Down Expand Up @@ -358,6 +361,7 @@ class PromptSession(Generic[_T]):
"enable_history_search",
"search_ignore_case",
"complete_while_typing",
"filter_noop_completions",
"validate_while_typing",
"complete_style",
"mouse_support",
Expand Down Expand Up @@ -386,6 +390,7 @@ def __init__(
vi_mode: bool = False,
editing_mode: EditingMode = EditingMode.EMACS,
complete_while_typing: FilterOrBool = True,
filter_noop_completions: FilterOrBool = True,
validate_while_typing: FilterOrBool = True,
enable_history_search: FilterOrBool = False,
search_ignore_case: FilterOrBool = False,
Expand Down Expand Up @@ -457,6 +462,7 @@ def __init__(
self.enable_history_search = enable_history_search
self.search_ignore_case = search_ignore_case
self.complete_while_typing = complete_while_typing
self.filter_noop_completions = filter_noop_completions
self.validate_while_typing = validate_while_typing
self.complete_style = complete_style
self.mouse_support = mouse_support
Expand Down Expand Up @@ -527,6 +533,7 @@ def accept(buff: Buffer) -> bool:
and not self.complete_style == CompleteStyle.READLINE_LIKE
)
),
filter_noop_completions=dyncond("filter_noop_completions"),
validate_while_typing=dyncond("validate_while_typing"),
enable_history_search=dyncond("enable_history_search"),
validator=DynamicValidator(lambda: self.validator),
Expand Down Expand Up @@ -907,6 +914,7 @@ def prompt(
enable_history_search: FilterOrBool | None = None,
search_ignore_case: FilterOrBool | None = None,
complete_while_typing: FilterOrBool | None = None,
filter_noop_completions: FilterOrBool | None = None,
validate_while_typing: FilterOrBool | None = None,
complete_style: CompleteStyle | None = None,
auto_suggest: AutoSuggest | None = None,
Expand Down Expand Up @@ -1018,6 +1026,8 @@ class itself. For these, passing in ``None`` will keep the current
self.search_ignore_case = search_ignore_case
if complete_while_typing is not None:
self.complete_while_typing = complete_while_typing
if filter_noop_completions is not None:
self.filter_noop_completions = filter_noop_completions
if validate_while_typing is not None:
self.validate_while_typing = validate_while_typing
if complete_style is not None:
Expand Down Expand Up @@ -1147,6 +1157,7 @@ async def prompt_async(
enable_history_search: FilterOrBool | None = None,
search_ignore_case: FilterOrBool | None = None,
complete_while_typing: FilterOrBool | None = None,
filter_noop_completions: FilterOrBool | None = None,
validate_while_typing: FilterOrBool | None = None,
complete_style: CompleteStyle | None = None,
auto_suggest: AutoSuggest | None = None,
Expand Down Expand Up @@ -1215,6 +1226,8 @@ async def prompt_async(
self.search_ignore_case = search_ignore_case
if complete_while_typing is not None:
self.complete_while_typing = complete_while_typing
if filter_noop_completions is not None:
self.filter_noop_completions = filter_noop_completions
if validate_while_typing is not None:
self.validate_while_typing = validate_while_typing
if complete_style is not None:
Expand Down Expand Up @@ -1423,6 +1436,7 @@ def prompt(
enable_history_search: FilterOrBool | None = None,
search_ignore_case: FilterOrBool | None = None,
complete_while_typing: FilterOrBool | None = None,
filter_noop_completions: FilterOrBool | None = None,
validate_while_typing: FilterOrBool | None = None,
complete_style: CompleteStyle | None = None,
auto_suggest: AutoSuggest | None = None,
Expand Down Expand Up @@ -1479,6 +1493,7 @@ def prompt(
enable_history_search=enable_history_search,
search_ignore_case=search_ignore_case,
complete_while_typing=complete_while_typing,
filter_noop_completions=filter_noop_completions,
validate_while_typing=validate_while_typing,
complete_style=complete_style,
auto_suggest=auto_suggest,
Expand Down
31 changes: 31 additions & 0 deletions tests/test_buffer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from __future__ import annotations

import asyncio

import pytest

from prompt_toolkit.buffer import Buffer
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.input import DummyInput
from prompt_toolkit.output import DummyOutput
from prompt_toolkit.shortcuts import PromptSession


@pytest.fixture
Expand All @@ -16,6 +22,31 @@ def test_initial(_buffer):
assert _buffer.cursor_position == 0


@pytest.mark.parametrize(
("filter_noop_completions", "has_completions"),
[(True, False), (False, True)],
)
def test_filter_noop_completions(filter_noop_completions, has_completions):
buffer = Buffer(
completer=WordCompleter(["show"]),
filter_noop_completions=filter_noop_completions,
)
buffer.text = "show"
buffer.cursor_position = len(buffer.text)

asyncio.run(buffer._create_completer_coroutine()())

assert (buffer.complete_state is not None) is has_completions


def test_prompt_session_filter_noop_completions():
session = PromptSession(
input=DummyInput(), output=DummyOutput(), filter_noop_completions=False
)

assert not session.default_buffer.filter_noop_completions()


def test_insert_text(_buffer):
_buffer.insert_text("some_text")
assert _buffer.text == "some_text"
Expand Down
Loading