Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new-window command functionality #145

Merged
merged 21 commits into from
May 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions doc/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,25 @@ JSON
.. literalinclude:: ../examples/focus-window-and-panes.json
:language: json

Terminal History
----------------

tmuxp allows ``suppress_history: false`` to override the default command /
suppression when building the workspace.
This will add the ``shell_command`` to the bash history in the pane.

YAML
~~~~

.. literalinclude:: ../examples/suppress-history.yaml
:language: yaml

JSON
~~~~

.. literalinclude:: ../examples/suppress-history.json
:language: json

Window Index
------------

Expand Down
44 changes: 44 additions & 0 deletions examples/suppress-history.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"windows": [
{
"panes": [
"echo 'window in the history!'"
],
"focus": true,
"suppress_history": false,
"window_name": "appended"
},
{
"panes": [
"echo 'window not in the history!'"
],
"suppress_history": true,
"window_name": "suppressed"
},
{
"panes": [
"echo 'session in the history!'"
],
"window_name": "default"
},
{
"panes": [
{
"shell_command": "echo 'command in the history!'",
"suppress_history": false
},
{
"shell_command": "echo 'command not in the history!'",
"suppress_history": true
},
{
"shell_command": "echo 'window not in the history!'"
}
],
"suppress_history": true,
"window_name": "mixed"
}
],
"suppress_history": false,
"session_name": "suppress"
}
29 changes: 29 additions & 0 deletions examples/suppress-history.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
session_name: suppress
suppress_history: false
windows:
- window_name: appended
focus: true
suppress_history: false
panes:
- echo "window in the history!"

- window_name: suppressed
suppress_history: true
panes:
- echo "window not in the history!"

- window_name: default
panes:
- echo "session in the history!"

- window_name: mixed
suppress_history: false
panes:
- shell_command:
- echo "command in the history!"
suppress_history: false
- shell_command:
- echo "command not in the history!"
suppress_history: true
- shell_command:
- echo "window in the history!"
10 changes: 10 additions & 0 deletions tmuxp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ def trickle(sconf):
else:
session_start_directory = None

if 'suppress_history' in sconf:
suppress_history = sconf['suppress_history']
else:
suppress_history = None

for windowconfig in sconf['windows']:

# Prepend start_directory to relative window commands
Expand All @@ -325,6 +330,11 @@ def trickle(sconf):
)
windowconfig['start_directory'] = window_start_path

# We only need to trickle to the window, workspace builder checks wconf
if suppress_history is not None:
if not 'suppress_history' in windowconfig:
windowconfig['suppress_history'] = suppress_history

for paneconfig in windowconfig['panes']:
commands_before = []

Expand Down
7 changes: 5 additions & 2 deletions tmuxp/pane.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def cmd(self, cmd, *args, **kwargs):

return self.server.cmd(cmd, *args, **kwargs)

def send_keys(self, cmd, enter=True):
def send_keys(self, cmd, enter=True, suppress_history=True):
"""``$ tmux send-keys`` to the pane.

A leading space character is added to cmd to avoid polluting the
Expand All @@ -85,9 +85,12 @@ def send_keys(self, cmd, enter=True):
:type cmd: str
:param enter: Send enter after sending the input.
:type enter: bool
:param suppress_history: Don't add these keys to the shell history
:type suppress_history: bool

"""
self.cmd('send-keys', ' ' + cmd)
prefix = ' ' if suppress_history else ''
self.cmd('send-keys', prefix + cmd)

if enter:
self.enter()
Expand Down
16 changes: 15 additions & 1 deletion tmuxp/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ def new_window(self,
window_name=None,
start_directory=None,
attach=True,
window_index=''):
window_index='',
window_shell=None):
"""Return :class:`Window` from ``$ tmux new-window``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the docstrings (:param window_index: description, so on) for these params?


.. note::
Expand All @@ -144,6 +145,16 @@ def new_window(self,
:type start_directory: string
:param attach: make new window the current window after creating it,
default True.
:param window_index: create the new window at the given index position.
Default is empty string which will create the window in the next
available position.
:type window_index: string
:param window_shell: execute a command on starting the window. The
window will close when the command exits.
NOTE: When this command exits the window will close. This feature
is useful for long-running processes where the closing of the
window upon completion is desired.
:type window_command: string
:param type: bool
:rtype: :class:`Window`

Expand Down Expand Up @@ -177,6 +188,9 @@ def new_window(self,
'-t%s:%s' % (self.get('session_id'), window_index),
)

if window_shell:
window_args += (window_shell,)

proc = self.cmd('new-window', *window_args)

if proc.stderr:
Expand Down
96 changes: 94 additions & 2 deletions tmuxp/testsuite/workspacebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
import tempfile
import time
import unittest
import subprocess

import kaptan

from .helpers import TmuxTestCase
from .. import Window, config, exc
from .._compat import text_type
from .._compat import text_type, console_to_str
from ..workspacebuilder import WorkspaceBuilder

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -214,6 +215,63 @@ def test_focus_pane_index(self):
self.assertEqual(p.get('pane_current_path'), pane_path)


class SuppressHistoryTest(TmuxTestCase):
yaml_config = """
session_name: sampleconfig
start_directory: '~'
suppress_history: false
windows:
- window_name: inHistory
panes:
- echo inHistory
- window_name: isMissing
suppress_history: true
panes:
- echo isMissing
"""
def test_suppress_history(self):
s = self.session
sconfig = kaptan.Kaptan(handler='yaml')
sconfig = sconfig.import_config(self.yaml_config).get()
sconfig = config.expand(sconfig)
sconfig = config.trickle(sconfig)

builder = WorkspaceBuilder(sconf=sconfig)
builder.build(session=self.session)
time.sleep(0.3) # give .bashrc, etc. time to load

s.server._update_windows()
for w in s.windows:
w.server._update_panes()
w.select_window()
for p in w.panes:
p.select_pane()

# Print the last-in-history command in the pane
self.session.cmd('send-keys', ' fc -ln -1')
self.session.cmd('send-keys', 'Enter')
time.sleep(0.1) # give fc time to run

# Get the contents of the pane
self.session.cmd('capture-pane')
captured_pane = self.session.cmd('show-buffer')
self.session.cmd('delete-buffer')

# Parse the sent and last-in-history commands
sent_cmd = captured_pane.stdout[0].strip()
history_cmd = captured_pane.stdout[-2].strip()

# If it was in the history, sent == history
if 'inHistory' in sent_cmd:
self.assertEqual(sent_cmd, history_cmd)
# Otherwise, sent != history
elif 'isMissing' in sent_cmd:
self.assertNotEqual(sent_cmd, history_cmd)
# Something went wrong
else:
self.assertTrue(False)


class WindowOptions(TmuxTestCase):

yaml_config = """
Expand Down Expand Up @@ -253,6 +311,39 @@ def test_window_options(self):
window_count += 1
w.select_layout(wconf['layout'])

def test_window_shell(self):
yaml_config = """
session_name: test window options
start_directory: '~'
windows:
- layout: main-horizontal
options:
main-pane-height: 5
panes:
- pane
- pane
- pane
window_name: editor
window_shell: top
"""
s = self.session
sconfig = kaptan.Kaptan(handler='yaml')
sconfig = sconfig.import_config(yaml_config).get()
sconfig = config.expand(sconfig)

builder = WorkspaceBuilder(sconf=sconfig)

for w, wconf in builder.iter_create_windows(s):
if 'window_shell' in wconf:
self.assertEqual(wconf['window_shell'], text_type('top'))
for i in range(10):
self.session.server._update_windows()
if w['window_name'] != 'top':
break
time.sleep(.2)

self.assertNotEqual(w.get('window_name'), text_type('top'))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are intended to be integration tests in the truest sense of the word. See .travis.yml.

We have a minimum tmux version we officially support (though we can bump it of course). I'd like to be sure that this behavior would work on older versions.

Try something like this:

diff --git a/tmuxp/testsuite/workspacebuilder.py b/tmuxp/testsuite/workspacebuilder.py
index 253834e..a8b79dc 100644
--- a/tmuxp/testsuite/workspacebuilder.py
+++ b/tmuxp/testsuite/workspacebuilder.py
@@ -266,7 +266,7 @@ class WindowOptions(TmuxTestCase):
           - pane
           - pane
           window_name: editor
-          window_shell: test_command
+          window_shell: top
         """
         s = self.session
         sconfig = kaptan.Kaptan(handler='yaml')
@@ -277,7 +277,14 @@ class WindowOptions(TmuxTestCase):

         for w, wconf in builder.iter_create_windows(s):
             if 'window_shell' in wconf:
-                self.assertEqual(wconf['window_shell'], text_type('test_command'))
+                self.assertEqual(wconf['window_shell'], text_type('top'))
+            for i in range(10):
+                self.session.server._update_windows()
+                if w['window_name'] != 'top':
+                    break
+                time.sleep(.2)
+
+            self.assertNotEqual(w.get('window_name'), text_type('top'))


 class EnvironmentVariables(TmuxTestCase):
@@ -305,7 +312,7 @@ class EnvironmentVariables(TmuxTestCase):

         self.assertEqual('BAR', self.session.show_environment('FOO'))
         self.assertEqual('/tmp', self.session.show_environment('PATH'))
-        
+
 class WindowAutomaticRename(TmuxTestCase):

     yaml_config = """


class EnvironmentVariables(TmuxTestCase):

Expand All @@ -279,7 +370,7 @@ def test_environment_variables(self):

self.assertEqual('BAR', self.session.show_environment('FOO'))
self.assertEqual('/tmp', self.session.show_environment('PATH'))

class WindowAutomaticRename(TmuxTestCase):

yaml_config = """
Expand Down Expand Up @@ -895,5 +986,6 @@ def suite():
suite.addTest(unittest.makeSuite(WindowAutomaticRename))
suite.addTest(unittest.makeSuite(WindowIndexTest))
suite.addTest(unittest.makeSuite(WindowOptions))
suite.addTest(unittest.makeSuite(SuppressHistoryTest))
suite.addTest(unittest.makeSuite(EnvironmentVariables))
return suite
8 changes: 7 additions & 1 deletion tmuxp/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ def by(val, *args):
return False
return True

return list(filter(by, self.server._windows))[0]
ret = list(filter(by, self.server._windows))
# If a window_shell option was configured which results in
# a short-lived process, the window id is @0. Use that instead of
# self._window_id
if len(ret) == 0 and self.server._windows[0]['window_id'] == '@0':
ret = self.server._windows
return ret[0]

def cmd(self, cmd, *args, **kwargs):
"""Return :meth:`Server.cmd` defaulting ``target_window`` as target.
Expand Down
15 changes: 14 additions & 1 deletion tmuxp/workspacebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,17 @@ def iter_create_windows(self, s):
else:
sd = None

if 'window_shell' in wconf:
ws = wconf['window_shell']
else:
ws = None

w = s.new_window(
window_name=window_name,
start_directory=sd,
attach=False, # do not move to the new window
window_index=wconf.get('window_index', ''),
window_shell=ws,
)

if i == int(1) and w1: # if first window, use window 1
Expand Down Expand Up @@ -261,8 +267,15 @@ def get_pane_start_directory():
if 'layout' in wconf:
w.select_layout(wconf['layout'])

if 'suppress_history' in pconf:
suppress = pconf['suppress_history']
elif 'suppress_history' in wconf:
suppress = wconf['suppress_history']
else:
suppress = True

for cmd in pconf['shell_command']:
p.send_keys(cmd)
p.send_keys(cmd, suppress_history=suppress)

if 'focus' in pconf and pconf['focus']:
w.select_pane(p['pane_id'])
Expand Down