Skip to content

Commit f3f0a56

Browse files
authored
feat(cli): Add shtab completions, remove unused code (#834)
Basic shtab completions, unused code
2 parents 43d167e + c272bf9 commit f3f0a56

File tree

8 files changed

+57
-142
lines changed

8 files changed

+57
-142
lines changed

CHANGES

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ $ pipx install --suffix=@next 'tmuxp' --pip-args '\--pre' --force
2121

2222
<!-- Maintainers, insert changes / features for the next release here -->
2323

24+
## tmuxp 1.17.1 (2022-10-15)
25+
26+
### Minor completion improvements
27+
28+
- Improved shtab completions for files with `tmuxp load [tab]` (#834)
29+
30+
### Internal
31+
32+
- Remove unused completion code leftover from click (#834)
33+
2434
## tmuxp 1.17.0 (2022-10-09)
2535

2636
### Breaking changes

docs/api.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ If you need an internal API stabilized please [file an issue](https://github.com
4949
.. automethod:: tmuxp.cli.utils.get_config_dir
5050
```
5151

52-
```{eval-rst}
53-
.. automethod:: tmuxp.cli.utils._validate_choices
54-
```
55-
5652
```{eval-rst}
5753
.. automethod:: tmuxp.cli.import_config.get_teamocil_dir
5854
```

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ files = [
157157

158158
[[tool.mypy.overrides]]
159159
module = [
160+
"shtab",
160161
"aafigure",
161162
"IPython.*",
162163
"ptpython.*",

src/tmuxp/cli/convert.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@
1111
def create_convert_subparser(
1212
parser: argparse.ArgumentParser,
1313
) -> argparse.ArgumentParser:
14-
parser.add_argument(
14+
config_file = parser.add_argument(
1515
dest="config_file",
1616
type=str,
1717
metavar="config-file",
1818
help="checks tmuxp and current directory for config files.",
1919
)
20+
try:
21+
import shtab
22+
23+
config_file.complete = shtab.FILE # type: ignore
24+
except ImportError:
25+
pass
26+
2027
parser.add_argument(
2128
"--yes",
2229
"-y",

src/tmuxp/cli/import_config.py

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,7 @@
77
from tmuxp.config_reader import ConfigReader
88

99
from .. import config
10-
from .utils import (
11-
get_abs_path,
12-
prompt,
13-
prompt_choices,
14-
prompt_yes_no,
15-
scan_config,
16-
tmuxp_echo,
17-
)
10+
from .utils import prompt, prompt_choices, prompt_yes_no, scan_config, tmuxp_echo
1811

1912

2013
def get_tmuxinator_dir() -> str:
@@ -55,10 +48,10 @@ def get_teamocil_dir() -> str:
5548

5649

5750
def _resolve_path_no_overwrite(config: str) -> str:
58-
path = get_abs_path(config)
59-
if os.path.exists(path):
51+
path = pathlib.Path(config).resolve()
52+
if path.exists():
6053
raise ValueError("%s exists. Pick a new filename." % path)
61-
return path
54+
return str(path)
6255

6356

6457
def command_import(
@@ -81,7 +74,7 @@ def create_import_subparser(
8174
)
8275

8376
import_teamocilgroup = import_teamocil.add_mutually_exclusive_group(required=True)
84-
import_teamocilgroup.add_argument(
77+
teamocil_config_file = import_teamocilgroup.add_argument(
8578
dest="config_file",
8679
type=str,
8780
nargs="?",
@@ -99,7 +92,7 @@ def create_import_subparser(
9992
import_tmuxinatorgroup = import_tmuxinator.add_mutually_exclusive_group(
10093
required=True
10194
)
102-
import_tmuxinatorgroup.add_argument(
95+
tmuxinator_config_file = import_tmuxinatorgroup.add_argument(
10396
dest="config_file",
10497
type=str,
10598
nargs="?",
@@ -111,6 +104,14 @@ def create_import_subparser(
111104
callback=command_import_tmuxinator, import_subparser_name="tmuxinator"
112105
)
113106

107+
try:
108+
import shtab
109+
110+
teamocil_config_file.complete = shtab.FILE # type: ignore
111+
tmuxinator_config_file.complete = shtab.FILE # type: ignore
112+
except ImportError:
113+
pass
114+
114115
return parser
115116

116117

@@ -175,24 +176,6 @@ def command_import_tmuxinator(
175176
import_config(config_file, config.import_tmuxinator)
176177

177178

178-
def create_convert_subparser(
179-
parser: argparse.ArgumentParser,
180-
) -> argparse.ArgumentParser:
181-
parser.add_argument(
182-
dest="config_file",
183-
type=str,
184-
help="checks current ~/.teamocil and current directory for yaml files",
185-
)
186-
parser.add_argument(
187-
"--yes",
188-
"-y",
189-
dest="answer_yes",
190-
action="store_true",
191-
help="always answer yes",
192-
)
193-
return parser
194-
195-
196179
def command_import_teamocil(
197180
config_file: str,
198181
parser: t.Optional[argparse.ArgumentParser] = None,

src/tmuxp/cli/load.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,6 @@ def load_workspace(
430430
)
431431
options = ["y", "n", "a"]
432432
choice = prompt_choices(msg, choices=options)
433-
# value_proc=_validate_choices(options))
434433

435434
if choice == "y":
436435
_load_attached(builder, detached)
@@ -450,7 +449,6 @@ def load_workspace(
450449
choice = prompt_choices(
451450
"Error loading workspace. (k)ill, (a)ttach, (d)etach?",
452451
choices=["k", "a", "d"],
453-
# value_proc=_validate_choices(["k", "a", "d"]),
454452
default="k",
455453
)
456454

@@ -488,7 +486,7 @@ def config_file_completion(ctx, params, incomplete):
488486

489487

490488
def create_load_subparser(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
491-
parser.add_argument(
489+
config_file = parser.add_argument(
492490
"config_file",
493491
metavar="config-file",
494492
help="filepath to session or filename of session if in tmuxp config directory",
@@ -508,12 +506,13 @@ def create_load_subparser(parser: argparse.ArgumentParser) -> argparse.ArgumentP
508506
help="passthru to tmux(1) -S",
509507
)
510508

511-
parser.add_argument(
509+
tmux_config_file = parser.add_argument(
512510
"-f",
513511
dest="tmux_config_file",
514512
metavar="tmux_config_file",
515513
help="passthru to tmux(1) -f",
516514
)
515+
517516
parser.add_argument(
518517
"-s",
519518
dest="new_session_name",
@@ -557,14 +556,24 @@ def create_load_subparser(parser: argparse.ArgumentParser) -> argparse.ArgumentP
557556
const=88,
558557
help="like -2, but indicates that the terminal supports 88 colours.",
559558
)
560-
561559
parser.set_defaults(colors=None)
562-
parser.add_argument(
560+
561+
log_file = parser.add_argument(
563562
"--log-file",
564563
metavar="file_path",
565564
action="store",
566565
help="file to log errors/output to",
567566
)
567+
568+
try:
569+
import shtab
570+
571+
config_file.complete = shtab.FILE # type: ignore
572+
tmux_config_file.complete = shtab.FILE # type: ignore
573+
log_file.complete = shtab.FILE # type: ignore
574+
except ImportError:
575+
pass
576+
568577
return parser
569578

570579

src/tmuxp/cli/utils.py

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from colorama import Fore
88

9-
from .. import config, log
9+
from .. import log
1010
from .constants import VALID_CONFIG_DIR_FILE_EXTENSIONS
1111

1212
logger = logging.getLogger(__name__)
@@ -63,82 +63,6 @@ def get_config_dir() -> str:
6363
return path
6464

6565

66-
def _validate_choices(options: t.List[str]) -> t.Callable:
67-
"""
68-
Callback wrapper for validating click.prompt input.
69-
70-
Parameters
71-
----------
72-
options : list
73-
List of allowed choices
74-
75-
Returns
76-
-------
77-
:func:`callable`
78-
callback function for value_proc in :func:`click.prompt`.
79-
80-
Raises
81-
------
82-
:class:`click.BadParameter`
83-
"""
84-
85-
def func(value):
86-
if value not in options:
87-
raise ValueError("Possible choices are: {}.".format(", ".join(options)))
88-
return value
89-
90-
return func
91-
92-
93-
class ConfigPath:
94-
def __init__(
95-
self, config_dir: t.Optional[t.Union[t.Callable, str]] = None, *args, **kwargs
96-
) -> None:
97-
super().__init__(*args, **kwargs)
98-
self.config_dir = config_dir
99-
100-
def convert(
101-
self, value: str, param: t.Any, ctx: t.Any
102-
) -> t.Optional[t.Union[str, pathlib.Path]]:
103-
config_dir = self.config_dir() if callable(self.config_dir) else self.config_dir
104-
105-
return scan_config(value, config_dir=config_dir)
106-
107-
108-
def scan_config_argument(ctx, param, value, config_dir=None):
109-
"""Validate / translate config name/path values for click config arg.
110-
111-
Wrapper on top of :func:`cli.scan_config`."""
112-
if callable(config_dir):
113-
config_dir = config_dir()
114-
115-
if not config:
116-
tmuxp_echo("Enter at least one CONFIG")
117-
tmuxp_echo(ctx.get_help())
118-
ctx.exit()
119-
120-
if isinstance(value, str):
121-
value = scan_config(value, config_dir=config_dir)
122-
123-
elif isinstance(value, tuple):
124-
value = tuple(scan_config(v, config_dir=config_dir) for v in value)
125-
126-
return value
127-
128-
129-
def get_abs_path(config: str) -> str:
130-
path = os.path
131-
join, isabs = path.join, path.isabs
132-
dirname, normpath = path.dirname, path.normpath
133-
cwd = os.getcwd()
134-
135-
config = os.path.expanduser(config)
136-
if not isabs(config) or len(dirname(config)) > 1:
137-
config = normpath(join(cwd, config))
138-
139-
return config
140-
141-
14266
def scan_config(
14367
config: t.Union[pathlib.Path, str],
14468
config_dir: t.Optional[t.Union[pathlib.Path, str]] = None,

tests/test_cli.py

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,7 @@
2323
load_plugins,
2424
load_workspace,
2525
)
26-
from tmuxp.cli.utils import (
27-
_validate_choices,
28-
get_abs_path,
29-
get_config_dir,
30-
is_pure_name,
31-
scan_config,
32-
tmuxp_echo,
33-
)
26+
from tmuxp.cli.utils import get_config_dir, is_pure_name, scan_config, tmuxp_echo
3427
from tmuxp.config_reader import ConfigReader
3528
from tmuxp.workspacebuilder import WorkspaceBuilder
3629

@@ -1127,13 +1120,15 @@ def test_freeze_overwrite(
11271120
assert yaml_config_path.exists()
11281121

11291122

1130-
def test_get_abs_path(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None:
1123+
def test_resolve_behavior(
1124+
tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
1125+
) -> None:
11311126
expect = str(tmp_path)
11321127
monkeypatch.chdir(tmp_path)
1133-
get_abs_path("../") == os.path.dirname(expect)
1134-
get_abs_path(".") == expect
1135-
get_abs_path("./") == expect
1136-
get_abs_path(expect) == expect
1128+
pathlib.Path("../").resolve() == os.path.dirname(expect)
1129+
pathlib.Path(".").resolve() == expect
1130+
pathlib.Path("./").resolve() == expect
1131+
pathlib.Path(expect).resolve() == expect
11371132

11381133

11391134
def test_get_tmuxinator_dir(monkeypatch: pytest.MonkeyPatch) -> None:
@@ -1152,16 +1147,6 @@ def test_get_teamocil_dir(monkeypatch: pytest.MonkeyPatch) -> None:
11521147
assert get_teamocil_dir() == os.path.expanduser("~/.teamocil/")
11531148

11541149

1155-
def test_validate_choices() -> None:
1156-
validate = _validate_choices(["choice1", "choice2"])
1157-
1158-
assert validate("choice1")
1159-
assert validate("choice2")
1160-
1161-
with pytest.raises(ValueError):
1162-
assert validate("choice3")
1163-
1164-
11651150
def test_pass_config_dir_ClickPath(
11661151
tmp_path: pathlib.Path,
11671152
monkeypatch: pytest.MonkeyPatch,

0 commit comments

Comments
 (0)