Skip to content

Commit a395a25

Browse files
Added option for hiding/showing private completions.
1 parent 9f7819e commit a395a25

File tree

3 files changed

+111
-19
lines changed

3 files changed

+111
-19
lines changed

ptpython/completer.py

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import ast
22
import keyword
33
import re
4-
from typing import TYPE_CHECKING, Any, Dict, Iterable, List
4+
from enum import Enum
5+
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional
56

67
from prompt_toolkit.completion import (
78
CompleteEvent,
@@ -12,21 +13,34 @@
1213
from prompt_toolkit.contrib.regular_languages.compiler import compile as compile_grammar
1314
from prompt_toolkit.contrib.regular_languages.completion import GrammarCompleter
1415
from prompt_toolkit.document import Document
16+
from prompt_toolkit.formatted_text import fragment_list_to_text, to_formatted_text
1517

1618
from ptpython.utils import get_jedi_script_from_document
1719

1820
if TYPE_CHECKING:
1921
from prompt_toolkit.contrib.regular_languages.compiler import _CompiledGrammar
2022

21-
__all__ = ["PythonCompleter"]
23+
__all__ = ["PythonCompleter", "CompletePrivateAttributes", "HidePrivateCompleter"]
24+
25+
26+
class CompletePrivateAttributes(Enum):
27+
"""
28+
Should we display private attributes in the completion pop-up?
29+
"""
30+
31+
NEVER = "NEVER"
32+
IF_NO_PUBLIC = "IF_NO_PUBLIC"
33+
ALWAYS = "ALWAYS"
2234

2335

2436
class PythonCompleter(Completer):
2537
"""
2638
Completer for Python code.
2739
"""
2840

29-
def __init__(self, get_globals, get_locals, get_enable_dictionary_completion):
41+
def __init__(
42+
self, get_globals, get_locals, get_enable_dictionary_completion
43+
) -> None:
3044
super().__init__()
3145

3246
self.get_globals = get_globals
@@ -35,8 +49,8 @@ def __init__(self, get_globals, get_locals, get_enable_dictionary_completion):
3549

3650
self.dictionary_completer = DictionaryCompleter(get_globals, get_locals)
3751

38-
self._path_completer_cache = None
39-
self._path_completer_grammar_cache = None
52+
self._path_completer_cache: Optional[GrammarCompleter] = None
53+
self._path_completer_grammar_cache: Optional["_CompiledGrammar"] = None
4054

4155
@property
4256
def _path_completer(self) -> GrammarCompleter:
@@ -158,7 +172,7 @@ def get_completions(
158172

159173
if script:
160174
try:
161-
completions = script.completions()
175+
jedi_completions = script.completions()
162176
except TypeError:
163177
# Issue #9: bad syntax causes completions() to fail in jedi.
164178
# https://github.com/jonathanslenders/python-prompt-toolkit/issues/9
@@ -196,12 +210,12 @@ def get_completions(
196210
# Supress all other Jedi exceptions.
197211
pass
198212
else:
199-
for c in completions:
213+
for jc in jedi_completions:
200214
yield Completion(
201-
c.name_with_symbols,
202-
len(c.complete) - len(c.name_with_symbols),
203-
display=c.name_with_symbols,
204-
style=_get_style_for_name(c.name_with_symbols),
215+
jc.name_with_symbols,
216+
len(jc.complete) - len(jc.name_with_symbols),
217+
display=jc.name_with_symbols,
218+
style=_get_style_for_name(jc.name_with_symbols),
205219
)
206220

207221

@@ -464,6 +478,49 @@ def sort_key(name: str):
464478
return sorted(names, key=sort_key)
465479

466480

481+
class HidePrivateCompleter(Completer):
482+
"""
483+
Wrapper around completer that hides private fields, deponding on whether or
484+
not public fields are shown.
485+
486+
(The reason this is implemented as a `Completer` wrapper is because this
487+
way it works also with `FuzzyCompleter`.)
488+
"""
489+
490+
def __init__(
491+
self,
492+
completer: Completer,
493+
complete_private_attributes: Callable[[], CompletePrivateAttributes],
494+
) -> None:
495+
self.completer = completer
496+
self.complete_private_attributes = complete_private_attributes
497+
498+
def get_completions(
499+
self, document: Document, complete_event: CompleteEvent
500+
) -> Iterable[Completion]:
501+
502+
completions = list(self.completer.get_completions(document, complete_event))
503+
complete_private_attributes = self.complete_private_attributes()
504+
hide_private = False
505+
506+
def is_private(completion: Completion) -> bool:
507+
text = fragment_list_to_text(to_formatted_text(completion.display))
508+
return text.startswith("_")
509+
510+
if complete_private_attributes == CompletePrivateAttributes.NEVER:
511+
hide_private = True
512+
513+
elif complete_private_attributes == CompletePrivateAttributes.IF_NO_PUBLIC:
514+
hide_private = any(not is_private(completion) for completion in completions)
515+
516+
if hide_private:
517+
completions = [
518+
completion for completion in completions if not is_private(completion)
519+
]
520+
521+
return completions
522+
523+
467524
class ReprFailedError(Exception):
468525
" Raised when the repr() call in `DictionaryCompleter` fails. "
469526

ptpython/layout.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,10 @@ def get_help_text():
213213

214214
return ConditionalContainer(
215215
content=Window(
216-
FormattedTextControl(get_help_text), style=token, height=Dimension(min=3)
216+
FormattedTextControl(get_help_text),
217+
style=token,
218+
height=Dimension(min=3),
219+
wrap_lines=True,
217220
),
218221
filter=ShowSidebar(python_input)
219222
& Condition(lambda: python_input.show_sidebar_help)

ptpython/python_input.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
from prompt_toolkit.validation import ConditionalValidator, Validator
5252
from pygments.lexers import Python3Lexer as PythonLexer
5353

54-
from .completer import PythonCompleter
54+
from .completer import CompletePrivateAttributes, HidePrivateCompleter, PythonCompleter
5555
from .history_browser import PythonHistory
5656
from .key_bindings import (
5757
load_confirm_exit_bindings,
@@ -180,13 +180,17 @@ def __init__(
180180
self.get_globals: _GetNamespace = get_globals or (lambda: {})
181181
self.get_locals: _GetNamespace = get_locals or self.get_globals
182182

183-
self._completer = _completer or FuzzyCompleter(
184-
PythonCompleter(
185-
self.get_globals,
186-
self.get_locals,
187-
lambda: self.enable_dictionary_completion,
183+
self._completer = HidePrivateCompleter(
184+
_completer
185+
or FuzzyCompleter(
186+
PythonCompleter(
187+
self.get_globals,
188+
self.get_locals,
189+
lambda: self.enable_dictionary_completion,
190+
),
191+
enable_fuzzy=Condition(lambda: self.enable_fuzzy_completion),
188192
),
189-
enable_fuzzy=Condition(lambda: self.enable_fuzzy_completion),
193+
lambda: self.complete_private_attributes,
190194
)
191195
self._validator = _validator or PythonValidator(self.get_compiler_flags)
192196
self._lexer = _lexer or PygmentsLexer(PythonLexer)
@@ -239,6 +243,9 @@ def __init__(
239243
self.enable_syntax_highlighting: bool = True
240244
self.enable_fuzzy_completion: bool = False
241245
self.enable_dictionary_completion: bool = False
246+
self.complete_private_attributes: CompletePrivateAttributes = (
247+
CompletePrivateAttributes.ALWAYS
248+
)
242249
self.swap_light_and_dark: bool = False
243250
self.highlight_matching_parenthesis: bool = False
244251
self.show_sidebar: bool = False # Currently show the sidebar.
@@ -530,6 +537,31 @@ def get_values():
530537
"off": lambda: disable("complete_while_typing"),
531538
},
532539
),
540+
Option(
541+
title="Complete private attrs",
542+
description="Show or hide private attributes in the completions. "
543+
"'If no public' means: show private attributes only if no public "
544+
"matches are found or if an underscore was typed.",
545+
get_current_value=lambda: {
546+
CompletePrivateAttributes.NEVER: "Never",
547+
CompletePrivateAttributes.ALWAYS: "Always",
548+
CompletePrivateAttributes.IF_NO_PUBLIC: "If no public",
549+
}[self.complete_private_attributes],
550+
get_values=lambda: {
551+
"Never": lambda: enable(
552+
"complete_private_attributes",
553+
CompletePrivateAttributes.NEVER,
554+
),
555+
"Always": lambda: enable(
556+
"complete_private_attributes",
557+
CompletePrivateAttributes.ALWAYS,
558+
),
559+
"If no public": lambda: enable(
560+
"complete_private_attributes",
561+
CompletePrivateAttributes.IF_NO_PUBLIC,
562+
),
563+
},
564+
),
533565
Option(
534566
title="Enable fuzzy completion",
535567
description="Enable fuzzy completion.",

0 commit comments

Comments
 (0)