diff --git a/CHANGES b/CHANGES index ca6b363a9f9..159640a0491 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,31 @@ - Fix loading of `.yml` files with `tmuxp convert`, thank you @kalixi! (#725) +#### Internal API + +- #752: Command structure (internal API) + + To pave the way for per-command options such as `enter: false` (#52), commands are now a different format: + + Before, [`str`](str): + + ```python + "echo hello" + ``` + + After, [`dict`](dict): + + ```python + { + "cmd": "echo hello" + } + ``` + + This is purely internal. Normal usage should be the same since the + configuration emits the equivalent result. + +- #752: Configuration parsing refactorings + #### Development - Run through black + isort with string normalization (#738). This way we can diff --git a/tests/fixtures/config/expand1.py b/tests/fixtures/config/expand1.py index d431741ef73..71e8e0704f3 100644 --- a/tests/fixtures/config/expand1.py +++ b/tests/fixtures/config/expand1.py @@ -36,39 +36,42 @@ { "window_name": "editor", "panes": [ - {"shell_command": ["vim", "top"]}, - {"shell_command": ["vim"]}, - {"shell_command": ['cowsay "hey"']}, + {"shell_command": [{"cmd": "vim"}, {"cmd": "top"}]}, + {"shell_command": [{"cmd": "vim"}]}, + {"shell_command": [{"cmd": 'cowsay "hey"'}]}, ], "layout": "main-verticle", }, { "window_name": "logging", - "panes": [{"shell_command": ["tail -F /var/log/syslog"]}], + "panes": [{"shell_command": [{"cmd": "tail -F /var/log/syslog"}]}], }, { "start_directory": "/var/log", "options": {"automatic-rename": True}, - "panes": [{"shell_command": ["htop"]}, {"shell_command": ["vim"]}], + "panes": [ + {"shell_command": [{"cmd": "htop"}]}, + {"shell_command": [{"cmd": "vim"}]}, + ], }, { "start_directory": os.path.normpath( os.path.join(os.path.expanduser("~"), "./") ), - "panes": [{"shell_command": ["pwd"]}], + "panes": [{"shell_command": [{"cmd": "pwd"}]}], }, { "start_directory": os.path.normpath( os.path.join(os.path.expanduser("~"), "./asdf") ), - "panes": [{"shell_command": ["pwd"]}], + "panes": [{"shell_command": [{"cmd": "pwd"}]}], }, { "start_directory": os.path.normpath( os.path.join(os.path.expanduser("~"), "../") ), - "panes": [{"shell_command": ["pwd"]}], + "panes": [{"shell_command": [{"cmd": "pwd"}]}], }, - {"panes": [{"shell_command": ["top"]}]}, + {"panes": [{"shell_command": [{"cmd": "top"}]}]}, ], } diff --git a/tests/fixtures/config/expand2-expanded.yaml b/tests/fixtures/config/expand2-expanded.yaml index 0fe5bbd3d9b..e407146427f 100644 --- a/tests/fixtures/config/expand2-expanded.yaml +++ b/tests/fixtures/config/expand2-expanded.yaml @@ -6,27 +6,27 @@ windows: focus: true panes: - shell_command: - - cd ~ + - cmd: cd ~ - shell_command: - - cd /usr + - cmd: cd /usr focus: true - shell_command: - - cd ~ - - echo "moo" - - top + - cmd: cd ~ + - cmd: echo "moo" + - cmd: top - window_name: window 2 panes: - shell_command: - - top + - cmd: top focus: true - shell_command: - - echo "hey" + - cmd: echo "hey" - shell_command: - - echo "moo" + - cmd: echo "moo" - window_name: window 3 panes: - shell_command: - - cd / + - cmd: cd / focus: true - shell_command: [] - shell_command: [] diff --git a/tests/fixtures/config/expand_blank.py b/tests/fixtures/config/expand_blank.py index 78343ca7110..4d0dad3b490 100644 --- a/tests/fixtures/config/expand_blank.py +++ b/tests/fixtures/config/expand_blank.py @@ -20,9 +20,9 @@ { "window_name": "Empty string (return)", "panes": [ - {"shell_command": [""]}, - {"shell_command": [""]}, - {"shell_command": [""]}, + {"shell_command": [{"cmd": ""}]}, + {"shell_command": [{"cmd": ""}]}, + {"shell_command": [{"cmd": ""}]}, ], }, { diff --git a/tests/fixtures/config/shell_command_before.py b/tests/fixtures/config/shell_command_before.py index 2f0b1a69660..0f5725e2eec 100644 --- a/tests/fixtures/config/shell_command_before.py +++ b/tests/fixtures/config/shell_command_before.py @@ -43,21 +43,27 @@ { "window_name": "editor", "start_directory": os.path.expanduser("~"), - "shell_command_before": ["source .venv/bin/activate"], + "shell_command_before": { + "shell_command": [{"cmd": "source .venv/bin/activate"}] + }, "panes": [ - {"shell_command": ["vim"]}, + {"shell_command": [{"cmd": "vim"}]}, { - "shell_command_before": ["rbenv local 2.0.0-p0"], - "shell_command": ['cowsay "hey"'], + "shell_command_before": { + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}] + }, + "shell_command": [{"cmd": 'cowsay "hey"'}], }, ], "layout": "main-verticle", }, { - "shell_command_before": ["rbenv local 2.0.0-p0"], + "shell_command_before": { + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}] + }, "window_name": "logging", "panes": [ - {"shell_command": ["tail -F /var/log/syslog"]}, + {"shell_command": [{"cmd": "tail -F /var/log/syslog"}]}, {"shell_command": []}, ], }, @@ -65,13 +71,18 @@ "window_name": "shufu", "panes": [ { - "shell_command_before": ["rbenv local 2.0.0-p0"], - "shell_command": ["htop"], + "shell_command_before": { + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}] + }, + "shell_command": [{"cmd": "htop"}], } ], }, - {"options": {"automatic-rename": True}, "panes": [{"shell_command": ["htop"]}]}, - {"panes": [{"shell_command": ["top"]}]}, + { + "options": {"automatic-rename": True}, + "panes": [{"shell_command": [{"cmd": "htop"}]}], + }, + {"panes": [{"shell_command": [{"cmd": "top"}]}]}, ], } @@ -82,27 +93,43 @@ { "window_name": "editor", "start_directory": os.path.expanduser("~"), - "shell_command_before": ["source .venv/bin/activate"], + "shell_command_before": { + "shell_command": [{"cmd": "source .venv/bin/activate"}] + }, "panes": [ - {"shell_command": ["source .venv/bin/activate", "vim"]}, { - "shell_command_before": ["rbenv local 2.0.0-p0"], "shell_command": [ - "source .venv/bin/activate", - "rbenv local 2.0.0-p0", - 'cowsay "hey"', + {"cmd": "source .venv/bin/activate"}, + {"cmd": "vim"}, + ] + }, + { + "shell_command_before": { + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}] + }, + "shell_command": [ + {"cmd": "source .venv/bin/activate"}, + {"cmd": "rbenv local 2.0.0-p0"}, + {"cmd": 'cowsay "hey"'}, ], }, ], "layout": "main-verticle", }, { - "shell_command_before": ["rbenv local 2.0.0-p0"], + "shell_command_before": { + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}] + }, "start_directory": "/", "window_name": "logging", "panes": [ - {"shell_command": ["rbenv local 2.0.0-p0", "tail -F /var/log/syslog"]}, - {"shell_command": ["rbenv local 2.0.0-p0"]}, + { + "shell_command": [ + {"cmd": "rbenv local 2.0.0-p0"}, + {"cmd": "tail -F /var/log/syslog"}, + ] + }, + {"shell_command": [{"cmd": "rbenv local 2.0.0-p0"}]}, ], }, { @@ -110,16 +137,18 @@ "window_name": "shufu", "panes": [ { - "shell_command_before": ["rbenv local 2.0.0-p0"], - "shell_command": ["rbenv local 2.0.0-p0", "htop"], + "shell_command_before": { + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}] + }, + "shell_command": [{"cmd": "rbenv local 2.0.0-p0"}, {"cmd": "htop"}], } ], }, { "start_directory": "/", "options": {"automatic-rename": True}, - "panes": [{"shell_command": ["htop"]}], + "panes": [{"shell_command": [{"cmd": "htop"}]}], }, - {"start_directory": "/", "panes": [{"shell_command": ["top"]}]}, + {"start_directory": "/", "panes": [{"shell_command": [{"cmd": "top"}]}]}, ], } diff --git a/tests/fixtures/config/shell_command_before_session-expected.yaml b/tests/fixtures/config/shell_command_before_session-expected.yaml index 4e1e3eb49a0..dd55247c886 100644 --- a/tests/fixtures/config/shell_command_before_session-expected.yaml +++ b/tests/fixtures/config/shell_command_before_session-expected.yaml @@ -1,23 +1,24 @@ shell_command_before: - - 'echo "hi"' + shell_command: + - cmd: 'echo "hi"' session_name: 'test' windows: - window_name: editor panes: - shell_command: - - 'echo "hi"' - - vim - - :Ex + - cmd: 'echo "hi"' + - cmd: vim + - cmd: :Ex - shell_command: - - 'echo "hi"' + - cmd: 'echo "hi"' - shell_command: - - 'echo "hi"' - - cd /usr + - cmd: 'echo "hi"' + - cmd: cd /usr - window_name: logging panes: - shell_command: - - 'echo "hi"' + - cmd: 'echo "hi"' - shell_command: - - 'echo "hi"' - - top - - emacs + - cmd: 'echo "hi"' + - cmd: top + - cmd: emacs diff --git a/tests/fixtures/config/trickle.py b/tests/fixtures/config/trickle.py index 7792ba425a9..595ee563604 100644 --- a/tests/fixtures/config/trickle.py +++ b/tests/fixtures/config/trickle.py @@ -5,14 +5,17 @@ { "window_name": "editor", "start_directory": "log", - "panes": [{"shell_command": ["vim"]}, {"shell_command": ['cowsay "hey"']}], + "panes": [ + {"shell_command": [{"cmd": "vim"}]}, + {"shell_command": [{"cmd": 'cowsay "hey"'}]}, + ], "layout": "main-verticle", }, { "window_name": "logging", "start_directory": "~", "panes": [ - {"shell_command": ["tail -F /var/log/syslog"]}, + {"shell_command": [{"cmd": "tail -F /var/log/syslog"}]}, {"shell_command": []}, ], }, @@ -26,14 +29,17 @@ { "window_name": "editor", "start_directory": "/var/log", - "panes": [{"shell_command": ["vim"]}, {"shell_command": ['cowsay "hey"']}], + "panes": [ + {"shell_command": [{"cmd": "vim"}]}, + {"shell_command": [{"cmd": 'cowsay "hey"'}]}, + ], "layout": "main-verticle", }, { "start_directory": "~", "window_name": "logging", "panes": [ - {"shell_command": ["tail -F /var/log/syslog"]}, + {"shell_command": [{"cmd": "tail -F /var/log/syslog"}]}, {"shell_command": []}, ], }, diff --git a/tests/fixtures/workspacebuilder/focus_and_pane.yaml b/tests/fixtures/workspacebuilder/focus_and_pane.yaml index e6917c3ff14..d7e9b5d9903 100644 --- a/tests/fixtures/workspacebuilder/focus_and_pane.yaml +++ b/tests/fixtures/workspacebuilder/focus_and_pane.yaml @@ -5,26 +5,27 @@ windows: focus: true panes: - shell_command: - - cd ~ + - cmd: cd ~ - shell_command: - - cd /usr + - cmd: cd /usr focus: true - shell_command: - - cd ~ - - echo "moo" - - top + - cmd: cd ~ + - cmd: echo "moo" + - cmd: top - window_name: window 2 panes: - shell_command: - - top + - cmd: top focus: true - shell_command: - - echo "hey" + - cmd: echo "hey" - shell_command: - - echo "moo" + - cmd: echo "moo" - window_name: window 3 panes: - - shell_command: cd / + - shell_command: + - cmd: cd / focus: true - pane - pane diff --git a/tests/fixtures/workspacebuilder/plugin_bs.yaml b/tests/fixtures/workspacebuilder/plugin_bs.yaml index a04d6eb3f30..5785afb4203 100644 --- a/tests/fixtures/workspacebuilder/plugin_bs.yaml +++ b/tests/fixtures/workspacebuilder/plugin_bs.yaml @@ -5,11 +5,11 @@ windows: - window_name: editor layout: tiled shell_command_before: - - cd ~/ + - cmd: cd ~/ panes: - shell_command: - - cd /var/log - - ls -al | grep \.log - - echo hello - - echo hello - - echo hello + - cmd: cd /var/log + - cmd: ls -al | grep \.log + - cmd: echo hello + - cmd: echo hello + - cmd: echo hello diff --git a/tests/fixtures/workspacebuilder/three_pane.yaml b/tests/fixtures/workspacebuilder/three_pane.yaml index f883fc2b36a..08995253252 100644 --- a/tests/fixtures/workspacebuilder/three_pane.yaml +++ b/tests/fixtures/workspacebuilder/three_pane.yaml @@ -5,8 +5,8 @@ windows: layout: main-horizontal panes: - shell_command: - - vim + - cmd: vim - shell_command: - - echo "hey" + - cmd: echo "hey" - shell_command: - - echo "moo" + - cmd: echo "moo" diff --git a/tests/fixtures/workspacebuilder/three_windows.yaml b/tests/fixtures/workspacebuilder/three_windows.yaml index e0c8286f851..b883a7da57f 100644 --- a/tests/fixtures/workspacebuilder/three_windows.yaml +++ b/tests/fixtures/workspacebuilder/three_windows.yaml @@ -3,12 +3,12 @@ windows: - window_name: first panes: - shell_command: - - echo 'first window' + - cmd: echo 'first window' - window_name: second panes: - shell_command: - - echo 'second window' + - cmd: echo 'second window' - window_name: third panes: - shell_command: - - echo 'third window' + - cmd: echo 'third window' diff --git a/tests/fixtures/workspacebuilder/two_pane.yaml b/tests/fixtures/workspacebuilder/two_pane.yaml index be083ff48b8..9bb96e70f37 100644 --- a/tests/fixtures/workspacebuilder/two_pane.yaml +++ b/tests/fixtures/workspacebuilder/two_pane.yaml @@ -4,15 +4,15 @@ windows: - layout: main-vertical panes: - shell_command: - - vim + - cmd: vim - shell_command: - - echo "hey" + - cmd: echo "hey" window_name: editor - panes: - shell_command: - - tail | echo 'hi' + - cmd: tail | echo 'hi' window_name: logging - window_name: test panes: - shell_command: - - htop + - cmd: htop diff --git a/tests/fixtures/workspacebuilder/two_windows.yaml b/tests/fixtures/workspacebuilder/two_windows.yaml index 0f1d40f34a9..490382fe5f3 100644 --- a/tests/fixtures/workspacebuilder/two_windows.yaml +++ b/tests/fixtures/workspacebuilder/two_windows.yaml @@ -3,8 +3,8 @@ windows: - window_name: first panes: - shell_command: - - echo 'first window' + - cmd: echo 'first window' - window_name: second panes: - shell_command: - - echo 'second window' + - cmd: echo 'second window' diff --git a/tests/fixtures/workspacebuilder/window_automatic_rename.yaml b/tests/fixtures/workspacebuilder/window_automatic_rename.yaml index 9b74b4fe7f5..08329afcfea 100644 --- a/tests/fixtures/workspacebuilder/window_automatic_rename.yaml +++ b/tests/fixtures/workspacebuilder/window_automatic_rename.yaml @@ -6,9 +6,9 @@ windows: automatic-rename: on panes: - shell_command: - - sh + - cmd: sh start_directory: '~' - shell_command: - - echo "hey" + - cmd: echo "hey" - shell_command: - - echo "moo" + - cmd: echo "moo" diff --git a/tests/fixtures/workspacefreezer/sampleconfig.yaml b/tests/fixtures/workspacefreezer/sampleconfig.yaml index b7a6d010703..fb8b11e3e22 100644 --- a/tests/fixtures/workspacefreezer/sampleconfig.yaml +++ b/tests/fixtures/workspacefreezer/sampleconfig.yaml @@ -4,18 +4,18 @@ windows: - layout: main-vertical panes: - shell_command: - - vim + - cmd: vim start_directory: '~' - shell_command: - - echo "hey" - - cd ../ + - cmd: echo "hey" + - cmd: cd ../ window_name: editor - panes: - shell_command: - - pane + - cmd: pane start_directory: /usr/bin window_name: logging - window_name: test panes: - shell_command: - - top + - cmd: top diff --git a/tests/test_config.py b/tests/test_config.py index a89b3631548..1352d0034c7 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -395,7 +395,10 @@ def test_replaces_env_variables(monkeypatch): monkeypatch.setenv(str(env_key), str(env_val)) sconfig = config.expand(sconfig) assert "%s/test" % env_val == sconfig["start_directory"] - assert "%s/test2" % env_val in sconfig["shell_command_before"] + assert ( + "%s/test2" % env_val + in sconfig["shell_command_before"]["shell_command"][0]["cmd"] + ) assert "%s/test3" % env_val == sconfig["before_script"] assert "hi - %s" % env_val == sconfig["session_name"] assert "%s/moo" % env_val == sconfig["global_options"]["default-shell"] diff --git a/tmuxp/config.py b/tmuxp/config.py index f8b8ec5deab..7d5cb2cae06 100644 --- a/tmuxp/config.py +++ b/tmuxp/config.py @@ -114,7 +114,7 @@ def expandshell(_path): """ Return expanded path based on user's ``$HOME`` and ``env``. - :py:func:`os.path.expanduser` and :py:func:`os.path.expandvars` + :py:func:`os.path.expanduser` and :py:func:`os.path.expandvar`s Parameters ---------- @@ -175,24 +175,31 @@ def inline(session_config): def expand_cmd(p: Dict) -> Dict: if isinstance(p, str): p = {"shell_command": [p]} + elif isinstance(p, list): + p = {"shell_command": p} elif not p: p = {"shell_command": []} assert isinstance(p, dict) if "shell_command" in p: - cmd = p["shell_command"] + cmds = p["shell_command"] if isinstance(p["shell_command"], str): - cmd = [cmd] + cmds = [cmds] - if not cmd or any(a == cmd for a in [None, "blank", "pane"]): - cmd = [] + if not cmds or any(a == cmds for a in [None, "blank", "pane"]): + cmds = [] - if isinstance(cmd, list) and len(cmd) == int(1): - if any(a in cmd for a in [None, "blank", "pane"]): - cmd = [] + if isinstance(cmds, list) and len(cmds) == int(1): + if any(a in cmds for a in [None, "blank", "pane"]): + cmds = [] - p["shell_command"] = cmd + for cmd_idx, cmd in enumerate(cmds): + if isinstance(cmd, str): + cmds[cmd_idx] = {"cmd": cmd} + cmds[cmd_idx]["cmd"] = expandshell(cmds[cmd_idx]["cmd"]) + + p["shell_command"] = cmds else: p["shell_command"] = [] return p @@ -295,19 +302,10 @@ def expand(session_config, cwd=None, parent=None): ): session_config["shell_command"] = [session_config["shell_command"]] - if "shell_command_before" in session_config and isinstance( - session_config["shell_command_before"], str - ): - session_config["shell_command_before"] = [ - session_config["shell_command_before"] - ] + if "shell_command_before" in session_config: + shell_command_before = session_config["shell_command_before"] - if "shell_command_before" in session_config and isinstance( - session_config["shell_command_before"], list - ): - session_config["shell_command_before"] = [ - expandshell(scmd) for scmd in session_config["shell_command_before"] - ] + session_config["shell_command_before"] = expand_cmd(shell_command_before) # recurse into window and pane config items if "windows" in session_config: @@ -390,11 +388,17 @@ def trickle(session_config): # Prepend shell_command_before to commands if "shell_command_before" in session_config: - commands_before.extend(session_config["shell_command_before"]) + commands_before.extend( + session_config["shell_command_before"]["shell_command"] + ) if "shell_command_before" in window_config: - commands_before.extend(window_config["shell_command_before"]) + commands_before.extend( + window_config["shell_command_before"]["shell_command"] + ) if "shell_command_before" in pane_config: - commands_before.extend(pane_config["shell_command_before"]) + commands_before.extend( + pane_config["shell_command_before"]["shell_command"] + ) if "shell_command" in pane_config: commands_before.extend(pane_config["shell_command"]) diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index a470ea07aaf..a51e13209b7 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -365,7 +365,7 @@ def get_pane_shell(): enter = pconf.get("enter", True) for cmd in pconf["shell_command"]: - p.send_keys(cmd, suppress_history=suppress, enter=enter) + p.send_keys(cmd["cmd"], suppress_history=suppress, enter=enter) if "focus" in pconf and pconf["focus"]: w.select_pane(p["pane_id"])