Coverage for src/pyselector/menus/dmenu.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-24 11:53 -0300

1# dmenu.py 

2 

3import logging 

4import shlex 

5import warnings 

6from typing import Iterable 

7from typing import Optional 

8from typing import Union 

9 

10from pyselector import helpers 

11from pyselector.interfaces import PromptReturn 

12from pyselector.key_manager import KeyManager 

13 

14log = logging.getLogger(__name__) 

15 

16 

17class Dmenu: 

18 def __init__(self) -> None: 

19 self.name = "dmenu" 

20 self.url = "https://tools.suckless.org/dmenu/" 

21 self.keybind = KeyManager() 

22 

23 @property 

24 def command(self) -> str: 

25 return helpers.check_command(self.name, self.url) 

26 

27 def _build_command( 

28 self, 

29 case_sensitive, 

30 multi_select, 

31 prompt, 

32 **kwargs, 

33 ) -> list[str]: 

34 args = shlex.split(self.command) 

35 

36 if kwargs.get("lines"): 

37 args.extend(["-l", str(kwargs.pop("lines"))]) 

38 

39 if prompt: 

40 args.extend(["-p", prompt]) 

41 

42 if kwargs.get("bottom"): 

43 kwargs.pop("bottom") 

44 args.append("-b") 

45 

46 if case_sensitive: 

47 args.append("-i") 

48 

49 if kwargs.get("font"): 

50 args.extend(["-fn", kwargs.pop("font")]) 

51 

52 if multi_select: 

53 log.warning("not supported in dmenu: %s", "multi-select") 

54 warnings.warn(UserWarning(f"'{multi_select=}' not supported")) 

55 

56 if kwargs: 

57 for arg, value in kwargs.items(): 

58 warnings.warn(UserWarning(f"'{arg}={value}' not supported")) 

59 return args 

60 

61 def prompt( 

62 self, 

63 items: Optional[Iterable[Union[str, int]]] = None, 

64 case_sensitive: bool = False, 

65 multi_select: bool = False, 

66 prompt: str = "PySelector> ", 

67 **kwargs, 

68 ) -> PromptReturn: 

69 """Prompts the user with a rofi window containing the given items 

70 and returns the selected item and code. 

71 

72 Args: 

73 items (Iterable[str, int], optional): The items to display in the rofi window 

74 case_sensitive (bool, optional): Whether or not to perform a case-sensitive search 

75 multi_select (bool, optional): Whether or not to allow the user to select multiple items 

76 prompt (str, optional): The prompt to display in the rofi window 

77 **kwargs: Additional keyword arguments. 

78 

79 Keyword Args: 

80 lines (int): dmenu lists items vertically, with the given number of lines. 

81 bottom (str): dmenu appears at the bottom of the screen. 

82 font (str): defines the font or font set used. 

83 height (str): The height of the selection window (e.g. 50%). 

84 

85 Returns: 

86 A tuple containing the selected item (str or list of str) and the return code (int). 

87 """ 

88 if items is None: 

89 items = [] 

90 

91 args = self._build_command(case_sensitive, multi_select, prompt, **kwargs) 

92 

93 selection, code = helpers._execute(args, items) 

94 return helpers.parse_bytes_line(selection), code