Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/prompt_toolkit/completion/filesystem.py: 23%

47 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1from __future__ import annotations 

2 

3import os 

4from typing import Callable, Iterable 

5 

6from prompt_toolkit.completion import CompleteEvent, Completer, Completion 

7from prompt_toolkit.document import Document 

8 

9__all__ = [ 

10 "PathCompleter", 

11 "ExecutableCompleter", 

12] 

13 

14 

15class PathCompleter(Completer): 

16 """ 

17 Complete for Path variables. 

18 

19 :param get_paths: Callable which returns a list of directories to look into 

20 when the user enters a relative path. 

21 :param file_filter: Callable which takes a filename and returns whether 

22 this file should show up in the completion. ``None`` 

23 when no filtering has to be done. 

24 :param min_input_len: Don't do autocompletion when the input string is shorter. 

25 """ 

26 

27 def __init__( 

28 self, 

29 only_directories: bool = False, 

30 get_paths: Callable[[], list[str]] | None = None, 

31 file_filter: Callable[[str], bool] | None = None, 

32 min_input_len: int = 0, 

33 expanduser: bool = False, 

34 ) -> None: 

35 self.only_directories = only_directories 

36 self.get_paths = get_paths or (lambda: ["."]) 

37 self.file_filter = file_filter or (lambda _: True) 

38 self.min_input_len = min_input_len 

39 self.expanduser = expanduser 

40 

41 def get_completions( 

42 self, document: Document, complete_event: CompleteEvent 

43 ) -> Iterable[Completion]: 

44 text = document.text_before_cursor 

45 

46 # Complete only when we have at least the minimal input length, 

47 # otherwise, we can too many results and autocompletion will become too 

48 # heavy. 

49 if len(text) < self.min_input_len: 

50 return 

51 

52 try: 

53 # Do tilde expansion. 

54 if self.expanduser: 

55 text = os.path.expanduser(text) 

56 

57 # Directories where to look. 

58 dirname = os.path.dirname(text) 

59 if dirname: 

60 directories = [ 

61 os.path.dirname(os.path.join(p, text)) for p in self.get_paths() 

62 ] 

63 else: 

64 directories = self.get_paths() 

65 

66 # Start of current file. 

67 prefix = os.path.basename(text) 

68 

69 # Get all filenames. 

70 filenames = [] 

71 for directory in directories: 

72 # Look for matches in this directory. 

73 if os.path.isdir(directory): 

74 for filename in os.listdir(directory): 

75 if filename.startswith(prefix): 

76 filenames.append((directory, filename)) 

77 

78 # Sort 

79 filenames = sorted(filenames, key=lambda k: k[1]) 

80 

81 # Yield them. 

82 for directory, filename in filenames: 

83 completion = filename[len(prefix) :] 

84 full_name = os.path.join(directory, filename) 

85 

86 if os.path.isdir(full_name): 

87 # For directories, add a slash to the filename. 

88 # (We don't add them to the `completion`. Users can type it 

89 # to trigger the autocompletion themselves.) 

90 filename += "/" 

91 elif self.only_directories: 

92 continue 

93 

94 if not self.file_filter(full_name): 

95 continue 

96 

97 yield Completion( 

98 text=completion, 

99 start_position=0, 

100 display=filename, 

101 ) 

102 except OSError: 

103 pass 

104 

105 

106class ExecutableCompleter(PathCompleter): 

107 """ 

108 Complete only executable files in the current path. 

109 """ 

110 

111 def __init__(self) -> None: 

112 super().__init__( 

113 only_directories=False, 

114 min_input_len=1, 

115 get_paths=lambda: os.environ.get("PATH", "").split(os.pathsep), 

116 file_filter=lambda name: os.access(name, os.X_OK), 

117 expanduser=True, 

118 )