Skip to content

Commit

Permalink
feat: tmux strategy - run tests in a tmux pane
Browse files Browse the repository at this point in the history
Close #119
  • Loading branch information
gerardroche committed Jan 20, 2024
1 parent a2a7b21 commit c441f37
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 8 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.

## 3.19.0

### Added

- Tmux strategy - Runs test commands in a tmux pane [#119](https://github.com/gerardroche/sublime-phpunit/issues/119)

## 3.18.3 - Unreleased

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Enhance your coding experience with seamless PHPUnit integration for [Sublime Te
- [xterm] - A terminal emulator for the X Window System.
- [cmd] - A command-line interpreter for Windows.
- [PowerShell] - A cross-platform command-line shell.
- [Tmux] - A terminal multiplexer.
* Zero configuration required

Read [Running PHPUnit Tests from Sublime Text](https://blog.gerardroche.com/2023/05/05/running-phpunit-tests-within-sublime-text/) for a quick introduction.
Expand Down Expand Up @@ -490,4 +491,5 @@ Released under the [GPL-3.0-or-later License](LICENSE).
[PowerShell]: https://learn.microsoft.com/en-us/powershell/
[cmd]: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/cmd
[iTerm2]: https://iterm2.com
[tmux]: https://github.com/tmux/tmux/wiki
[xterm]: https://invisible-island.net/xterm/
34 changes: 27 additions & 7 deletions lib/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with PHPUnitKit. If not, see <https://www.gnu.org/licenses/>.

import os
import shlex
import webbrowser

from sublime import ENCODED_POSITION
Expand Down Expand Up @@ -44,6 +45,7 @@
from PHPUnitKit.lib.utils import save_views
from PHPUnitKit.lib.utils import set_last_run
from PHPUnitKit.lib.utils import set_session
from PHPUnitKit.lib.utils import shell_read


class PHPUnit():
Expand Down Expand Up @@ -138,13 +140,31 @@ def run(self, working_dir=None, file=None, options=None) -> None:
'options': options
})

strategy.execute(
self.window,
self.view,
env,
cmd,
working_dir
)
if get_setting(self.view, 'strategy') == 'tmux':
tmux = get_setting(self.view, 'tmux')

if 'session' not in tmux or isinstance(tmux['session'], int):
sessions = shell_read(self.view, 'tmux list-sessions -F \'#{session_name}\'')
if sessions:
sessions = sessions.split('\n')
try:
tmux['session'] = sessions[tmux['session'] - 1]
except (KeyError, IndexError):
tmux['session'] = sessions[0]

if cmd[0].startswith(working_dir):
cmd = [os.path.relpath(cmd[0], working_dir)] + cmd[1:]

tmux_cmds = []
if 'clear' not in tmux or tmux['clear']:
tmux_cmds.append(shlex.join(['clear']))
tmux_cmds.append(shlex.join(['cd', working_dir]))
tmux_cmds.append(shlex.join(cmd) + '\n')

tmux_target = '{}:{}.{}'.format(tmux['session'], tmux['window'], tmux['pane'])
cmd = ['tmux', 'send-keys', '-t', tmux_target, ';'.join(tmux_cmds)]

strategy.execute(self.window, self.view, env, cmd, working_dir)

def run_last(self) -> None:
last_test_args = get_last_run()
Expand Down
2 changes: 1 addition & 1 deletion lib/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@


def execute(window, view, env: dict, cmd: list, working_dir: str) -> None:
if get_setting(view, 'strategy') in ('cmd', 'external', 'iterm', 'kitty', 'powershell', 'xterm'):
if get_setting(view, 'strategy') in ('cmd', 'external', 'iterm', 'kitty', 'powershell', 'tmux', 'xterm'):
window.run_command('exec', {
'env': env,
'cmd': cmd,
Expand Down
76 changes: 76 additions & 0 deletions lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import os
import re
import shutil
import subprocess
import sys
import traceback

from sublime import active_window
from sublime import platform
Expand Down Expand Up @@ -750,3 +753,76 @@ def toggle_on_post_save(view, item: str) -> None:
view.settings().erase('phpunit.on_post_save')
if on_post_save != view.settings().get('phpunit.on_post_save'):
view.settings().set('phpunit.on_post_save', on_post_save)


def _get_default_shell() -> str:
if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
return os.environ.get('SHELL', 'sh')
elif sys.platform.startswith('win'):
return 'cmd.exe'
else:
return ''


if sys.platform.startswith('win'):
try:
import ctypes
except ImportError:
traceback.print_exc()
ctypes = None

def _get_startup_info():
# Hide the child process window.
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

return startupinfo

def _get_encoding() -> str:
return str(ctypes.windll.kernel32.GetOEMCP())

def _shell_filter_newlines(text: str):
return text.replace('\r\n', '\n')

def _shell_decode(res):
return _shell_filter_newlines(res.decode(_get_encoding()))

def _shell_read(view, cmd: str) -> str:
p = subprocess.Popen([_get_default_shell(), '/c', cmd],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
startupinfo=_get_startup_info())
out, err = p.communicate()

if out:
return _shell_decode(out)

if err:
return _shell_decode(err)

return ''

else:
def _shell_read(view, cmd: str) -> str:
p = subprocess.Popen([_get_default_shell(), '-c', cmd],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)

out, err = p.communicate()

if out:
return out.decode('utf-8').strip()

if err:
return err.decode('utf-8').strip()

return ''


def shell_read(view, cmd: str) -> str:
try:
return _shell_read(view, cmd)
except Exception:
traceback.print_exc()

return ''

0 comments on commit c441f37

Please sign in to comment.