177 Commits

Author SHA1 Message Date
2633722423 test(refactor): switch to bashunit and start fleshing out a new test suite 2025-12-02 01:15:42 +00:00
f268c12f3f Merge pull request #117 from jimeh/improve-shell-script-formatting 2025-12-01 23:11:59 +00:00
adb008b301 style(shell): improve shell script formatting and quoting
Apply shfmt formatting and fix some schellcheck complaints.
2025-12-01 23:04:40 +00:00
9941b28063 Merge pull request #109 from plaffitt/skip-run_cmd-history
Prepend commands in run_cmd with a space to prevent them to be stored in the history
2025-02-24 21:25:18 +00:00
Paul Laffitte
68b02f07b0 Prepend commands in run_cmd with a space to prevent them to be stored in the history 2024-09-30 17:57:15 +02:00
895dace853 fix(layout-helpers): split_h/split_v work correctly on latest tmux (#99)
The `-p` flag on `split-window` was deprecated in Tmux 3.1 in favor of
just adding a `%` suffix to the numeric value given to the `-l` flag.

This uses the new `-l <n>%` format on Tmux 3.1 and later, and uses the
old `-p <n>` format on 3.0 and older.
2024-02-18 00:42:44 +00:00
2b6239c6f0 Merge pull request #96 from gabyx/patch-1
fix: Wrong link in help command
2024-02-18 00:28:53 +00:00
de509d8a08 Merge pull request #95 from joaopedroaat/master
Bugfix: add fix to tmux next-* versions.
2024-02-18 00:28:39 +00:00
Gabriel Nützi
67ee31d783 fix: Wrong link in help command 2024-01-17 13:25:55 +01:00
João Pedro
2e4d5197ae Remove incorrect formatting. 2024-01-09 14:54:23 -03:00
João Pedro
c2cbd5d7ea Bugfix: add fix to tmux next-* versions. 2024-01-06 17:38:36 -03:00
fe1f6c4734 docs(readme): add TPM installation instructions 2023-04-11 19:24:15 +01:00
d147958750 docs(readme): format readme with prettier-js 2023-04-11 19:23:52 +01:00
957229a1e8 Merge pull request #88 from 0inp/master 2023-04-11 18:54:19 +01:00
Stephane Point
ea4a7aa57c Add TPM support 2023-04-09 14:17:14 -05:00
8987dd4492 Bump version to 0.13.0 2017-04-27 19:49:05 +01:00
9049818b25 Add optional target window argument to newly added layout helpers 2017-04-27 19:48:15 +01:00
47ef3bd857 Merge pull request #75 from leesei/sort-list
feat: sort sessions and windows list
2017-04-27 19:32:01 +01:00
a9ca566c28 Merge pull request #73 from Yuki-Inoue/synchronize-helper-methods
Add synchronize helper methods
2017-04-27 19:23:22 +01:00
87e31a03c9 Merge pull request #58 from mlavi/fish2-0-0
Accommodate fish shell 2.0.0
2017-04-27 19:21:02 +01:00
7f3ec1cd5b Merge pull request #76 from xsteve/feature/fix-has-session
Work around a problem with tmux has-session:
2017-04-27 19:18:49 +01:00
9baadfbb1e Bump version to 0.12.3 2017-04-27 18:59:38 +01:00
2adc885bb8 Fix issue with using a tmux version compiled source
Resolves #79.

When tmux is compiled from source the version string is "master" which
the tmux-version command didn't deal with correctly.
2017-04-27 18:59:38 +01:00
7cc0fa2d0e Fix typo in help text of tmux-version command 2017-04-27 18:59:38 +01:00
Stefan Reichoer
e41b15c515 Work around a problem with tmux has-session:
tmux has-session does a prefix match and not an exact match.

When a session "ABC" does exist, the session "A" is also interpreted as "ABC"
Using tmux list-sessions fixes this problem
2016-10-28 13:07:17 +02:00
leesei
690a4465b0 feat: sort sessions and windows list
On branch sort-list
Changes to be committed:
	modified:   libexec/tmuxifier-list-sessions
	modified:   libexec/tmuxifier-list-windows
2016-08-19 23:14:08 +08:00
Yuki Inoue
9bcfbd3428 Add synchronize helper methods 2016-05-09 12:34:48 +09:00
7aeeaf31d1 Merge pull request #71 from Yuki-Inoue/balance-windows-layout-helpers
Add balance_window helper methods
2016-04-28 18:35:42 +01:00
ca6dcfaaf2 Merge pull request #72 from Yuki-Inoue/fix-ci-use-github
Fix tmux sourcecode url to github
2016-04-28 18:30:26 +01:00
Yuki Inoue
fdbb1704e0 Fix tmux sourcecode url to github
The sourceforge project of tmux seems to have been removed.  So,
wgetting from github releases instead of sourceforge.
2016-04-28 22:08:30 +09:00
Yuki Inoue
499c5abd83 Add balance_window helper methods 2016-04-28 15:17:05 +09:00
3563c3d975 Bump version to 0.12.2 2016-04-02 22:28:37 +01:00
3bfbc50918 Merge pull request #70 from blueyed/fix-load-session
Fixes for load_session with file in current dir
2016-04-02 22:26:23 +01:00
Daniel Hahler
3a8a43ccdc style: load_session: move return case up, removing indent 2016-04-02 22:38:40 +02:00
Daniel Hahler
a9a87992df load_session: prefer existing session instead of file in cwd
This also adds './' to a file used from the current working dir (in case
there is no session with that name), which is required for Bash's
`source` to use it (and not look for it in `$PATH`).

Fixes https://github.com/jimeh/tmuxifier/issues/69.
2016-04-02 22:38:25 +02:00
5f4dd92d7f Merge pull request #66 from shalecraig/patch-1
Update link to iterm2
2016-01-26 23:09:54 +00:00
shale
bdaa272ca5 Update link to iterm2
iterm2 moved to gitlab from google project hosting.
2016-01-19 10:30:28 -08:00
dce4fb3ad2 Merge pull request #65 from bchretien/topic/window-rename
new_window: disable allow-rename if a window name was given
2015-12-20 23:38:43 +00:00
Benjamin Chrétien
6f8773133d new_window: disable allow-rename if a window name was given 2015-12-15 17:53:45 +01:00
92d188f9f5 Bump version to 0.12.1 2015-07-25 13:38:00 +01:00
8d1751daea Merge pull request #62 from jimeh/fix-issue-61
Fix issue #61
2015-07-25 13:35:24 +01:00
dafa938923 Add Tmux 2.0 to Travis-CI test environments 2015-07-25 13:27:12 +01:00
595269dd6a Make load-window within a session adhere to session_root setting
This should fix #61. Previously when you manually ran `tmuxifier
load-window` from within a session created by Tmuxifier, the
`session_root` path set in the session was ignored, and the new window
would be cd'd to `$HOME` unless the window configuration had
`window_root` set.
2015-07-25 13:24:02 +01:00
Mark Lavi
3c37e18987 Accommodate fish shell 2.0.0 2015-03-22 00:38:17 -07:00
b801aade99 Bump version to 0.12.0 2014-12-02 22:23:37 +00:00
a888efe6d0 Update __go_to_session layout helper test 2014-12-02 22:22:09 +00:00
4a4f62fcf2 Improve/fix help messages for a few commands 2014-12-01 21:03:26 +00:00
41da75ad39 Add support for iTerm2's Tmux integration
This should resolve #52.
2014-12-01 21:01:58 +00:00
6f98020309 Bump version to 0.11.6 2014-08-29 22:59:23 +01:00
a96b5a1d44 Merge pull request #50 from jimeh/fix-new_window-active-window-tracking
Fix new window active window tracking
2014-08-29 22:52:48 +01:00
fe3beeac29 Attempt to avoid timing issue which sometimes causes test to fail 2014-08-29 22:46:41 +01:00
ef0f25591c Set $window var based on currently active window
Previously $window was only set by the new_window() helper when it was
passed a name argument. This caused weird behavior cause if it was
called without a name it would simply attempt to recreate the same
window and fail. That was until @blueyed's fix in 2249cf8.

However, the $window var still wasn't being set correctly, leaving
split_v(), split_h() and other helpers to operate on the wrong
window. This is no longer an issue as $window is always set to the index
of the currently active window at the end of new_window() and
select_window().
2014-08-29 22:29:03 +01:00
0ae0bc84e3 Add __get_current_window_index internal helper function 2014-08-29 22:28:25 +01:00
Daniel Hahler
2249cf8d1b new_window: only set $window and pass -n if a name is provided
Otherwise `new_window` after `new_window foo` would re-use the same
name, resulting in an error.
2014-08-29 20:20:07 +01:00
4bf105eebc Improve wording of comment 2014-08-29 20:15:32 +01:00
71236afccf Clean up structure of initialize_session helper function 2014-08-29 20:14:59 +01:00
6e5794a2b4 Add travis build status to readme 2014-08-29 19:33:38 +01:00
f8f0054c99 Merge pull request #46 from jimeh/add-tests
Add tests
2014-08-29 19:26:47 +01:00
6a1e9e4de7 Cleanup Makefile a bit 2014-08-21 01:54:05 +01:00
77ccb5d532 Clean up test a bit 2014-07-21 16:13:16 +01:00
48b5150b0d Bump version to 0.11.5 2014-07-21 16:08:22 +01:00
38932bf33e Fix issue where EDITOR contains flags 2014-07-21 16:07:33 +01:00
d8b8dff61f Add tests for new_window layout helper 2014-06-04 00:36:33 +01:00
d47838ca1f Add and use test helpers to create/kill test-specific tmux sessions 2014-06-04 00:07:23 +01:00
87d767d1c5 Fix issue with PATH in test environment 2014-06-03 23:19:34 +01:00
1b0b3b8ba8 Add tests for __get_first_window_index layout helper 2014-06-03 20:31:41 +01:00
94b9559bfa Use full tmux command names rather than aliases 2014-06-03 20:31:19 +01:00
636e92b118 Add tests for __go_to_window_or_session_path layout helper 2014-06-03 20:01:47 +01:00
8a06ad149e Update test-runner.sh to v0.2.0 2014-06-03 20:01:31 +01:00
7e63149c26 Add tests for tmux layout helper 2014-05-26 20:20:39 +01:00
36add22637 Use test-runner.sh instead of homegrown test.sh 2014-05-26 13:52:55 +01:00
3aa151b865 Add tests for __go_to_session layout helper 2014-05-26 11:35:10 +01:00
f977850ea9 Add tests for __expand_path layout helper 2014-05-26 11:34:53 +01:00
47219d2d40 Improve test environment for individual test files 2014-05-26 11:28:28 +01:00
6e634ecba9 Update stub.sh 2014-05-26 11:28:16 +01:00
396120cf53 Add slight speed improvements for Travis-CI 2014-05-25 02:41:54 +01:00
a875b63033 Attempt to fix test failing with Tmux 1.6 and 1.7 2014-05-25 02:38:05 +01:00
0d0106e7ba Attempt to run travis-ci tests against multiple versions of tmux 2014-05-25 02:34:13 +01:00
ed52353bba Attempt to get tmux 1.8 on Travis-CI boxes 2014-05-25 01:42:09 +01:00
57b4f303f2 Install tmux on travis-ci.org 2014-05-25 01:32:27 +01:00
359f1a9a94 Use tput instead of hard-coded color codes 2014-05-25 01:32:07 +01:00
41218e3072 Colorize part of test output 2014-05-25 01:24:49 +01:00
5602bf650e Add basic tests for tmuxifier-tmux 2014-05-25 01:24:30 +01:00
54f6f890bb Add tests for lib/util.sh 2014-05-25 00:27:09 +01:00
e5ffdc6f16 A few further tweaks to how path handling in tests 2014-05-25 00:27:09 +01:00
1fb80660b8 Add tests for lib/runtime.sh 2014-05-25 00:27:09 +01:00
a700770757 Fix path related test setup issue 2014-05-25 00:27:09 +01:00
c927126cb3 Improve global test setup in test-helper.sh 2014-05-25 00:27:08 +01:00
279e68f7c5 Add tests for lib/env.sh 2014-05-25 00:27:08 +01:00
1bf087faa3 Basic setup for tests
Based on the test setup of stub.sh: https://github.com/jimeh/stub.sh
2014-05-25 00:27:08 +01:00
2aa549ff70 Bump version to 0.11.4 2014-05-25 00:17:14 +01:00
6f0fdba121 Remove all argument handling from tmuxifier-tmux
It's meant to be a wrapper for tmux, allowing additional arguments to be
passed. Hence having the wrapper itself intercept -h as previously, or
--help as removed in this commit prevents the wrapper from working
properly.
2014-05-25 00:15:29 +01:00
a1e6972434 Bump version to 0.11.3 2014-05-25 00:12:22 +01:00
7443dd74f8 Fix #45 - tmuxifier-tmux should not treat -h flag as output help 2014-05-25 00:12:17 +01:00
e08ee38927 Bump version to 0.11.2 2014-05-15 14:10:53 +01:00
8416e63094 Merge pull request #38 from fritzgrabo/source-missing-utility-functions
Source missing utility functions in tmuxifier-tmux
2014-05-15 14:06:13 +01:00
Fritz Grabo
fe1ac9d2f9 Source missing utility functions in tmuxifier-tmux 2014-05-15 14:22:34 +02:00
87c38ae818 Bump version to 0.11.1 2014-05-14 00:11:38 +01:00
3a74ff3a60 Minor tweaks and updates to a few help messages 2014-05-14 00:08:09 +01:00
7df4a33a7d Fix typo in readme 2014-05-13 23:56:43 +01:00
255fe78572 Bump version to 0.11.0 2014-05-13 23:47:35 +01:00
a5426d4e12 Add some comments, if for nothing else, then for educational purposes 2014-05-13 23:47:35 +01:00
5850c15d87 Check for minimum required Tmux version (fixed #37) 2014-05-13 23:47:34 +01:00
4ccf61f692 Merge pull request #36 from MrAlexLau/master
Correct typo in window template, fixes #35.
2014-05-03 08:09:01 +01:00
mralexlau
44c443efe4 Correct typo in window template, fixes #35. 2014-05-02 16:19:18 -05:00
72cfab20a0 Fix typo in fish examples 2014-02-28 11:14:42 +00:00
33f26bca56 Wrap long line 2014-02-27 23:41:11 +00:00
90caa0d362 Fix typo in code comment 2014-02-27 23:40:48 +00:00
0aa0e43949 Improve custom tmux arguments section
Don't ask why there was no header, cause it's beyond me >_<
2014-02-27 22:46:00 +00:00
2a09683851 Bump version to 0.10.0
The 0.9.2 bump should have been 0.10.0. Support for fish shell was
added, hence a minor version bump is needed, not a patch.
2014-02-27 22:36:40 +00:00
5b3f4d8488 Bump version to 0.9.2 2014-02-27 22:34:23 +00:00
36c702cb88 Improve TMUXIFIER_TMUX_OPTS section 2014-02-27 22:33:39 +00:00
50f84b1586 Improve Update section, slightly, just slightly :) 2014-02-27 22:33:05 +00:00
feed17581a Mention fish shell where sensible 2014-02-27 22:32:23 +00:00
91722a4895 Update copyright year 2014-02-27 22:31:55 +00:00
cd7ae2ebce Merge pull request #32 from trekdemo/fish_support
Full fish shell support
2014-02-27 22:23:47 +00:00
Gergő Sulymosi
a9479df7c1 Update README with fish related stuff 2014-02-27 23:03:09 +01:00
Gergő Sulymosi
84de3da9ac Initialization under fish 2014-02-27 23:02:54 +01:00
7f8840eac9 Bump version to 0.9.1 2014-02-25 00:35:13 +00:00
0653074570 Fix issue #28, default-path error with Tmux 1.9
When using Tmux 1.9 and later the "-c" argument is given to the
"new-session" command to set the session's root/default path. When using
Tmux 1.8.x and earlier, the old "default-path" session option method is
used instead.
2014-02-25 00:30:34 +00:00
5047f596af Merge pull request #31 from trekdemo/fish_completion
Add completion for fish shell
2014-02-24 22:41:45 +00:00
Gergő Sulymosi
f2c5e9bb66 Add completion for fish shell 2014-02-24 10:06:01 +01:00
ae96c17580 Merge pull request #29 from matthias-guenther/installation-fix-for-zsh
Problems with zsh installation
2014-02-11 09:28:49 +00:00
Matthias Guenther
f5c4361268 Add /home/wikimatze variable 2014-02-04 20:28:48 +01:00
Matthias Guenther
8a9174c1c5 Fixing the export path option for bash and zsh in the README 2014-02-04 18:23:21 +01:00
3dfa166041 Bump version to 0.9.0 2014-01-29 08:12:42 +00:00
e231f2d642 Enable passing custom arguments to tmux
Custom arguments can now be passed to tmux by setting the
TMUXIFIER_TMUX_OPTS environment variable.
2014-01-29 08:11:20 +00:00
966e500b40 Bump version to 0.8.1 2013-07-17 14:43:17 +01:00
4c1cb0762a Fix issue #23 - Some consoles don't seem to support C-l 2013-07-17 14:42:46 +01:00
a7473208c0 Bump version to 0.8.0 2013-07-02 23:06:03 +02:00
1dddbb502c Enable load commands to accept file paths in addition to layout names
Resolves issue #20. Additionally, load_session now has an optional
second argument to set the default session name. And error output from
both load commands is now printed to STDERR and give a return code of 1
on error.
2013-07-02 23:05:18 +02:00
da1354d5b7 Bump version to 0.7.3 2013-06-27 08:56:40 +02:00
f01c789de4 Fix typo 2013-06-27 08:55:43 +02:00
b52ef20be8 Merge pull request #22 from limeyd/master
Add optional window name when loading windows
2013-06-26 23:54:38 -07:00
limeyd
212693b1e9 added optional window name 2013-06-26 20:55:29 -06:00
908152bb57 Bump version to 0.7.2 2013-06-20 09:38:22 +01:00
a0365273d0 Minor formatting fixes 2013-06-20 09:38:00 +01:00
6c8777adc2 Merge pull request #19 from gryftir/master
split_hl, split_vl and clock functions
2013-06-20 01:36:45 -07:00
Lawrence Siebert
5e33aefa7d modified: lib/layout-helpers.sh
added split_hl and split_hl and split_vl which split with a count of
columns/lines instead of by percentage,  and clock which starts
clock-mode.  Comments for each added.
2013-06-19 23:35:13 -07:00
e15ae597e4 Bump version to 0.7.1 2013-06-18 09:13:41 +01:00
d982588302 Merge pull request #18 from fomichev/master
tmux set-option default-path
2013-06-18 01:11:42 -07:00
Stanislav Fomichev
0fc1f20af7 Fix typo 2013-06-18 11:11:22 +04:00
Stanislav Fomichev
8c2582a948 Add set_default_path option
This option lets user disable 'tmux set-option default-path' for
$session_root, like this:
	session_root "~/x/y/z"
	set_default_path=false
2013-06-18 11:10:48 +04:00
c1ecc0a7c8 Update LICENSE file to match license details in readme 2013-06-18 00:27:22 +01:00
85718b9a9e Update Todos section in readme 2013-06-18 00:24:51 +01:00
1b5c451e39 Remove "Heed My Warning" section from readme, it's no longer relevant 2013-06-18 00:24:36 +01:00
887bbc4fbc No need to attempt to syntax highlight shell command examples 2013-06-18 00:23:18 +01:00
103cf66ec3 Bump version to 0.7.0 2013-06-18 00:13:57 +01:00
f3797204fb Merge pull request #15 from jimeh/new-init-system
New init system
2013-06-17 16:11:56 -07:00
83b6b47f7c Update readme 2013-06-18 00:05:15 +01:00
fb5a775d98 Improve EDITOR checks 2013-06-17 13:39:13 +01:00
0359e09806 Merge branch 'master' into new-init-system 2013-06-17 13:36:09 +01:00
ee32ac25b8 Merge pull request #17 from peter-d/new-init-system-check
New init system check
2013-06-17 05:32:04 -07:00
peter-d
54561b9bbd fixed a typo 2013-06-17 14:25:24 +02:00
peter-d
a4e3edc4ca Fixed the path setup for tcsh 2013-06-17 14:24:32 +02:00
9f1a3621f0 Fix an error and tweak some styling in readme 2013-06-12 09:00:18 +01:00
831deec069 Update readme with details of new init system 2013-06-12 08:50:25 +01:00
536f625b5d Print correct help info for init command based on the shell used 2013-06-12 00:53:40 +01:00
9e8a5c3dc9 Separate init command output commands with ; fixing issues with tcsh 2013-06-12 00:48:48 +01:00
f0647b0326 Update init scripts 2013-06-12 00:31:51 +01:00
c9c3534f05 Improve init command's argument parsing 2013-06-12 00:08:44 +01:00
7a9c94ff6f Merge pull request #14 from raulbrito/patch-1
Update README.md
2013-06-06 11:43:16 -07:00
Raul Brito
0caf3a78f5 Update README.md 2013-06-06 20:31:26 +02:00
21c43be558 Merge branch 'master' into new-init-system 2013-06-03 09:50:38 +03:00
bb97d5791b Bump version to 0.6.1 2013-06-03 09:48:21 +03:00
dea8939ee0 Remove forgotten and useless variable 2013-06-03 09:46:26 +03:00
df5e6031cd Alter how internal help invocation work to make life a bit easier 2013-06-03 09:46:03 +03:00
adcea18bdc Get rid of now needless for loops 2013-06-03 09:44:57 +03:00
f9c91e5fcd Improve --help and --complete argument handling 2013-06-03 09:32:13 +03:00
1a9dd4787d Improve argument handling of init command 2013-06-03 09:16:58 +03:00
4d486d48d0 Fix a typo 2013-06-02 21:30:56 +03:00
d94ccf560e Simplify internals of init command a bit 2013-06-02 21:29:38 +03:00
ed3fda5769 Update init command to use new help system 2013-06-02 21:25:19 +03:00
35832165ec Merge branch 'master' into new-init-system 2013-06-02 21:04:49 +03:00
7cc9228839 Add early version new tmuxifier-init command 2013-06-02 17:51:43 +03:00
7ab7586f74 Auto-set $TMUXIFIER to correct directory based on relative path 2013-06-02 17:43:41 +03:00
51ebf880dc Only add $TMUXIFIER/bin to $PATH if it is not in $PATH already 2013-06-02 17:42:31 +03:00
83 changed files with 9574 additions and 230 deletions

1
.env Normal file
View File

@@ -0,0 +1 @@
BASHUNIT_BOOTSTRAP=tests/bootstrap.sh

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
test-legacy/test-runner.sh
test-legacy/assert.sh
test-legacy/stub.sh
test/bashunit

16
.travis.yml Normal file
View File

@@ -0,0 +1,16 @@
language: c
env:
- TMUX_VERSION="1.6"
- TMUX_VERSION="1.7"
- TMUX_VERSION="1.8"
- TMUX_VERSION="1.9a"
- TMUX_VERSION="2.0"
before_install:
- sudo apt-get update
- sudo apt-get install -y bc build-essential libevent-dev libncurses5-dev
- wget https://github.com/tmux/tmux/releases/download/${TMUX_VERSION}/tmux-${TMUX_VERSION}.tar.gz
- tar -zxf tmux-${TMUX_VERSION}.tar.gz
- cd tmux-${TMUX_VERSION}
- ./configure && make && sudo make install
- cd ..
script: make test

150
AGENTS.md Normal file
View File

@@ -0,0 +1,150 @@
# AGENTS.md
This file provides guidance to AI Agents when working with code in this
repository.
## Project Overview
Tmuxifier is a shell-based tool for creating and managing complex Tmux session
and window layouts. Users write layout files as shell scripts that use tmux
commands and helper functions to define session/window configurations.
## Architecture
### Core Components
- **bin/tmuxifier**: Main executable that bootstraps the environment, validates
Tmux version (≥1.6), and dispatches to libexec commands
- **libexec/**: Command implementations (tmuxifier-*, e.g.,
tmuxifier-load-session, tmuxifier-new-window)
- **lib/layout-helpers.sh**: Helper functions available within layout files
(new_window, split_v, split_h, run_cmd, select_pane, etc.)
- **lib/runtime.sh**: Runtime environment loader sourced by layout files
- **lib/env.sh**: Sets up TMUXIFIER_LAYOUT_PATH (defaults to $TMUXIFIER/layouts)
- **templates/**: Templates for new session.sh and window.sh layout files
- **examples/**: Example layout files demonstrating usage
### Layout File Types
**Session layouts** (*.session.sh):
- Define entire Tmux sessions with multiple windows
- Must call `initialize_session` to create the session
- Can load window layouts via `load_window` or define windows inline
- Must call `finalize_and_go_to_session` at the end
- Can set `session_root` for default directory
**Window layouts** (*.window.sh):
- Define single window configurations with panes
- Loaded into existing sessions or from session layouts
- Can set `window_root` for window-specific directory
- Use helper functions to split panes and run commands
### Key Concepts
- Layout files are executed as shell scripts with lib/layout-helpers.sh sourced
- Helper functions wrap tmux commands, managing session/window context
- The `tmux` command itself is aliased to tmuxifier-tmux wrapper
- Session creation moves default window to position 999, then kills it in
finalize_and_go_to_session
- TMUXIFIER_TMUX_OPTS allows passing custom arguments to tmux
## Development Commands
### Testing
Tests use [bashunit](https://github.com/TypedDevs/bashunit) framework. Use
deepwiki MCP tool to lookup bashunit documentation if needed.
```bash
make test # Run all tests
make test FILE=tests/lib/util/foo_test.sh # Run a single test file
make bootstrap # Fetch test dependencies
```
Tests are located in `tests/` directory and follow bashunit conventions. Test
files are named `*_test.sh`.
Legacy tests in `test-legacy/` use test-runner.sh framework with assert.sh and
stub.sh libraries. Run with `make test-legacy`.
### Manual Testing
```bash
# Create and load a test window layout
./bin/tmuxifier new-window test-window
./bin/tmuxifier load-window test-window
# Create and load a test session layout
./bin/tmuxifier new-session test-session
./bin/tmuxifier load-session test-session
# List available layouts
./bin/tmuxifier list-sessions
./bin/tmuxifier list-windows
```
## Code Style
- Shell scripts follow Bash conventions
- 2-space indentation
- Functions document arguments in comments
- Use local variables for function scope
- Prefer `[ ]` over `[[ ]]` for basic tests
- Command substitution uses `$()` not backticks
## Important Implementation Details
### Helper Function Pattern
Helper functions in lib/layout-helpers.sh follow this pattern:
```bash
function_name() {
# Parse optional arguments
if [ -n "$1" ]; then local arg=(-flag "$1"); fi
# Execute tmux command with session/window context
tmuxifier-tmux command -t "$session:$window" "${arg[@]}"
# Update state if needed
__go_to_window_or_session_path
}
```
### Tmux Version Handling
Code must support Tmux 1.6+. Version-specific behavior uses
tmuxifier-tmux-version comparisons:
```bash
if [ "$(tmuxifier-tmux-version "1.9")" == "<" ]; then
# Tmux 1.8 and earlier
else
# Tmux 1.9 and later
fi
```
### Path Expansion
Use `__expand_path` to handle ~ and variables in paths:
```bash
session_root() {
local dir="$(__expand_path $@)"
if [ -d "$dir" ]; then
session_root="$dir"
fi
}
```
## Environment Variables
- **TMUXIFIER**: Set to installation directory (auto-detected from bin location)
- **TMUXIFIER_LAYOUT_PATH**: Custom layouts directory (default:
$TMUXIFIER/layouts)
- **TMUXIFIER_TMUX_OPTS**: Custom arguments passed to tmux
- **TMUXIFIER_TMUX_ITERM_ATTACH**: Set to "-CC" for iTerm2 integration
- **TMUXIFIER_NO_COMPLETE**: Disable shell completion if set
- **TMUXIFIER_MIN_TMUX_VERSION**: Minimum required Tmux version (1.6)

1
CLAUDE.md Symbolic link
View File

@@ -0,0 +1 @@
./AGENTS.md

View File

@@ -1,4 +1,4 @@
Copyright (c) 2012 Jim Myhrberg. Copyright (c) 2014 Jim Myhrberg.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

43
Makefile Normal file
View File

@@ -0,0 +1,43 @@
FETCHED_FILES :=
# $(1) = local file path, $(2) = remote URL, $(3) = optional post-curl command
define FETCH_FILE
FETCHED_FILES += $(1)
$(1):
echo "fetching $(1)..." && \
mkdir -p $(dir $(1)) && \
curl -s -L -o $(1) $(2)$(if $(3), && $(3),)
remove_$(1):
test -f "$(1)" && rm "$(1)" && echo "removed $(1)" || true
update_$(1): remove_$(1) $(1)
endef
$(eval $(call FETCH_FILE,tests/bashunit,\
https://github.com/TypedDevs/bashunit/releases/download/0.26.0/bashunit,\
chmod +x tests/bashunit))
$(eval $(call FETCH_FILE,test-legacy/test-runner.sh,\
https://github.com/jimeh/test-runner.sh/raw/v0.2.0/test-runner.sh,\
chmod +x test-legacy/test-runner.sh))
$(eval $(call FETCH_FILE,test-legacy/assert.sh,\
https://raw.github.com/lehmannro/assert.sh/v1.0.2/assert.sh))
$(eval $(call FETCH_FILE,test-legacy/stub.sh,\
https://raw.github.com/jimeh/stub.sh/v1.0.1/stub.sh))
test: bootstrap
./tests/bashunit $(FILE)
test-legacy: bootstrap
./test-legacy/test-runner.sh $(FILE)
bootstrap: $(FETCHED_FILES)
clean: $(addprefix remove_,$(FETCHED_FILES))
update: $(addprefix update_,$(FETCHED_FILES))
.SILENT:
.PHONY: test bootstrap clean update \
$(addprefix remove_,$(FETCHED_FILES)) \
$(addprefix update_,$(FETCHED_FILES))

227
README.md
View File

@@ -1,20 +1,20 @@
# Tmuxifier # Tmuxifier [![Build Status](https://api.travis-ci.org/jimeh/tmuxifier.svg)](https://travis-ci.org/jimeh/tmuxifier)
Tmuxify your Tmux. Create, edit, mangage and load complex Tmux session, window Tmuxify your Tmux. Create, edit, manage and load complex Tmux session, window
and pane configurations with ease. and pane configurations with ease.
In short, Tmuxifier allows you to easily create, edit, and load "layout" In short, Tmuxifier allows you to easily create, edit, and load "layout" files,
files, which are simple shell scripts where you use the `tmux` command and which are simple shell scripts where you use the `tmux` command and helper
helper commands provided by tmuxifier to manage Tmux sessions and windows commands provided by `tmuxifier` to manage Tmux sessions and windows
### Window Layouts ### Window Layouts
Window layouts create a new Tmux window, optionally setting the window title Window layouts create a new Tmux window, optionally setting the window title and
and root path where all shells are cd'd to by default. It allows you to easily root path where all shells are cd'd to by default. It allows you to easily split
split a window into specifically sized panes and more as you wish. a window into specifically sized panes and more as you wish.
You can load a window layout directly into your current Tmux session, or into You can load a window layout directly into your current Tmux session, or into a
a session layout to have the window created along with the session. session layout to have the window created along with the session.
### Session Layouts ### Session Layouts
@@ -25,10 +25,11 @@ defined directly within the session layout file.
## Example ## Example
Given we have a window layout file called [example.window.sh][] which Given we have a window layout file called [example.window.sh][] which looks
looks like: like:
[example.window.sh]: https://github.com/jimeh/tmuxifier/blob/master/examples/example.window.sh [example.window.sh]:
https://github.com/jimeh/tmuxifier/blob/master/examples/example.window.sh
```bash ```bash
window_root "~/Desktop" window_root "~/Desktop"
@@ -39,12 +40,10 @@ split_h 60
select_pane 0 select_pane 0
``` ```
You can then load that window layout into a new window in the You can then load that window layout into a new window in the current tmux
current tmux session using: session using:
```bash tmuxifier load-window example
tmuxifier load-window example
```
Which will yield a Tmux window looking like this: Which will yield a Tmux window looking like this:
@@ -52,34 +51,109 @@ Which will yield a Tmux window looking like this:
## Installation ## Installation
### Manual
Clone the repo to your machine: Clone the repo to your machine:
git clone https://github.com/jimeh/tmuxifier.git ~/.tmuxifier
Then add `$HOME/.tmuxifier/bin` to your PATH to make the `tmuxifier` executable
available to you:
**In bash & zsh:**
```bash ```bash
git clone https://github.com/jimeh/tmuxifier.git ~/.tmuxifier export PATH="$HOME/.tmuxifier/bin:$PATH"
``` ```
### bash & zsh **In tcsh:**
```tcsh
set path = ( "~/.tmuxifier/bin" $path )
```
**In fish:**
```bash
set -gx PATH "~/.tmuxifier/bin" $PATH
```
#### Custom Installation Path
To install Tmuxifier somewhere else than the suggested `~/.tmuxifier`, simply
clone the repository to your custom location, and ensure the `bin` folder is
added to your PATH making the `tmuxifier` executable available to you.
### TPM
You can also install and update Tmuxifier with
[TPM](https://github.com/tmux-plugins/tpm):
```bash
set -g @plugin 'jimeh/tmuxifier'
```
Trigger TPM's install command with `prefix` + `I` to install Tmuxifier to TPM's
plugin directory (default is `$HOME/.tmux/plugins`).
To use the `tmuxifier` command, you will need to add the `bin` directory to your
PATH. If you are using the default TPM plugin directory, the `bin` directory
will be `$HOME/.tmux/plugins/tmuxifier/bin`.
## Setup
**In bash & zsh:**
And add the following to your `~/.profile`, `~/.bash_profile`, `~/.zshrc` or And add the following to your `~/.profile`, `~/.bash_profile`, `~/.zshrc` or
equivalent: equivalent:
```bash ```bash
[[ -s "$HOME/.tmuxifier/init.sh" ]] && source "$HOME/.tmuxifier/init.sh" eval "$(tmuxifier init -)"
``` ```
### tcsh **In tcsh:**
Add the following to your `~/.cshrc`, `~/.tcshrc` or equivalent: Add the following to your `~/.cshrc`, `~/.tcshrc` or equivalent:
```tcsh ```tcsh
if ( -s "$HOME/.tmuxifier/init.sh" ) then eval `tmuxifier init -`
source "$HOME/.tmuxifier/init.sh" ```
endif
**In fish:**
And add the following to your `~/.config/fish/config.fish` or equivalent:
```bash
eval (tmuxifier init - fish)
```
### Custom Tmux Arguments
If you need to pass custom arguments to `tmux` itself, you can do so by setting
the `TMUXIFIER_TMUX_OPTS` environment variable. For example to set custom
arguments globally:
```bash
export TMUXIFIER_TMUX_OPTS="-L my-awesome-socket-name"
eval "$(tmuxifier init -)"
```
And/or specify dynamically when calling `tmuxifier`:
```bash
TMUXIFIER_TMUX_OPTS="-L other-socket" tmuxifier load-session welcome
```
## Updating
```bash
cd ~/.tmuxifier # or where you've cloned tmuxifier to
git pull
``` ```
## Usage ## Usage
*__Note:__ This section needs expanding upon.* _**Note:** This section needs expanding upon._
For a quick reference on available commands and their aliases, please run: For a quick reference on available commands and their aliases, please run:
@@ -87,8 +161,8 @@ For a quick reference on available commands and their aliases, please run:
Tmuxifier doesn't come with any layouts, so you'll want to create your own Tmuxifier doesn't come with any layouts, so you'll want to create your own
window and session layout files. New layout files are populated with examples window and session layout files. New layout files are populated with examples
and comments explaining what things do. Also, having a look at the and comments explaining what things do. Also, having a look at the [examples][]
[examples][] directory will also give you a good idea. directory will also give you a good idea.
### Window Layouts ### Window Layouts
@@ -96,16 +170,16 @@ First off you'll want to define a window layout:
tmuxifier new-window my-awesome-window tmuxifier new-window my-awesome-window
This will create a new layout file called `my-awesome-window.window.sh` in This will create a new layout file called `my-awesome-window.window.sh` in your
your `$TMUXIFIER_LAYOUT_PATH`, and open it with the editor defined in `$TMUXIFIER_LAYOUT_PATH`, and open it with the editor defined in `$EDITOR`.
`$EDITOR`. Customize it as you wish, and save. Customize it as you wish, and save.
You can now load *my-awesome-window* with the following command: You can now load _my-awesome-window_ with the following command:
tmuxifier load-window my-awesome-window tmuxifier load-window my-awesome-window
You should now have a new Tmux window open created from your custom and You should now have a new Tmux window open created from your custom and awesome
awesome window layout. window layout.
### Session Layouts ### Session Layouts
@@ -115,8 +189,9 @@ To create your first session layout, run:
Same deal as with creating a new window, except the filename ends with Same deal as with creating a new window, except the filename ends with
`.session.sh` instead of `.window.sh`, and the file's pre-populated content `.session.sh` instead of `.window.sh`, and the file's pre-populated content
looks different. To have your awesome window loaded, add `load_window looks different. To have your awesome window loaded, add
"my-awesome-window"` to the session layout next to existing examples. `load_window "my-awesome-window"` to the session layout next to existing
examples.
To load the session layout simply run: To load the session layout simply run:
@@ -129,17 +204,6 @@ in it.
## Configure & Customize ## Configure & Customize
### Custom Installaton Path
To install Tmuxifier to a custom path, clone the repository to your desired
path and set `$TMUXIFIER` to that path, additionally loading `init.sh` or
`init.tcsh` from that same path.
```bash
export TMUXIFIER="$HOME/.dotfiles/tmuxifier"
[[ -s "$TMUXIFIER/init.sh" ]] && source "$TMUXIFIER/init.sh"
```
### Custom Layouts Path ### Custom Layouts Path
You can customize the layouts directory used by Tmuxifier by setting You can customize the layouts directory used by Tmuxifier by setting
@@ -151,13 +215,28 @@ export TMUXIFIER_LAYOUT_PATH="$HOME/.tmux-layouts"
### Disable Shell-Completion ### Disable Shell-Completion
Tmuxifier comes with shell-completion for bash, zsh and tcsh. If for any Tmuxifier comes with shell-completion for bash, zsh, tcsh, and fish. If for any
reason you need to disable it, just set `$TMUXIFIER_NO_COMPLETE`. reason you need to disable it, just set `$TMUXIFIER_NO_COMPLETE`.
```bash ```bash
export TMUXIFIER_NO_COMPLETE=1 export TMUXIFIER_NO_COMPLETE=1
``` ```
## Tips
### iTerm2 Integration
Tmuxifier supports iTerm2's [Tmux integration][]. It can be used in two ways:
- Passing `-CC` as a second argument to the `load-session` command. For example:
tmuxifier load-session my-awesome-session -CC
- Setting the `TMUXIFIER_TMUX_ITERM_ATTACH` environment variable to `-CC` before
calling the `load-session` command.
[tmux integration]: https://gitlab.com/gnachman/iterm2/wikis/TmuxIntegration
## Inspiration ## Inspiration
- Tmuxifier is largely inspired by [Tmuxinator][]. - Tmuxifier is largely inspired by [Tmuxinator][].
@@ -166,56 +245,46 @@ export TMUXIFIER_NO_COMPLETE=1
## Tmuxifier vs. Tmuxinator ## Tmuxifier vs. Tmuxinator
Though Tmuxifier is largely inspired by the excellent [Tmuxinator][] project, Though Tmuxifier is largely inspired by the excellent [Tmuxinator][] project, it
it does set itself apart in a number of ways: does set itself apart in a number of ways:
- Uses shell scripts to define Tmux sessions and windows instead of YAML - Uses shell scripts to define Tmux sessions and windows instead of YAML files.
files. The benefit is total control over Tmux, but the definition files are The benefit is total control over Tmux, but the definition files are more
more complicated to work with. complicated to work with.
- Instead of using a "project" concept, Tmuxifier uses a concept of "sessions" - Instead of using a "project" concept, Tmuxifier uses a concept of "sessions"
and "windows" just like Tmux itself. This allows you to load a whole session and "windows" just like Tmux itself. This allows you to load a whole session
with multiple pre-defined window configurations, or just load a single with multiple pre-defined window configurations, or just load a single window
window configuration into your existing session. configuration into your existing session.
- Tmuxifier is a set of shell scripts, meaning it doesn't require Ruby to be - Tmuxifier is a set of shell scripts, meaning it doesn't require Ruby to be
installed on the machine. installed on the machine.
[tmuxinator]: https://github.com/aziz/tmuxinator [tmuxinator]: https://github.com/aziz/tmuxinator
[rbenv]: https://github.com/sstephenson/rbenv [rbenv]: https://github.com/sstephenson/rbenv
## Heed My Warning
Tmuxifier is pretty much an alpha product hacked together over a weekend at
this point. Documentation is sketchy at best, and things might drastically
change and/or break.
But if that doesn't put you off, please enjoy Tmuxifier :)
## Todos ## Todos
* Improve Readme, specially Usage section. - Improve Readme, specially Usage section.
* Expand `help` command with details for most commands, rather than just the - Write up a detailed reference for all available layout helper functions.
essential ones.
## License ## License
(The MIT license) (The MIT license)
Copyright (c) 2013 Jim Myhrberg. Copyright (c) 2014 Jim Myhrberg.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy of
of this software and associated documentation files (the "Software"), to deal this software and associated documentation files (the "Software"), to deal in
in the Software without restriction, including without limitation the rights the Software without restriction, including without limitation the rights to
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
copies of the Software, and to permit persons to whom the Software is the Software, and to permit persons to whom the Software is furnished to do so,
furnished to do so, subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE.

View File

@@ -2,28 +2,58 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
resolve_link() {
$(type -p greadlink readlink | head -1) $1
}
abs_dirname() {
local cwd="$(pwd)"
local path="$1"
while [ -n "$path" ]; do
cd "${path%/*}"
local name="${path##*/}"
path="$(resolve_link "$name" || true)"
done
pwd
cd "$cwd"
}
if [ -z "${TMUXIFIER}" ]; then if [ -z "${TMUXIFIER}" ]; then
export TMUXIFIER="${HOME}/.tmuxifier" # Set TMUXIFIER relative to the "tmuxifier" executable.
export TMUXIFIER="$(dirname "$(abs_dirname "$0")")"
else else
# Strip any trailing slash (/) characters from TMUXIFIER variable.
export TMUXIFIER="${TMUXIFIER%/}" export TMUXIFIER="${TMUXIFIER%/}"
fi fi
# Load tmuxifier environment variables. # Load tmuxifier environment variables.
source "$TMUXIFIER/lib/env.sh" source "$TMUXIFIER/lib/env.sh"
# Add tmuxifier's internal commands to PATH.
export PATH="$TMUXIFIER/libexec:$PATH" export PATH="$TMUXIFIER/libexec:$PATH"
# Check Tmux version.
export TMUXIFIER_MIN_TMUX_VERSION="1.6"
if [ "$(tmuxifier-tmux-version "$TMUXIFIER_MIN_TMUX_VERSION")" == "<" ]; then
echo -e "ERROR: Tmuxifier requires Tmux v${TMUXIFIER_MIN_TMUX_VERSION}" \
"or newer. You have v$(tmuxifier-tmux-version)." >&2
exit 1
fi
# Parse given command
command="$1" command="$1"
case "$command" in case "$command" in
"" | "-h" | "--help" ) "" | "-h" | "--help")
echo -e "tmuxifier $(tmuxifier-version)\n$(tmuxifier-help)" >&2 echo -e "tmuxifier $(tmuxifier-version)\n$(tmuxifier-help)" >&2
;; ;;
"-v" | "--version" ) "-v" | "--version")
tmuxifier-version tmuxifier-version
;; ;;
* ) *)
! command_path="$(tmuxifier-resolve-command-path "$command")" ! command_path="$(tmuxifier-resolve-command-path "$command")"
if [ -z "$command_path" ]; then if [ -z "$command_path" ]; then

View File

@@ -3,11 +3,11 @@ _tmuxifier() {
local word="${COMP_WORDS[COMP_CWORD]}" local word="${COMP_WORDS[COMP_CWORD]}"
if [ "$COMP_CWORD" -eq 1 ]; then if [ "$COMP_CWORD" -eq 1 ]; then
COMPREPLY=( $(compgen -W "$(tmuxifier commands)" -- "$word") ) COMPREPLY=($(compgen -W "$(tmuxifier commands)" -- "$word"))
else else
local command="${COMP_WORDS[1]}" local command="${COMP_WORDS[1]}"
local completions="$(tmuxifier completions "$command")" local completions="$(tmuxifier completions "$command")"
COMPREPLY=( $(compgen -W "$completions" -- "$word") ) COMPREPLY=($(compgen -W "$completions" -- "$word"))
fi fi
} }

36
completion/tmuxifier.fish Normal file
View File

@@ -0,0 +1,36 @@
set -l cmd_load_session 'load-session s'
set -l cmd_load_window 'load-window w'
set -l cmd_list 'list l'
set -l cmd_list_sessions 'list-sessions ls'
set -l cmd_list_windows 'list-windows lw'
set -l cmd_new_session 'new-session ns'
set -l cmd_new_window 'new-window nw'
set -l cmd_edit_session 'edit-session es'
set -l cmd_edit_window 'edit-window ew'
set -l cmd_commands 'commands'
set -l cmd_version 'version'
set -l cmd_help 'help'
complete -c tmuxifier -x
# Commands
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_load_session -d 'Load the specified session layout.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_load_window -d 'Load the specified window layout into current session.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_list -d 'List all session and window layouts.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_list_sessions -d 'List session layouts.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_list_windows -d 'List window layouts.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_new_session -d 'Create new session layout and open it with $EDITOR.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_new_window -d 'Create new window layout and open it with $EDITOR.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_edit_session -d 'Edit specified session layout with $EDITOR.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_edit_window -d 'Edit specified window layout with $EDITOR.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_commands -d 'List all tmuxifier commands.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_version -d 'Print Tmuxifier version.'
complete -c tmuxifier -n '__fish_use_subcommand' -a $cmd_help -d 'Show this message.'
# Complete subcommands
complete -c tmuxifier -x -n "__fish_seen_subcommand_from $cmd_load_session" -a '(tmuxifier list-sessions)' -d 'session-template'
complete -c tmuxifier -x -n "__fish_seen_subcommand_from $cmd_load_window" -a '(tmuxifier list-windows)' -d 'window-template'
complete -c tmuxifier -x -n "__fish_seen_subcommand_from $cmd_edit_session" -a '(tmuxifier list-sessions)' -d 'session-template'
complete -c tmuxifier -x -n "__fish_seen_subcommand_from $cmd_edit_window" -a '(tmuxifier list-windows)' -d 'window-template'

20
init.fish Normal file
View File

@@ -0,0 +1,20 @@
# Set/fix Tmuxifier root path if needed.
if test -z $TMUXIFIER
set -gx TMUXIFIER "$HOME/.tmuxifier"
end
# Add `bin` directroy to `$PATH`.
if not contains "$TMUXIFIER/bin" $PATH
set -gx PATH "$TMUXIFIER/bin" $PATH
end
# If `tmuxifier` is available, and `$TMUXIFIER_NO_COMPLETE` is not set, then
# load Tmuxifier shell completion.
if test -n (which tmuxifier); and test -z $TMUXIFIER_NO_COMPLETE
# fish shell 2.0.0 does not have the source alias
if [ (fish --version 2>| awk -F'version ' '{print $2}') = '2.0.0' ];
. "$TMUXIFIER/completion/tmuxifier.fish"
else
source "$TMUXIFIER/completion/tmuxifier.fish"
end
end

View File

@@ -1,4 +1,4 @@
# Set tmuxifier root path. # Set/fix Tmuxifier root path if needed.
if [ -z "${TMUXIFIER}" ]; then if [ -z "${TMUXIFIER}" ]; then
export TMUXIFIER="${HOME}/.tmuxifier" export TMUXIFIER="${HOME}/.tmuxifier"
else else
@@ -6,10 +6,12 @@ else
fi fi
# Add `bin` directroy to `$PATH`. # Add `bin` directroy to `$PATH`.
export PATH="$TMUXIFIER/bin:$PATH" if [[ ":$PATH:" != *":$TMUXIFIER/bin:"* ]]; then
export PATH="$TMUXIFIER/bin:$PATH"
fi
# If `tmuxifier` is available, and `$TMUXIFIER_NO_COMPLETE` is not set, then # If `tmuxifier` is available, and `$TMUXIFIER_NO_COMPLETE` is not set, then
# load tmuxifier shell completion. # load Tmuxifier shell completion.
if [ -n "$(command -v "tmuxifier")" ] && [ -z "$TMUXIFIER_NO_COMPLETE" ]; then if [ -n "$(command -v "tmuxifier")" ] && [ -z "$TMUXIFIER_NO_COMPLETE" ]; then
if [ -n "$BASH_VERSION" ]; then if [ -n "$BASH_VERSION" ]; then
source "$TMUXIFIER/completion/tmuxifier.bash" source "$TMUXIFIER/completion/tmuxifier.bash"

View File

@@ -1,13 +1,15 @@
# Set tmuxifier root path. # Set Tmuxifier root path if needed.
if ( ! $?TMUXIFIER ) then if ( ! $?TMUXIFIER ) then
setenv TMUXIFIER "${HOME}/.tmuxifier" setenv TMUXIFIER "${HOME}/.tmuxifier"
endif endif
# Add `bin` directroy to `$PATH`. # Add `bin` directroy to `$path` if needed.
set path = ( $TMUXIFIER/bin $path ) if ( ! (" $path " =~ "* $TMUXIFIER/bin *" ) ) then
set path = ( $TMUXIFIER/bin $path )
endif
# If `tmuxifier` is available, and `$TMUXIFIER_NO_COMPLETE` is not set, then # If `tmuxifier` is available, and `$TMUXIFIER_NO_COMPLETE` is not set, then
# load tmuxifier shell completion. # load Tmuxifier shell completion.
if ( ! $?TMUXIFIER_NO_COMPLETE ) then if ( ! $?TMUXIFIER_NO_COMPLETE ) then
which tmuxifier > /dev/null && source "$TMUXIFIER/completion/tmuxifier.tcsh" which tmuxifier > /dev/null && source "$TMUXIFIER/completion/tmuxifier.tcsh"
endif endif

View File

@@ -6,6 +6,11 @@
# otherwise more complex means. # otherwise more complex means.
# #
# Alias tmux to tmuxifier-tmux wrapper.
tmux() {
tmuxifier-tmux "$@"
}
# Create a new window. # Create a new window.
# #
# Arguments: # Arguments:
@@ -13,11 +18,15 @@
# - $2: (optional) Shell command to execute when window is created. # - $2: (optional) Shell command to execute when window is created.
# #
new_window() { new_window() {
if [ -n "$1" ]; then window="$1"; fi if [ -n "$1" ]; then local winarg=(-n "$1"); fi
if [ -n "$2" ]; then local command=("$2"); fi if [ -n "$2" ]; then local command=("$2"); fi
if [ -n "$window" ]; then local winarg=(-n "$window"); fi
tmux new-window -t "$session:" "${winarg[@]}" "${command[@]}" tmuxifier-tmux new-window -t "$session:" "${winarg[@]}" "${command[@]}"
# Disable renaming if a window name was given.
if [ -n "$1" ]; then tmuxifier-tmux set-option -t "$1" allow-rename off; fi
window="$(__get_current_window_index)"
__go_to_window_or_session_path __go_to_window_or_session_path
} }
@@ -28,8 +37,13 @@ new_window() {
# - $2: (optional) Target pane ID to split in current window. # - $2: (optional) Target pane ID to split in current window.
# #
split_v() { split_v() {
if [ -n "$1" ]; then local percentage=(-p "$1"); fi if [ "$(tmuxifier-tmux-version "3.0")" == ">" ]; then
tmux split-window -t "$session:$window.$2" -v "${percentage[@]}" # Tmux 3.1 and later.
if [ -n "$1" ]; then local percentage=(-l "$1"'%'); fi
else
if [ -n "$1" ]; then local percentage=(-p "$1"); fi
fi
tmuxifier-tmux split-window -t "$session:$window.$2" -v "${percentage[@]}"
__go_to_window_or_session_path __go_to_window_or_session_path
} }
@@ -40,18 +54,56 @@ split_v() {
# - $2: (optional) Target pane ID to split in current window. # - $2: (optional) Target pane ID to split in current window.
# #
split_h() { split_h() {
if [ -n "$1" ]; then local percentage=(-p "$1"); fi if [ "$(tmuxifier-tmux-version "3.0")" == ">" ]; then
tmux split-window -t "$session:$window.$2" -h "${percentage[@]}" # Tmux 3.1 and later.
if [ -n "$1" ]; then local percentage=(-l "$1"'%'); fi
else
if [ -n "$1" ]; then local percentage=(-p "$1"); fi
fi
tmuxifier-tmux split-window -t "$session:$window.$2" -h "${percentage[@]}"
__go_to_window_or_session_path __go_to_window_or_session_path
} }
# Split current window/pane vertically by line count.
#
# Arguments:
# - $1: (optional) Number of lines the new pane will use.
# - $2: (optional) Target pane ID to split in current window.
#
split_vl() {
if [ -n "$1" ]; then local count=(-l "$1"); fi
tmuxifier-tmux split-window -t "$session:$window.$2" -v "${count[@]}"
__go_to_window_or_session_path
}
# Split current window/pane horizontally by column count.
#
# Arguments:
# - $1: (optional) Number of columns the new pane will use.
# - $2: (optional) Target pane ID to split in current window.
#
split_hl() {
if [ -n "$1" ]; then local count=(-l "$1"); fi
tmuxifier-tmux split-window -t "$session:$window.$2" -h "${count[@]}"
__go_to_window_or_session_path
}
# Run clock mode.
#
# Arguments:
# - $1: (optional) Target pane ID in which to run
clock() {
tmuxifier-tmux clock-mode -t "$session:$window.$1"
}
# Select a specific window. # Select a specific window.
# #
# Arguments: # Arguments:
# - $1: Window ID or name to select. # - $1: Window ID or name to select.
# #
select_window() { select_window() {
tmux select-window -t "$session:$1" tmuxifier-tmux select-window -t "$session:$1"
window="$(__get_current_window_index)"
} }
# Select a specific pane in the current window. # Select a specific pane in the current window.
@@ -60,7 +112,45 @@ select_window() {
# - $1: Pane ID to select. # - $1: Pane ID to select.
# #
select_pane() { select_pane() {
tmux select-pane -t "$session:$window.$1" tmuxifier-tmux select-pane -t "$session:$window.$1"
}
# Balance windows vertically with the "even-vertical" layout.
#
# Arguments:
# - $1: (optional) Window ID or name to operate on.
#
balance_windows_vertical() {
tmuxifier-tmux select-layout -t "$session:${1:-$window}" even-vertical
}
# Balance windows horizontally with the "even-horizontal" layout.
#
# Arguments:
# - $1: (optional) Window ID or name to operate on.
#
balance_windows_horizontal() {
tmuxifier-tmux select-layout -t "$session:${1:-$window}" even-horizontal
}
# Turn on synchronize-panes in a window.
#
# Arguments:
# - $1: (optional) Window ID or name to operate on.
#
synchronize_on() {
tmuxifier-tmux set-window-option -t "$session:${1:-$window}" \
synchronize-panes on
}
# Turn off synchronize-panes in a window.
#
# Arguments:
# - $1: (optional) Window ID or name to operate on.
#
synchronize_off() {
tmuxifier-tmux set-window-option -t "$session:${1:-$window}" \
synchronize-panes off
} }
# Send/paste keys to the currently active pane/window. # Send/paste keys to the currently active pane/window.
@@ -70,7 +160,7 @@ select_pane() {
# - $2: (optional) Target pane ID to send input to. # - $2: (optional) Target pane ID to send input to.
# #
send_keys() { send_keys() {
tmux send-keys -t "$session:$window.$2" "$1" tmuxifier-tmux send-keys -t "$session:$window.$2" "$1"
} }
# Runs a shell command in the currently active pane/window. # Runs a shell command in the currently active pane/window.
@@ -84,7 +174,7 @@ run_cmd() {
send_keys "C-m" "$2" send_keys "C-m" "$2"
} }
# Cusomize session root path. Default is `$HOME`. # Customize session root path. Default is `$HOME`.
# #
# Arguments: # Arguments:
# - $1: Directory path to use for session root. # - $1: Directory path to use for session root.
@@ -111,12 +201,22 @@ window_root() {
# Load specified window layout. # Load specified window layout.
# #
# Arguments: # Arguments:
# - $1: Name of window layout to load. # - $1: Name of or file path to window layout to load.
# - $2: (optional) Override default window name.
# #
load_window() { load_window() {
local file="$TMUXIFIER_LAYOUT_PATH/$1.window.sh" local file="$1"
if [ ! -f "$file" ]; then
file="$TMUXIFIER_LAYOUT_PATH/$1.window.sh"
fi
if [ -f "$file" ]; then if [ -f "$file" ]; then
window="$1" if [ $# -gt 1 ]; then
window="$2"
else
window="${1/%.window.sh/}"
window="${window/%.sh/}"
fi
source "$file" source "$file"
window= window=
@@ -125,28 +225,50 @@ load_window() {
window_root "$session_root" window_root "$session_root"
fi fi
else else
echo "No such window layout found '$1' in '$TMUXIFIER_LAYOUT_PATH'." echo "\"$1\" window layout not found." >&2
return 1
fi fi
} }
# Load specified session layout. # Load specified session layout.
# #
# Arguments: # Arguments:
# - $1: Name of session layout to load. # - $1: Name of or file path to session layout to load.
# - $2: (optional) Override default window name.
# #
load_session() { load_session() {
local file="$TMUXIFIER_LAYOUT_PATH/$1.session.sh" local file
if [ -f "$file" ]; then if [ "${1#*/}" = "$1" ]; then
session="$1" # There's no slash in the path.
source "$file" if [ -f "$TMUXIFIER_LAYOUT_PATH/$1.session.sh" ] || [ ! -f "$1" ]; then
session= file="$TMUXIFIER_LAYOUT_PATH/$1.session.sh"
else
# Reset `$session_root`. # bash's 'source' requires an slash in the filename to not use $PATH.
if [[ "$session_root" != "$HOME" ]]; then file="./$1"
session_root="$HOME"
fi fi
else else
echo "No such session layout found '$1' in '$TMUXIFIER_LAYOUT_PATH'." file="$1"
fi
if ! [ -f "$file" ]; then
echo "\"$1\" session layout not found." >&2
return 1
fi
if [ $# -gt 1 ]; then
session="$2"
else
session="${1/%.session.sh/}"
session="${session/%.sh/}"
fi
set_default_path=true
source "$file"
session=
# Reset `$session_root`.
if [[ "$session_root" != "$HOME" ]]; then
session_root="$HOME"
fi fi
} }
@@ -168,50 +290,66 @@ initialize_session() {
fi fi
# Ensure tmux server is running for has-session check. # Ensure tmux server is running for has-session check.
tmux start-server tmuxifier-tmux start-server
# Check if the named session already exists. # Check if the named session already exists.
if ! tmux has-session -t "$session:" 2>/dev/null; then if tmuxifier-tmux list-sessions | grep -q "^$session:"; then
return 1
fi
# Tmux 1.8 and earlier.
if [ "$(tmuxifier-tmux-version "1.9")" == "<" ]; then
# Create the new session. # Create the new session.
env TMUX="" tmux new-session -d -s "$session" TMUX="" tmuxifier-tmux new-session -d -s "$session"
# Set default-path for session # Set default-path for session
if [ -n "$session_root" ] && [ -d "$session_root" ]; then if [ -n "$session_root" ] && [ -d "$session_root" ]; then
cd "$session_root" cd "$session_root"
tmux set-option -t "$session:" default-path "$session_root" 1>/dev/null
$set_default_path && tmuxifier-tmux \
set-option -t "$session:" \
default-path "$session_root" 1> /dev/null
fi fi
# In order to ensure only specified windows are created, we move the # Tmux 1.9 and later.
# default window to position 999, and later remove it with the else
# `finalize_and_go_to_session` function. if $set_default_path; then
local first_window_index=$(__get_first_window_index) local session_args=(-c "$session_root")
tmux move-window -s "$session:$first_window_index" -t "$session:999" fi
# Session created, return ok exit status. TMUX="" tmuxifier-tmux new-session \
return 0 -d -s "$session" "${session_args[@]}"
fi fi
# Session already existed, return error exit status.
return 1 if $set_default_path && [[ "$session_root" != "$HOME" ]]; then
tmuxifier-tmux setenv -t "$session:" \
TMUXIFIER_SESSION_ROOT "$session_root"
fi
# In order to ensure only specified windows are created, we move the
# default window to position 999, and later remove it with the
# `finalize_and_go_to_session` function.
local first_window_index=$(__get_first_window_index)
tmuxifier-tmux move-window \
-s "$session:$first_window_index" -t "$session:999"
} }
# Finalize session creation and then switch to it if needed. # Finalize session creation and then switch to it if needed.
# #
# When the session is created, it leaves a unused window in position #99, this # When the session is created, it leaves a unused window in position #999,
# is the default window which was created with the session, but it's also a # this is the default window which was created with the session, but it's also
# window that was not explicitly created. Hence we kill it. # a window that was not explicitly created. Hence we kill it.
# #
# If the session was created, we've already been switched to it. If it was not # If the session was created, we've already been switched to it. If it was not
# created, the session already exists, and we'll need to specifically switch # created, but already existed, then we'll need to specifically switch to it.
# to it here.
# #
finalize_and_go_to_session() { finalize_and_go_to_session() {
! tmux kill-window -t "$session:999" 2>/dev/null ! tmuxifier-tmux kill-window -t "$session:999" 2> /dev/null
if [[ "$(tmuxifier-current-session)" != "$session" ]]; then if [[ "$(tmuxifier-current-session)" != "$session" ]]; then
__go_to_session __go_to_session
fi fi
} }
# #
# Internal functions # Internal functions
# #
@@ -224,12 +362,13 @@ finalize_and_go_to_session() {
# /Users/jimeh/Projects # /Users/jimeh/Projects
# #
__expand_path() { __expand_path() {
echo $(eval echo "$@") eval echo "$*"
} }
__get_first_window_index() { __get_first_window_index() {
local index local index=$(tmuxifier-tmux list-windows -t "$session:" \
index=$(tmux list-windows -t "$session:" -F "#{window_index}" 2>/dev/null) -F "#{window_index}" 2> /dev/null)
if [ -n "$index" ]; then if [ -n "$index" ]; then
echo "$index" | head -1 echo "$index" | head -1
else else
@@ -237,18 +376,38 @@ __get_first_window_index() {
fi fi
} }
__get_current_window_index() {
local lookup=$(tmuxifier-tmux list-windows -t "$session:" \
-F "#{window_active}:#{window_index}" 2> /dev/null | grep "^1:")
if [ -n "$lookup" ]; then
echo "${lookup/1:/}"
fi
}
__go_to_session() { __go_to_session() {
if [ -z "$TMUX" ]; then if [ -z "$TMUX" ]; then
tmux -u attach-session -t "$session:" tmuxifier-tmux $TMUXIFIER_TMUX_ITERM_ATTACH -u \
attach-session -t "$session:"
else else
tmux -u switch-client -t "$session:" tmuxifier-tmux -u switch-client -t "$session:"
fi fi
} }
__go_to_window_or_session_path() { __go_to_window_or_session_path() {
local window_or_session_root=${window_root-$session_root} local target_path
if [ -n "$window_or_session_root" ]; then
run_cmd "cd \"$window_or_session_root\"" if [ -n "$window_root" ]; then
send_keys "C-l" target_path="$window_root"
elif [ -n "$TMUXIFIER_SESSION_ROOT" ]; then
target_path="$TMUXIFIER_SESSION_ROOT"
elif [ -n "$session_root" ]; then
target_path="$session_root"
fi
# local window_or_session_root=${window_root-$session_root}
if [ -n "$target_path" ]; then
run_cmd " cd \"$target_path\""
run_cmd " clear"
fi fi
} }

79
lib/util.sh Normal file
View File

@@ -0,0 +1,79 @@
# Check if --help or -h flag is present in arguments.
#
# Usage:
# calling-help "$@" && { show_help; exit 0; }
#
# Arguments:
# $@ - Command-line arguments to check
#
# Returns:
# 0 - If --help or -h is present as a standalone argument
# 1 - Otherwise
calling-help() {
if [[ " $* " != *" --help "* ]] && [[ " $* " != *" -h "* ]]; then
return 1
fi
}
# Check if --complete flag is present in arguments.
#
# Used to detect when shell completion is requesting completions.
#
# Usage:
# calling-complete "$@" && { generate_completions; exit 0; }
#
# Arguments:
# $@ - Command-line arguments to check
#
# Returns:
# 0 - If --complete is present as a standalone argument
# 1 - Otherwise
calling-complete() {
if [[ " $* " != *" --complete "* ]]; then
return 1
fi
}
# Compare two dot-separated version strings.
#
# Based on: http://stackoverflow.com/a/4025065/42146
#
# Usage:
# vercomp "1.9.0" "1.10.0"
# case $? in
# 0) echo "equal" ;;
# 1) echo "first is greater" ;;
# 2) echo "second is greater" ;;
# esac
#
# Arguments:
# $1 - First version string (e.g., "1.2.3")
# $2 - Second version string (e.g., "1.2.4")
#
# Returns:
# 0 - Versions are equal
# 1 - First version is greater than second
# 2 - First version is less than second
vercomp() {
if [[ "$1" == "$2" ]]; then return 0; fi
local IFS=. i
local -a ver1 ver2
read -ra ver1 <<< "$1"
read -ra ver2 <<< "$2"
# Fill empty fields in ver1 with zeros
for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do ver1[i]=0; done
for ((i = 0; i < ${#ver1[@]}; i++)); do
# Fill empty fields in ver2 with zeros
if [[ -z ${ver2[i]} ]]; then ver2[i]=0; fi
if ((10#${ver1[i]} > 10#${ver2[i]})); then
return 1
elif ((10#${ver1[i]} < 10#${ver2[i]})); then
return 2
fi
done
return 0
}

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier alias <alias> echo "usage: tmuxifier alias <alias>
Resolve a command alias to it's full name." Resolve a command alias to it's full name."
@@ -11,33 +14,34 @@ Resolve a command alias to it's full name."
fi fi
case "$1" in case "$1" in
"session" | "ses" | "s" ) "session" | "ses" | "s")
echo "load-session" echo "load-session"
;; ;;
"window" | "win" | "w" ) "window" | "win" | "w")
echo "load-window" echo "load-window"
;; ;;
"new-ses" | "nses" | "ns" ) "new-ses" | "nses" | "ns")
echo "new-session" echo "new-session"
;; ;;
"new-win" | "nwin" | "nw" ) "new-win" | "nwin" | "nw")
echo "new-window" echo "new-window"
;; ;;
"edit-ses" | "eses" | "es" ) "edit-ses" | "eses" | "es")
echo "edit-session" echo "edit-session"
;; ;;
"edit-win" | "ewin" | "ew" ) "edit-win" | "ewin" | "ew")
echo "edit-window" echo "edit-window"
;; ;;
"l" ) "l")
echo "list" echo "list"
;; ;;
"list-ses" | "lses" | "ls" ) "list-ses" | "lses" | "ls")
echo "list-sessions" echo "list-sessions"
;; ;;
"list-win" | "lwin" | "lw" ) "list-win" | "lwin" | "lw")
echo "list-windows" echo "list-windows"
;; ;;
* ) *)
exit 1 exit 1
;;
esac esac

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier commands echo "usage: tmuxifier commands
List all available commands, includes internal commands not intended for List all available commands, includes internal commands not intended for
@@ -13,7 +16,8 @@ fi
shopt -s nullglob shopt -s nullglob
{ for path in ${PATH//:/$'\n'}; do {
for path in ${PATH//:/$'\n'}; do
for command in "${path}/tmuxifier-"*; do for command in "${path}/tmuxifier-"*; do
command="${command##*tmuxifier-}" command="${command##*tmuxifier-}"
echo "$command" echo "$command"

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier completion <command> echo "usage: tmuxifier completion <command>
Print a list of available completions for specified command." Print a list of available completions for specified command."
@@ -11,17 +14,17 @@ Print a list of available completions for specified command."
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
tmuxifier-commands tmuxifier-commands
exit exit
fi fi
has-completions() { has-completions() {
grep -i "^# Provide tmuxifier completions" "$1" >/dev/null grep -i "^# Provide tmuxifier completions" "$1" > /dev/null
} }
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help completions)" >&2 tmuxifier-help completions "$@" >&2
exit 1 exit 1
fi fi

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier current-session echo "usage: tmuxifier current-session
Outputs the name of the current Tmux session." Outputs the name of the current Tmux session."
@@ -11,8 +14,8 @@ Outputs the name of the current Tmux session."
fi fi
if [ -n "$TMUX" ]; then if [ -n "$TMUX" ]; then
for item in $(tmux list-pane -F "#{session_name}");do for item in $(tmuxifier-tmux list-pane -F "#{session_name}"); do
echo $item echo "$item"
exit 0 exit 0
done done
fi fi

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier edit-session <layout_name> echo "usage: tmuxifier edit-session <layout_name>
Aliases: edit-ses, eses, es Aliases: edit-ses, eses, es
@@ -13,15 +16,13 @@ Open specified session layout for editing in \$EDITOR."
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
for item in $(tmuxifier-list-sessions); do tmuxifier-list-sessions
echo "$item"
done
exit exit
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help edit-session)" >&2 tmuxifier-help edit-session "$@" >&2
exit 1 exit 1
fi fi
@@ -36,4 +37,10 @@ if [ ! -f "$layout_file" ]; then
exit 1 exit 1
fi fi
exec "$EDITOR" "$layout_file" if [ -n "$EDITOR" ]; then
exec $EDITOR "$layout_file"
else
echo "'\$EDITOR' is not set. Please manually open the layout for editing:"
echo "$layout_file"
echo
fi

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier edit-window <layout_name> echo "usage: tmuxifier edit-window <layout_name>
Aliases: edit-win, ewin, ew Aliases: edit-win, ewin, ew
@@ -13,15 +16,13 @@ Open specified window layout for editing in \$EDITOR."
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
for item in $(tmuxifier-list-windows); do tmuxifier-list-windows
echo "$item"
done
exit exit
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help edit-window)" >&2 tmuxifier-help edit-window "$@" >&2
exit 1 exit 1
fi fi
@@ -36,4 +37,10 @@ if [ ! -f "$layout_file" ]; then
exit 1 exit 1
fi fi
exec "$EDITOR" "$layout_file" if [ -n "$EDITOR" ]; then
exec $EDITOR "$layout_file"
else
echo "'\$EDITOR' is not set. Please manually open the layout for editing:"
echo "$layout_file"
echo
fi

View File

@@ -2,23 +2,25 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
tmuxifier-help tmuxifier-help
exit exit
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
tmuxifier-commands tmuxifier-commands
exit exit
fi fi
has-help() { has-help() {
grep -i "^# Provide tmuxifier help" "$1" >/dev/null grep -i "^# Provide tmuxifier help" "$1" > /dev/null
} }
command="$1"
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "usage: tmuxifier <command> [<args>] echo "usage: tmuxifier <command> [<args>]
@@ -33,7 +35,7 @@ Some useful tmuxifier commands are:
new-window nw Create new window layout and open it with \$EDITOR. new-window nw Create new window layout and open it with \$EDITOR.
edit-session es Edit specified session layout with \$EDITOR. edit-session es Edit specified session layout with \$EDITOR.
edit-window ew Edit specified window layout with \$EDITOR. edit-window ew Edit specified window layout with \$EDITOR.
commands List all tmuxifier commands. commands List all tmuxifier commands (including internal).
version Print Tmuxifier version. version Print Tmuxifier version.
help Show this message. help Show this message.
@@ -50,7 +52,7 @@ fi
if has-help "$command_path"; then if has-help "$command_path"; then
shift shift
exec "$command_path" --help "$@" exec "$command_path" "$@" --help
else else
command="$(basename "$command_path")" command="$(basename "$command_path")"
command="${command/tmuxifier\-/}" command="${command/tmuxifier\-/}"

90
libexec/tmuxifier-init Executable file
View File

@@ -0,0 +1,90 @@
#! /usr/bin/env bash
set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x
# Set shell to first argument that is not "-", "-h" or "--help".
for arg in "$@"; do
if [ "$arg" != "-" ] && [ "$arg" != "-h" ] && [ "$arg" != "--help" ]; then
shell="$arg"
fi
done
if [ -z "$shell" ]; then
shell="$(basename "$SHELL")"
fi
case "$shell" in
bash)
profile='~/.bash_profile'
;;
zsh)
profile='~/.zshrc'
;;
ksh)
profile='~/.profile'
;;
csh)
profile='~/.cshrc'
;;
tcsh)
profile='~/.tcshrc'
;;
fish)
profile='~/.config/fish/config.fish'
;;
*)
profile='shell init file'
;;
esac
# Provide tmuxifier help
if [[ " $@ " == *" --help "* ]]; then
echo "usage: tmuxifier init -
Load Tmuxifier by adding the following to your ${profile}:
"
case "$shell" in
csh | tcsh)
echo " eval \`tmuxifier init -\`
"
;;
fish)
echo " eval (tmuxifier init -)
"
;;
*)
echo " eval \"\$(tmuxifier init -)\"
"
;;
esac
echo "You might also need to add Tmuxifier's bin directory to your PATH."
exit
fi
# Print help if "-" argument is not given
if [[ " $* " != *" - "* ]]; then
tmuxifier-help init "$@" >&2
exit 1
fi
case "$shell" in
csh | tcsh)
echo "setenv TMUXIFIER \"$TMUXIFIER\";"
echo "source \"\$TMUXIFIER/init.tcsh\";"
;;
fish)
echo "set -gx TMUXIFIER \"$TMUXIFIER\";"
# fish shell 2.0.0 does not have the source alias
if [[ $(fish --version 2>&1 | awk -F'version ' '{print $2}') = '2.0.0' ]]; then
echo ". \"\$TMUXIFIER/init.fish\";"
else
echo "source \"\$TMUXIFIER/init.fish\";"
fi
;;
*)
echo "export TMUXIFIER=\"$TMUXIFIER\";"
echo "source \"\$TMUXIFIER/init.sh\";"
;;
esac

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier list echo "usage: tmuxifier list
Aliases: l Aliases: l

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier list-sessions echo "usage: tmuxifier list-sessions
Aliases: list-ses, lses, ls Aliases: list-ses, lses, ls
@@ -12,7 +15,7 @@ List all session layouts."
exit exit
fi fi
list=$(find -L "$TMUXIFIER_LAYOUT_PATH" -name "*.session.sh") list=$(find -L "$TMUXIFIER_LAYOUT_PATH" -name "*.session.sh" | sort)
for file in $list; do for file in $list; do
file=${file/$TMUXIFIER_LAYOUT_PATH\//} file=${file/$TMUXIFIER_LAYOUT_PATH\//}
echo "${file/.session.sh/}" echo "${file/.session.sh/}"

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier list-windows echo "usage: tmuxifier list-windows
Aliases: list-win, lwin, lw Aliases: list-win, lwin, lw
@@ -12,7 +15,7 @@ List all window layouts."
exit exit
fi fi
list=$(find -L "$TMUXIFIER_LAYOUT_PATH" -name "*.window.sh") list=$(find -L "$TMUXIFIER_LAYOUT_PATH" -name "*.window.sh" | sort)
for file in $list; do for file in $list; do
file=${file/$TMUXIFIER_LAYOUT_PATH\//} file=${file/$TMUXIFIER_LAYOUT_PATH\//}
echo "${file/.window.sh/}" echo "${file/.window.sh/}"

View File

@@ -2,32 +2,44 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier load-session <layout_name> echo "usage: tmuxifier load-session <layout_name | file_path> [<iterm mode>]
Aliases: session, ses, s Aliases: session, ses, s
Create a session using the session layout, unless the session already exists Create a session using the session layout, unless the session already exists
in which case, we simply attach/switch to the existing one." in which case, we simply attach/switch to the existing one.
Arguments:
<layout_name | file_path> - Name of a session layout stored in the layouts
directory, or path to a session layout file.
<iterm mode> - When given as \"-CC\" tmux will be called with
the -CC argument enabling iTerm2 integration.
More info: https://iterm2.com"
exit exit
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
for item in $(tmuxifier-list-sessions); do tmuxifier-list-sessions
echo "$item"
done
exit exit
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help load-session)" >&2 tmuxifier-help load-session "$@" >&2
exit 1 exit 1
fi fi
# Load runtime functions. # Load runtime functions.
source "$TMUXIFIER/lib/runtime.sh" source "$TMUXIFIER/lib/runtime.sh"
if [ "$2" == "-CC" ]; then
export TMUXIFIER_TMUX_ITERM_ATTACH="-CC"
fi
# Load session file. # Load session file.
load_session "$1" load_session "$1"

View File

@@ -2,33 +2,38 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier load-window <layout_name> echo "usage: tmuxifier load-window <layout_name | file_path>
Aliases: window, win, w Aliases: window, win, w
Create a new window using the specified window layout in the current session." Create a new window using the specified window layout in the current session.
Arguments:
<layout_name | file_path> - Name of a window layout stored in the layouts
directory, or path to a window layout file."
exit exit
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
for item in $(tmuxifier-list-windows); do tmuxifier-list-windows
echo "$item"
done
exit exit
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help load-window)" >&2 tmuxifier-help load-window "$@" >&2
exit 1 exit 1
fi fi
# Load runtime functions. # Load runtime functions.
source "$TMUXIFIER/lib/runtime.sh" source "$TMUXIFIER/lib/runtime.sh"
if [ ! -z $TMUX ]; then if [ ! -z "$TMUX" ]; then
session="$(tmuxifier-current-session)" session="$(tmuxifier-current-session)"
load_window "$1" load_window "$1"
else else

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier new-session <layout_name> echo "usage: tmuxifier new-session <layout_name>
Aliases: new-ses, nses, ns Aliases: new-ses, nses, ns
@@ -13,15 +16,13 @@ Create a new session layout and open it for editing in \$EDITOR."
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
for item in $(tmuxifier-list-sessions); do tmuxifier-list-sessions
echo "$item"
done
exit exit
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help new-session)" >&2 tmuxifier-help new-session "$@" >&2
exit 1 exit 1
fi fi
@@ -45,8 +46,8 @@ fi
content="$(cat "$template")" content="$(cat "$template")"
echo "${content//\{\{SESSION_NAME\}\}/$layout_name}" > "$layout_file" echo "${content//\{\{SESSION_NAME\}\}/$layout_name}" > "$layout_file"
if [ ! -z "$EDITOR" ]; then if [ -n "$EDITOR" ]; then
exec "$EDITOR" "$layout_file" exec $EDITOR "$layout_file"
else else
echo "Layout file has been created, but '\$EDITOR' is not set. Please " echo "Layout file has been created, but '\$EDITOR' is not set. Please "
echo "manually open the layout for editing:" echo "manually open the layout for editing:"

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier new-window <layout_name> echo "usage: tmuxifier new-window <layout_name>
Aliases: new-win, nwin, nw Aliases: new-win, nwin, nw
@@ -13,15 +16,13 @@ Create a new window layout and open it for editing in \$EDITOR."
fi fi
# Provide tmuxifier completions # Provide tmuxifier completions
if [ "$1" == "--complete" ]; then if calling-complete "$@"; then
for item in $(tmuxifier-list-windows); do tmuxifier-list-windows
echo "$item"
done
exit exit
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "$(tmuxifier-help new-window)" >&2 tmuxifier-help new-window "$@" >&2
exit 1 exit 1
fi fi
@@ -45,8 +46,8 @@ fi
content="$(cat "$template")" content="$(cat "$template")"
echo "${content//\{\{WINDOW_NAME\}\}/$layout_name}" > "$layout_file" echo "${content//\{\{WINDOW_NAME\}\}/$layout_name}" > "$layout_file"
if [ ! -z "$EDITOR" ]; then if [ -n "$EDITOR" ]; then
exec "$EDITOR" "$layout_file" exec $EDITOR "$layout_file"
else else
echo "Layout file has been created, but '\$EDITOR' is not set. Please " echo "Layout file has been created, but '\$EDITOR' is not set. Please "
echo "manually open the layout for editing:" echo "manually open the layout for editing:"

View File

@@ -2,8 +2,11 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier resolve-command-path <command_or_alias> echo "usage: tmuxifier resolve-command-path <command_or_alias>
Outputs the absolute path to the given command or command alias." Outputs the absolute path to the given command or command alias."

5
libexec/tmuxifier-tmux Executable file
View File

@@ -0,0 +1,5 @@
#! /usr/bin/env bash
set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x
tmux $TMUXIFIER_TMUX_OPTS "$@"

46
libexec/tmuxifier-tmux-version Executable file
View File

@@ -0,0 +1,46 @@
#! /usr/bin/env bash
shopt -s extglob
[ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help
if calling-help "$@"; then
echo "usage: tmuxifier tmux-version [<target-version>]
Outputs current Tmux version. If given optional target-version it outputs one
of three possible characters indicating if the current Tmux version number is
equal to, less than, or greater than the <target-version>.
The three possible outputs are \"=\", \"<\", and \">\"."
exit
fi
version=$(tmux -V)
version=${version/tmux /}
# Fix for tmux next-* versions
version=${version/next-/}
if [ -z "$1" ]; then
echo "$version"
exit
fi
if [ "$version" == "master" ]; then
# When version string is "master", tmux was compiled from source, and we
# assume it's later than whatever the <target-version> is.
echo '>'
else
# Fix for "1.9a" version comparison, as vercomp() can only deal with
# purely numeric version numbers.
version=${version//+([a-zA-Z])/}
vercomp "$version" "$1"
case $? in
0) echo '=' ;;
1) echo '>' ;;
2) echo '<' ;;
esac
fi

View File

@@ -2,12 +2,15 @@
set -e set -e
[ -n "$TMUXIFIER_DEBUG" ] && set -x [ -n "$TMUXIFIER_DEBUG" ] && set -x
# Load internal utility functions.
source "$TMUXIFIER/lib/util.sh"
# Provide tmuxifier help # Provide tmuxifier help
if [ "$1" == "--help" ]; then if calling-help "$@"; then
echo "usage: tmuxifier version echo "usage: tmuxifier version
Outputs Tmuxifier version." Outputs Tmuxifier version."
exit exit
fi fi
echo "0.6.0" echo "0.13.0"

View File

@@ -16,7 +16,7 @@ new_window "{{WINDOW_NAME}}"
# Paste text # Paste text
#send_keys "top" # paste into active pane #send_keys "top" # paste into active pane
#send_keys "date" 1 # paste into active pane #send_keys "date" 1 # paste into pane 1
# Set active pane. # Set active pane.
#select_pane 0 #select_pane 0

33
test-legacy/lib/env.test.sh Executable file
View File

@@ -0,0 +1,33 @@
#! /usr/bin/env bash
source "../test-helper.sh"
#
# env.sh tests.
#
# Setup.
realTMUXIFIER="$TMUXIFIER"
TMUXIFER="/path/to/tmuxifier"
# When TMUXIFIER_LAYOUT_PATH is not set.
source "${root}/lib/env.sh"
assert 'echo $TMUXIFIER_LAYOUT_PATH' "${TMUXIFIER}/layouts"
# When TMUXIFIER_LAYOUT_PATH is set and has a trailing slash.
TMUXIFIER_LAYOUT_PATH="/path/to/layouts/"
source "${root}/lib/env.sh"
assert 'echo $TMUXIFIER_LAYOUT_PATH' "/path/to/layouts"
unset TMUXIFIER_LAYOUT_PATH
# When TMUXIFIER_LAYOUT_PATH is set and does not have a trailing slash.
TMUXIFIER_LAYOUT_PATH="/path/to/layouts"
source "${root}/lib/env.sh"
assert 'echo $TMUXIFIER_LAYOUT_PATH' "/path/to/layouts"
unset TMUXIFIER_LAYOUT_PATH
# Tear down.
TMUXIFER="$realTMUXIFIER"
unset realTMUXIFIER
# End of tests.
assert_end "env.sh"

View File

@@ -0,0 +1,27 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# __expand_path() tests.
#
# Setup.
realHOME="$HOME"
HOME="/home/test-user"
# When given a path containing "~", it expands "~" to "$HOME".
assert '__expand_path "~/Foo/Bar"' "${HOME}/Foo/Bar"
# When given a path without "~", it returns path as is.
assert '__expand_path "/path/to/file"' "/path/to/file"
# When given a path containing spaces, it returns path correctly.
assert '__expand_path "~/Path To/File"' "${HOME}/Path To/File"
# Tear down.
HOME="$realHOME"
unset realHOME
# End of tests.
assert_end "__expand_path()"

View File

@@ -0,0 +1,48 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# __get_current_window_index() tests.
#
# When current window is the first and only window.
create-test-session
assert "__get_current_window_index" "0"
kill-test-session
# When creating a second window.
create-test-session
test-socket-tmux new-window -t "$session:1"
assert "__get_current_window_index" "1"
kill-test-session
# When creating a second window and then switching back to the first window.
create-test-session
test-socket-tmux new-window -t "$session:1"
test-socket-tmux select-window -t "$session:0"
assert "__get_current_window_index" "0"
kill-test-session
# When creating multiples windows and switching between them randomly.
create-test-session
assert "__get_current_window_index" "0"
test-socket-tmux new-window -t "$session:1"
assert "__get_current_window_index" "1"
test-socket-tmux new-window -t "$session:2"
assert "__get_current_window_index" "2"
test-socket-tmux new-window -t "$session:3"
assert "__get_current_window_index" "3"
test-socket-tmux select-window -t "$session:1"
assert "__get_current_window_index" "1"
test-socket-tmux select-window -t "$session:0"
assert "__get_current_window_index" "0"
test-socket-tmux select-window -t "$session:3"
assert "__get_current_window_index" "3"
test-socket-tmux select-window -t "$session:2"
assert "__get_current_window_index" "2"
kill-test-session
# End of tests.
assert_end "__get_current_window_index()"

View File

@@ -0,0 +1,30 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# __get_first_window_index() tests.
#
# When first window has a index of 0.
create-test-session
assert "__get_first_window_index" "0"
kill-test-session
# When first window has a index of 1.
create-test-session
test-socket-tmux new-window -t "$session:1"
test-socket-tmux kill-window -t "$session:0"
assert "__get_first_window_index" "1"
kill-test-session
# When first window has a index of 2.
create-test-session
test-socket-tmux new-window -t "$session:2"
test-socket-tmux kill-window -t "$session:0"
assert "__get_first_window_index" "2"
kill-test-session
# End of tests.
assert_end "__get_first_window_index()"

View File

@@ -0,0 +1,42 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# __go_to_session() tests.
#
# Setup.
session="tmuxifier-test-session"
# When TMUX is not set, attach to $session.
stub tmuxifier-tmux
__go_to_session
assert_raises \
"stub_called_with tmuxifier-tmux -u attach-session -t \"${session}:\"" 0
restore tmuxifier-tmux
# When TMUXIFIER_TMUX_ITERM_ATTACH is set, pass it in as first argument(s) to
# tmuxifier-tmux
TMUXIFIER_TMUX_ITERM_ATTACH="-CC"
stub tmuxifier-tmux
__go_to_session
assert_raises \
"stub_called_with tmuxifier-tmux -CC -u attach-session -t \"${session}:\"" 0
restore tmuxifier-tmux
unset TMUXIFIER_TMUX_ITERM_ATTACH
# When TMUX is set, switch to $session.
TMUX="/tmp/tmux-501/default,1203,0"
stub tmuxifier-tmux
__go_to_session
assert_raises \
"stub_called_with tmuxifier-tmux -u switch-client -t \"${session}:\"" 0
restore tmuxifier-tmux
unset TMUX
# Tear down.
unset session
# End of tests.
assert_end "__go_to_session()"

View File

@@ -0,0 +1,88 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# __go_to_window_or_session_path() tests.
#
# When neither $window_root or $session_root are set, does nothing.
stub run_cmd
__go_to_window_or_session_path
assert "stub_called_times run_cmd" "0"
restore run_cmd
# When only $window_root is set, runs cd to $window_root path.
stub run_cmd
window_root="/tmp"
__go_to_window_or_session_path
assert 'stub_called_with_times run_cmd cd \"/tmp\"' "1"
assert 'stub_called_with_times run_cmd clear' "1"
unset window_root
restore run_cmd
# When only $TMUXIFIER_SESSION_ROOT is set, runs cd to $TMUXIFIER_SESSION_ROOT
# path.
stub run_cmd
TMUXIFIER_SESSION_ROOT="/opt"
__go_to_window_or_session_path
assert 'stub_called_with_times run_cmd cd \"/opt\"' "1"
assert 'stub_called_with_times run_cmd clear' "1"
unset TMUXIFIER_SESSION_ROOT
restore run_cmd
# When only $session_root is set, runs cd to $session_root path.
stub run_cmd
session_root="/usr"
__go_to_window_or_session_path
assert 'stub_called_with_times run_cmd cd \"/usr\"' "1"
assert 'stub_called_with_times run_cmd clear' "1"
unset session_root
restore run_cmd
# When $window_root and $session_root are set, runs cd to $window_root path.
stub run_cmd
window_root="/tmp"
session_root="/usr"
__go_to_window_or_session_path
assert 'stub_called_with_times run_cmd cd \"/tmp\"' "1"
assert 'stub_called_with_times run_cmd clear' "1"
unset window_root
unset session_root
restore run_cmd
# When $TMUXIFIER_SESSION_ROOT and $session_root are set, runs cd to
# $TMUXIFIER_SESSION_ROOT path.
stub run_cmd
TMUXIFIER_SESSION_ROOT="/opt"
session_root="/usr"
__go_to_window_or_session_path
assert 'stub_called_with_times run_cmd cd \"/opt\"' "1"
assert 'stub_called_with_times run_cmd clear' "1"
unset TMUXIFIER_SESSION_ROOT
unset session_root
restore run_cmd
# When $window_root, $TMUXIFIER_SESSION_ROOT, and $session_root are set, runs
# cd to $window_root path.
stub run_cmd
window_root="/tmp"
TMUXIFIER_SESSION_ROOT="/opt"
session_root="/usr"
__go_to_window_or_session_path
assert 'stub_called_with_times run_cmd cd \"/tmp\"' "1"
assert 'stub_called_with_times run_cmd clear' "1"
unset window_root
unset TMUXIFIER_SESSION_ROOT
unset session_root
restore run_cmd
# End of tests.
assert_end "__go_to_window_or_session_path()"

View File

@@ -0,0 +1,59 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# new_window() tests.
#
# When called without arguments, creates new window.
create-test-session
stub __go_to_window_or_session_path
assert "test-socket-window-count" "1"
new_window
assert "test-socket-window-count" "2"
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
kill-test-session
# When called with name argument, creates new window with specified name.
create-test-session
stub __go_to_window_or_session_path
assert "test-socket-window-count yippieezzz" "0"
new_window "yippieezzz"
assert "test-socket-window-count" "2"
assert "test-socket-window-count yippieezzz" "1"
restore __go_to_window_or_session_path
kill-test-session
# When called with name and command argument, creates new window with
# specified name and executes given command.
rm "/tmp/tmuxifier-new_window-test" &> /dev/null
create-test-session
stub __go_to_window_or_session_path
new_window "foobardoo" "touch /tmp/tmuxifier-new_window-test; bash"
assert "test-socket-window-count" "2"
assert "test-socket-window-count foobardoo" "1"
sleep 0.1 # attempt to avoid timing issue causing flicker
assert_raises 'test -f "/tmp/tmuxifier-new_window-test"' 0
restore __go_to_window_or_session_path
kill-test-session
rm "/tmp/tmuxifier-new_window-test" &> /dev/null
# When called ensure it sets the $window variable to the index of the newly
# created window.
unset window
create-test-session
stub __go_to_window_or_session_path
new_window "foo"
assert "echo $window" "1"
new_window
assert "echo $window" "2"
new_window "bar"
assert "echo $window" "3"
restore __go_to_window_or_session_path
kill-test-session
unset window
# End of tests.
assert_end "new_window()"

View File

@@ -0,0 +1,55 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# select_window() tests.
#
window_list() {
test-socket-tmux list-windows -t "$session:" \
-F "#{window_active}:#{window_index}" 2>/dev/null
}
# Selects given window when passed a window index
create-test-session
test-socket-tmux new-window -t "$session:1"
test-socket-tmux new-window -t "$session:2"
select_window 0
assert "window_list | grep '^1:'" "1:0"
select_window 1
assert "window_list | grep '^1:'" "1:1"
select_window 2
assert "window_list | grep '^1:'" "1:2"
kill-test-session
# Selects given window when passed a window name
create-test-session
test-socket-tmux new-window -t "$session:1" -n "foo"
test-socket-tmux new-window -t "$session:2" -n "bar"
select_window foo
assert "window_list | grep '^1:'" "1:1"
select_window bar
assert "window_list | grep '^1:'" "1:2"
kill-test-session
# When called ensure it sets the $window variable to the index of the newly
# created window.
unset window
create-test-session
test-socket-tmux new-window -t "$session:1" -n "foo"
test-socket-tmux new-window -t "$session:2" -n "bar"
select_window "foo"
assert "echo $window" "1"
select_window "bar"
assert "echo $window" "2"
select_window 1
assert "echo $window" "1"
select_window 2
assert "echo $window" "2"
kill-test-session
unset window
# End of tests.
assert_end "select_window()"

View File

@@ -0,0 +1,70 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# split_h() tests.
#
# When called without arguments, calls tmuxifier-tmux split-window with -h flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_h
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -h" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with percentage argument, includes -p flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_h 30
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -h -p 30" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with percentage and target pane, targets that pane.
session="mysession"
window="2"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_h 50 1
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t mysession:2.1 -h -p 50" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with only target pane (empty percentage), targets that pane.
session="test"
window="1"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_h "" 2
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test:1.2 -h" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# Integration: actually splits pane in tmux session.
create-test-session
window="0"
stub __go_to_window_or_session_path
assert "test-socket-pane-count" "1"
split_h
assert "test-socket-pane-count" "2"
split_h 30
assert "test-socket-pane-count" "3"
restore __go_to_window_or_session_path
kill-test-session
# End of tests.
assert_end "split_h()"

View File

@@ -0,0 +1,70 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# split_hl() tests.
#
# When called without arguments, calls tmuxifier-tmux split-window with -h flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_hl
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -h" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with column count argument, includes -l flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_hl 20
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -h -l 20" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with column count and target pane, targets that pane.
session="mysession"
window="2"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_hl 25 1
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t mysession:2.1 -h -l 25" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with only target pane (empty column count), targets that pane.
session="test"
window="1"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_hl "" 2
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test:1.2 -h" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# Integration: actually splits pane in tmux session.
create-test-session
window="0"
stub __go_to_window_or_session_path
assert "test-socket-pane-count" "1"
split_hl
assert "test-socket-pane-count" "2"
split_hl 10
assert "test-socket-pane-count" "3"
restore __go_to_window_or_session_path
kill-test-session
# End of tests.
assert_end "split_hl()"

View File

@@ -0,0 +1,70 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# split_v() tests.
#
# When called without arguments, calls tmuxifier-tmux split-window with -v flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_v
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -v" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with percentage argument, includes -p flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_v 30
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -v -p 30" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with percentage and target pane, targets that pane.
session="mysession"
window="2"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_v 50 1
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t mysession:2.1 -v -p 50" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with only target pane (empty percentage), targets that pane.
session="test"
window="1"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_v "" 2
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test:1.2 -v" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# Integration: actually splits pane in tmux session.
create-test-session
window="0"
stub __go_to_window_or_session_path
assert "test-socket-pane-count" "1"
split_v
assert "test-socket-pane-count" "2"
split_v 30
assert "test-socket-pane-count" "3"
restore __go_to_window_or_session_path
kill-test-session
# End of tests.
assert_end "split_v()"

View File

@@ -0,0 +1,70 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# split_vl() tests.
#
# When called without arguments, calls tmuxifier-tmux split-window with -v flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_vl
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -v" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with line count argument, includes -l flag.
session="test-session"
window="0"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_vl 10
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test-session:0. -v -l 10" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with line count and target pane, targets that pane.
session="mysession"
window="2"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_vl 15 1
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t mysession:2.1 -v -l 15" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# When called with only target pane (empty line count), targets that pane.
session="test"
window="1"
stub tmuxifier-tmux
stub __go_to_window_or_session_path
split_vl "" 2
assert_raises \
"stub_called_with tmuxifier-tmux split-window -t test:1.2 -v" 0
assert "stub_called_times __go_to_window_or_session_path" "1"
restore __go_to_window_or_session_path
restore tmuxifier-tmux
# Integration: actually splits pane in tmux session.
create-test-session
window="0"
stub __go_to_window_or_session_path
assert "test-socket-pane-count" "1"
split_vl
assert "test-socket-pane-count" "2"
split_vl 5
assert "test-socket-pane-count" "3"
restore __go_to_window_or_session_path
kill-test-session
# End of tests.
assert_end "split_vl()"

View File

@@ -0,0 +1,20 @@
#! /usr/bin/env bash
source "../../test-helper.sh"
source "${root}/lib/layout-helpers.sh"
#
# tmux() tests.
#
# Passes all arguments to tmuxifier-tmux.
stub tmuxifier-tmux
tmux -V
tmux --help
tmux new -s dude
assert_raises "stub_called_with tmuxifier-tmux -V" 0
assert_raises "stub_called_with tmuxifier-tmux --help" 0
assert_raises "stub_called_with tmuxifier-tmux new -s dude" 0
restore tmuxifier-tmux
# End of tests.
assert_end "tmux()"

23
test-legacy/lib/runtime.test.sh Executable file
View File

@@ -0,0 +1,23 @@
#! /usr/bin/env bash
source "../test-helper.sh"
#
# runtime.sh tests.
#
source "${root}/lib/runtime.sh"
# We assume env.sh has been sourced if $TMUXIFIER_LAYOUT_PATH has been set.
assert 'echo $TMUXIFIER_LAYOUT_PATH' "${TMUXIFIER}/layouts"
# We ensure $session_root is set to $HOME by default.
assert 'echo $session_root' "$HOME"
# We assume layout-helpers.sh has been sourced if a few of them are available.
for helper in new_window split_v split_h select_window select_pane; do
assert "type $helper | head -1" "$helper is a function"
done
# End of tests.
assert_end "runtime.sh"

58
test-legacy/lib/util.test.sh Executable file
View File

@@ -0,0 +1,58 @@
#! /usr/bin/env bash
source "../test-helper.sh"
source "${root}/lib/util.sh"
#
# calling-help() tests.
#
# Returns 0 when "--help" is part of passed arguments.
assert_raises 'calling-help --help' 0
assert_raises 'calling-help foo --help' 0
assert_raises 'calling-help --help bar' 0
assert_raises 'calling-help foo --help bar' 0
# Returns 0 when "-h" is part of passed arguments.
assert_raises 'calling-help -h' 0
assert_raises 'calling-help foo -h' 0
assert_raises 'calling-help -h bar' 0
assert_raises 'calling-help foo -h bar' 0
# Returns 1 when neither "--help" or "-h" is not part of passed arguments.
assert_raises 'calling-help' 1
assert_raises 'calling-help foo' 1
assert_raises 'calling-help foo bar' 1
# Returns 1 when "--help" is part of passed arguments, but not free-standing.
assert_raises 'calling-help --help-me' 1
assert_raises 'calling-help foo--help' 1
# Returns 1 when "-h" is part of passed arguments, but not free-standing.
assert_raises 'calling-help -hj' 1
assert_raises 'calling-help welcome-home' 1
# End of tests.
assert_end "calling-help()"
#
# calling-complete() tests.
#
# Returns 0 when "--complete" is part of passed arguments.
assert_raises 'calling-complete --complete' 0
assert_raises 'calling-complete foo --complete' 0
assert_raises 'calling-complete --complete bar' 0
assert_raises 'calling-complete foo --complete bar' 0
# Returns 1 when "--complete" is not part of passed arguments.
assert_raises 'calling-complete' 1
assert_raises 'calling-complete foo' 1
assert_raises 'calling-complete foo bar' 1
# Returns 1 when "--complete" is part of passed arguments, but not free-standing.
assert_raises 'calling-complete --complete-me' 1
assert_raises 'calling-complete foo--complete' 1
# End of tests.
assert_end "calling-complete()"

View File

@@ -0,0 +1,22 @@
#! /usr/bin/env bash
source "../test-helper.sh"
source "${root}/lib/util.sh"
#
# tmuxifier-tmux tests.
#
# Setup.
test-socket-tmux new-session -d -s foobar
test-socket-tmux new-session -d -s dude
baseCommand="${root}/bin/tmuxifier tmux"
# Passes all arguments to Tmux.
assert "${baseCommand} list-sessions -F \"- #{session_name}\"" \
"- dude\n- foobar"
# Tear down.
kill-test-server
# End of tests.
assert_end "tmuxifier-tmux"

View File

@@ -0,0 +1,91 @@
[ -n "$TEST_DEBUG" ] && set -x
resolve_link() {
$(type -p greadlink readlink | head -1) $1
}
abs_dirname() {
local cwd="$(pwd)"
local path="$1"
while [ -n "$path" ]; do
cd "${path%/*}"
local name="${path##*/}"
path="$(resolve_link "$name" || true)"
done
pwd
cd "$cwd"
}
# Find and store path to Tmux binary.
TMUX_BIN="$(command -v tmux)"
# Set testroot variable.
testroot="$(abs_dirname "$BASH_SOURCE")"
# Set root variable.
root="$(abs_dirname "$testroot/../..")"
# Set TMUXIFIER environment variable.
TMUXIFIER="$root"
# Setup PATH environment variable.
PATH="$root/bin:$root/libexec:$PATH"
# Unset TMUX environment variable, tests assume they're not running within
# Tmux.
unset TMUX
# Unset various Tmuxifier environment variables to prevent a local install of
# Tmuxifier interfering with tests.
unset TMUXIFIER_LAYOUT_PATH
unset TMUXIFIER_TMUX_OPTS
unset TMUXIFIER_NO_COMPLETE
# Include assert.sh and stub.sh libraries.
source "${testroot}/assert.sh"
source "${testroot}/stub.sh"
#
# Test Helpers
#
test-socket-tmux() {
export TMUXIFIER_TMUX_OPTS="-L tmuxifier-tests"
"$TMUX_BIN" $TMUXIFIER_TMUX_OPTS "$@"
}
create-test-session() {
session="$1"
if [ -z "$session" ]; then session="test"; fi
test-socket-tmux new-session -d -s "$session"
}
kill-test-session() {
local target="$1"
if [ -z "$target" ]; then target="$session"; fi
test-socket-tmux kill-session -t "$target"
}
kill-test-server() {
test-socket-tmux kill-server
unset TMUXIFIER_TMUX_OPTS
unset session
}
test-socket-window-count() {
local list="$(test-socket-tmux list-windows)"
if [ -n "$1" ]; then
echo "$list" | grep $1 | wc -l | awk '{print $1}'
else
echo "$list" | wc -l | awk '{print $1}'
fi
}
test-socket-pane-count() {
local list="$(test-socket-tmux list-panes -t "$session:")"
echo "$list" | wc -l | awk '{print $1}'
}

4501
tests/bashunit Executable file

File diff suppressed because it is too large Load Diff

13
tests/bootstrap.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
# Place your common test setup here
# Resolve the project root directory
_test_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
_root_dir="$(cd "${_test_dir}/.." && pwd)"
# Set TMUXIFIER so libexec commands can find lib/util.sh
export TMUXIFIER="${_root_dir}"
# Add libexec to PATH so tmuxifier commands are available
export PATH="${_root_dir}/libexec:${PATH}"

View File

@@ -0,0 +1,209 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# __get_current_window_index() tests
#
function set_up() {
# Reset session variable to known state
session=""
}
function tear_down() {
unset session
}
#
# Basic functionality
#
function test_get_current_window_index_returns_active_window_index() {
session="test-session"
mock tmuxifier-tmux << EOF
1:0
0:1
0:2
EOF
local result
result=$(__get_current_window_index)
assert_same "0" "$result"
}
function test_get_current_window_index_returns_index_when_second_window_active() {
session="test-session"
mock tmuxifier-tmux << EOF
0:0
1:1
0:2
EOF
local result
result=$(__get_current_window_index)
assert_same "1" "$result"
}
function test_get_current_window_index_returns_index_when_last_window_active() {
session="test-session"
mock tmuxifier-tmux << EOF
0:0
0:1
1:2
EOF
local result
result=$(__get_current_window_index)
assert_same "2" "$result"
}
#
# Non-standard window indices
#
function test_get_current_window_index_handles_non_zero_base_index() {
session="test-session"
# When base-index is 1
mock tmuxifier-tmux << EOF
1:1
0:2
0:3
EOF
local result
result=$(__get_current_window_index)
assert_same "1" "$result"
}
function test_get_current_window_index_handles_high_window_index() {
session="test-session"
mock tmuxifier-tmux << EOF
0:0
0:1
1:999
EOF
local result
result=$(__get_current_window_index)
assert_same "999" "$result"
}
function test_get_current_window_index_handles_gaps_in_window_indices() {
session="test-session"
# Windows 0, 5, 10 with window 5 being active
mock tmuxifier-tmux << EOF
0:0
1:5
0:10
EOF
local result
result=$(__get_current_window_index)
assert_same "5" "$result"
}
#
# Single window
#
function test_get_current_window_index_returns_index_for_single_window() {
session="test-session"
mock tmuxifier-tmux echo "1:0"
local result
result=$(__get_current_window_index)
assert_same "0" "$result"
}
function test_get_current_window_index_returns_index_for_single_window_non_zero() {
session="test-session"
mock tmuxifier-tmux echo "1:5"
local result
result=$(__get_current_window_index)
assert_same "5" "$result"
}
#
# Edge cases and error handling
#
function test_get_current_window_index_returns_empty_when_no_active_window() {
session="test-session"
# No window marked as active (shouldn't happen in practice)
mock tmuxifier-tmux << EOF
0:0
0:1
0:2
EOF
local result
result=$(__get_current_window_index)
assert_empty "$result"
}
function test_get_current_window_index_returns_empty_when_no_windows() {
session="test-session"
mock tmuxifier-tmux echo ""
local result
result=$(__get_current_window_index)
assert_empty "$result"
}
function test_get_current_window_index_returns_empty_on_tmux_error() {
session="test-session"
# Simulate tmux error (stderr is redirected to /dev/null in the function)
mock tmuxifier-tmux return 1
local result
result=$(__get_current_window_index)
assert_empty "$result"
}
#
# Tmux command verification
#
function test_get_current_window_index_calls_tmux_with_correct_args() {
session="my-session"
spy tmuxifier-tmux
__get_current_window_index
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t my-session: -F #{window_active}:#{window_index}"
}
function test_get_current_window_index_uses_session_variable() {
session="another-session"
spy tmuxifier-tmux
__get_current_window_index
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t another-session: -F #{window_active}:#{window_index}"
}
function test_get_current_window_index_handles_special_session_names() {
session="my-project_v2"
spy tmuxifier-tmux
__get_current_window_index
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t my-project_v2: -F #{window_active}:#{window_index}"
}

View File

@@ -0,0 +1,146 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# __get_first_window_index() tests
#
function set_up() {
# Reset session variable to known state
session=""
}
function tear_down() {
unset session
}
#
# Return value behavior
#
function test_get_first_window_index_returns_first_index_from_list() {
session="test-session"
mock tmuxifier-tmux echo "0"
local result
result=$(__get_first_window_index)
assert_same "0" "$result"
}
function test_get_first_window_index_returns_first_of_multiple_indices() {
session="test-session"
mock tmuxifier-tmux echo $'1\n2\n3'
local result
result=$(__get_first_window_index)
assert_same "1" "$result"
}
function test_get_first_window_index_returns_0_when_list_empty() {
session="test-session"
mock tmuxifier-tmux echo ""
local result
result=$(__get_first_window_index)
assert_same "0" "$result"
}
function test_get_first_window_index_returns_0_when_command_fails() {
session="test-session"
# Simulate tmux command failure by returning nothing
mock tmuxifier-tmux true
local result
result=$(__get_first_window_index)
assert_same "0" "$result"
}
#
# Non-zero first window index
#
function test_get_first_window_index_handles_nonzero_first_index() {
session="test-session"
mock tmuxifier-tmux echo "5"
local result
result=$(__get_first_window_index)
assert_same "5" "$result"
}
function test_get_first_window_index_returns_first_even_when_not_sequential() {
session="test-session"
# Simulate windows at indices 3, 7, 12
mock tmuxifier-tmux echo $'3\n7\n12'
local result
result=$(__get_first_window_index)
assert_same "3" "$result"
}
#
# Session target format
#
function test_get_first_window_index_uses_session_variable() {
session="my-project"
spy tmuxifier-tmux
__get_first_window_index > /dev/null
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t my-project: -F #{window_index}"
}
function test_get_first_window_index_includes_trailing_colon_in_target() {
session="test"
spy tmuxifier-tmux
__get_first_window_index > /dev/null
# Verify the -t argument includes trailing colon
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t test: -F #{window_index}"
}
#
# Edge cases
#
function test_get_first_window_index_handles_session_with_special_chars() {
session="my-project_v2"
spy tmuxifier-tmux
__get_first_window_index > /dev/null
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t my-project_v2: -F #{window_index}"
}
function test_get_first_window_index_handles_high_window_index() {
session="test-session"
mock tmuxifier-tmux echo "999"
local result
result=$(__get_first_window_index)
assert_same "999" "$result"
}
function test_get_first_window_index_handles_empty_session_name() {
session=""
spy tmuxifier-tmux
__get_first_window_index > /dev/null
assert_have_been_called_with tmuxifier-tmux \
"list-windows -t : -F #{window_index}"
}

View File

@@ -0,0 +1,197 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# __go_to_window_or_session_path() tests
#
function set_up() {
# Reset all path-related variables before each test
window_root=""
session_root=""
TMUXIFIER_SESSION_ROOT=""
# Default session and window for run_cmd context
session="test-session"
window="0"
}
function tear_down() {
unset window_root session_root TMUXIFIER_SESSION_ROOT
unset session window
}
#
# No path set
#
function test_does_nothing_when_no_paths_set() {
spy run_cmd
__go_to_window_or_session_path
assert_not_called run_cmd
}
function test_does_nothing_with_empty_string_paths() {
window_root=""
session_root=""
TMUXIFIER_SESSION_ROOT=""
spy run_cmd
__go_to_window_or_session_path
assert_not_called run_cmd
}
#
# Single path set
#
function test_uses_session_root_when_only_session_root_is_set() {
session_root="/path/to/session"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_times 2 run_cmd
assert_have_been_called_with run_cmd ' cd "/path/to/session"' 1
assert_have_been_called_with run_cmd ' clear' 2
}
function test_uses_tmuxifier_session_root_when_only_env_var_is_set() {
TMUXIFIER_SESSION_ROOT="/path/from/env"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_times 2 run_cmd
assert_have_been_called_with run_cmd ' cd "/path/from/env"' 1
assert_have_been_called_with run_cmd ' clear' 2
}
function test_uses_window_root_when_only_window_root_is_set() {
window_root="/path/to/window"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_times 2 run_cmd
assert_have_been_called_with run_cmd ' cd "/path/to/window"' 1
assert_have_been_called_with run_cmd ' clear' 2
}
#
# Priority: window_root > TMUXIFIER_SESSION_ROOT > session_root
#
function test_window_root_takes_priority_over_session_root() {
window_root="/window/path"
session_root="/session/path"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_with run_cmd ' cd "/window/path"' 1
}
function test_tmuxifier_session_root_takes_priority_over_session_root() {
TMUXIFIER_SESSION_ROOT="/env/path"
session_root="/session/path"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_with run_cmd ' cd "/env/path"' 1
}
function test_window_root_takes_priority_over_tmuxifier_session_root() {
window_root="/window/path"
TMUXIFIER_SESSION_ROOT="/env/path"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_with run_cmd ' cd "/window/path"' 1
}
function test_window_root_takes_priority_over_all_other_paths() {
window_root="/window/path"
TMUXIFIER_SESSION_ROOT="/env/path"
session_root="/session/path"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_with run_cmd ' cd "/window/path"' 1
}
#
# Command format
#
function test_cd_command_has_leading_space_for_history_suppression() {
session_root="/some/path"
spy run_cmd
__go_to_window_or_session_path
# Leading space prevents command from being saved in shell history
assert_have_been_called_with run_cmd ' cd "/some/path"' 1
}
function test_clear_command_has_leading_space_for_history_suppression() {
session_root="/some/path"
spy run_cmd
__go_to_window_or_session_path
# Leading space prevents command from being saved in shell history
assert_have_been_called_with run_cmd ' clear' 2
}
function test_path_is_quoted_in_cd_command() {
session_root="/path/with spaces/in it"
spy run_cmd
__go_to_window_or_session_path
# Path should be quoted to handle spaces
assert_have_been_called_with run_cmd ' cd "/path/with spaces/in it"' 1
}
#
# Edge cases
#
function test_handles_path_with_special_characters() {
session_root="/path/with\$pecial-chars_123"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_with run_cmd ' cd "/path/with$pecial-chars_123"' 1
}
function test_handles_home_directory_path() {
session_root="$HOME"
spy run_cmd
__go_to_window_or_session_path
assert_have_been_called_with run_cmd " cd \"$HOME\"" 1
}
function test_always_calls_clear_after_cd() {
window_root="/any/path"
spy run_cmd
__go_to_window_or_session_path
# Verify order: cd first, then clear
assert_have_been_called_times 2 run_cmd
assert_have_been_called_with run_cmd ' cd "/any/path"' 1
assert_have_been_called_with run_cmd ' clear' 2
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# balance_windows_horizontal() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_balance_windows_horizontal_uses_current_window_by_default() {
spy tmuxifier-tmux
balance_windows_horizontal
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t test-session:0 even-horizontal"
}
function test_balance_windows_horizontal_with_specific_window() {
spy tmuxifier-tmux
balance_windows_horizontal 2
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t test-session:2 even-horizontal"
}
function test_balance_windows_horizontal_with_window_name() {
spy tmuxifier-tmux
balance_windows_horizontal "editor"
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t test-session:editor even-horizontal"
}
function test_balance_windows_horizontal_with_different_session() {
session="mysession"
window="3"
spy tmuxifier-tmux
balance_windows_horizontal
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t mysession:3 even-horizontal"
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# balance_windows_vertical() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_balance_windows_vertical_uses_current_window_by_default() {
spy tmuxifier-tmux
balance_windows_vertical
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t test-session:0 even-vertical"
}
function test_balance_windows_vertical_with_specific_window() {
spy tmuxifier-tmux
balance_windows_vertical 2
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t test-session:2 even-vertical"
}
function test_balance_windows_vertical_with_window_name() {
spy tmuxifier-tmux
balance_windows_vertical "editor"
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t test-session:editor even-vertical"
}
function test_balance_windows_vertical_with_different_session() {
session="mysession"
window="3"
spy tmuxifier-tmux
balance_windows_vertical
assert_have_been_called_with \
tmuxifier-tmux "select-layout -t mysession:3 even-vertical"
}

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# clock() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_clock_calls_tmux_clock_mode() {
spy tmuxifier-tmux
clock
assert_have_been_called_with tmuxifier-tmux "clock-mode -t test-session:0."
}
function test_clock_with_target_pane() {
spy tmuxifier-tmux
clock 1
assert_have_been_called_with tmuxifier-tmux "clock-mode -t test-session:0.1"
}
function test_clock_with_different_session_and_window() {
session="mysession"
window="2"
spy tmuxifier-tmux
clock 3
assert_have_been_called_with tmuxifier-tmux "clock-mode -t mysession:2.3"
}
function test_clock_with_named_window() {
session="dev"
window="editor"
spy tmuxifier-tmux
clock 0
assert_have_been_called_with tmuxifier-tmux "clock-mode -t dev:editor.0"
}

View File

@@ -0,0 +1,255 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# finalize_and_go_to_session() tests
#
function set_up() {
# Create temp directory for testing
_test_tmp_dir=$(mktemp -d)
# Save original values
_orig_home="$HOME"
_orig_tmux="$TMUX"
_orig_iterm_attach="$TMUXIFIER_TMUX_ITERM_ATTACH"
HOME="$_test_tmp_dir"
# Reset variables to known state
session=""
TMUX=""
TMUXIFIER_TMUX_ITERM_ATTACH=""
}
function tear_down() {
HOME="$_orig_home"
TMUX="$_orig_tmux"
TMUXIFIER_TMUX_ITERM_ATTACH="$_orig_iterm_attach"
unset session
rm -rf "$_test_tmp_dir"
}
#
# Kill window 999 behavior
#
function test_finalize_kills_window_999() {
session="mysession"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "mysession"
finalize_and_go_to_session
assert_have_been_called_with tmuxifier-tmux "kill-window -t mysession:999"
}
function test_finalize_continues_when_kill_window_fails() {
session="mysession"
# Simulate kill-window failure (window doesn't exist)
mock tmuxifier-tmux return 1
mock tmuxifier-current-session echo "mysession"
local result
finalize_and_go_to_session
result=$?
# Function should succeed even if kill-window fails due to ! negation
assert_same "0" "$result"
}
function test_finalize_continues_when_kill_window_succeeds() {
session="mysession"
mock tmuxifier-tmux return 0
mock tmuxifier-current-session echo "mysession"
local result
finalize_and_go_to_session
result=$?
# Function succeeds when kill-window succeeds
# Note: ! negation means exit code is inverted (1 becomes 0, 0 becomes 1)
# but the conditional check for __go_to_session still runs
assert_successful_code "true"
}
#
# Session switching when current session differs
#
function test_finalize_calls_attach_when_current_session_differs_and_not_in_tmux() {
session="newsession"
TMUX=""
spy tmuxifier-tmux
mock tmuxifier-current-session echo "othersession"
finalize_and_go_to_session
# Should call attach-session when not inside tmux
assert_have_been_called_with tmuxifier-tmux \
"-u attach-session -t newsession:" 2
}
function test_finalize_calls_switch_when_current_session_differs_and_inside_tmux() {
session="newsession"
TMUX="/tmp/tmux-1000/default,12345,0"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "othersession"
finalize_and_go_to_session
# Should call switch-client when inside tmux
assert_have_been_called_with tmuxifier-tmux \
"-u switch-client -t newsession:" 2
}
#
# Session switching when current session matches
#
function test_finalize_does_not_switch_when_current_session_matches() {
session="mysession"
TMUX=""
spy tmuxifier-tmux
mock tmuxifier-current-session echo "mysession"
finalize_and_go_to_session
# Should only call kill-window, not attach/switch
assert_have_been_called_times 1 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "kill-window -t mysession:999" 1
}
function test_finalize_does_not_switch_when_already_in_session_inside_tmux() {
session="current"
TMUX="/tmp/tmux-1000/default,12345,0"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "current"
finalize_and_go_to_session
# Should only call kill-window
assert_have_been_called_times 1 tmuxifier-tmux
}
#
# iTerm2 integration
#
function test_finalize_uses_iterm_attach_flag_when_set() {
session="newsession"
TMUX=""
TMUXIFIER_TMUX_ITERM_ATTACH="-CC"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "othersession"
finalize_and_go_to_session
# Should include -CC flag for iTerm2 integration
assert_have_been_called_with tmuxifier-tmux \
"-CC -u attach-session -t newsession:" 2
}
function test_finalize_iterm_flag_not_used_when_switching_client() {
session="newsession"
TMUX="/tmp/tmux-1000/default,12345,0"
TMUXIFIER_TMUX_ITERM_ATTACH="-CC"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "othersession"
finalize_and_go_to_session
# switch-client doesn't use ITERM_ATTACH
assert_have_been_called_with tmuxifier-tmux \
"-u switch-client -t newsession:" 2
}
#
# Edge cases
#
function test_finalize_handles_session_with_special_characters() {
session="my-project_v2.0"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "my-project_v2.0"
finalize_and_go_to_session
assert_have_been_called_with tmuxifier-tmux \
"kill-window -t my-project_v2.0:999"
}
function test_finalize_handles_empty_current_session_output() {
session="newsession"
TMUX=""
spy tmuxifier-tmux
# Empty output from tmuxifier-current-session (not in any session)
mock tmuxifier-current-session echo ""
finalize_and_go_to_session
# Empty != "newsession", so should call attach
assert_have_been_called_with tmuxifier-tmux \
"-u attach-session -t newsession:" 2
}
function test_finalize_handles_session_name_with_spaces() {
session="my session"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "my session"
finalize_and_go_to_session
assert_have_been_called_with tmuxifier-tmux \
"kill-window -t my session:999"
}
#
# Integration-style tests
#
function test_finalize_full_flow_when_session_exists_and_matches() {
session="existing"
TMUX=""
spy tmuxifier-tmux
mock tmuxifier-current-session echo "existing"
finalize_and_go_to_session
# Verify single call to kill-window only
assert_have_been_called_times 1 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "kill-window -t existing:999" 1
}
function test_finalize_full_flow_when_session_needs_attach() {
session="newproject"
TMUX=""
spy tmuxifier-tmux
mock tmuxifier-current-session echo ""
finalize_and_go_to_session
# Verify both calls: kill-window and attach-session
assert_have_been_called_times 2 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux \
"kill-window -t newproject:999" 1
assert_have_been_called_with tmuxifier-tmux \
"-u attach-session -t newproject:" 2
}
function test_finalize_full_flow_when_switching_from_another_session() {
session="target"
TMUX="/tmp/tmux-1000/default,12345,0"
spy tmuxifier-tmux
mock tmuxifier-current-session echo "source"
finalize_and_go_to_session
# Verify both calls: kill-window and switch-client
assert_have_been_called_times 2 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux \
"kill-window -t target:999" 1
assert_have_been_called_with tmuxifier-tmux \
"-u switch-client -t target:" 2
}

View File

@@ -0,0 +1,430 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# initialize_session() tests
#
function set_up() {
# Create temp directory for testing
_test_tmp_dir=$(mktemp -d)
# Save original values
_orig_home="$HOME"
HOME="$_test_tmp_dir"
# Reset variables to known state
session=""
session_root="$HOME"
set_default_path=true
window=""
TMUX=""
}
function tear_down() {
HOME="$_orig_home"
unset session session_root set_default_path window
rm -rf "$_test_tmp_dir"
}
#
# Session name handling
#
function test_initialize_session_uses_session_variable_when_no_argument() {
session="my-session"
mock tmuxifier-tmux echo ""
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
assert_same "my-session" "$session"
}
function test_initialize_session_uses_argument_as_session_name() {
session=""
mock tmuxifier-tmux echo ""
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session "custom-session"
assert_same "custom-session" "$session"
}
function test_initialize_session_overrides_session_variable_with_argument() {
session="original"
mock tmuxifier-tmux echo ""
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session "override"
assert_same "override" "$session"
}
#
# Server startup
#
function test_initialize_session_starts_tmux_server() {
session="test"
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
assert_have_been_called_with tmuxifier-tmux "start-server" 1
}
#
# Session existence check
#
function test_initialize_session_returns_1_when_session_exists() {
session="existing"
# Mock list-sessions to return a matching session (output is also used by
# start-server but ignored there)
mock tmuxifier-tmux printf '%s\n' "existing: 1 windows"
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
assert_same "1" "$result"
}
function test_initialize_session_returns_0_when_session_does_not_exist() {
session="newsession"
mock tmuxifier-tmux echo ""
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
assert_same "0" "$result"
}
function test_initialize_session_checks_exact_session_name_match() {
session="test"
# Return a session with similar but different name - grep pattern "^test:"
# won't match "test-other:"
mock tmuxifier-tmux printf '%s\n' "test-other: 1 windows"
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
# Should succeed because "test:" pattern doesn't match "test-other:"
assert_same "0" "$result"
}
#
# Tmux 1.9+ behavior (modern tmux)
#
function test_initialize_session_creates_session_with_c_flag_for_tmux_19_plus() {
session="newsession"
session_root="$_test_tmp_dir"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
# Calls: start-server(1), list-sessions(2), new-session(3), setenv(4),
# move-window(5)
assert_have_been_called_with tmuxifier-tmux \
"new-session -d -s newsession -c $_test_tmp_dir" 3
}
function test_initialize_session_omits_c_flag_when_set_default_path_false() {
session="newsession"
session_root="$_test_tmp_dir"
set_default_path=false
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
# Calls: start-server(1), list-sessions(2), new-session(3), move-window(4)
assert_have_been_called_with tmuxifier-tmux \
"new-session -d -s newsession" 3
}
#
# Tmux 1.8 and earlier behavior (legacy tmux)
#
function test_initialize_session_creates_session_without_c_for_tmux_18() {
session="newsession"
session_root="$_test_tmp_dir"
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< "<"
mock __get_first_window_index echo "0"
initialize_session
# Calls: start-server(1), list-sessions(2), new-session(3), ...
assert_have_been_called_with tmuxifier-tmux \
"new-session -d -s newsession" 3
}
function test_initialize_session_sets_default_path_option_for_tmux_18() {
session="newsession"
session_root="$_test_tmp_dir"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< "<"
mock __get_first_window_index echo "0"
initialize_session
# Calls: start-server(1), list-sessions(2), new-session(3), set-option(4),
# setenv(5), move-window(6)
assert_have_been_called_with tmuxifier-tmux \
"set-option -t newsession: default-path $_test_tmp_dir" 4
}
function test_initialize_session_skips_default_path_when_set_default_path_false() {
session="newsession"
session_root="$_test_tmp_dir"
set_default_path=false
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< "<"
mock __get_first_window_index echo "0"
initialize_session
# Should have 4 calls: start-server, list-sessions, new-session, move-window
# (no set-option default-path call, no setenv call)
assert_have_been_called_times 4 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "start-server" 1
assert_have_been_called_with tmuxifier-tmux "list-sessions" 2
assert_have_been_called_with tmuxifier-tmux "new-session -d -s newsession" 3
assert_have_been_called_with tmuxifier-tmux \
"move-window -s newsession:0 -t newsession:999" 4
}
#
# Session root environment variable
#
function test_initialize_session_sets_session_root_env_when_not_home() {
session="newsession"
# Use a subdirectory so session_root != HOME
mkdir -p "$_test_tmp_dir/project"
session_root="$_test_tmp_dir/project"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
# Calls: start-server(1), list-sessions(2), new-session(3), setenv(4),
# move-window(5)
assert_have_been_called_with tmuxifier-tmux \
"setenv -t newsession: TMUXIFIER_SESSION_ROOT $_test_tmp_dir/project" 4
}
function test_initialize_session_skips_session_root_env_when_equal_to_home() {
session="newsession"
session_root="$HOME"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
# Should have 4 calls (no setenv call when session_root == HOME)
assert_have_been_called_times 4 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "start-server" 1
assert_have_been_called_with tmuxifier-tmux "list-sessions" 2
assert_have_been_called_with tmuxifier-tmux \
"new-session -d -s newsession -c $HOME" 3
assert_have_been_called_with tmuxifier-tmux \
"move-window -s newsession:0 -t newsession:999" 4
}
function test_initialize_session_skips_session_root_env_when_set_default_path_false() {
session="newsession"
session_root="$_test_tmp_dir"
set_default_path=false
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
# Should have 4 calls (no setenv call when set_default_path is false)
assert_have_been_called_times 4 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "start-server" 1
assert_have_been_called_with tmuxifier-tmux "list-sessions" 2
assert_have_been_called_with tmuxifier-tmux "new-session -d -s newsession" 3
assert_have_been_called_with tmuxifier-tmux \
"move-window -s newsession:0 -t newsession:999" 4
}
#
# Default window handling
#
function test_initialize_session_moves_default_window_to_position_999() {
session="newsession"
session_root="$HOME"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
assert_have_been_called_with tmuxifier-tmux \
"move-window -s newsession:0 -t newsession:999"
}
function test_initialize_session_uses_first_window_index_for_move() {
session="newsession"
session_root="$HOME"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "1"
initialize_session
# Should use the actual first window index (1 in this case)
assert_have_been_called_with tmuxifier-tmux \
"move-window -s newsession:1 -t newsession:999"
}
#
# Integration-style tests
#
function test_initialize_session_full_flow_tmux_19_returns_success() {
session="myproject"
mkdir -p "$_test_tmp_dir/project"
session_root="$_test_tmp_dir/project"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
assert_same "0" "$result"
assert_same "myproject" "$session"
}
function test_initialize_session_full_flow_tmux_19_calls_expected_commands() {
session="myproject"
mkdir -p "$_test_tmp_dir/project"
session_root="$_test_tmp_dir/project"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
initialize_session
# Verify all expected calls
assert_have_been_called_times 5 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "start-server" 1
assert_have_been_called_with tmuxifier-tmux "list-sessions" 2
assert_have_been_called_with tmuxifier-tmux \
"new-session -d -s myproject -c $_test_tmp_dir/project" 3
assert_have_been_called_with tmuxifier-tmux \
"setenv -t myproject: TMUXIFIER_SESSION_ROOT $_test_tmp_dir/project" 4
assert_have_been_called_with tmuxifier-tmux \
"move-window -s myproject:0 -t myproject:999" 5
}
function test_initialize_session_full_flow_tmux_18_returns_success() {
session="oldproject"
mkdir -p "$_test_tmp_dir/project"
session_root="$_test_tmp_dir/project"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< "<"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
assert_same "0" "$result"
assert_same "oldproject" "$session"
}
function test_initialize_session_full_flow_tmux_18_calls_expected_commands() {
session="oldproject"
mkdir -p "$_test_tmp_dir/project"
session_root="$_test_tmp_dir/project"
set_default_path=true
spy tmuxifier-tmux
mock tmuxifier-tmux-version <<< "<"
mock __get_first_window_index echo "0"
initialize_session
# Verify all expected calls
assert_have_been_called_times 6 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "start-server" 1
assert_have_been_called_with tmuxifier-tmux "list-sessions" 2
assert_have_been_called_with tmuxifier-tmux \
"new-session -d -s oldproject" 3
assert_have_been_called_with tmuxifier-tmux \
"set-option -t oldproject: default-path $_test_tmp_dir/project" 4
assert_have_been_called_with tmuxifier-tmux \
"setenv -t oldproject: TMUXIFIER_SESSION_ROOT $_test_tmp_dir/project" 5
assert_have_been_called_with tmuxifier-tmux \
"move-window -s oldproject:0 -t oldproject:999" 6
}
#
# Edge cases
#
function test_initialize_session_does_not_create_when_session_already_exists() {
session="existing"
mock tmuxifier-tmux printf '%s\n' "existing: 1 windows"
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
assert_same "1" "$result"
}
function test_initialize_session_handles_session_with_special_chars() {
session="my-project_v2"
mock tmuxifier-tmux echo ""
mock tmuxifier-tmux-version <<< ">"
mock __get_first_window_index echo "0"
local result
initialize_session
result=$?
assert_same "0" "$result"
assert_same "my-project_v2" "$session"
}

View File

@@ -0,0 +1,200 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# load_session() tests
#
function set_up() {
# Create temp directory structure for testing (per-test for parallel support)
_test_tmp_dir=$(mktemp -d)
_test_layout_path="${_test_tmp_dir}/layouts"
mkdir -p "$_test_layout_path"
# Create a simple session layout file in layout path
cat > "${_test_layout_path}/mysession.session.sh" << 'EOF'
_test_layout_sourced="mysession"
EOF
# Create layout file with .sh extension only
cat > "${_test_layout_path}/other.sh" << 'EOF'
_test_layout_sourced="other"
EOF
# Create a layout file as a direct path (with slash)
cat > "${_test_tmp_dir}/direct.session.sh" << 'EOF'
_test_layout_sourced="direct"
EOF
# Save original values and set test values
_orig_layout_path="$TMUXIFIER_LAYOUT_PATH"
_orig_home="$HOME"
TMUXIFIER_LAYOUT_PATH="$_test_layout_path"
# Reset variables
session=""
session_root=""
set_default_path=""
_test_layout_sourced=""
}
function tear_down() {
TMUXIFIER_LAYOUT_PATH="$_orig_layout_path"
HOME="$_orig_home"
unset session session_root set_default_path _test_layout_sourced
rm -rf "$_test_tmp_dir"
}
function test_load_session_finds_layout_by_name_in_layout_path() {
load_session "mysession"
assert_same "mysession" "$_test_layout_sourced"
}
function test_load_session_finds_layout_by_direct_file_path() {
load_session "${_test_tmp_dir}/direct.session.sh"
assert_same "direct" "$_test_layout_sourced"
}
function test_load_session_sets_session_from_name_stripping_session_sh() {
# Capture session value during source, before it's reset
cat > "${_test_layout_path}/capture.session.sh" << 'EOF'
_captured_session="$session"
EOF
load_session "capture"
assert_same "capture" "$_captured_session"
}
function test_load_session_sets_session_from_path_stripping_session_sh() {
cat > "${_test_tmp_dir}/pathtest.session.sh" << 'EOF'
_captured_session="$session"
EOF
load_session "${_test_tmp_dir}/pathtest.session.sh"
assert_same "${_test_tmp_dir}/pathtest" "$_captured_session"
}
function test_load_session_uses_override_name_when_provided() {
cat > "${_test_layout_path}/named.session.sh" << 'EOF'
_captured_session="$session"
EOF
load_session "named" "custom-session"
assert_same "custom-session" "$_captured_session"
}
function test_load_session_resets_session_variable_after_load() {
load_session "mysession"
assert_empty "$session"
}
function test_load_session_sets_set_default_path_to_true() {
cat > "${_test_layout_path}/checkpath.session.sh" << 'EOF'
_captured_set_default_path="$set_default_path"
EOF
load_session "checkpath"
assert_same "true" "$_captured_set_default_path"
}
function test_load_session_resets_session_root_to_home_when_different() {
HOME="$_test_tmp_dir"
session_root="${_test_tmp_dir}/layouts"
load_session "mysession"
assert_same "$_test_tmp_dir" "$session_root"
}
function test_load_session_does_not_reset_session_root_when_equal_to_home() {
HOME="$_test_tmp_dir"
session_root="$_test_tmp_dir"
# Create a layout that changes session_root
cat > "${_test_layout_path}/nochange.session.sh" << 'EOF'
# This layout doesn't change session_root
EOF
load_session "nochange"
# session_root should still be the same (HOME)
assert_same "$_test_tmp_dir" "$session_root"
}
function test_load_session_returns_1_when_file_not_found() {
load_session "nonexistent" 2> /dev/null
local exit_code=$?
assert_same "1" "$exit_code"
}
function test_load_session_prints_error_to_stderr_when_not_found() {
local stderr_output
stderr_output=$(load_session "nonexistent" 2>&1 > /dev/null)
assert_contains "nonexistent" "$stderr_output"
assert_contains "not found" "$stderr_output"
}
function test_load_session_sources_file_content() {
cat > "${_test_layout_path}/content.session.sh" << 'EOF'
_test_var_one="session_value1"
_test_var_two="session_value2"
EOF
load_session "content"
assert_same "session_value1" "$_test_var_one"
assert_same "session_value2" "$_test_var_two"
}
function test_load_session_prefers_layout_path_when_no_slash_in_name() {
# Create a file in layout path
cat > "${_test_layout_path}/conflict.session.sh" << 'EOF'
_test_layout_sourced="from_layout_path"
EOF
# When given name without slash, should use layout path
load_session "conflict"
assert_same "from_layout_path" "$_test_layout_sourced"
}
function test_load_session_uses_direct_path_when_slash_present() {
mkdir -p "${_test_layout_path}/sub"
cat > "${_test_layout_path}/sub/nested.session.sh" << 'EOF'
_test_layout_sourced="from_nested"
EOF
# When given path with slash, should use it directly
load_session "${_test_layout_path}/sub/nested.session.sh"
assert_same "from_nested" "$_test_layout_sourced"
}
function test_load_session_handles_relative_path_in_current_dir() {
# Save current directory and change to temp dir
local orig_pwd="$PWD"
cd "$_test_tmp_dir"
# Create a file without .session.sh suffix in current dir
cat > "localfile.sh" << 'EOF'
_test_layout_sourced="from_local"
EOF
# When file exists locally and no slash, it should prepend ./
load_session "localfile.sh"
assert_same "from_local" "$_test_layout_sourced"
cd "$orig_pwd"
}

View File

@@ -0,0 +1,175 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# load_window() tests
#
function set_up() {
# Create temp directory structure for testing (per-test for parallel support)
_test_tmp_dir=$(mktemp -d)
_test_layout_path="${_test_tmp_dir}/layouts"
mkdir -p "$_test_layout_path"
# Create a simple window layout file in layout path
cat > "${_test_layout_path}/mywindow.window.sh" << 'EOF'
_test_layout_sourced="mywindow"
EOF
# Create layout file with .sh extension only
cat > "${_test_layout_path}/other.sh" << 'EOF'
_test_layout_sourced="other"
EOF
# Create a layout file as a direct path
cat > "${_test_tmp_dir}/direct.window.sh" << 'EOF'
_test_layout_sourced="direct"
EOF
# Create a layout that modifies window_root
cat > "${_test_layout_path}/chroot.window.sh" << 'EOF'
_test_layout_sourced="chroot"
EOF
# Save original TMUXIFIER_LAYOUT_PATH and set test value
_orig_layout_path="$TMUXIFIER_LAYOUT_PATH"
TMUXIFIER_LAYOUT_PATH="$_test_layout_path"
# Reset variables
window=""
window_root=""
session_root=""
_test_layout_sourced=""
}
function tear_down() {
TMUXIFIER_LAYOUT_PATH="$_orig_layout_path"
unset window window_root session_root _test_layout_sourced
rm -rf "$_test_tmp_dir"
}
function test_load_window_finds_layout_by_name_in_layout_path() {
load_window "mywindow"
assert_same "mywindow" "$_test_layout_sourced"
}
function test_load_window_finds_layout_by_direct_file_path() {
load_window "${_test_tmp_dir}/direct.window.sh"
assert_same "direct" "$_test_layout_sourced"
}
function test_load_window_sets_window_from_name_stripping_window_sh() {
# We need to capture window value during source, before it's reset
cat > "${_test_layout_path}/capture.window.sh" << 'EOF'
_captured_window="$window"
EOF
load_window "capture"
assert_same "capture" "$_captured_window"
}
function test_load_window_sets_window_from_name_stripping_sh_only() {
cat > "${_test_layout_path}/simple.sh" << 'EOF'
_captured_window="$window"
EOF
# Load by direct path to test .sh stripping
load_window "${_test_layout_path}/simple.sh"
assert_same "${_test_layout_path}/simple" "$_captured_window"
}
function test_load_window_uses_override_name_when_provided() {
cat > "${_test_layout_path}/named.window.sh" << 'EOF'
_captured_window="$window"
EOF
load_window "named" "custom-name"
assert_same "custom-name" "$_captured_window"
}
function test_load_window_resets_window_variable_after_load() {
load_window "mywindow"
assert_empty "$window"
}
function test_load_window_resets_window_root_when_different_from_session_root() {
session_root="$_test_tmp_dir"
window_root="${_test_tmp_dir}/layouts"
# Mock the window_root function to track if it's called
_window_root_called=""
_window_root_arg=""
function window_root() {
_window_root_called="yes"
_window_root_arg="$1"
}
load_window "mywindow"
assert_same "yes" "$_window_root_called"
assert_same "$_test_tmp_dir" "$_window_root_arg"
}
function test_load_window_does_not_reset_window_root_when_equal_to_session_root() {
session_root="$_test_tmp_dir"
window_root="$_test_tmp_dir"
_window_root_called=""
function window_root() {
_window_root_called="yes"
}
load_window "mywindow"
assert_empty "$_window_root_called"
}
function test_load_window_returns_1_when_file_not_found() {
load_window "nonexistent" 2> /dev/null
local exit_code=$?
assert_same "1" "$exit_code"
}
function test_load_window_prints_error_to_stderr_when_not_found() {
local stderr_output
stderr_output=$(load_window "nonexistent" 2>&1 > /dev/null)
assert_contains "nonexistent" "$stderr_output"
assert_contains "not found" "$stderr_output"
}
function test_load_window_sources_file_content() {
cat > "${_test_layout_path}/content.window.sh" << 'EOF'
_test_var_one="value1"
_test_var_two="value2"
EOF
load_window "content"
assert_same "value1" "$_test_var_one"
assert_same "value2" "$_test_var_two"
}
function test_load_window_prefers_direct_file_over_layout_path() {
# Create a file that would match both direct path and layout path lookup
cat > "${_test_layout_path}/conflict.window.sh" << 'EOF'
_test_layout_sourced="from_layout_path"
EOF
cat > "${_test_tmp_dir}/conflict.window.sh" << 'EOF'
_test_layout_sourced="from_direct_path"
EOF
# When given as direct path, should use direct file
load_window "${_test_tmp_dir}/conflict.window.sh"
assert_same "from_direct_path" "$_test_layout_sourced"
}

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# new_window() tests
#
function set_up() {
session="test-session"
window=""
}
function tear_down() {
unset session window
}
function test_new_window_calls_tmux_new_window() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window
assert_have_been_called_with tmuxifier-tmux "new-window -t test-session:"
}
function test_new_window_calls_go_to_window_or_session_path() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window
assert_have_been_called __go_to_window_or_session_path
}
function test_new_window_sets_window_variable_to_current_index() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "5"
new_window
assert_same "5" "$window"
}
function test_new_window_with_name_includes_n_flag() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window "mywindow"
assert_have_been_called_with tmuxifier-tmux "new-window -t test-session: -n mywindow" 1
}
function test_new_window_with_name_disables_allow_rename() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window "mywindow"
assert_have_been_called_with tmuxifier-tmux "set-option -t mywindow allow-rename off" 2
}
function test_new_window_with_name_and_command() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window "editor" "vim"
assert_have_been_called_with \
tmuxifier-tmux "new-window -t test-session: -n editor vim" 1
}
function test_new_window_with_only_command_via_empty_name() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window "" "htop"
assert_have_been_called_with tmuxifier-tmux "new-window -t test-session: htop"
}
function test_new_window_without_name_does_not_disable_rename() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
mock __get_current_window_index echo "1"
new_window
# Only one call to tmuxifier-tmux (new-window), no set-option call
assert_have_been_called_times 1 tmuxifier-tmux
}

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# run_cmd() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_run_cmd_sends_command_then_enter() {
spy tmuxifier-tmux
run_cmd "ls -la"
assert_have_been_called_times 2 tmuxifier-tmux
}
function test_run_cmd_first_call_sends_command() {
spy tmuxifier-tmux
run_cmd "ls -la"
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. ls -la" 1
}
function test_run_cmd_second_call_sends_enter_key() {
spy tmuxifier-tmux
run_cmd "ls -la"
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. C-m" 2
}
function test_run_cmd_with_target_pane() {
spy tmuxifier-tmux
run_cmd "echo hello" 1
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0.1 echo hello" 1
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0.1 C-m" 2
}
function test_run_cmd_with_different_session_and_window() {
session="mysession"
window="2"
spy tmuxifier-tmux
run_cmd "npm start" 3
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t mysession:2.3 npm start" 1
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t mysession:2.3 C-m" 2
}
function test_run_cmd_with_complex_command() {
spy tmuxifier-tmux
run_cmd "cd /tmp && ls"
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. cd /tmp && ls" 1
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. C-m" 2
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# select_pane() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_select_pane_calls_tmux_select_pane() {
spy tmuxifier-tmux
select_pane 1
assert_have_been_called_with \
tmuxifier-tmux "select-pane -t test-session:0.1"
}
function test_select_pane_with_pane_zero() {
spy tmuxifier-tmux
select_pane 0
assert_have_been_called_with \
tmuxifier-tmux "select-pane -t test-session:0.0"
}
function test_select_pane_with_different_session_and_window() {
session="mysession"
window="2"
spy tmuxifier-tmux
select_pane 3
assert_have_been_called_with tmuxifier-tmux "select-pane -t mysession:2.3"
}
function test_select_pane_with_named_window() {
session="dev"
window="editor"
spy tmuxifier-tmux
select_pane 1
assert_have_been_called_with tmuxifier-tmux "select-pane -t dev:editor.1"
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# select_window() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_select_window_calls_tmux_select_window() {
spy tmuxifier-tmux
mock __get_current_window_index echo "1"
select_window 1
assert_have_been_called_with tmuxifier-tmux "select-window -t test-session:1"
}
function test_select_window_with_window_name() {
spy tmuxifier-tmux
mock __get_current_window_index echo "editor"
select_window "editor"
assert_have_been_called_with \
tmuxifier-tmux "select-window -t test-session:editor"
}
function test_select_window_updates_window_variable() {
spy tmuxifier-tmux
mock __get_current_window_index echo "5"
select_window 5
assert_equals "5" "$window"
}
function test_select_window_with_different_session() {
session="mysession"
spy tmuxifier-tmux
mock __get_current_window_index echo "2"
select_window 2
assert_have_been_called_with tmuxifier-tmux "select-window -t mysession:2"
}

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# send_keys() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_send_keys_sends_string_to_current_pane() {
spy tmuxifier-tmux
send_keys "hello"
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. hello"
}
function test_send_keys_with_target_pane() {
spy tmuxifier-tmux
send_keys "hello" 1
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0.1 hello"
}
function test_send_keys_with_special_key() {
spy tmuxifier-tmux
send_keys "C-m"
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. C-m"
}
function test_send_keys_with_command_string() {
spy tmuxifier-tmux
send_keys "ls -la"
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t test-session:0. ls -la"
}
function test_send_keys_with_different_session_and_window() {
session="mysession"
window="2"
spy tmuxifier-tmux
send_keys "echo test" 3
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t mysession:2.3 echo test"
}
function test_send_keys_with_named_window() {
session="dev"
window="editor"
spy tmuxifier-tmux
send_keys "vim ." 0
assert_have_been_called_with \
tmuxifier-tmux "send-keys -t dev:editor.0 vim ."
}

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# session_root() tests
#
function set_up() {
# Create temp directories for testing (per-test for parallel support)
_test_tmp_dir=$(mktemp -d)
_test_valid_dir="${_test_tmp_dir}/valid"
mkdir -p "$_test_valid_dir"
_test_nonexistent_dir="${_test_tmp_dir}/nonexistent"
# Reset session_root variable before each test
session_root=""
}
function tear_down() {
unset session_root
rm -rf "$_test_tmp_dir"
}
function test_session_root_sets_variable_for_existing_directory() {
# Mock __expand_path to return the valid directory
mock __expand_path echo "$_test_valid_dir"
session_root "~/some/path"
assert_same "$_test_valid_dir" "$session_root"
}
function test_session_root_does_not_set_variable_for_nonexistent_directory() {
# Mock __expand_path to return a nonexistent directory
mock __expand_path echo "$_test_nonexistent_dir"
session_root "~/nonexistent"
assert_empty "$session_root"
}
function test_session_root_calls_expand_path_with_arguments() {
spy __expand_path
# Since spy doesn't return anything, the dir check will fail
# but we can still verify __expand_path was called
session_root "~/Projects"
assert_have_been_called_with __expand_path "~/Projects"
}
function test_session_root_passes_multiple_arguments_to_expand_path() {
spy __expand_path
session_root '~/$USER/path'
assert_have_been_called_with __expand_path '~/$USER/path'
}
function test_session_root_preserves_existing_value_on_invalid_path() {
session_root="$_test_valid_dir"
mock __expand_path echo "$_test_nonexistent_dir"
session_root "~/invalid"
# Original value should be preserved since new path doesn't exist
assert_same "$_test_valid_dir" "$session_root"
}
function test_session_root_overwrites_existing_value_on_valid_path() {
local new_dir="${_test_tmp_dir}/another"
mkdir -p "$new_dir"
session_root="$_test_valid_dir"
mock __expand_path echo "$new_dir"
session_root "~/another"
assert_same "$new_dir" "$session_root"
}
function test_session_root_handles_home_directory() {
# Use actual HOME which should exist
mock __expand_path echo "$HOME"
session_root "~"
assert_same "$HOME" "$session_root"
}

View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# split_h() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_split_h_calls_tmux_then_go_to_path() {
local calls=()
function tmuxifier-tmux() { calls+=("tmuxifier-tmux:$*"); }
function __go_to_window_or_session_path() { calls+=("go_to_path"); }
split_h
assert_equals "tmuxifier-tmux:split-window -t test-session:0. -h" "${calls[0]}"
assert_equals "go_to_path" "${calls[1]}"
}
#
# Tmux 3.1+ tests (uses -l with % suffix)
#
function test_split_h_tmux_31_with_percentage_uses_l_flag() {
mock tmuxifier-tmux-version <<< ">"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h 30
assert_have_been_called_with \
tmuxifier-tmux "split-window -t test-session:0. -h -l 30%"
}
function test_split_h_tmux_31_with_percentage_and_target_pane() {
session="mysession"
window="2"
mock tmuxifier-tmux-version <<< ">"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h 50 1
assert_have_been_called_with \
tmuxifier-tmux "split-window -t mysession:2.1 -h -l 50%"
}
function test_split_h_tmux_31_with_only_target_pane_empty_percentage() {
session="test"
window="1"
mock tmuxifier-tmux-version <<< ">"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h "" 2
assert_have_been_called_with tmuxifier-tmux "split-window -t test:1.2 -h"
}
#
# Tmux 3.0 and earlier tests (uses -p flag)
#
function test_split_h_tmux_30_with_percentage_uses_p_flag() {
mock tmuxifier-tmux-version <<< "="
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h 30
assert_have_been_called_with \
tmuxifier-tmux "split-window -t test-session:0. -h -p 30"
}
function test_split_h_tmux_30_with_percentage_and_target_pane() {
session="mysession"
window="2"
mock tmuxifier-tmux-version <<< "<"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h 50 1
assert_have_been_called_with \
tmuxifier-tmux "split-window -t mysession:2.1 -h -p 50"
}
function test_split_h_tmux_30_with_only_target_pane_empty_percentage() {
session="test"
window="1"
mock tmuxifier-tmux-version <<< "="
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h "" 2
assert_have_been_called_with tmuxifier-tmux "split-window -t test:1.2 -h"
}
function test_split_h_always_calls_go_to_window_or_session_path() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_h 50 1
assert_have_been_called_times 1 __go_to_window_or_session_path
}

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# split_hl() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_split_hl_calls_tmux_then_go_to_path() {
local calls=()
function tmuxifier-tmux() { calls+=("tmuxifier-tmux:$*"); }
function __go_to_window_or_session_path() { calls+=("go_to_path"); }
split_hl
assert_equals "tmuxifier-tmux:split-window -t test-session:0. -h" "${calls[0]}"
assert_equals "go_to_path" "${calls[1]}"
}
function test_split_hl_with_column_count_includes_l_flag() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_hl 80
assert_have_been_called_with \
tmuxifier-tmux "split-window -t test-session:0. -h -l 80"
}
function test_split_hl_with_column_count_and_target_pane() {
session="mysession"
window="2"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_hl 40 1
assert_have_been_called_with \
tmuxifier-tmux "split-window -t mysession:2.1 -h -l 40"
}
function test_split_hl_with_only_target_pane_empty_count() {
session="test"
window="1"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_hl "" 2
assert_have_been_called_with tmuxifier-tmux "split-window -t test:1.2 -h"
}
function test_split_hl_always_calls_go_to_window_or_session_path() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_hl 60 1
assert_have_been_called_times 1 __go_to_window_or_session_path
}

View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# split_v() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_split_v_calls_tmux_then_go_to_path() {
local calls=()
function tmuxifier-tmux() { calls+=("tmuxifier-tmux:$*"); }
function __go_to_window_or_session_path() { calls+=("go_to_path"); }
split_v
assert_equals "tmuxifier-tmux:split-window -t test-session:0. -v" "${calls[0]}"
assert_equals "go_to_path" "${calls[1]}"
}
#
# Tmux 3.1+ tests (uses -l with % suffix)
#
function test_split_v_tmux_31_with_percentage_uses_l_flag() {
mock tmuxifier-tmux-version <<< ">"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v 30
assert_have_been_called_with \
tmuxifier-tmux "split-window -t test-session:0. -v -l 30%"
}
function test_split_v_tmux_31_with_percentage_and_target_pane() {
session="mysession"
window="2"
mock tmuxifier-tmux-version <<< ">"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v 50 1
assert_have_been_called_with \
tmuxifier-tmux "split-window -t mysession:2.1 -v -l 50%"
}
function test_split_v_tmux_31_with_only_target_pane_empty_percentage() {
session="test"
window="1"
mock tmuxifier-tmux-version <<< ">"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v "" 2
assert_have_been_called_with tmuxifier-tmux "split-window -t test:1.2 -v"
}
#
# Tmux 3.0 and earlier tests (uses -p flag)
#
function test_split_v_tmux_30_with_percentage_uses_p_flag() {
mock tmuxifier-tmux-version <<< "="
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v 30
assert_have_been_called_with \
tmuxifier-tmux "split-window -t test-session:0. -v -p 30"
}
function test_split_v_tmux_30_with_percentage_and_target_pane() {
session="mysession"
window="2"
mock tmuxifier-tmux-version <<< "<"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v 50 1
assert_have_been_called_with \
tmuxifier-tmux "split-window -t mysession:2.1 -v -p 50"
}
function test_split_v_tmux_30_with_only_target_pane_empty_percentage() {
session="test"
window="1"
mock tmuxifier-tmux-version <<< "="
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v "" 2
assert_have_been_called_with tmuxifier-tmux "split-window -t test:1.2 -v"
}
function test_split_v_always_calls_go_to_window_or_session_path() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_v 50 1
assert_have_been_called_times 1 __go_to_window_or_session_path
}

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# split_vl() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_split_vl_calls_tmux_then_go_to_path() {
local calls=()
function tmuxifier-tmux() { calls+=("tmuxifier-tmux:$*"); }
function __go_to_window_or_session_path() { calls+=("go_to_path"); }
split_vl
assert_equals "tmuxifier-tmux:split-window -t test-session:0. -v" "${calls[0]}"
assert_equals "go_to_path" "${calls[1]}"
}
function test_split_vl_with_line_count_includes_l_flag() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_vl 20
assert_have_been_called_with \
tmuxifier-tmux "split-window -t test-session:0. -v -l 20"
}
function test_split_vl_with_line_count_and_target_pane() {
session="mysession"
window="2"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_vl 15 1
assert_have_been_called_with \
tmuxifier-tmux "split-window -t mysession:2.1 -v -l 15"
}
function test_split_vl_with_only_target_pane_empty_count() {
session="test"
window="1"
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_vl "" 2
assert_have_been_called_with tmuxifier-tmux "split-window -t test:1.2 -v"
}
function test_split_vl_always_calls_go_to_window_or_session_path() {
spy tmuxifier-tmux
spy __go_to_window_or_session_path
split_vl 10 1
assert_have_been_called_times 1 __go_to_window_or_session_path
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# synchronize_off() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_synchronize_off_uses_current_window_by_default() {
spy tmuxifier-tmux
synchronize_off
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t test-session:0 synchronize-panes off"
}
function test_synchronize_off_with_specific_window() {
spy tmuxifier-tmux
synchronize_off 2
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t test-session:2 synchronize-panes off"
}
function test_synchronize_off_with_window_name() {
spy tmuxifier-tmux
synchronize_off "editor"
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t test-session:editor synchronize-panes off"
}
function test_synchronize_off_with_different_session() {
session="mysession"
window="3"
spy tmuxifier-tmux
synchronize_off
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t mysession:3 synchronize-panes off"
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# synchronize_on() tests
#
function set_up() {
# Default session and window for tests
session="test-session"
window="0"
}
function tear_down() {
unset session window
}
function test_synchronize_on_uses_current_window_by_default() {
spy tmuxifier-tmux
synchronize_on
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t test-session:0 synchronize-panes on"
}
function test_synchronize_on_with_specific_window() {
spy tmuxifier-tmux
synchronize_on 2
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t test-session:2 synchronize-panes on"
}
function test_synchronize_on_with_window_name() {
spy tmuxifier-tmux
synchronize_on "editor"
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t test-session:editor synchronize-panes on"
}
function test_synchronize_on_with_different_session() {
session="mysession"
window="3"
spy tmuxifier-tmux
synchronize_on
assert_have_been_called_with \
tmuxifier-tmux "set-window-option -t mysession:3 synchronize-panes on"
}

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# tmux() tests
#
function test_tmux_passes_single_arg_to_tmuxifier_tmux() {
spy tmuxifier-tmux
tmux -V
assert_have_been_called_with tmuxifier-tmux "-V"
}
function test_tmux_passes_help_flag_to_tmuxifier_tmux() {
spy tmuxifier-tmux
tmux --help
assert_have_been_called_with tmuxifier-tmux "--help"
}
function test_tmux_passes_multiple_args_to_tmuxifier_tmux() {
spy tmuxifier-tmux
tmux new -s dude
assert_have_been_called_with tmuxifier-tmux "new -s dude"
}
function test_tmux_passes_complex_args_to_tmuxifier_tmux() {
spy tmuxifier-tmux
tmux new-session -d -s "my-session" -n "main"
assert_have_been_called_with \
tmuxifier-tmux "new-session -d -s my-session -n main"
}
function test_tmux_called_multiple_times() {
spy tmuxifier-tmux
tmux list-sessions
tmux list-windows
tmux list-panes
assert_have_been_called_times 3 tmuxifier-tmux
assert_have_been_called_with tmuxifier-tmux "list-sessions" 1
assert_have_been_called_with tmuxifier-tmux "list-windows" 2
assert_have_been_called_with tmuxifier-tmux "list-panes" 3
}

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Load the layout-helpers.sh library under test
source "${_root_dir}/lib/layout-helpers.sh"
#
# window_root() tests
#
function set_up() {
# Create temp directories for testing (per-test for parallel support)
_test_tmp_dir=$(mktemp -d)
_test_valid_dir="${_test_tmp_dir}/valid"
mkdir -p "$_test_valid_dir"
_test_nonexistent_dir="${_test_tmp_dir}/nonexistent"
# Reset window_root variable before each test
window_root=""
}
function tear_down() {
unset window_root
rm -rf "$_test_tmp_dir"
}
function test_window_root_sets_variable_for_existing_directory() {
# Mock __expand_path to return the valid directory
mock __expand_path echo "$_test_valid_dir"
window_root "~/some/path"
assert_same "$_test_valid_dir" "$window_root"
}
function test_window_root_does_not_set_variable_for_nonexistent_directory() {
# Mock __expand_path to return a nonexistent directory
mock __expand_path echo "$_test_nonexistent_dir"
window_root "~/nonexistent"
assert_empty "$window_root"
}
function test_window_root_calls_expand_path_with_arguments() {
spy __expand_path
# Since spy doesn't return anything, the dir check will fail
# but we can still verify __expand_path was called
window_root "~/Projects"
assert_have_been_called_with __expand_path "~/Projects"
}
function test_window_root_passes_multiple_arguments_to_expand_path() {
spy __expand_path
window_root '~/$USER/path'
assert_have_been_called_with __expand_path '~/$USER/path'
}
function test_window_root_preserves_existing_value_on_invalid_path() {
window_root="$_test_valid_dir"
mock __expand_path echo "$_test_nonexistent_dir"
window_root "~/invalid"
# Original value should be preserved since new path doesn't exist
assert_same "$_test_valid_dir" "$window_root"
}
function test_window_root_overwrites_existing_value_on_valid_path() {
local new_dir="${_test_tmp_dir}/another"
mkdir -p "$new_dir"
window_root="$_test_valid_dir"
mock __expand_path echo "$new_dir"
window_root "~/another"
assert_same "$new_dir" "$window_root"
}
function test_window_root_handles_home_directory() {
# Use actual HOME which should exist
mock __expand_path echo "$HOME"
window_root "~"
assert_same "$HOME" "$window_root"
}

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# Load the util.sh library under test
source "${_root_dir}/lib/util.sh"
#
# calling-complete() tests
#
function test_calling-complete_returns_0_with_complete_flag() {
calling-complete --complete
assert_exit_code "0"
}
function test_calling-complete_returns_0_with_complete_flag_after_arg() {
calling-complete foo --complete
assert_exit_code "0"
}
function test_calling-complete_returns_0_with_complete_flag_before_arg() {
calling-complete --complete bar
assert_exit_code "0"
}
function test_calling-complete_returns_0_with_complete_flag_between_args() {
calling-complete foo --complete bar
assert_exit_code "0"
}
function test_calling-complete_returns_1_with_no_args() {
calling-complete
assert_exit_code "1"
}
function test_calling-complete_returns_1_with_unrelated_arg() {
calling-complete foo
assert_exit_code "1"
}
function test_calling-complete_returns_1_with_multiple_unrelated_args() {
calling-complete foo bar
assert_exit_code "1"
}
function test_calling-complete_returns_1_when_complete_is_not_freestanding() {
calling-complete --complete-me
assert_exit_code "1"
}
function test_calling-complete_returns_1_when_complete_is_suffix() {
calling-complete foo--complete
assert_exit_code "1"
}

View File

@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# Load the util.sh library under test
source "${_root_dir}/lib/util.sh"
#
# calling-help() tests
#
function test_calling-help_returns_0_with_help_flag() {
calling-help --help
assert_exit_code "0"
}
function test_calling-help_returns_0_with_help_flag_after_arg() {
calling-help foo --help
assert_exit_code "0"
}
function test_calling-help_returns_0_with_help_flag_before_arg() {
calling-help --help bar
assert_exit_code "0"
}
function test_calling-help_returns_0_with_help_flag_between_args() {
calling-help foo --help bar
assert_exit_code "0"
}
function test_calling-help_returns_0_with_h_flag() {
calling-help -h
assert_exit_code "0"
}
function test_calling-help_returns_0_with_h_flag_after_arg() {
calling-help foo -h
assert_exit_code "0"
}
function test_calling-help_returns_0_with_h_flag_before_arg() {
calling-help -h bar
assert_exit_code "0"
}
function test_calling-help_returns_0_with_h_flag_between_args() {
calling-help foo -h bar
assert_exit_code "0"
}
function test_calling-help_returns_1_with_no_args() {
calling-help
assert_exit_code "1"
}
function test_calling-help_returns_1_with_unrelated_arg() {
calling-help foo
assert_exit_code "1"
}
function test_calling-help_returns_1_with_multiple_unrelated_args() {
calling-help foo bar
assert_exit_code "1"
}
function test_calling-help_returns_1_when_help_is_not_freestanding() {
calling-help --help-me
assert_exit_code "1"
}
function test_calling-help_returns_1_when_help_is_suffix() {
calling-help foo--help
assert_exit_code "1"
}
function test_calling-help_returns_1_when_h_is_not_freestanding() {
calling-help -hj
assert_exit_code "1"
}
function test_calling-help_returns_1_when_h_is_embedded_in_word() {
calling-help welcome-home
assert_exit_code "1"
}

132
tests/lib/util/vercomp_test.sh Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/env bash
# Load the util.sh library under test
source "${_root_dir}/lib/util.sh"
#
# vercomp() tests
#
# Return values:
# 0 = versions are equal
# 1 = first version is greater
# 2 = first version is less
#
# Equal versions
function test_vercomp_returns_0_for_identical_versions() {
vercomp "1.0.0" "1.0.0"
assert_exit_code "0"
}
function test_vercomp_returns_0_for_identical_two_part_versions() {
vercomp "1.2" "1.2"
assert_exit_code "0"
}
function test_vercomp_returns_0_for_identical_single_part_versions() {
vercomp "5" "5"
assert_exit_code "0"
}
function test_vercomp_returns_0_when_trailing_zeros_differ() {
vercomp "1.0" "1.0.0"
assert_exit_code "0"
}
function test_vercomp_returns_0_when_trailing_zeros_differ_reversed() {
vercomp "1.0.0" "1.0"
assert_exit_code "0"
}
function test_vercomp_returns_0_for_equal_versions_with_many_parts() {
vercomp "1.2.3.4.5" "1.2.3.4.5"
assert_exit_code "0"
}
# First version greater (returns 1)
function test_vercomp_returns_1_when_major_is_greater() {
vercomp "2.0.0" "1.0.0"
assert_exit_code "1"
}
function test_vercomp_returns_1_when_minor_is_greater() {
vercomp "1.2.0" "1.1.0"
assert_exit_code "1"
}
function test_vercomp_returns_1_when_patch_is_greater() {
vercomp "1.0.2" "1.0.1"
assert_exit_code "1"
}
function test_vercomp_returns_1_when_first_has_more_parts_and_greater() {
vercomp "1.0.1" "1.0"
assert_exit_code "1"
}
function test_vercomp_returns_1_for_double_digit_greater() {
vercomp "1.10.0" "1.9.0"
assert_exit_code "1"
}
function test_vercomp_returns_1_for_large_version_numbers() {
vercomp "100.200.300" "100.200.299"
assert_exit_code "1"
}
# First version less (returns 2)
function test_vercomp_returns_2_when_major_is_less() {
vercomp "1.0.0" "2.0.0"
assert_exit_code "2"
}
function test_vercomp_returns_2_when_minor_is_less() {
vercomp "1.1.0" "1.2.0"
assert_exit_code "2"
}
function test_vercomp_returns_2_when_patch_is_less() {
vercomp "1.0.1" "1.0.2"
assert_exit_code "2"
}
function test_vercomp_returns_2_when_second_has_more_parts_and_greater() {
vercomp "1.0" "1.0.1"
assert_exit_code "2"
}
function test_vercomp_returns_2_for_double_digit_less() {
vercomp "1.9.0" "1.10.0"
assert_exit_code "2"
}
function test_vercomp_returns_2_for_large_version_numbers() {
vercomp "100.200.299" "100.200.300"
assert_exit_code "2"
}
# Edge cases
function test_vercomp_returns_0_for_empty_strings() {
vercomp "" ""
assert_exit_code "0"
}
function test_vercomp_returns_0_for_zeros() {
vercomp "0" "0"
assert_exit_code "0"
}
function test_vercomp_returns_0_for_zero_and_zero_zero() {
vercomp "0" "0.0"
assert_exit_code "0"
}
function test_vercomp_handles_leading_zeros_in_parts() {
vercomp "1.01" "1.1"
assert_exit_code "0"
}
function test_vercomp_handles_leading_zeros_comparison() {
vercomp "1.02" "1.1"
assert_exit_code "1"
}

1
tmuxifier.tmux Executable file
View File

@@ -0,0 +1 @@
#!/usr/bin/env bash